Mar 20 2026: refactor 2

This commit is contained in:
2026-03-20 17:14:58 -04:00
parent 7caf12a760
commit f6ad3bd930
49 changed files with 9173 additions and 9332 deletions
+2 -2
View File
@@ -212,7 +212,7 @@
with a fixed distance of 0.010 miles.
</div>
<form id="manualAttendanceForm" method="POST" action="{{ url_for('save_manual_attendance') }}">
<form id="manualAttendanceForm" method="POST" action="{{ url_for('attendance.save_manual_attendance') }}">
<!-- Employee Selection with Autocomplete -->
<div class="form-group">
<label for="employee_search">
@@ -307,7 +307,7 @@
<!-- Form Actions -->
<div class="form-actions">
<a href="{{ url_for('attendance_report') }}" class="btn btn-secondary">
<a href="{{ url_for('attendance.attendance_report') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel
</a>
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -44,95 +44,95 @@
<div class="sidebar-menu">
<div class="menu-section">
<div class="menu-items">
<a href="{{ url_for('dashboard') }}" class="menu-item">
<a href="{{ url_for('dashboard.dashboard') }}" class="menu-item">
<i class="fas fa-tachometer-alt"></i>
<span class="menu-text">Dashboard</span>
</a>
{% if session.role == 'admin' %}
<a href="{{ url_for('create_qr_code') }}" class="menu-item">
<a href="{{ url_for('qr_codes.create_qr_code') }}" class="menu-item">
<i class="fas fa-plus"></i>
<span class="menu-text">Create QR</span>
</a>
<a
href="{{ url_for('projects') }}"
href="{{ url_for('projects.projects') }}"
class="menu-item {% if request.endpoint in ['projects', 'create_project', 'edit_project'] %}active{% endif %}"
>
<i class="fas fa-folder"></i>
<span class="menu-text">Projects</span>
</a>
<a href="{{ url_for('users') }}" class="menu-item">
<a href="{{ url_for('users.users') }}" class="menu-item">
<i class="fas fa-user-cog"></i>
<span class="menu-text">Users</span>
</a>
<a href="{{ url_for('employees') }}" class="menu-item">
<a href="{{ url_for('employees.employees') }}" class="menu-item">
<i class="fas fa-user"></i>
<span class="menu-text">Employees</span>
</a>
<a href="{{ url_for('attendance_report') }}" class="menu-item">
<a href="{{ url_for('attendance.attendance_report') }}" class="menu-item">
<i class="fas fa-chart-line"></i>
<span class="menu-text">Reports</span>
</a>
<a href="{{ url_for('verification_review') }}"
<a href="{{ url_for('attendance.verification_review') }}"
class="menu-item {% if request.endpoint == 'verification_review' %}active{% endif %}">
<i class="fas fa-camera-retro"></i>
<span class="menu-text">Verification Review</span>
</a>
<a href="{{ url_for('time_attendance_dashboard') }}"
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}"
class="menu-item {% if request.endpoint and (request.endpoint.startswith('time_attendance') or request.endpoint.startswith('import_time_attendance')) %}active{% endif %}">
<i class="fas fa-clock"></i>
<span class="menu-text">Time Attendance</span>
</a>
<a href="{{ url_for('payroll_dashboard') }}" class="menu-item">
<a href="{{ url_for('payroll.payroll_dashboard') }}" class="menu-item">
<i class="fas fa-calculator"></i>
<span class="menu-text">Payroll</span>
</a>
<a
href="{{ url_for('qr_statistics') }}"
href="{{ url_for('statistics.qr_statistics') }}"
class="menu-item {% if request.endpoint == 'qr_statistics' %}active{% endif %}"
>
<i class="fas fa-chart-pie"></i>
<span class="menu-text">Statistics</span>
</a>
<a
href="{{ url_for('admin_logs') }}"
href="{{ url_for('admin.admin_logs') }}"
class="menu-item {% if request.endpoint == 'admin_logs' %}active{% endif %}"
>
<i class="fas fa-clipboard-list"></i>
<span class="menu-text">System Logs</span>
</a>
{% elif session.role in ['payroll', 'accounting'] %}
<a href="{{ url_for('employees') }}" class="menu-item">
<a href="{{ url_for('employees.employees') }}" class="menu-item">
<i class="fas fa-user"></i>
<span class="menu-text">Employees</span>
</a>
<a href="{{ url_for('attendance_report') }}" class="menu-item">
<a href="{{ url_for('attendance.attendance_report') }}" class="menu-item">
<i class="fas fa-chart-line"></i>
<span class="menu-text">Reports</span>
</a>
<a href="{{ url_for('verification_review') }}"
<a href="{{ url_for('attendance.verification_review') }}"
class="menu-item {% if request.endpoint == 'verification_review' %}active{% endif %}">
<i class="fas fa-camera-retro"></i>
<span class="menu-text">Verification Review</span>
</a>
<a href="{{ url_for('time_attendance_dashboard') }}"
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}"
class="menu-item {% if request.endpoint and (request.endpoint.startswith('time_attendance') or request.endpoint.startswith('import_time_attendance')) %}active{% endif %}">
<i class="fas fa-clock"></i>
<span class="menu-text">Time Attendance</span>
</a>
<!--
<a href="{{ url_for('payroll_dashboard') }}" class="menu-item">
<a href="{{ url_for('payroll.payroll_dashboard') }}" class="menu-item">
<i class="fas fa-calculator"></i>
<span class="menu-text">Payroll</span>
</a>
-->
{% elif session.role in ['project_manager'] %}
<a href="{{ url_for('attendance_report') }}" class="menu-item">
<a href="{{ url_for('attendance.attendance_report') }}" class="menu-item">
<i class="fas fa-chart-line"></i>
<span class="menu-text">Reports</span>
</a>
{% endif %}
<a href="{{ url_for('profile') }}" class="menu-item">
<a href="{{ url_for('auth.profile') }}" class="menu-item">
<i class="fas fa-user"></i>
<span class="menu-text">Profile</span>
</a>
@@ -142,7 +142,7 @@
<!-- Bottom Section -->
<div class="sidebar-bottom">
<div class="menu-items">
<a href="{{ url_for('logout') }}" class="menu-item logout">
<a href="{{ url_for('auth.logout') }}" class="menu-item logout">
<i class="fas fa-sign-out-alt"></i>
<span class="menu-text">Logout</span>
</a>
+5 -5
View File
@@ -58,7 +58,7 @@
</div>
<h3>Download Template</h3>
<p>Use our pre-formatted template to ensure proper column structure:</p>
<a href="{{ url_for('download_qr_import_template') }}" class="btn btn-primary">
<a href="{{ url_for('qr_codes.download_qr_import_template') }}" class="btn btn-primary">
<i class="fas fa-file-excel"></i>
Download Excel Template
</a>
@@ -128,7 +128,7 @@
</h2>
</div>
<div class="import-body">
<form id="importForm" method="POST" enctype="multipart/form-data" action="{{ url_for('import_bulk_qr_codes') }}">
<form id="importForm" method="POST" enctype="multipart/form-data" action="{{ url_for('qr_codes.import_bulk_qr_codes') }}">
<!-- File Upload Area -->
<div class="file-upload-area" id="fileUploadArea">
<div class="upload-icon">
@@ -171,7 +171,7 @@
<!-- Submit Button -->
<div class="form-actions">
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">
<a href="{{ url_for('dashboard.dashboard') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i>
Cancel
</a>
@@ -233,7 +233,7 @@
<h3>Validation Successful!</h3>
<p>All {{ validation_result.valid_rows }} records are valid and ready to import.</p>
</div>
<form method="POST" action="{{ url_for('import_bulk_qr_codes') }}">
<form method="POST" action="{{ url_for('qr_codes.import_bulk_qr_codes') }}">
<input type="hidden" name="proceed_import" value="true">
<button type="submit" class="btn btn-success">
<i class="fas fa-check"></i>
@@ -321,7 +321,7 @@
<h3>Import Successful!</h3>
<p>Successfully imported {{ import_result.imported_records }} QR codes.</p>
</div>
<a href="{{ url_for('dashboard') }}" class="btn btn-primary">
<a href="{{ url_for('dashboard.dashboard') }}" class="btn btn-primary">
<i class="fas fa-eye"></i>
View QR Codes
</a>
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -171,7 +171,7 @@
<div class="employees-header">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('employees') }}" class="back-button">
<a href="{{ url_for('employees.employees') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Employees
</a>
@@ -287,7 +287,7 @@
<!-- Form Actions -->
<div class="form-actions">
<a href="{{ url_for('employees') }}" class="btn btn-secondary">
<a href="{{ url_for('employees.employees') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel
</a>
+2 -2
View File
@@ -14,7 +14,7 @@
<p>Create a new project to organize your QR codes</p>
</div>
<div class="header-actions">
<a href="{{ url_for('projects') }}" class="btn btn-secondary">
<a href="{{ url_for('projects.projects') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i>
Back to Projects
</a>
@@ -71,7 +71,7 @@
<!-- Form Actions -->
<div style="display: flex; justify-content: flex-start; gap: 1rem; margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid #e5e7eb;">
<a href="{{ url_for('projects') }}" class="btn btn-secondary" style="background: #f1f5f9; color: #475569; padding: 0.75rem 1.5rem; border-radius: 0.5rem; text-decoration: none; font-weight: 500; display: inline-flex; align-items: center; gap: 0.5rem; transition: all 0.2s ease-in-out; border: 1px solid #cbd5e1;">
<a href="{{ url_for('projects.projects') }}" class="btn btn-secondary" style="background: #f1f5f9; color: #475569; padding: 0.75rem 1.5rem; border-radius: 0.5rem; text-decoration: none; font-weight: 500; display: inline-flex; align-items: center; gap: 0.5rem; transition: all 0.2s ease-in-out; border: 1px solid #cbd5e1;">
<i class="fas fa-arrow-left"></i>
Cancel
</a>
+1407 -1407
View File
File diff suppressed because it is too large Load Diff
+669 -669
View File
File diff suppressed because it is too large Load Diff
+2070 -2070
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -144,7 +144,7 @@
</p>
</div>
<form method="POST" action="{{ url_for('edit_attendance', record_id=attendance_record.id) }}">
<form method="POST" action="{{ url_for('attendance.edit_attendance', record_id=attendance_record.id) }}">
<!-- Audit Note Section -->
<div class="audit-note-section">
@@ -299,7 +299,7 @@
Update Record
</button>
{% endif %}
<a href="{{ url_for('attendance_report') }}" class="btn btn-secondary">
<a href="{{ url_for('attendance.attendance_report') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel
</a>
+2 -2
View File
@@ -166,7 +166,7 @@
<div class="employees-header">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('employees') }}" class="back-button">
<a href="{{ url_for('employees.employees') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Employees
</a>
@@ -291,7 +291,7 @@
<!-- Form Actions -->
<div class="form-actions">
<a href="{{ url_for('employees') }}" class="btn btn-secondary">
<a href="{{ url_for('employees.employees') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel
</a>
+2 -2
View File
@@ -14,7 +14,7 @@
<p>Update project information and settings</p>
</div>
<div class="header-actions">
<a href="{{ url_for('projects') }}" class="btn btn-secondary">
<a href="{{ url_for('projects.projects') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i>
Back to Projects
</a>
@@ -108,7 +108,7 @@
<!-- Form Actions -->
<div style="display: flex; justify-content: flex-start; gap: 1rem; margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid #e5e7eb;">
<a href="{{ url_for('projects') }}" class="btn btn-secondary" style="background: #f1f5f9; color: #475569; padding: 0.75rem 1.5rem; border-radius: 0.5rem; text-decoration: none; font-weight: 500; display: inline-flex; align-items: center; gap: 0.5rem; transition: all 0.2s ease-in-out; border: 1px solid #cbd5e1;">
<a href="{{ url_for('projects.projects') }}" class="btn btn-secondary" style="background: #f1f5f9; color: #475569; padding: 0.75rem 1.5rem; border-radius: 0.5rem; text-decoration: none; font-weight: 500; display: inline-flex; align-items: center; gap: 0.5rem; transition: all 0.2s ease-in-out; border: 1px solid #cbd5e1;">
<i class="fas fa-arrow-left"></i>
Cancel
</a>
+1453 -1453
View File
File diff suppressed because it is too large Load Diff
+728 -728
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -331,7 +331,7 @@
<div class="employees-header" style="margin-bottom: 1rem;">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('employees') }}" class="back-button">
<a href="{{ url_for('employees.employees') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Employees
</a>
+10 -10
View File
@@ -11,7 +11,7 @@ extra_head %}
<div class="employees-header">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('dashboard') }}" class="back-button">
<a href="{{ url_for('dashboard.dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Dashboard
</a>
@@ -25,7 +25,7 @@ extra_head %}
<div class="header-actions">
{% if session.role in ['admin', 'payroll'] %}
<a href="{{ url_for('create_employee') }}" class="btn btn-primary">
<a href="{{ url_for('employees.create_employee') }}" class="btn btn-primary">
<i class="fas fa-plus"></i>
Add Employee
</a>
@@ -95,7 +95,7 @@ extra_head %}
</button>
{% if search %}
<a
href="{{ url_for('employees') }}"
href="{{ url_for('employees.employees') }}"
class="clear-search-btn"
title="Clear search"
>
@@ -170,7 +170,7 @@ extra_head %}
<td class="actions">
<div class="action-buttons">
<a
href="{{ url_for('employee_detail', employee_index=employee.index) }}"
href="{{ url_for('employees.employee_detail', employee_index=employee.index) }}"
class="btn btn-sm btn-info"
title="View Details"
>
@@ -179,7 +179,7 @@ extra_head %}
{% if session.role in ['admin', 'payroll'] %}
<a
href="{{ url_for('edit_employee', employee_index=employee.index) }}"
href="{{ url_for('employees.edit_employee', employee_index=employee.index) }}"
class="btn btn-sm btn-warning"
title="Edit Employee"
>
@@ -212,7 +212,7 @@ extra_head %}
{% if employees.has_prev %}
<li>
<a
href="{{ url_for('employees', page=employees.prev_num, search=search) }}"
href="{{ url_for('employees.employees', page=employees.prev_num, search=search) }}"
class="pagination-link"
>
<i class="fas fa-chevron-left"></i>
@@ -226,7 +226,7 @@ extra_head %}
page_num != employees.page %}
<li>
<a
href="{{ url_for('employees', page=page_num, search=search) }}"
href="{{ url_for('employees.employees', page=page_num, search=search) }}"
class="pagination-link"
>
{{ page_num }}
@@ -246,7 +246,7 @@ extra_head %}
{% if employees.has_next %}
<li>
<a
href="{{ url_for('employees', page=employees.next_num, search=search) }}"
href="{{ url_for('employees.employees', page=employees.next_num, search=search) }}"
class="pagination-link"
>
Next
@@ -271,9 +271,9 @@ extra_head %}
</h3>
<p>
{% if search %} Try adjusting your search terms or
<a href="{{ url_for('employees') }}">view all employees</a>. {% else %}
<a href="{{ url_for('employees.employees') }}">view all employees</a>. {% else %}
Get started by
<a href="{{ url_for('create_employee') }}">adding your first employee</a
<a href="{{ url_for('employees.create_employee') }}">adding your first employee</a
>. {% endif %}
</p>
</div>
+2 -2
View File
@@ -85,7 +85,7 @@
<!-- Export Configuration Form -->
<div class="export-config-section">
<form method="POST" action="{{ url_for('generate_excel_export') }}" id="exportForm">
<form method="POST" action="{{ url_for('attendance.generate_excel_export') }}" id="exportForm">
<!-- Hidden fields for filters -->
<input type="hidden" name="date_from" value="{{ filters.date_from }}">
<input type="hidden" name="date_to" value="{{ filters.date_to }}">
@@ -262,7 +262,7 @@ function goBackToReport() {
if (employeeFilter) params.append('employee', employeeFilter);
if (projectFilter) params.append('project', projectFilter);
const url = "{{ url_for('attendance_report') }}" + (params.toString() ? '?' + params.toString() : '');
const url = "{{ url_for('attendance.attendance_report') }}" + (params.toString() ? '?' + params.toString() : '');
window.location.href = url;
}
+7 -7
View File
@@ -642,7 +642,7 @@
{% block content %}
<div class="payroll-container">
<!-- Back Navigation -->
<a href="{{ url_for('dashboard') }}" class="back-nav">
<a href="{{ url_for('dashboard.dashboard') }}" class="back-nav">
<i class="fas fa-arrow-left"></i>
<span>Back to Dashboard</span>
</a>
@@ -663,7 +663,7 @@
Calculation Parameters
</h3>
<form method="GET" action="{{ url_for('payroll_dashboard') }}" class="filters-form">
<form method="GET" action="{{ url_for('payroll.payroll_dashboard') }}" class="filters-form">
<div class="form-group">
<label for="date_from">Start Date</label>
<input type="date" id="date_from" name="date_from" value="{{ date_from }}" required>
@@ -820,7 +820,7 @@
<!-- Export Actions -->
<div class="export-actions">
<!--
<form method="POST" action="{{ url_for('export_payroll_excel') }}" style="display: inline;">
<form method="POST" action="{{ url_for('payroll.export_payroll_excel') }}" style="display: inline;">
<input type="hidden" name="date_from" value="{{ date_from }}">
<input type="hidden" name="date_to" value="{{ date_to }}">
<input type="hidden" name="project_filter" value="{{ project_filter }}">
@@ -831,7 +831,7 @@
</button>
</form>
<form method="POST" action="{{ url_for('export_payroll_excel') }}" style="display: inline;">
<form method="POST" action="{{ url_for('payroll.export_payroll_excel') }}" style="display: inline;">
<input type="hidden" name="date_from" value="{{ date_from }}">
<input type="hidden" name="date_to" value="{{ date_to }}">
<input type="hidden" name="project_filter" value="{{ project_filter }}">
@@ -842,7 +842,7 @@
</button>
</form>
-->
<form method="POST" action="{{ url_for('export_payroll_excel') }}" style="display: inline;">
<form method="POST" action="{{ url_for('payroll.export_payroll_excel') }}" style="display: inline;">
<input type="hidden" name="date_from" value="{{ date_from }}">
<input type="hidden" name="date_to" value="{{ date_to }}">
<input type="hidden" name="project_filter" value="{{ project_filter }}">
@@ -853,7 +853,7 @@
</button>
</form>
<!--
<form method="POST" action="{{ url_for('export_payroll_excel') }}" style="display: inline;">
<form method="POST" action="{{ url_for('payroll.export_payroll_excel') }}" style="display: inline;">
<input type="hidden" name="date_from" value="{{ date_from }}">
<input type="hidden" name="date_to" value="{{ date_to }}">
<input type="hidden" name="project_filter" value="{{ project_filter }}">
@@ -864,7 +864,7 @@
</button>
</form>
<form method="POST" action="{{ url_for('export_payroll_excel') }}" style="display: inline;">
<form method="POST" action="{{ url_for('payroll.export_payroll_excel') }}" style="display: inline;">
<input type="hidden" name="date_from" value="{{ date_from }}">
<input type="hidden" name="date_to" value="{{ date_to }}">
<input type="hidden" name="project_filter" value="{{ project_filter }}">
+7 -7
View File
@@ -688,7 +688,7 @@
<p class="project-qr-description">{{ project.description }}</p>
{% endif %}
</div>
<a href="{{ url_for('dashboard') }}" class="back-button">
<a href="{{ url_for('dashboard.dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Dashboard
</a>
@@ -712,7 +712,7 @@
<!-- QR Code Search Section -->
<div class="search-section">
<form action="{{ url_for('project_qr_codes', project_id=project.id) }}" method="GET" class="search-form">
<form action="{{ url_for('dashboard.project_qr_codes', project_id=project.id) }}" method="GET" class="search-form">
<div class="search-inputs">
<div class="search-input-group">
<label for="search_name">
@@ -745,7 +745,7 @@
Search
</button>
{% if search_name or search_status %}
<a href="{{ url_for('project_qr_codes', project_id=project.id) }}" class="btn btn-outline">
<a href="{{ url_for('dashboard.project_qr_codes', project_id=project.id) }}" class="btn btn-outline">
<i class="fas fa-times"></i>
Clear
</a>
@@ -766,7 +766,7 @@
{% if search_status %} - Status: <strong>{{ search_status|title }}</strong>{% endif %}
({{ qr_codes|length }} QR code{{ 's' if qr_codes|length != 1 else '' }} found)
</span>
<a href="{{ url_for('project_qr_codes', project_id=project.id) }}" class="btn btn-sm btn-outline">
<a href="{{ url_for('dashboard.project_qr_codes', project_id=project.id) }}" class="btn btn-sm btn-outline">
<i class="fas fa-times"></i>
Clear Filters
</a>
@@ -846,7 +846,7 @@
<i class="fas fa-download"></i>
</button>
<a href="{{ url_for('edit_qr_code', qr_id=qr.id) }}"
<a href="{{ url_for('qr_codes.edit_qr_code', qr_id=qr.id) }}"
class="qr-action-btn edit"
onclick="event.stopPropagation()"
title="Edit QR Code">
@@ -876,7 +876,7 @@
{% if search_name and search_status %} or {% endif %}
{% if search_status %}try changing the status filter{% endif %}.
</p>
<a href="{{ url_for('project_qr_codes', project_id=project.id) }}" class="btn btn-primary" style="margin-top: var(--spacing-4)">
<a href="{{ url_for('dashboard.project_qr_codes', project_id=project.id) }}" class="btn btn-primary" style="margin-top: var(--spacing-4)">
<i class="fas fa-times"></i>
Clear Filters
</a>
@@ -885,7 +885,7 @@
<h3>No QR Codes Found</h3>
<p>This project doesn't have any QR codes yet.</p>
{% if session.role == 'admin' %}
<a href="{{ url_for('create_qr_code') }}" class="btn btn-primary" style="margin-top: var(--spacing-4)">
<a href="{{ url_for('qr_codes.create_qr_code') }}" class="btn btn-primary" style="margin-top: var(--spacing-4)">
<i class="fas fa-plus"></i> Create QR Code
</a>
{% endif %}
+5 -5
View File
@@ -11,7 +11,7 @@
<div class="projects-header">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('dashboard') }}" class="back-button">
<a href="{{ url_for('dashboard.dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
<span>Back to Dashboard</span>
</a>
@@ -20,7 +20,7 @@
<p>Organize and manage your QR code projects</p>
</div>
<div class="header-actions">
<a href="{{ url_for('create_project') }}" class="btn btn-primary">
<a href="{{ url_for('projects.create_project') }}" class="btn btn-primary">
<i class="fas fa-plus"></i>
Create Project
</a>
@@ -106,13 +106,13 @@
</div>
<div class="project-actions">
<a href="{{ url_for('edit_project', project_id=project.id) }}"
<a href="{{ url_for('projects.edit_project', project_id=project.id) }}"
class="btn btn-secondary">
<i class="fas fa-edit"></i>
Edit
</a>
<!-- Activate/Deactivate button (for future use)
<form method="POST" action="{{ url_for('toggle_project', project_id=project.id) }}"
<form method="POST" action="{{ url_for('projects.toggle_project', project_id=project.id) }}"
style="display: inline;">
<button type="submit"
class="btn {% if project.active_status %}btn-warning{% else %}btn-success{% endif %}">
@@ -132,7 +132,7 @@
</div>
<h3>No Projects Yet</h3>
<p>Create your first project to organize your QR codes</p>
<a href="{{ url_for('create_project') }}" class="btn btn-primary">
<a href="{{ url_for('projects.create_project') }}" class="btn btn-primary">
<i class="fas fa-plus"></i>
Create First Project
</a>
+79 -79
View File
@@ -1,79 +1,79 @@
{% extends "base.html" %} {% block title %}QR Code Not Found - QR Code
Management{% endblock %} {% block content %}
<div class="error-page">
<div class="error-container">
<div class="error-icon">
<i class="fas fa-qrcode"></i>
</div>
<div class="error-message">
<h1>QR Code Not Found</h1>
<p>
The QR code you're looking for doesn't exist or has been deactivated.
</p>
<p class="error-detail">
Please check with the person who provided this QR code.
</p>
</div>
<div class="error-actions">
{% if session.user_id %}
<a href="{{ url_for('dashboard') }}" class="btn btn-primary">
<i class="fas fa-home"></i>
Go to Dashboard
</a>
{% else %}
<a href="{{ url_for('login') }}" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i>
Login
</a>
{% endif %}
</div>
</div>
</div>
<style>
.error-page {
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
padding: var(--spacing-8);
}
.error-container {
text-align: center;
max-width: 600px;
}
.error-icon {
font-size: 6rem;
color: var(--gray-400);
margin-bottom: var(--spacing-6);
}
.error-message h1 {
font-size: var(--font-size-3xl);
color: var(--gray-900);
margin-bottom: var(--spacing-4);
}
.error-message p {
font-size: var(--font-size-lg);
color: var(--gray-600);
margin-bottom: var(--spacing-4);
}
.error-detail {
font-size: var(--font-size-sm);
color: var(--gray-500);
font-style: italic;
margin-bottom: var(--spacing-8) !important;
}
.error-actions {
display: flex;
gap: var(--spacing-4);
justify-content: center;
flex-wrap: wrap;
}
</style>
{% endblock %}
{% extends "base.html" %} {% block title %}QR Code Not Found - QR Code
Management{% endblock %} {% block content %}
<div class="error-page">
<div class="error-container">
<div class="error-icon">
<i class="fas fa-qrcode"></i>
</div>
<div class="error-message">
<h1>QR Code Not Found</h1>
<p>
The QR code you're looking for doesn't exist or has been deactivated.
</p>
<p class="error-detail">
Please check with the person who provided this QR code.
</p>
</div>
<div class="error-actions">
{% if session.user_id %}
<a href="{{ url_for('dashboard.dashboard') }}" class="btn btn-primary">
<i class="fas fa-home"></i>
Go to Dashboard
</a>
{% else %}
<a href="{{ url_for('auth.login') }}" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i>
Login
</a>
{% endif %}
</div>
</div>
</div>
<style>
.error-page {
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
padding: var(--spacing-8);
}
.error-container {
text-align: center;
max-width: 600px;
}
.error-icon {
font-size: 6rem;
color: var(--gray-400);
margin-bottom: var(--spacing-6);
}
.error-message h1 {
font-size: var(--font-size-3xl);
color: var(--gray-900);
margin-bottom: var(--spacing-4);
}
.error-message p {
font-size: var(--font-size-lg);
color: var(--gray-600);
margin-bottom: var(--spacing-4);
}
.error-detail {
font-size: var(--font-size-sm);
color: var(--gray-500);
font-style: italic;
margin-bottom: var(--spacing-8) !important;
}
.error-actions {
display: flex;
gap: var(--spacing-4);
justify-content: center;
flex-wrap: wrap;
}
</style>
{% endblock %}
+181 -181
View File
@@ -1,181 +1,181 @@
{% extends "base.html" %} {% block title %}Register - QR Code Management{%
endblock %} {% block content %}
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<div class="auth-logo">
<i class="fas fa-user-plus"></i>
</div>
<h1>Create Account</h1>
<p>Join our QR management platform</p>
</div>
<form method="POST" class="auth-form" id="registerForm">
<div class="form-group">
<label for="full_name">
<i class="fas fa-id-card"></i>
Full Name
</label>
<input type="text" id="full_name" name="full_name" required />
</div>
<div class="form-group">
<label for="email">
<i class="fas fa-envelope"></i>
Email Address
</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="username">
<i class="fas fa-user"></i>
Username
</label>
<input type="text" id="username" name="username" required />
</div>
<div class="form-group">
<label for="password">
<i class="fas fa-lock"></i>
Password
</label>
<input
type="password"
id="password"
name="password"
required
minlength="6"
/>
<div class="password-strength" id="passwordStrength"></div>
</div>
<div class="form-group">
<label for="confirm_password">
<i class="fas fa-lock"></i>
Confirm Password
</label>
<input
type="password"
id="confirm_password"
name="confirm_password"
required
/>
<div class="password-match" id="passwordMatch"></div>
</div>
<button type="submit" class="btn btn-primary btn-full">
<i class="fas fa-user-plus"></i>
Create Account
</button>
</form>
<div class="auth-footer">
<p>
Already have an account?
<a href="{{ url_for('login') }}" class="auth-link">Sign in here</a>
</p>
</div>
</div>
</div>
{% endblock %} {% block extra_scripts %}
<script>
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("registerForm");
const password = document.getElementById("password");
const confirmPassword = document.getElementById("confirm_password");
const passwordStrength = document.getElementById("passwordStrength");
const passwordMatch = document.getElementById("passwordMatch");
// Password strength checker
password.addEventListener("input", function () {
const value = this.value;
let strength = 0;
let feedback = [];
if (value.length >= 6) strength++;
else feedback.push("At least 6 characters");
if (/[A-Z]/.test(value)) strength++;
else feedback.push("One uppercase letter");
if (/[a-z]/.test(value)) strength++;
else feedback.push("One lowercase letter");
if (/[0-9]/.test(value)) strength++;
else feedback.push("One number");
if (/[^A-Za-z0-9]/.test(value)) strength++;
else feedback.push("One special character");
let strengthText = "";
let strengthClass = "";
if (strength < 2) {
strengthText = "Weak";
strengthClass = "weak";
} else if (strength < 4) {
strengthText = "Medium";
strengthClass = "medium";
} else {
strengthText = "Strong";
strengthClass = "strong";
}
passwordStrength.className = `password-strength ${strengthClass}`;
passwordStrength.textContent = `Strength: ${strengthText}`;
if (feedback.length > 0 && value.length > 0) {
passwordStrength.textContent += ` (Missing: ${feedback.join(", ")})`;
}
});
// Password match checker
function checkPasswordMatch() {
if (confirmPassword.value) {
if (password.value === confirmPassword.value) {
passwordMatch.textContent = "Passwords match";
passwordMatch.className = "password-match match";
} else {
passwordMatch.textContent = "Passwords do not match";
passwordMatch.className = "password-match no-match";
}
} else {
passwordMatch.textContent = "";
passwordMatch.className = "password-match";
}
}
password.addEventListener("input", checkPasswordMatch);
confirmPassword.addEventListener("input", checkPasswordMatch);
// Form submission validation
form.addEventListener("submit", function (e) {
if (password.value !== confirmPassword.value) {
e.preventDefault();
alert("Passwords do not match!");
return;
}
const submitBtn = form.querySelector('button[type="submit"]');
submitBtn.innerHTML =
'<i class="fas fa-spinner fa-spin"></i> Creating Account...';
submitBtn.disabled = true;
});
// Add focus effects
const inputs = form.querySelectorAll("input");
inputs.forEach((input) => {
input.addEventListener("focus", function () {
this.parentElement.classList.add("focused");
});
input.addEventListener("blur", function () {
if (!this.value) {
this.parentElement.classList.remove("focused");
}
});
});
});
</script>
{% endblock %}
{% extends "base.html" %} {% block title %}Register - QR Code Management{%
endblock %} {% block content %}
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<div class="auth-logo">
<i class="fas fa-user-plus"></i>
</div>
<h1>Create Account</h1>
<p>Join our QR management platform</p>
</div>
<form method="POST" class="auth-form" id="registerForm">
<div class="form-group">
<label for="full_name">
<i class="fas fa-id-card"></i>
Full Name
</label>
<input type="text" id="full_name" name="full_name" required />
</div>
<div class="form-group">
<label for="email">
<i class="fas fa-envelope"></i>
Email Address
</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="username">
<i class="fas fa-user"></i>
Username
</label>
<input type="text" id="username" name="username" required />
</div>
<div class="form-group">
<label for="password">
<i class="fas fa-lock"></i>
Password
</label>
<input
type="password"
id="password"
name="password"
required
minlength="6"
/>
<div class="password-strength" id="passwordStrength"></div>
</div>
<div class="form-group">
<label for="confirm_password">
<i class="fas fa-lock"></i>
Confirm Password
</label>
<input
type="password"
id="confirm_password"
name="confirm_password"
required
/>
<div class="password-match" id="passwordMatch"></div>
</div>
<button type="submit" class="btn btn-primary btn-full">
<i class="fas fa-user-plus"></i>
Create Account
</button>
</form>
<div class="auth-footer">
<p>
Already have an account?
<a href="{{ url_for('auth.login') }}" class="auth-link">Sign in here</a>
</p>
</div>
</div>
</div>
{% endblock %} {% block extra_scripts %}
<script>
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("registerForm");
const password = document.getElementById("password");
const confirmPassword = document.getElementById("confirm_password");
const passwordStrength = document.getElementById("passwordStrength");
const passwordMatch = document.getElementById("passwordMatch");
// Password strength checker
password.addEventListener("input", function () {
const value = this.value;
let strength = 0;
let feedback = [];
if (value.length >= 6) strength++;
else feedback.push("At least 6 characters");
if (/[A-Z]/.test(value)) strength++;
else feedback.push("One uppercase letter");
if (/[a-z]/.test(value)) strength++;
else feedback.push("One lowercase letter");
if (/[0-9]/.test(value)) strength++;
else feedback.push("One number");
if (/[^A-Za-z0-9]/.test(value)) strength++;
else feedback.push("One special character");
let strengthText = "";
let strengthClass = "";
if (strength < 2) {
strengthText = "Weak";
strengthClass = "weak";
} else if (strength < 4) {
strengthText = "Medium";
strengthClass = "medium";
} else {
strengthText = "Strong";
strengthClass = "strong";
}
passwordStrength.className = `password-strength ${strengthClass}`;
passwordStrength.textContent = `Strength: ${strengthText}`;
if (feedback.length > 0 && value.length > 0) {
passwordStrength.textContent += ` (Missing: ${feedback.join(", ")})`;
}
});
// Password match checker
function checkPasswordMatch() {
if (confirmPassword.value) {
if (password.value === confirmPassword.value) {
passwordMatch.textContent = "Passwords match";
passwordMatch.className = "password-match match";
} else {
passwordMatch.textContent = "Passwords do not match";
passwordMatch.className = "password-match no-match";
}
} else {
passwordMatch.textContent = "";
passwordMatch.className = "password-match";
}
}
password.addEventListener("input", checkPasswordMatch);
confirmPassword.addEventListener("input", checkPasswordMatch);
// Form submission validation
form.addEventListener("submit", function (e) {
if (password.value !== confirmPassword.value) {
e.preventDefault();
alert("Passwords do not match!");
return;
}
const submitBtn = form.querySelector('button[type="submit"]');
submitBtn.innerHTML =
'<i class="fas fa-spinner fa-spin"></i> Creating Account...';
submitBtn.disabled = true;
});
// Add focus effects
const inputs = form.querySelectorAll("input");
inputs.forEach((input) => {
input.addEventListener("focus", function () {
this.parentElement.classList.add("focused");
});
input.addEventListener("blur", function () {
if (!this.value) {
this.parentElement.classList.remove("focused");
}
});
});
});
</script>
{% endblock %}
+2 -2
View File
@@ -39,7 +39,7 @@
</h3>
</div>
<div class="filters-form">
<form method="GET" action="{{ url_for('qr_statistics') }}" id="statisticsFilters">
<form method="GET" action="{{ url_for('statistics.qr_statistics') }}" id="statisticsFilters">
<div class="filter-row">
<!-- Date Range -->
<div class="filter-group">
@@ -106,7 +106,7 @@
<i class="fas fa-search"></i>
Apply Filters
</button>
<a href="{{ url_for('qr_statistics') }}" class="btn btn-outline">
<a href="{{ url_for('statistics.qr_statistics') }}" class="btn btn-outline">
<i class="fas fa-times"></i>
Clear Filters
</a>
+2 -2
View File
@@ -93,7 +93,7 @@
<!-- Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('time_attendance_dashboard') }}" class="back-button">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Dashboard
</a>
@@ -110,7 +110,7 @@
</div>
<div class="header-actions">
<a href="{{ url_for('time_attendance_records', import_batch=batch_summary.batch_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', import_batch=batch_summary.batch_id) }}"
class="btn btn-primary">
<i class="fas fa-eye"></i>
View All Records
+8 -8
View File
@@ -19,12 +19,12 @@
<div class="header-actions">
{% if session.role in ['admin', 'payroll', 'accounting'] %}
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary">
<i class="fas fa-upload"></i>
Import Excel Data
</a>
{% endif %}
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.time_attendance_records') }}" class="btn btn-secondary">
<i class="fas fa-search"></i>
View All Records
</a>
@@ -201,7 +201,7 @@
<span>Showing {{ recent_records|length }} of {{ "{:,}".format(total_records) }} total records</span>
</div>
<div class="table-actions">
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.time_attendance_records') }}" class="btn btn-primary">
<i class="fas fa-list"></i>
View All Records
</a>
@@ -257,11 +257,11 @@
</td>
<td>
<div class="record-actions">
<a href="{{ url_for('time_attendance_records', import_batch=import_batch.import_batch_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', import_batch=import_batch.import_batch_id) }}"
class="action-btn btn-view" title="View Records">
<i class="fas fa-eye"></i>
</a>
<a href="{{ url_for('view_import_batch', batch_id=import_batch.import_batch_id) }}"
<a href="{{ url_for('time_attendance.view_import_batch', batch_id=import_batch.import_batch_id) }}"
class="action-btn btn-info" title="Batch Details">
<i class="fas fa-info-circle"></i>
</a>
@@ -294,7 +294,7 @@
</p>
{% if session.role == 'admin' %}
<div class="empty-actions">
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary">
<i class="fas fa-upload"></i>
Import Your First File
</a>
@@ -510,7 +510,7 @@
<script>
// View record details
function viewRecord(recordId) {
window.location.href = "{{ url_for('time_attendance_record_detail', record_id=0) }}".replace('0', recordId);
window.location.href = "{{ url_for('time_attendance.time_attendance_record_detail', record_id=0) }}".replace('0', recordId);
}
// Delete record with confirmation
@@ -518,7 +518,7 @@ function deleteRecord(recordId, employeeName, date) {
if (confirm(`Are you sure you want to delete the attendance record for ${employeeName} on ${date}?`)) {
const form = document.createElement('form');
form.method = 'POST';
form.action = "{{ url_for('delete_time_attendance_record', record_id=0) }}".replace('0', recordId);
form.action = "{{ url_for('time_attendance.delete_time_attendance_record', record_id=0) }}".replace('0', recordId);
document.body.appendChild(form);
form.submit();
}
@@ -315,7 +315,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('import_time_attendance') }}" class="back-button">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Import
</a>
@@ -366,7 +366,7 @@
<!-- Duplicates List -->
{% if analysis.duplicate_records > 0 %}
<form id="duplicateReviewForm" method="POST" action="{{ url_for('import_time_attendance') }}">
<form id="duplicateReviewForm" method="POST" action="{{ url_for('time_attendance.import_time_attendance') }}">
<input type="hidden" name="analyze_duplicates" value="false">
<input type="hidden" name="skip_duplicates" value="true">
<input type="hidden" name="import_source" value="Import with Duplicates - {{ filename }}">
@@ -522,7 +522,7 @@
<!-- Action Buttons -->
<div class="action-buttons">
<div class="left-actions">
<a href="{{ url_for('cancel_pending_import') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.cancel_pending_import') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel Import
</a>
@@ -549,7 +549,7 @@
<i class="fas fa-check-circle"></i>
<h3>No Duplicates Found</h3>
<p>All records in the file are unique. You can proceed with the import.</p>
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary" style="margin-top: 1rem;">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary" style="margin-top: 1rem;">
<i class="fas fa-arrow-left"></i>
Back to Import
</a>
+8 -8
View File
@@ -309,7 +309,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('time_attendance_dashboard') }}" class="back-button">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Time Attendance
</a>
@@ -326,7 +326,7 @@
</div>
<div class="header-actions">
<a href="{{ url_for('download_import_template') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.download_import_template') }}" class="btn btn-secondary">
<i class="fas fa-download"></i>
Download Template
</a>
@@ -342,7 +342,7 @@
</h2>
</div>
<div class="import-body">
<form id="importForm" method="POST" enctype="multipart/form-data" action="{{ url_for('import_time_attendance') }}">
<form id="importForm" method="POST" enctype="multipart/form-data" action="{{ url_for('time_attendance.import_time_attendance') }}">
<!-- Project Selection - REQUIRED (moved to top) -->
<div class="form-group" style="margin-bottom: 1.5rem;">
@@ -707,12 +707,12 @@
<strong>Batch ID:</strong> <code>{{ import_result.batch_id }}</code>
</p>
<div class="action-buttons">
<a href="{{ url_for('time_attendance_records', import_batch=import_result.batch_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', import_batch=import_result.batch_id) }}"
class="btn btn-primary">
<i class="fas fa-eye"></i>
View Imported Records
</a>
<a href="{{ url_for('time_attendance_dashboard') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="btn btn-secondary">
<i class="fas fa-tachometer-alt"></i>
Back to Dashboard
</a>
@@ -883,7 +883,7 @@ importForm.addEventListener('submit', async (e) => {
// ── Step 1: POST the file to /start → get job_id ──────────────────────
let jobId;
try {
const resp = await fetch('{{ url_for("start_import_job") }}', {
const resp = await fetch('{{ url_for("time_attendance.start_import_job") }}', {
method: 'POST',
body: formData
});
@@ -905,7 +905,7 @@ importForm.addEventListener('submit', async (e) => {
progressMessage.textContent = 'File received. Starting import...';
// ── Step 2: Open SSE stream for this job ──────────────────────────────
const streamUrl = '{{ url_for("stream_import_progress", job_id="__JOB_ID__") }}'.replace('__JOB_ID__', jobId);
const streamUrl = '{{ url_for("time_attendance.stream_import_progress", job_id="__JOB_ID__") }}'.replace('__JOB_ID__', jobId);
const evtSource = new EventSource(streamUrl);
evtSource.onmessage = (event) => {
@@ -942,7 +942,7 @@ importForm.addEventListener('submit', async (e) => {
// Redirect to records view after a short delay
if (result.success && result.batch_id) {
setTimeout(() => {
window.location.href = '{{ url_for("time_attendance_records") }}?import_batch=' + result.batch_id;
window.location.href = '{{ url_for("time_attendance.time_attendance_records") }}?import_batch=' + result.batch_id;
}, 2500);
} else {
submitBtn.disabled = false;
@@ -204,11 +204,11 @@
Import Completed Successfully!
</h2>
<div class="completion-actions">
<a href="{{ url_for('time_attendance_dashboard') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="btn btn-primary">
<i class="fas fa-chart-line"></i>
View Dashboard
</a>
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.time_attendance_records') }}" class="btn btn-secondary">
<i class="fas fa-list"></i>
View Records
</a>
@@ -299,7 +299,7 @@ eventSource.onerror = function(error) {
// Try to check if import completed
setTimeout(() => {
window.location.href = "{{ url_for('time_attendance_dashboard') }}";
window.location.href = "{{ url_for('time_attendance.time_attendance_dashboard') }}";
}, 2000);
};
</script>
+7 -7
View File
@@ -12,7 +12,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('import_time_attendance') }}" class="back-button">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Import
</a>
@@ -39,13 +39,13 @@
<div class="header-actions">
{% if import_result.success %}
<a href="{{ url_for('time_attendance_records', import_batch=import_result.batch_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', import_batch=import_result.batch_id) }}"
class="btn btn-primary">
<i class="fas fa-eye"></i>
View Imported Records
</a>
{% endif %}
<a href="{{ url_for('time_attendance_dashboard') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="btn btn-secondary">
<i class="fas fa-tachometer-alt"></i>
Dashboard
</a>
@@ -157,7 +157,7 @@
What's Next?
</h3>
<div class="action-grid">
<a href="{{ url_for('time_attendance_records', import_batch=import_result.batch_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', import_batch=import_result.batch_id) }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-eye"></i>
@@ -168,7 +168,7 @@
</div>
</a>
<a href="{{ url_for('time_attendance_records') }}"
<a href="{{ url_for('time_attendance.time_attendance_records') }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-search"></i>
@@ -179,7 +179,7 @@
</div>
</a>
<a href="{{ url_for('import_time_attendance') }}"
<a href="{{ url_for('time_attendance.import_time_attendance') }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-plus"></i>
@@ -231,7 +231,7 @@
</div>
<div class="retry-buttons">
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary">
<i class="fas fa-upload"></i>
Try Import Again
</a>
@@ -263,7 +263,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('import_time_attendance') }}" class="back-button">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Import
</a>
@@ -320,7 +320,7 @@
<!-- Invalid Rows List -->
{% if analysis.invalid_rows > 0 %}
<form id="invalidReviewForm" method="POST" action="{{ url_for('import_time_attendance') }}">
<form id="invalidReviewForm" method="POST" action="{{ url_for('time_attendance.import_time_attendance') }}">
<input type="hidden" name="from_invalid_review" value="true">
<input type="hidden" name="analyze_invalid" value="false">
<input type="hidden" name="analyze_duplicates" value="false">
@@ -434,7 +434,7 @@
<!-- Action Buttons -->
<div class="action-buttons">
<div class="left-actions">
<a href="{{ url_for('cancel_pending_import') }}" class="btn btn-secondary">
<a href="{{ url_for('time_attendance.cancel_pending_import') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel Import
</a>
@@ -452,7 +452,7 @@
<i class="fas fa-check-circle"></i>
<h3>All rows are valid!</h3>
<p>No invalid rows found. You can proceed with the import.</p>
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary" style="margin-top: 1rem;">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary" style="margin-top: 1rem;">
<i class="fas fa-arrow-left"></i>
Back to Import
</a>
+5 -5
View File
@@ -12,7 +12,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('time_attendance_records') }}" class="back-button">
<a href="{{ url_for('time_attendance.time_attendance_records') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Records
</a>
@@ -239,7 +239,7 @@
</div>
<div class="section-body">
<div class="action-grid">
<a href="{{ url_for('time_attendance_records', employee_id=record.employee_id) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', employee_id=record.employee_id) }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-user-clock"></i>
@@ -250,7 +250,7 @@
</div>
</a>
<a href="{{ url_for('time_attendance_records', location_name=record.location_name) }}"
<a href="{{ url_for('time_attendance.time_attendance_records', location_name=record.location_name) }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-map-marker-alt"></i>
@@ -262,7 +262,7 @@
</a>
{% if record.import_batch_id %}
<a href="{{ url_for('view_import_batch', batch_id=record.import_batch_id) }}"
<a href="{{ url_for('time_attendance.view_import_batch', batch_id=record.import_batch_id) }}"
class="action-card">
<div class="action-icon">
<i class="fas fa-file-import"></i>
@@ -854,7 +854,7 @@ function submitDelete() {
// Create form
const form = document.createElement('form');
form.method = 'POST';
form.action = "{{ url_for('delete_time_attendance_record', record_id=record.id) }}";
form.action = "{{ url_for('time_attendance.delete_time_attendance_record', record_id=record.id) }}";
// Add all URL parameters as hidden form inputs
for (const [key, value] of params.entries()) {
+8 -8
View File
@@ -244,7 +244,7 @@
<!-- Page Header -->
<div class="time-attendance-header">
<div class="header-navigation">
<a href="{{ url_for('time_attendance_dashboard') }}" class="back-button">
<a href="{{ url_for('time_attendance.time_attendance_dashboard') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Dashboard
</a>
@@ -262,7 +262,7 @@
<div class="header-actions">
{% if session.role == 'admin' %}
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
<a href="{{ url_for('time_attendance.import_time_attendance') }}" class="btn btn-primary">
<i class="fas fa-upload"></i>
Import Data
</a>
@@ -288,7 +288,7 @@
</h3>
</div>
<div class="filters-form">
<form method="GET" action="{{ url_for('time_attendance_records') }}">
<form method="GET" action="{{ url_for('time_attendance.time_attendance_records') }}">
<div class="filter-row">
<div class="filter-group">
@@ -499,7 +499,7 @@
<!-- Actions -->
<td class="actions-cell">
<div class="action-buttons">
<a href="{{ url_for('time_attendance_record_detail', record_id=record.id, **request.args) }}"
<a href="{{ url_for('time_attendance.time_attendance_record_detail', record_id=record.id, **request.args) }}"
class="action-btn view">
<i class="fas fa-eye"></i>
View
@@ -527,7 +527,7 @@
</div>
<div class="pagination-controls">
{% if records.has_prev %}
<a href="{{ url_for('time_attendance_records', page=records.prev_num,
<a href="{{ url_for('time_attendance.time_attendance_records', page=records.prev_num,
employee_id=request.args.get('employee_id', ''),
location_name=request.args.get('location_name', ''),
project_id=request.args.get('project_id', ''),
@@ -542,7 +542,7 @@
{% for page_num in records.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
{% if page_num %}
{% if page_num != records.page %}
<a href="{{ url_for('time_attendance_records', page=page_num,
<a href="{{ url_for('time_attendance.time_attendance_records', page=page_num,
employee_id=request.args.get('employee_id', ''),
location_name=request.args.get('location_name', ''),
project_id=request.args.get('project_id', ''),
@@ -560,7 +560,7 @@
{% endfor %}
{% if records.has_next %}
<a href="{{ url_for('time_attendance_records', page=records.next_num,
<a href="{{ url_for('time_attendance.time_attendance_records', page=records.next_num,
employee_id=request.args.get('employee_id', ''),
location_name=request.args.get('location_name', ''),
project_id=request.args.get('project_id', ''),
@@ -905,7 +905,7 @@ document.addEventListener('keydown', function(event) {
chipsWrapper.closest('form').submit();
};
window.taClearAllFilters = function () {
window.location.href = '{{ url_for("time_attendance_records") }}';
window.location.href = '{{ url_for("time_attendance.time_attendance_records") }}';
};
}());
+573 -573
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -48,7 +48,7 @@
<!-- Filters Section -->
<div class="filter-section">
<form method="GET" action="{{ url_for('verification_review') }}">
<form method="GET" action="{{ url_for('attendance.verification_review') }}">
<div class="filter-grid">
<div class="filter-group">
<label for="status">Status</label>
@@ -104,7 +104,7 @@
<button type="submit" class="btn-filter">
<i class="fas fa-filter"></i> Apply Filters
</button>
<a href="{{ url_for('verification_review') }}" class="btn-reset">
<a href="{{ url_for('attendance.verification_review') }}" class="btn-reset">
<i class="fas fa-undo"></i> Reset
</a>
</div>
@@ -193,7 +193,7 @@
<button type="button" class="btn-photo email" onclick="sendByEmail({{ record.id }}, '{{ record.employee_id }}', '{{ employee_names.get(record.employee_id) or 'Unknown' }}', '{{ record.check_in_date.strftime('%b %d, %Y') }}', '{{ record.check_in_time.strftime('%I:%M %p') }}', '{{ record.location_name }}', '{{ record.qr_code.location_event if record.qr_code and record.qr_code.location_event else 'N/A' }}', '{{ record.verification_status }}', '{{ record.qr_code.location_address if record.qr_code and record.qr_code.location_address else 'N/A' }}', '{{ record.address or 'N/A' }}', '{{ '%.3f'|format(record.location_accuracy) if record.location_accuracy else 'N/A' }}', '{{ record.device_info or 'Unknown' }}')" title="Send by Email">
<i class="fas fa-envelope"></i>
</button>
<a href="{{ url_for('verification_review_detail', record_id=record.id) }}" class="btn-photo view" title="View Details">
<a href="{{ url_for('attendance.verification_review_detail', record_id=record.id) }}" class="btn-photo view" title="View Details">
<i class="fas fa-expand"></i>
</a>
</div>
+4 -4
View File
@@ -446,14 +446,14 @@ QR Code Management{% endblock %} {% block extra_head %}
<i class="fas fa-times"></i>
Reject Verification
</button>
<a href="{{ url_for('attendance_report') }}" class="btn btn-back">
<a href="{{ url_for('attendance.attendance_report') }}" class="btn btn-back">
<i class="fas fa-arrow-left"></i>
Back to Attendance
</a>
</div>
{% else %}
<div class="action-buttons">
<a href="{{ url_for('attendance_report') }}" class="btn btn-back">
<a href="{{ url_for('attendance.attendance_report') }}" class="btn btn-back">
<i class="fas fa-arrow-left"></i>
Back to Attendance
</a>
@@ -509,7 +509,7 @@ QR Code Management{% endblock %} {% block extra_head %}
console.log(`[LOG] Successfully updated verification status to ${status}`);
alert(`Verification ${status} successfully!`);
// Redirect back to attendance report
window.location.href = '{{ url_for('attendance_report') }}';
window.location.href = '{{ url_for('attendance.attendance_report') }}';
} else {
throw new Error(data.message || 'Failed to update verification status');
}
@@ -578,7 +578,7 @@ QR Code Management{% endblock %} {% block extra_head %}
const distance = '{% if record.location_accuracy %}{{ "%.3f"|format(record.location_accuracy) }} miles{% else %}N/A{% endif %}';
const deviceInfo = '{{ record.device_info or "Unknown" }}';
const recordId = '{{ record.id }}';
const recordUrl = window.location.origin + '{{ url_for("verification_review_detail", record_id=record.id) }}';
const recordUrl = window.location.origin + '{{ url_for("attendance.verification_review_detail", record_id=record.id) }}';
// Build email subject
const subject = encodeURIComponent(`Verification Review - Employee ${employeeId} (${employeeName}) - ${checkInDate}`);