Mar 20 2026: refactor 2
This commit is contained in:
@@ -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>
|
||||
|
||||
+1084
-1084
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
+609
-609
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+669
-669
File diff suppressed because it is too large
Load Diff
+2070
-2070
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+728
-728
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }}">
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
Reference in New Issue
Block a user