- Add Modules and UserModules database tables - Create home page with module selection grid - Implement per-user module assignment in user management - Add route guards for module access control - Refactor navigation: login -> home -> modules, admin console via button - Add Font Awesome icons
203 lines
7.5 KiB
HTML
203 lines
7.5 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}My Counts - {{ count_session.session_name }} - ScanLook{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="dashboard-container">
|
|
<div class="page-header">
|
|
<div>
|
|
<a href="{{ url_for('counting.index') }}" class="breadcrumb">← Back to Sessions</a>
|
|
<h1 class="page-title">My Active Counts</h1>
|
|
<p class="page-subtitle">{{ count_session.session_name }}</p>
|
|
{% if not count_session.master_baseline_timestamp %}
|
|
<p class="page-subtitle">Master File not uploaded yet. Please contact an admin before starting bins.</p>
|
|
{% endif %}
|
|
</div>
|
|
{% if count_session.master_baseline_timestamp %}
|
|
<button class="btn btn-primary" onclick="showStartBinModal()">
|
|
<span class="btn-icon">+</span> Start New Bin
|
|
</button>
|
|
{% else %}
|
|
<button class="btn btn-primary" disabled title="Upload a Master File to start bins">
|
|
<span class="btn-icon">+</span> Start New Bin
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Active Bins -->
|
|
{% if active_bins %}
|
|
<div class="section-card">
|
|
<h2 class="section-title">🔄 Active Bins (In Progress)</h2>
|
|
<div class="bins-grid">
|
|
{% for bin in active_bins %}
|
|
<div class="bin-card bin-active">
|
|
<div class="bin-header">
|
|
<h3 class="bin-name">{{ bin.location_name }}</h3>
|
|
<span class="bin-status status-progress">In Progress</span>
|
|
</div>
|
|
<div class="bin-stats">
|
|
<div class="bin-stat">
|
|
<span class="stat-label">Scanned:</span>
|
|
<span class="stat-value">{{ bin.scan_count or 0 }}</span>
|
|
</div>
|
|
<div class="bin-stat">
|
|
<span class="stat-label">Started:</span>
|
|
<span class="stat-value">{{ bin.start_timestamp[11:16] if bin.start_timestamp else '-' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="bin-actions">
|
|
<a href="{{ url_for('counting.count_location', session_id=count_session.session_id, location_count_id=bin.location_count_id) }}" class="btn btn-primary btn-block">
|
|
Resume Counting
|
|
</a>
|
|
<div class="bin-actions-row">
|
|
<button class="btn btn-secondary" onclick="markComplete('{{ bin.location_count_id }}')">
|
|
✓ Mark Complete
|
|
</button>
|
|
<button class="btn btn-danger" onclick="deleteBinCount('{{ bin.location_count_id }}', '{{ bin.location_name }}')">
|
|
🗑️ Delete
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Completed Bins -->
|
|
{% if completed_bins %}
|
|
<div class="section-card">
|
|
<h2 class="section-title">✅ Completed Bins</h2>
|
|
<div class="bins-grid">
|
|
{% for bin in completed_bins %}
|
|
<div class="bin-card bin-completed">
|
|
<div class="bin-header">
|
|
<h3 class="bin-name">{{ bin.location_name }}</h3>
|
|
<span class="bin-status status-success">Completed</span>
|
|
</div>
|
|
<div class="bin-stats">
|
|
<div class="bin-stat">
|
|
<span class="stat-label">Scanned:</span>
|
|
<span class="stat-value">{{ bin.scan_count or 0 }}</span>
|
|
</div>
|
|
<div class="bin-stat">
|
|
<span class="stat-label">Completed:</span>
|
|
<span class="stat-value">{{ bin.end_timestamp[11:16] if bin.end_timestamp else '-' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="bin-actions">
|
|
<button class="btn btn-secondary btn-block" disabled title="This bin has been finalized">
|
|
🔒 Finalized (Read-Only)
|
|
</button>
|
|
<p class="bin-note">Contact an admin to view details</p>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if not active_bins and not completed_bins %}
|
|
<div class="empty-state">
|
|
<div class="empty-icon">📦</div>
|
|
<h2 class="empty-title">No Bins Started Yet</h2>
|
|
<p class="empty-text">Click "Start New Bin" to begin counting</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Start New Bin Modal -->
|
|
<div id="startBinModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header-bar">
|
|
<h3 class="modal-title">Start New Bin</h3>
|
|
<button type="button" class="btn-close-modal" onclick="closeStartBinModal()">✕</button>
|
|
</div>
|
|
|
|
<form id="startBinForm" action="{{ url_for('counting.start_bin_count', session_id=count_session.session_id) }}" method="POST">
|
|
<div class="form-group">
|
|
<label class="form-label">Bin Number *</label>
|
|
<input type="text" name="location_name" class="form-input scan-input" required autofocus placeholder="Scan or type bin number">
|
|
</div>
|
|
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-secondary" onclick="closeStartBinModal()">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Start Counting</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function showStartBinModal() {
|
|
document.getElementById('startBinModal').style.display = 'flex';
|
|
document.querySelector('#startBinForm input[name="location_name"]').focus();
|
|
}
|
|
|
|
function closeStartBinModal() {
|
|
document.getElementById('startBinModal').style.display = 'none';
|
|
document.getElementById('startBinForm').reset();
|
|
}
|
|
|
|
function markComplete(locationCountId) {
|
|
if (!confirm('Mark this bin as complete? You can still view it later.')) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/location/${locationCountId}/complete`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert(data.message || 'Error marking bin as complete');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Error: ' + error.message);
|
|
});
|
|
}
|
|
|
|
function deleteBinCount(locationCountId, binName) {
|
|
if (!confirm(`Delete ALL counts for bin "${binName}"?\n\nThis will remove all scanned entries for this bin. This action cannot be undone.`)) {
|
|
return;
|
|
}
|
|
|
|
// Double confirmation for safety
|
|
if (!confirm('Are you absolutely sure? All data for this bin will be lost.')) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/location/${locationCountId}/delete`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert(data.message || 'Error deleting bin count');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Error: ' + error.message);
|
|
});
|
|
}
|
|
|
|
// Close modal on escape
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') {
|
|
closeStartBinModal();
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|