merge v0.7.1 dev into main. #31
@@ -397,13 +397,14 @@
|
|||||||
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-2xl max-w-lg w-full max-h-[90vh] overflow-y-auto" onclick="event.stopPropagation()">
|
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-2xl max-w-lg w-full max-h-[90vh] overflow-y-auto" onclick="event.stopPropagation()">
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="flex items-center justify-between mb-6">
|
<div class="flex items-center justify-between mb-6">
|
||||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">New Reservation</h2>
|
<h2 class="text-xl font-semibold text-gray-900 dark:text-white" id="modal-title">New Reservation</h2>
|
||||||
<button onclick="closeReservationModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
<button onclick="closeReservationModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<input type="hidden" id="editing-reservation-id" value="">
|
||||||
|
|
||||||
<form id="reservation-form" onsubmit="submitReservation(event)">
|
<form id="reservation-form" onsubmit="submitReservation(event)">
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
@@ -522,7 +523,7 @@
|
|||||||
class="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg">
|
class="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button type="submit"
|
<button type="submit" id="modal-submit-btn"
|
||||||
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
|
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
|
||||||
Create Reservation
|
Create Reservation
|
||||||
</button>
|
</button>
|
||||||
@@ -600,27 +601,83 @@ function closeDayPanel() {
|
|||||||
let reservationModeActive = false;
|
let reservationModeActive = false;
|
||||||
|
|
||||||
function openReservationModal() {
|
function openReservationModal() {
|
||||||
|
// Reset to "create" mode
|
||||||
|
document.getElementById('modal-title').textContent = 'New Reservation';
|
||||||
|
document.getElementById('modal-submit-btn').textContent = 'Create Reservation';
|
||||||
|
document.getElementById('editing-reservation-id').value = '';
|
||||||
|
document.getElementById('reservation-form').reset();
|
||||||
|
|
||||||
document.getElementById('reservation-modal').classList.remove('hidden');
|
document.getElementById('reservation-modal').classList.remove('hidden');
|
||||||
reservationModeActive = true;
|
reservationModeActive = true;
|
||||||
// Show reservation legend, hide main legend
|
|
||||||
document.getElementById('main-legend').classList.add('md:hidden');
|
document.getElementById('main-legend').classList.add('md:hidden');
|
||||||
document.getElementById('main-legend').classList.remove('md:flex');
|
document.getElementById('main-legend').classList.remove('md:flex');
|
||||||
document.getElementById('reservation-legend').classList.remove('md:hidden');
|
document.getElementById('reservation-legend').classList.remove('md:hidden');
|
||||||
document.getElementById('reservation-legend').classList.add('md:flex');
|
document.getElementById('reservation-legend').classList.add('md:flex');
|
||||||
// Trigger availability update
|
|
||||||
updateCalendarAvailability();
|
updateCalendarAvailability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function editReservation(id) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/fleet-calendar/reservations/${id}`);
|
||||||
|
if (!response.ok) { alert('Failed to load reservation'); return; }
|
||||||
|
const res = await response.json();
|
||||||
|
|
||||||
|
// Switch modal to "edit" mode
|
||||||
|
document.getElementById('modal-title').textContent = 'Edit Reservation';
|
||||||
|
document.getElementById('modal-submit-btn').textContent = 'Save Changes';
|
||||||
|
document.getElementById('editing-reservation-id').value = id;
|
||||||
|
|
||||||
|
// Populate fields
|
||||||
|
const form = document.getElementById('reservation-form');
|
||||||
|
form.querySelector('input[name="name"]').value = res.name;
|
||||||
|
form.querySelector('select[name="project_id"]').value = res.project_id || '';
|
||||||
|
form.querySelector('input[name="start_date"]').value = res.start_date;
|
||||||
|
form.querySelector('textarea[name="notes"]').value = res.notes || '';
|
||||||
|
|
||||||
|
// Color radio
|
||||||
|
const colorRadio = form.querySelector(`input[name="color"][value="${res.color}"]`);
|
||||||
|
if (colorRadio) colorRadio.checked = true;
|
||||||
|
|
||||||
|
// Assignment type
|
||||||
|
const atRadio = form.querySelector(`input[name="assignment_type"][value="${res.assignment_type}"]`);
|
||||||
|
if (atRadio) { atRadio.checked = true; toggleAssignmentType(res.assignment_type); }
|
||||||
|
if (res.assignment_type === 'quantity') {
|
||||||
|
form.querySelector('input[name="quantity_needed"]').value = res.quantity_needed || 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End date / TBD
|
||||||
|
const tbdCheckbox = document.getElementById('end_date_tbd');
|
||||||
|
if (res.end_date_tbd) {
|
||||||
|
tbdCheckbox.checked = true;
|
||||||
|
form.querySelector('input[name="estimated_end_date"]').value = res.estimated_end_date || '';
|
||||||
|
} else {
|
||||||
|
tbdCheckbox.checked = false;
|
||||||
|
document.getElementById('end_date_input').value = res.end_date || '';
|
||||||
|
}
|
||||||
|
toggleEndDateTBD();
|
||||||
|
|
||||||
|
document.getElementById('reservation-modal').classList.remove('hidden');
|
||||||
|
reservationModeActive = true;
|
||||||
|
document.getElementById('main-legend').classList.add('md:hidden');
|
||||||
|
document.getElementById('main-legend').classList.remove('md:flex');
|
||||||
|
document.getElementById('reservation-legend').classList.remove('md:hidden');
|
||||||
|
document.getElementById('reservation-legend').classList.add('md:flex');
|
||||||
|
updateCalendarAvailability();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading reservation:', error);
|
||||||
|
alert('Error loading reservation');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function closeReservationModal() {
|
function closeReservationModal() {
|
||||||
document.getElementById('reservation-modal').classList.add('hidden');
|
document.getElementById('reservation-modal').classList.add('hidden');
|
||||||
document.getElementById('reservation-form').reset();
|
document.getElementById('reservation-form').reset();
|
||||||
|
document.getElementById('editing-reservation-id').value = '';
|
||||||
reservationModeActive = false;
|
reservationModeActive = false;
|
||||||
// Restore main legend
|
|
||||||
document.getElementById('main-legend').classList.remove('md:hidden');
|
document.getElementById('main-legend').classList.remove('md:hidden');
|
||||||
document.getElementById('main-legend').classList.add('md:flex');
|
document.getElementById('main-legend').classList.add('md:flex');
|
||||||
document.getElementById('reservation-legend').classList.add('md:hidden');
|
document.getElementById('reservation-legend').classList.add('md:hidden');
|
||||||
document.getElementById('reservation-legend').classList.remove('md:flex');
|
document.getElementById('reservation-legend').classList.remove('md:flex');
|
||||||
// Reset calendar colors
|
|
||||||
resetCalendarColors();
|
resetCalendarColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,6 +809,7 @@ async function submitReservation(event) {
|
|||||||
const form = event.target;
|
const form = event.target;
|
||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
const endDateTbd = formData.get('end_date_tbd') === 'on';
|
const endDateTbd = formData.get('end_date_tbd') === 'on';
|
||||||
|
const editingId = document.getElementById('editing-reservation-id').value;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
name: formData.get('name'),
|
name: formData.get('name'),
|
||||||
@@ -766,7 +824,6 @@ async function submitReservation(event) {
|
|||||||
notes: formData.get('notes') || null
|
notes: formData.get('notes') || null
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate: need either end_date or TBD checked
|
|
||||||
if (!data.end_date && !data.end_date_tbd) {
|
if (!data.end_date && !data.end_date_tbd) {
|
||||||
alert('Please enter an end date or check "TBD / Ongoing"');
|
alert('Please enter an end date or check "TBD / Ongoing"');
|
||||||
return;
|
return;
|
||||||
@@ -778,9 +835,15 @@ async function submitReservation(event) {
|
|||||||
data.unit_ids = formData.getAll('unit_ids');
|
data.unit_ids = formData.getAll('unit_ids');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isEdit = editingId !== '';
|
||||||
|
const url = isEdit
|
||||||
|
? `/api/fleet-calendar/reservations/${editingId}`
|
||||||
|
: '/api/fleet-calendar/reservations';
|
||||||
|
const method = isEdit ? 'PUT' : 'POST';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/fleet-calendar/reservations', {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
@@ -789,14 +852,13 @@ async function submitReservation(event) {
|
|||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
closeReservationModal();
|
closeReservationModal();
|
||||||
// Reload the page to refresh calendar
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} else {
|
} else {
|
||||||
alert('Error creating reservation: ' + (result.detail || 'Unknown error'));
|
alert(`Error ${isEdit ? 'saving' : 'creating'} reservation: ` + (result.detail || 'Unknown error'));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
alert('Error creating reservation');
|
alert(`Error ${isEdit ? 'saving' : 'creating'} reservation`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,7 @@ async function deleteReservation(id, name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function editReservation(id) {
|
// editReservation is defined in fleet_calendar.html
|
||||||
// For now, just show alert - can implement edit modal later
|
|
||||||
alert('Edit functionality coming soon. For now, delete and recreate the reservation.');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-center py-8">
|
<div class="text-center py-8">
|
||||||
|
|||||||
Reference in New Issue
Block a user