Enhanced add attendance manually UI

This commit is contained in:
2026-02-09 11:43:42 -05:00
parent 7f911df988
commit 15c7c93def
2 changed files with 76 additions and 25 deletions
+19 -4
View File
@@ -5438,12 +5438,27 @@ def get_project_locations_api():
active_status=True active_status=True
).order_by(QRCode.location).all() ).order_by(QRCode.location).all()
location_list = [{ # Group QR codes by location to get unique locations
'id': qr.id, locations_dict = {}
for qr in qr_codes:
location_key = f"{qr.location}||{qr.location_address}"
if location_key not in locations_dict:
locations_dict[location_key] = {
'location': qr.location, 'location': qr.location,
'location_address': qr.location_address, 'location_address': qr.location_address,
'location_event': qr.location_event 'qr_codes': {}
} for qr in qr_codes] }
# Store QR code ID for each event type
locations_dict[location_key]['qr_codes'][qr.location_event] = qr.id
# Convert to list format
location_list = [{
'location': loc_data['location'],
'location_address': loc_data['location_address'],
'qr_codes': loc_data['qr_codes']
} for loc_data in locations_dict.values()]
return jsonify({'success': True, 'locations': location_list}) return jsonify({'success': True, 'locations': location_list})
+55 -19
View File
@@ -249,13 +249,13 @@
<!-- Location Selection --> <!-- Location Selection -->
<div class="form-group"> <div class="form-group">
<label for="location_id"> <label for="location_select">
Location <span class="required">*</span> Location <span class="required">*</span>
</label> </label>
<select id="location_id" name="location_id" class="form-control" required disabled> <select id="location_select" class="form-control" required disabled>
<option value="">-- Select Project First --</option> <option value="">-- Select Project First --</option>
</select> </select>
<div class="help-text">Locations will be loaded based on the selected project</div> <div class="help-text">Locations will be loaded based on the selected project (each location shown once)</div>
<div id="location_loading" class="loading-spinner"> <div id="location_loading" class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i> Loading locations... <i class="fas fa-spinner fa-spin"></i> Loading locations...
</div> </div>
@@ -263,15 +263,18 @@
<!-- Event Type Selection --> <!-- Event Type Selection -->
<div class="form-group"> <div class="form-group">
<label for="event_type"> <label for="event_type_select">
Event Type <span class="required">*</span> Event Type <span class="required">*</span>
</label> </label>
<select id="event_type" name="event_type" class="form-control" required disabled> <select id="event_type_select" class="form-control" required disabled>
<option value="">-- Select Location First --</option> <option value="">-- Select Location First --</option>
</select> </select>
<div class="help-text">Select whether this is a check-in or check-out event</div> <div class="help-text">Select whether this is a check-in or check-out event</div>
</div> </div>
<!-- Hidden field for the actual QR code ID that will be submitted -->
<input type="hidden" id="location_id" name="location_id" required>
<!-- Date and Time --> <!-- Date and Time -->
<div class="form-group"> <div class="form-group">
<label for="check_date"> <label for="check_date">
@@ -381,10 +384,14 @@ document.addEventListener('click', function(e) {
// Project selection - load locations // Project selection - load locations
const projectSelect = document.getElementById('project_id'); const projectSelect = document.getElementById('project_id');
const locationSelect = document.getElementById('location_id'); const locationSelect = document.getElementById('location_select');
const eventTypeSelect = document.getElementById('event_type'); const eventTypeSelect = document.getElementById('event_type_select');
const locationIdHidden = document.getElementById('location_id');
const locationLoading = document.getElementById('location_loading'); const locationLoading = document.getElementById('location_loading');
// Store location data for later use
let locationData = {};
projectSelect.addEventListener('change', function() { projectSelect.addEventListener('change', function() {
const projectId = this.value; const projectId = this.value;
@@ -393,6 +400,8 @@ projectSelect.addEventListener('change', function() {
locationSelect.disabled = true; locationSelect.disabled = true;
eventTypeSelect.innerHTML = '<option value="">-- Select Location First --</option>'; eventTypeSelect.innerHTML = '<option value="">-- Select Location First --</option>';
eventTypeSelect.disabled = true; eventTypeSelect.disabled = true;
locationIdHidden.value = '';
locationData = {};
if (!projectId) { if (!projectId) {
locationSelect.innerHTML = '<option value="">-- Select Project First --</option>'; locationSelect.innerHTML = '<option value="">-- Select Project First --</option>';
@@ -410,11 +419,13 @@ projectSelect.addEventListener('change', function() {
if (data.success && data.locations.length > 0) { if (data.success && data.locations.length > 0) {
locationSelect.disabled = false; locationSelect.disabled = false;
data.locations.forEach(loc => { data.locations.forEach((loc, index) => {
const locationKey = `loc_${index}`;
locationData[locationKey] = loc.qr_codes;
const option = document.createElement('option'); const option = document.createElement('option');
option.value = loc.id; option.value = locationKey;
option.textContent = `${loc.location} - ${loc.location_address}`; option.textContent = `${loc.location} - ${loc.location_address}`;
option.dataset.event = loc.location_event;
locationSelect.appendChild(option); locationSelect.appendChild(option);
}); });
} else { } else {
@@ -428,23 +439,48 @@ projectSelect.addEventListener('change', function() {
}); });
}); });
// Location selection - set event type // Location selection - populate event type options
locationSelect.addEventListener('change', function() { locationSelect.addEventListener('change', function() {
const selectedOption = this.options[this.selectedIndex]; const locationKey = this.value;
const eventType = selectedOption.dataset.event;
eventTypeSelect.innerHTML = ''; eventTypeSelect.innerHTML = '';
eventTypeSelect.disabled = false; eventTypeSelect.disabled = false;
locationIdHidden.value = '';
if (eventType) { if (locationKey && locationData[locationKey]) {
const qrCodes = locationData[locationKey];
// Add available event types
if (qrCodes['Check In']) {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = eventType; option.value = qrCodes['Check In'];
option.textContent = eventType; option.textContent = 'Check In';
option.selected = true;
eventTypeSelect.appendChild(option); eventTypeSelect.appendChild(option);
} else {
eventTypeSelect.innerHTML = '<option value="">Event type not available</option>';
} }
if (qrCodes['Check Out']) {
const option = document.createElement('option');
option.value = qrCodes['Check Out'];
option.textContent = 'Check Out';
eventTypeSelect.appendChild(option);
}
if (eventTypeSelect.options.length === 0) {
eventTypeSelect.innerHTML = '<option value="">No event types available</option>';
eventTypeSelect.disabled = true;
} else {
// Set the hidden location_id to the first available option
locationIdHidden.value = eventTypeSelect.options[0].value;
}
} else {
eventTypeSelect.innerHTML = '<option value="">-- Select Location First --</option>';
eventTypeSelect.disabled = true;
}
});
// Event type selection - update hidden location_id field
eventTypeSelect.addEventListener('change', function() {
locationIdHidden.value = this.value;
}); });
// Set default date to today // Set default date to today