Files
TimeTrack/templates/index_old.html
Jens Luedicke 9a79778ad6 Squashed commit of the following:
commit 1eeea9f83ad9230a5c1f7a75662770eaab0df837
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 21:15:41 2025 +0200

    Disable resuming of old time entries.

commit 3e3ec2f01cb7943622b819a19179388078ae1315
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 20:59:19 2025 +0200

    Refactor db migrations.

commit 15a51a569da36c6b7c9e01ab17b6fdbdee6ad994
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 19:58:04 2025 +0200

    Apply new style for Time Tracking view.

commit 77e5278b303e060d2b03853b06277f8aa567ae68
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 18:06:04 2025 +0200

    Allow direct registrations as a Company.

commit 188a8772757cbef374243d3a5f29e4440ddecabe
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 18:04:45 2025 +0200

    Add email invitation feature.

commit d9ebaa02aa01b518960a20dccdd5a327d82f30c6
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 17:12:32 2025 +0200

    Apply common style for Company, User, Team management pages.

commit 81149caf4d8fc6317e2ab1b4f022b32fc5aa6d22
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 16:44:32 2025 +0200

    Move export functions to own module.

commit 1a26e19338e73f8849c671471dd15cc3c1b1fe82
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 15:51:15 2025 +0200

    Split up models.py.

commit 61f1ccd10f721b0ff4dc1eccf30c7a1ee13f204d
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 12:05:28 2025 +0200

    Move utility function into own modules.

commit 84b341ed35e2c5387819a8b9f9d41eca900ae79f
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 11:44:24 2025 +0200

    Refactor auth functions use.

commit 923e311e3da5b26d85845c2832b73b7b17c48adb
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 11:35:52 2025 +0200

    Refactor route nameing and fix bugs along the way.

commit f0a5c4419c340e62a2615c60b2a9de28204d2995
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 10:34:33 2025 +0200

    Fix URL endpoints in announcement template.

commit b74d74542a1c8dc350749e4788a9464d067a88b5
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 09:25:53 2025 +0200

    Move announcements to own module.

commit 9563a28021ac46c82c04fe4649b394dbf96f92c7
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 09:16:30 2025 +0200

    Combine Company view and edit templates.

commit 6687c373e681d54e4deab6b2582fed5cea9aadf6
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 08:17:42 2025 +0200

    Move Users, Company and System Administration to own modules.

commit 8b7894a2e3eb84bb059f546648b6b9536fea724e
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 07:40:57 2025 +0200

    Move Teams and Projects to own modules.

commit d11bf059d99839ecf1f5d7020b8c8c8a2454c00b
Author: Jens Luedicke <jens@luedicke.me>
Date:   Mon Jul 7 07:09:33 2025 +0200

    Move Tasks and Sprints to own modules.
2025-07-07 21:16:36 +02:00

938 lines
37 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "layout.html" %}
{% block content %}
{% if not g.user %}
<!-- Decadent Splash Page -->
<div class="splash-container">
<!-- Hero Section -->
<section class="splash-hero">
<div class="hero-content">
<h1 class="hero-title">Transform Your Productivity</h1>
<p class="hero-subtitle">Experience the future of time management with {{ g.branding.app_name if g.branding else 'TimeTrack' }}'s intelligent tracking system</p>
<div class="cta-buttons">
<a href="{{ url_for('register') }}" class="btn-primary">Get Started Free</a>
<a href="{{ url_for('login') }}" class="btn-secondary">Sign In</a>
</div>
</div>
<div class="hero-visual">
<div class="floating-clock">
<div class="clock-face">
<div class="hour-hand"></div>
<div class="minute-hand"></div>
<div class="second-hand"></div>
</div>
</div>
</div>
</section>
<!-- Features Grid -->
<section class="features-grid">
<h2 class="section-title">Powerful Features for Modern Teams</h2>
<div class="feature-cards">
<div class="feature-card">
<div class="feature-icon"></div>
<h3>Lightning Fast</h3>
<p>Start tracking in seconds with our intuitive one-click interface</p>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<h3>Advanced Analytics</h3>
<p>Gain insights with comprehensive reports and visual dashboards</p>
</div>
<div class="feature-card">
<div class="feature-icon">🏃‍♂️</div>
<h3>Sprint Management</h3>
<p>Organize work into sprints with agile project tracking</p>
</div>
<div class="feature-card">
<div class="feature-icon">👥</div>
<h3>Team Collaboration</h3>
<p>Manage teams, projects, and resources all in one place</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔒</div>
<h3>Enterprise Security</h3>
<p>Bank-level encryption with role-based access control</p>
</div>
<div class="feature-card">
<div class="feature-icon">🌐</div>
<h3>Multi-Company Support</h3>
<p>Perfect for agencies managing multiple client accounts</p>
</div>
</div>
</section>
<!-- Why Choose Section -->
<section class="statistics">
<h2 class="section-title">Why Choose {{ g.branding.app_name if g.branding else 'TimeTrack' }}?</h2>
<div class="stat-item">
<div class="stat-number">100%</div>
<div class="stat-label">Free & Open Source</div>
</div>
<div class="stat-item">
<div class="stat-number"></div>
<div class="stat-label">Unlimited Tracking</div>
</div>
<div class="stat-item">
<div class="stat-number">0</div>
<div class="stat-label">Hidden Fees</div>
</div>
<div class="stat-item">
<div class="stat-number">24/7</div>
<div class="stat-label">Always Available</div>
</div>
</section>
<!-- Getting Started Section -->
<section class="testimonials">
<h2 class="section-title">Get Started in Minutes</h2>
<div class="testimonial-grid">
<div class="testimonial-card">
<div class="feature-icon">1</div>
<h3>Sign Up</h3>
<p>Create your free account in seconds. No credit card required.</p>
</div>
<div class="testimonial-card">
<div class="feature-icon">2</div>
<h3>Set Up Your Workspace</h3>
<p>Add your company, teams, and projects to organize your time tracking.</p>
</div>
<div class="testimonial-card">
<div class="feature-icon">3</div>
<h3>Start Tracking</h3>
<p>Click "Arrive" to start tracking, "Leave" when done. It's that simple!</p>
</div>
</div>
</section>
<!-- Open Source Section -->
<section class="pricing">
<h2 class="section-title">Forever Free, Forever Open</h2>
<div class="pricing-cards">
<div class="pricing-card featured">
<div class="badge">100% Free</div>
<h3>{{ g.branding.app_name if g.branding else 'TimeTrack' }} Community</h3>
<div class="price">$0<span>/forever</span></div>
<ul class="pricing-features">
<li>✓ Unlimited users</li>
<li>✓ All features included</li>
<li>✓ Time tracking & analytics</li>
<li>✓ Sprint management</li>
<li>✓ Team collaboration</li>
<li>✓ Project management</li>
<li>✓ Self-hosted option</li>
<li>✓ No restrictions</li>
</ul>
<a href="{{ url_for('register') }}" class="btn-pricing">Get Started Free</a>
</div>
</div>
<p style="text-align: center; margin-top: 2rem; color: #666;">
The software {{ g.branding.app_name if g.branding else 'TimeTrack' }} runs is open source software.<br />
Host it yourself or use our free hosted version.<br />
The source is available on GitHub:
<a href="https://github.com/nullmedium/TimeTrack" target="_blank">https://github.com/nullmedium/TimeTrack</a>
</p>
</section>
<!-- Final CTA -->
<section class="final-cta">
<h2>Ready to Take Control of Your Time?</h2>
<p>Start tracking your time effectively today - no strings attached</p>
<a href="{{ url_for('register') }}" class="btn-primary large">Create Free Account</a>
</section>
</div>
{% else %}
<!-- Include the modern time tracking interface from time_tracking.html -->
<div class="time-tracking-container">
<!-- Header Section -->
<div class="page-header">
<div class="header-content">
<div class="header-left">
<h1 class="page-title">
<span class="page-icon">⏱️</span>
Time Tracking
</h1>
<p class="page-subtitle">Track your work hours efficiently</p>
</div>
<div class="header-actions">
<button id="manual-entry-btn" class="btn btn-secondary">
<span class="icon">📝</span>
Manual Entry
</button>
<a href="{{ url_for('analytics') }}" class="btn btn-secondary">
<span class="icon">📊</span>
View Analytics
</a>
</div>
</div>
</div>
<!-- Timer Section -->
<div class="timer-section">
{% if active_entry %}
<!-- Active Timer -->
<div class="timer-card active">
<div class="timer-display">
<div class="timer-value" id="timer"
data-start="{{ active_entry.arrival_time.timestamp() }}"
data-breaks="{{ active_entry.total_break_duration }}"
data-paused="{{ 'true' if active_entry.is_paused else 'false' }}">
00:00:00
</div>
<div class="timer-status">
{% if active_entry.is_paused %}
<span class="status-badge paused">On Break</span>
{% else %}
<span class="status-badge active">Working</span>
{% endif %}
</div>
</div>
<div class="timer-info">
<div class="info-row">
<span class="info-label">Started:</span>
<span class="info-value">{{ active_entry.arrival_time|format_datetime }}</span>
</div>
{% if active_entry.project %}
<div class="info-row">
<span class="info-label">Project:</span>
<span class="info-value project-badge" style="background-color: {{ active_entry.project.color or '#667eea' }}">
{{ active_entry.project.code }} - {{ active_entry.project.name }}
</span>
</div>
{% endif %}
{% if active_entry.task %}
<div class="info-row">
<span class="info-label">Task:</span>
<span class="info-value task-badge">
{{ active_entry.task.title }}
</span>
</div>
{% endif %}
{% if active_entry.notes %}
<div class="info-row">
<span class="info-label">Notes:</span>
<span class="info-value">{{ active_entry.notes }}</span>
</div>
{% endif %}
{% if active_entry.is_paused %}
<div class="info-row">
<span class="info-label">Break started:</span>
<span class="info-value">{{ active_entry.pause_start_time|format_time }}</span>
</div>
{% endif %}
{% if active_entry.total_break_duration > 0 %}
<div class="info-row">
<span class="info-label">Total breaks:</span>
<span class="info-value">{{ active_entry.total_break_duration|format_duration }}</span>
</div>
{% endif %}
</div>
<div class="timer-actions">
<button id="pause-btn" class="btn {% if active_entry.is_paused %}btn-success{% else %}btn-warning{% endif %}"
data-id="{{ active_entry.id }}">
{% if active_entry.is_paused %}
<span class="icon">▶️</span>
Resume Work
{% else %}
<span class="icon">⏸️</span>
Take Break
{% endif %}
</button>
<button id="leave-btn" class="btn btn-danger" data-id="{{ active_entry.id }}">
<span class="icon">⏹️</span>
Stop Working
</button>
</div>
</div>
{% else %}
<!-- Inactive Timer -->
<div class="timer-card inactive">
<div class="start-work-container">
<h2>Start Tracking Time</h2>
<p>Select a project and task to begin tracking your work</p>
<form id="start-work-form" class="modern-form">
<div class="form-row">
<div class="form-group">
<label for="project-select" class="form-label">
Project <span class="optional-badge">Optional</span>
</label>
<select id="project-select" name="project_id" class="form-control">
<option value="">No specific project</option>
{% for project in available_projects %}
<option value="{{ project.id }}" data-color="{{ project.color or '#667eea' }}">
{{ project.code }} - {{ project.name }}
</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="task-select" class="form-label">
Task <span class="optional-badge">Optional</span>
</label>
<select id="task-select" name="task_id" class="form-control" disabled>
<option value="">Select a project first</option>
</select>
</div>
</div>
<div class="form-group">
<label for="work-notes" class="form-label">
Notes <span class="optional-badge">Optional</span>
</label>
<textarea id="work-notes" name="notes" class="form-control"
rows="2" placeholder="What are you working on?"></textarea>
</div>
<div class="form-actions">
<button type="submit" id="arrive-btn" class="btn btn-primary btn-large">
<span class="icon">▶️</span>
Start Working
</button>
</div>
</form>
</div>
</div>
{% endif %}
</div>
<!-- Quick Stats -->
{% if today_hours is defined %}
<div class="stats-section">
<div class="stat-card">
<div class="stat-value">{{ today_hours|format_duration }}</div>
<div class="stat-label">Today</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ week_hours|format_duration }}</div>
<div class="stat-label">This Week</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ month_hours|format_duration }}</div>
<div class="stat-label">This Month</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ active_projects|length if active_projects else 0 }}</div>
<div class="stat-label">Active Projects</div>
</div>
</div>
{% endif %}
<!-- Recent Entries -->
<div class="entries-section">
<div class="section-header">
<h2 class="section-title">
<span class="icon">📋</span>
Recent Time Entries
</h2>
<div class="view-toggle">
<button class="toggle-btn active" data-view="list">
<span class="icon">📝</span>
List
</button>
<button class="toggle-btn" data-view="grid">
<span class="icon">📊</span>
Grid
</button>
</div>
</div>
<!-- List View -->
<div id="list-view" class="view-container active">
{% if history %}
<div class="entries-table-container">
<table class="entries-table">
<thead>
<tr>
<th>Date</th>
<th>Time</th>
<th>Project / Task</th>
<th>Duration</th>
<th>Break</th>
<th>Notes</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entry in history %}
<tr data-entry-id="{{ entry.id }}" class="entry-row">
<td>
<div class="date-cell">
<span class="date-day">{{ entry.arrival_time.strftime('%d') }}</span>
<span class="date-month">{{ entry.arrival_time.strftime('%b') }}</span>
</div>
</td>
<td>
<div class="time-cell">
<span class="time-start">{{ entry.arrival_time|format_time }}</span>
<span class="time-separator"></span>
<span class="time-end">{{ entry.departure_time|format_time if entry.departure_time else 'Active' }}</span>
</div>
</td>
<td>
<div class="project-task-cell">
{% if entry.project %}
<span class="project-tag" style="background-color: {{ entry.project.color or '#667eea' }}">
{{ entry.project.code }}
</span>
{% endif %}
{% if entry.task %}
<span class="task-name">{{ entry.task.title }}</span>
{% elif entry.project %}
<span class="project-name">{{ entry.project.name }}</span>
{% else %}
<span class="no-project">No project</span>
{% endif %}
</div>
</td>
<td>
<span class="duration-badge">
{{ entry.duration|format_duration if entry.duration is not none else 'In progress' }}
</span>
</td>
<td>
<span class="break-duration">
{{ entry.total_break_duration|format_duration if entry.total_break_duration else '-' }}
</span>
</td>
<td>
<span class="notes-preview" title="{{ entry.notes or '' }}">
{{ entry.notes[:30] + '...' if entry.notes and entry.notes|length > 30 else entry.notes or '-' }}
</span>
</td>
<td>
<div class="actions-cell">
{% if entry.departure_time and not active_entry %}
<button class="btn-icon resume-work-btn" data-id="{{ entry.id }}" title="Resume">
<span class="icon">🔄</span>
</button>
{% endif %}
<button class="btn-icon edit-entry-btn" data-id="{{ entry.id }}" title="Edit">
<span class="icon">✏️</span>
</button>
<button class="btn-icon delete-entry-btn" data-id="{{ entry.id }}" title="Delete">
<span class="icon">🗑️</span>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
<div class="empty-icon">📭</div>
<h3>No time entries yet</h3>
<p>Start tracking your time to see entries here</p>
</div>
{% endif %}
</div>
<!-- Grid View -->
<div id="grid-view" class="view-container">
<div class="entries-grid">
{% for entry in history %}
<div class="entry-card" data-entry-id="{{ entry.id }}">
<div class="entry-header">
<div class="entry-date">
{{ entry.arrival_time.strftime('%d %b %Y') }}
</div>
<div class="entry-duration">
{{ entry.duration|format_duration if entry.duration is not none else 'Active' }}
</div>
</div>
<div class="entry-body">
{% if entry.project %}
<div class="entry-project" style="border-left-color: {{ entry.project.color or '#667eea' }}">
<strong>{{ entry.project.code }}</strong> - {{ entry.project.name }}
</div>
{% endif %}
{% if entry.task %}
<div class="entry-task">
<span class="icon">📋</span> {{ entry.task.title }}
</div>
{% endif %}
<div class="entry-time">
<span class="icon">🕐</span>
{{ entry.arrival_time|format_time }} - {{ entry.departure_time|format_time if entry.departure_time else 'Active' }}
</div>
{% if entry.notes %}
<div class="entry-notes">
<span class="icon">📝</span>
{{ entry.notes }}
</div>
{% endif %}
</div>
<div class="entry-footer">
<button class="btn-sm edit-entry-btn" data-id="{{ entry.id }}">Edit</button>
<button class="btn-sm btn-danger delete-entry-btn" data-id="{{ entry.id }}">Delete</button>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Edit Entry Modal -->
<div id="edit-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3>Edit Time Entry</h3>
<form id="edit-entry-form">
<input type="hidden" id="edit-entry-id">
<div class="form-group">
<label for="edit-arrival-date">Arrival Date:</label>
<input type="date" id="edit-arrival-date" required>
<small>Format: YYYY-MM-DD</small>
</div>
<div class="form-group">
<label for="edit-arrival-time">Arrival Time (24h):</label>
<input type="time" id="edit-arrival-time" required step="1">
<small>Format: HH:MM (24-hour)</small>
</div>
<div class="form-group">
<label for="edit-departure-date">Departure Date:</label>
<input type="date" id="edit-departure-date">
<small>Format: YYYY-MM-DD</small>
</div>
<div class="form-group">
<label for="edit-departure-time">Departure Time (24h):</label>
<input type="time" id="edit-departure-time" step="1">
<small>Format: HH:MM (24-hour)</small>
</div>
<button type="submit" class="btn">Save Changes</button>
</form>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div id="delete-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3>Confirm Deletion</h3>
<p>Are you sure you want to delete this time entry? This action cannot be undone.</p>
<input type="hidden" id="delete-entry-id">
<div class="modal-actions">
<button id="confirm-delete" class="btn btn-danger">Delete</button>
<button id="cancel-delete" class="btn">Cancel</button>
</div>
</div>
</div>
<!-- Manual Time Entry Modal -->
<div id="manual-entry-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3>Add Manual Time Entry</h3>
<form id="manual-entry-form">
<div class="form-group">
<label for="manual-project-select">Project (Optional):</label>
<select id="manual-project-select" name="project_id">
<option value="">No specific project</option>
{% for project in available_projects %}
<option value="{{ project.id }}">{{ project.code }} - {{ project.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="manual-start-date">Start Date:</label>
<input type="date" id="manual-start-date" required>
</div>
<div class="form-group">
<label for="manual-start-time">Start Time:</label>
<input type="time" id="manual-start-time" required step="1">
</div>
<div class="form-group">
<label for="manual-end-date">End Date:</label>
<input type="date" id="manual-end-date" required>
</div>
<div class="form-group">
<label for="manual-end-time">End Time:</label>
<input type="time" id="manual-end-time" required step="1">
</div>
<div class="form-group">
<label for="manual-break-minutes">Break Duration (minutes):</label>
<input type="number" id="manual-break-minutes" min="0" value="0" placeholder="Break time in minutes">
</div>
<div class="form-group">
<label for="manual-notes">Notes (Optional):</label>
<textarea id="manual-notes" name="notes" rows="3" placeholder="Description of work performed"></textarea>
</div>
<button type="submit" class="btn">Add Entry</button>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Manual entry functionality
document.getElementById('manual-entry-btn').addEventListener('click', function() {
// Set default dates to today
const today = new Date().toISOString().split('T')[0];
document.getElementById('manual-start-date').value = today;
document.getElementById('manual-end-date').value = today;
document.getElementById('manual-entry-modal').style.display = 'block';
});
// Manual entry form submission
document.getElementById('manual-entry-form').addEventListener('submit', function(e) {
e.preventDefault();
const projectId = document.getElementById('manual-project-select').value || null;
const startDate = document.getElementById('manual-start-date').value;
const startTime = document.getElementById('manual-start-time').value;
const endDate = document.getElementById('manual-end-date').value;
const endTime = document.getElementById('manual-end-time').value;
const breakMinutes = parseInt(document.getElementById('manual-break-minutes').value) || 0;
const notes = document.getElementById('manual-notes').value;
// Validate end time is after start time
const startDateTime = new Date(`${startDate}T${startTime}`);
const endDateTime = new Date(`${endDate}T${endTime}`);
if (endDateTime <= startDateTime) {
alert('End time must be after start time');
return;
}
// Send request to create manual entry
fetch('/api/manual-entry', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
project_id: projectId,
start_date: startDate,
start_time: startTime,
end_date: endDate,
end_time: endTime,
break_minutes: breakMinutes,
notes: notes
}),
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('manual-entry-modal').style.display = 'none';
location.reload(); // Refresh to show new entry
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while adding the manual entry');
});
});
// Edit entry functionality
document.querySelectorAll('.edit-entry-btn').forEach(button => {
button.addEventListener('click', function() {
const entryId = this.getAttribute('data-id');
const row = document.querySelector(`tr[data-entry-id="${entryId}"]`);
const cells = row.querySelectorAll('td');
// Get date and time from the row
const dateStr = cells[0].textContent.trim();
const arrivalTimeStr = cells[2].textContent.trim(); // arrival time is now in column 2
const departureTimeStr = cells[3].textContent.trim(); // departure time is now in column 3
// Set values in the form
document.getElementById('edit-entry-id').value = entryId;
document.getElementById('edit-arrival-date').value = dateStr;
// Format time for input (HH:MM format)
document.getElementById('edit-arrival-time').value = arrivalTimeStr.substring(0, 5);
if (departureTimeStr && departureTimeStr !== 'Active') {
document.getElementById('edit-departure-date').value = dateStr;
document.getElementById('edit-departure-time').value = departureTimeStr.substring(0, 5);
} else {
document.getElementById('edit-departure-date').value = '';
document.getElementById('edit-departure-time').value = '';
}
// Show the modal
document.getElementById('edit-modal').style.display = 'block';
});
});
// Delete entry functionality
document.querySelectorAll('.delete-entry-btn').forEach(button => {
button.addEventListener('click', function() {
const entryId = this.getAttribute('data-id');
document.getElementById('delete-entry-id').value = entryId;
document.getElementById('delete-modal').style.display = 'block';
});
});
// Close modals when clicking the X
document.querySelectorAll('.close').forEach(closeBtn => {
closeBtn.addEventListener('click', function() {
this.closest('.modal').style.display = 'none';
});
});
// Close modals when clicking outside
window.addEventListener('click', function(event) {
if (event.target.classList.contains('modal')) {
event.target.style.display = 'none';
}
});
// Cancel delete
document.getElementById('cancel-delete').addEventListener('click', function() {
document.getElementById('delete-modal').style.display = 'none';
});
// Confirm delete
document.getElementById('confirm-delete').addEventListener('click', function() {
const entryId = document.getElementById('delete-entry-id').value;
fetch(`/api/delete/${entryId}`, {
method: 'DELETE',
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove the row from the table
document.querySelector(`tr[data-entry-id="${entryId}"]`).remove();
// Close the modal
document.getElementById('delete-modal').style.display = 'none';
// Show success message
alert('Entry deleted successfully');
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while deleting the entry');
});
});
// Submit edit form
document.getElementById('edit-entry-form').addEventListener('submit', function(e) {
e.preventDefault();
const entryId = document.getElementById('edit-entry-id').value;
const arrivalDate = document.getElementById('edit-arrival-date').value;
const arrivalTime = document.getElementById('edit-arrival-time').value;
const departureDate = document.getElementById('edit-departure-date').value || '';
const departureTime = document.getElementById('edit-departure-time').value || '';
// Ensure we have seconds in the time strings
const arrivalTimeWithSeconds = arrivalTime.includes(':') ?
(arrivalTime.split(':').length === 2 ? arrivalTime + ':00' : arrivalTime) :
arrivalTime + ':00:00';
// Format datetime strings for the API (ISO 8601: YYYY-MM-DDTHH:MM:SS)
const arrivalDateTime = `${arrivalDate}T${arrivalTimeWithSeconds}`;
let departureDateTime = null;
if (departureDate && departureTime) {
const departureTimeWithSeconds = departureTime.includes(':') ?
(departureTime.split(':').length === 2 ? departureTime + ':00' : departureTime) :
departureTime + ':00:00';
departureDateTime = `${departureDate}T${departureTimeWithSeconds}`;
}
console.log('Sending update:', {
arrival_time: arrivalDateTime,
departure_time: departureDateTime
});
// Send update request
fetch(`/api/update/${entryId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
arrival_time: arrivalDateTime,
departure_time: departureDateTime
}),
})
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.message || 'Server error');
});
}
return response.json();
})
.then(data => {
if (data.success) {
// Close the modal
document.getElementById('edit-modal').style.display = 'none';
// Refresh the page to show updated data
location.reload();
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while updating the entry: ' + error.message);
});
});
});
</script>
<style>
.start-work-form {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
margin-bottom: 1rem;
}
.start-work-form .form-group {
margin-bottom: 1rem;
}
.start-work-form label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #333;
}
.start-work-form select,
.start-work-form textarea {
width: 100%;
padding: 0.75rem;
border: 2px solid #e9ecef;
border-radius: 6px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
.start-work-form select:focus,
.start-work-form textarea:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1);
}
.project-info {
color: #4CAF50;
font-size: 0.9rem;
margin-top: 0.5rem;
}
.project-tag {
background: #4CAF50;
color: white;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 500;
margin-right: 0.5rem;
}
.project-tag + small {
color: #666;
font-size: 0.85rem;
}
.time-history td {
vertical-align: middle;
}
.time-history .project-tag + small {
display: block;
margin-top: 0.25rem;
}
.manual-entry-btn {
background: #17a2b8;
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 6px;
font-size: 1rem;
cursor: pointer;
margin-left: 1rem;
transition: background-color 0.2s ease;
}
.manual-entry-btn:hover {
background: #138496;
}
.modal {
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 5% auto;
padding: 20px;
border: 1px solid #888;
border-radius: 8px;
width: 500px;
max-width: 90%;
max-height: 80%;
overflow-y: auto;
}
.modal .form-group {
margin-bottom: 1rem;
}
.modal label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #333;
}
.modal input,
.modal select,
.modal textarea {
width: 100%;
padding: 0.75rem;
border: 2px solid #e9ecef;
border-radius: 6px;
font-size: 1rem;
box-sizing: border-box;
}
.modal input:focus,
.modal select:focus,
.modal textarea:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1);
}
</style>
{% endif %}
{% endblock %}