BookingSystem/public/getData.js
2025-08-17 15:38:51 +00:00

316 lines
10 KiB
JavaScript
Executable File

// Private variable scoped to this file only
let todaysBookings = [];
let selectedDateBookings = [];
const input1 = document.getElementById("name");
const input2 = document.getElementById("email");
const input3 = document.getElementById("phone");
const dpicker = document.getElementById("ranged");
const dpicker2 = document.getElementById("currentDate");
export async function getData() {
try {
const res = await fetch('/api/book', { method: 'GET' });
if (!res.ok) throw new Error(`HTTP error! Status: ${res.status}`);
return await res.json();
} catch (err) {
console.error("Error fetching data:", err);
return [];
}
}
//formats timestamp to dd/mm/yyyy
function formatToDMY(isoString) {
const date = new Date(isoString);
const day = String(date.getUTCDate()).padStart(2, '0');
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
const year = date.getUTCFullYear();
return `${day}/${month}/${year}`;
}
//formats timestamp to dd/MM/yyyy
function formatDateToDayMonthYear(dateStr) {
const parts = dateStr.split(/[-\/]/);
if (parts.length < 3) return "Invalid Date";
const year = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1;
const day = parseInt(parts[2], 10);
if (isNaN(year) || isNaN(month) || isNaN(day)) return "Invalid Date";
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
return `${day} ${months[month]} ${year}`;
}
const todayStr = new Date().toISOString().split("T")[0]; // "YYYY-MM-DD"
function addDays(dateStr, days) {
const date = new Date(dateStr);
date.setDate(date.getDate() + days);
return date.toISOString().split("T")[0];
}
function formatToYMD(timestamp) {
return new Date(timestamp).toISOString().split("T")[0];
}
// Loads bookings for the given day offset and stores them in todaysBookings
export async function loadTodaysBookings(dayOffset = 0) {
const bookings = await getData();
const targetDate = addDays(todayStr, dayOffset);
// Filter bookings for the selected day by time
const unsortedBookings = bookings.filter(
b => formatToYMD(b.booking_date) === targetDate
);
// Sort by booking_time from earliest to latest
todaysBookings = unsortedBookings.sort((a, b) => {
const [hA, mA, sA] = a.booking_time.split(':').map(Number);
const [hB, mB, sB] = b.booking_time.split(':').map(Number);
const totalA = hA * 3600 + mA * 60 + sA;
const totalB = hB * 3600 + mB * 60 + sB;
return totalA - totalB;
});
return todaysBookings;
}
//loads date selected bookings
export async function loadSelectedDateBookings(date) {
const bookings = await getData();
// Filter bookings for the selected day by time
const unsortedBookings = bookings.filter(
b => formatToDMY(b.booking_date) === date
);
// Sort by booking_time from earliest to latest
selectedDateBookings = unsortedBookings.sort((a, b) => {
const [hA, mA, sA] = a.booking_time.split(':').map(Number);
const [hB, mB, sB] = b.booking_time.split(':').map(Number);
const totalA = hA * 3600 + mA * 60 + sA;
const totalB = hB * 3600 + mB * 60 + sB;
return totalA - totalB;
});
return selectedDateBookings;
}
// Checks if a given hour is booked in todaysBookings
export function isHourBooked(time) {
return selectedDateBookings.some(b => b.booking_time === time);
}
// Render the bookings for the dayOffset and update the DOM
export async function renderBookings(dayOffset = 0) {
await loadTodaysBookings(dayOffset);
const listContainer = document.getElementById("bookingsList");
const today = addDays(todayStr, dayOffset);
dpicker2.value = today;
dpicker2.addEventListener("change", () => {
const date1 = new Date(dpicker2.value);
const date2 = new Date(todayStr);
if (!isNaN(date1) && !isNaN(date2)) {
currentDayOffset = Math.round((date1 - date2) / (1000 * 60 * 60 * 24));
renderBookings(currentDayOffset);
}
});
// Clear the container first
listContainer.innerHTML = "";
if (todaysBookings.length === 0) {
// Display message if no bookings
const noBookingsDiv = document.createElement("div");
noBookingsDiv.className = "no-bookings";
noBookingsDiv.textContent = "No bookings found for this date.";
listContainer.appendChild(noBookingsDiv);
return; // Exit early since there are no bookings
}
// Render bookings if there are any
todaysBookings.forEach(booking => {
const bookingDiv = document.createElement("div");
bookingDiv.className = "booking-item";
//update booking
window.updateData = function(id) {
fetch('/api/book', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ accepted: true, id })
})
.then(response => {
if (!response.ok) throw new Error('Failed to update booking');
return response.json();
})
.then(() => {
loadTodaysBookings(currentDayOffset);
renderBookings(currentDayOffset);
})
.catch(err => console.error('Error updating booking:', err));
};
//delete booking
window.deleteBooking = async function(id) {
try {
const res = await fetch(`/api/book/${id}`, { method: 'DELETE' });
if (!res.ok) throw new Error('Failed to delete booking');
await loadTodaysBookings(currentDayOffset);
renderBookings(currentDayOffset);
} catch (err) {
console.error('Error deleting booking:', err);
}
};
const formattedDate = booking.booking_date ? formatDateToDayMonthYear(booking.booking_date) : "No date";
const bookingHour = booking.booking_time ? booking.booking_time.split(':')[0] + ":" + booking.booking_time.split(':')[1] : "No hour";
let status = "Pending approval";
let buttonsStyle = "padding-left: 2vh; width: 20%;";
let buttonsStyle2 = "padding-left: 2vh; width: 20%;";
if (booking.accepted) {
status = "Accepted";
buttonsStyle += " display: none;";
} else {
buttonsStyle2 += " display: none;";
}
let buttonsStyle3 = "padding-left: 2vh; width: 20%;";
window.getInfo = function(button, showClosed) {
const bookingContainer = button.closest(".bookingContainer");
const openedDiv = bookingContainer.querySelector(".opened");
const closedDiv = bookingContainer.querySelector(".closed");
const btns2 = bookingContainer.querySelector(".btns2");
const btns3 = bookingContainer.querySelector(".btns3");
const openedInfo = bookingContainer.querySelector(".openedInfo");
const closedInfo = bookingContainer.querySelector(".closedInfo");
if (showClosed) {
openedDiv.style.display = "none";
btns2.style.display = "none";
openedInfo.style.display = "none";
closedDiv.style.display = "block";
btns3.style.display = "block";
closedInfo.style.display = "block";
} else {
openedDiv.style.display = "block";
btns2.style.display = "block";
closedDiv.style.display = "none";
btns3.style.display = "none";
openedInfo.style.display = "block";
closedInfo.style.display = "none";
}
};
bookingDiv.innerHTML = `
<div class="bookingContainer">
<div style="padding-left: 2vh; width: 20%;">
<h1 class="opened" style="font-size: 5vmin; display: block;">${bookingHour}</h1>
<button class="closed" style="display: none; margin-left: 2vh;" onclick="deleteBooking(${booking.id})">
<img style="width: 4vh; height: 4vh;" src="img/delete.png">
</button>
</div>
<div class="openedInfo" style="display: block;">
<div class="userinfo-container">
<h3 class="userinfo-target">
Booking for: <br>${booking.name}
<div class="userinfo-box">Email: ${booking.email || "No email"}<br>Phone: ${booking.phone || "No phone"}</div>
</h3>
<div class="bookingContent">
<h5>Status: ${status}</h5>
</div>
</div>
</div>
<div class="closedInfo" style="display: none;">
<div>
<h5>
Name: ${booking.name || "No name"}<br>
</h5>
<h5>
Email: ${booking.email || "No email"}<br>
</h5>
<h5>
Phone: ${booking.phone || "No phone"}<br>
</h5>
<h5>
Booking Date: ${formattedDate}, ${booking.booking_time}<br>
</h5>
</div>
</div>
<div class="btns" style="${buttonsStyle}">
<div style="margin-right: 2.5vh;">
<button class="bookingBtns" onclick="updateData(${booking.id})">
<img style="width: 5vh; height: 5vh;" src="img/done.png">
</button>
</div>
<div style="margin-right: 2.5vh;">
<button class="bookingBtns" onclick="deleteBooking(${booking.id})">
<img style="width: 5vh; height: 5vh;" src="img/delete.png">
</button>
</div>
</div>
<div class="btns2" style="${buttonsStyle2}">
<div style="margin-right: 2vh;">
<button class="bookingBtns">
<img style="width: 4vh; height: 4vh;" src="img/info.png" onclick="getInfo(this, true)">
</button>
</div>
</div>
<div class="btns3" style="${buttonsStyle3} display: none;">
<div class="backBtn" style="margin-right: 2vh;">
<button class="bookingBtns">
<img style="width: 4vh; height: 4vh;" src="img/back.png" onclick="getInfo(this, false)">
</button>
</div>
</div>
</div>
`;
listContainer.appendChild(bookingDiv);
});
}
window.renderBookings = renderBookings;
// Controls to move days in the admin panel
let currentDayOffset = 0;
document.getElementById("prevBtn").addEventListener("click", () => {
currentDayOffset--;
renderBookings(currentDayOffset);
});
document.getElementById("nextBtn").addEventListener("click", () => {
currentDayOffset++;
renderBookings(currentDayOffset);
});
// Initial render
document.addEventListener("DOMContentLoaded", () => {
renderBookings(currentDayOffset);
});
//loads selected date bookings
[input1, input2, input3, dpicker].forEach(input => {
input.addEventListener("input", () => loadSelectedDateBookings(dpicker.value));
input.addEventListener("change", () => loadSelectedDateBookings(dpicker.value));
});
setInterval(() => {
loadSelectedDateBookings(dpicker.value);
}, 200);