[743de55] | 1 | import { deleteAppointment, confirmCarriedOut, getUsersByTermExcept, removeRequestAndUpdateUser, removeAppointment, makeReservation ,displayDiv} from './shared.js';
|
---|
| 2 |
|
---|
| 3 | let calendar = document.querySelector('.calendar')
|
---|
| 4 | let importantDate;
|
---|
| 5 | const month_names = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
---|
| 6 | const modal = document.getElementById('popupModal');
|
---|
| 7 | const cancelBtn = document.getElementById('cancelBtn');
|
---|
| 8 | const approveBtn = document.getElementById('approveBtn');
|
---|
| 9 | const closeSpan = document.querySelector('.close');
|
---|
| 10 | const deleteBtn=document.getElementById("temporal-deletion");
|
---|
| 11 |
|
---|
| 12 | function resetFields() {
|
---|
| 13 | document.getElementById('start-time').selectedIndex = 0;
|
---|
| 14 | document.getElementById('timePicker').selectedIndex=0;
|
---|
| 15 | document.getElementById('end-time').selectedIndex=0;
|
---|
| 16 | document.getElementById('time-interval').value = '';
|
---|
| 17 | document.getElementById('start-date').value = '';
|
---|
| 18 | document.getElementById('end-date').value='';
|
---|
| 19 | document.getElementById('delete-date-from').value='';
|
---|
| 20 | document.getElementById('delete-date-to').value='';
|
---|
| 21 | }
|
---|
| 22 | function checkOverlap(existingTimes, newTime) {
|
---|
| 23 | const [newHour, newMinutes] = newTime.split(':').map(Number);
|
---|
| 24 |
|
---|
| 25 | const newStartTime = new Date(0, 0, 0, newHour, newMinutes);
|
---|
| 26 | const newEndTime = new Date(newStartTime);
|
---|
| 27 | newEndTime.setHours(newEndTime.getHours() + 1);
|
---|
| 28 |
|
---|
| 29 | return existingTimes.some(existingTime => {
|
---|
| 30 | const [existingHour, existingMinutes] = existingTime.split(':').map(Number);
|
---|
| 31 | const existingStartTime = new Date(0, 0, 0, existingHour, existingMinutes);
|
---|
| 32 | const existingEndTime = new Date(existingStartTime);
|
---|
| 33 | existingEndTime.setHours(existingEndTime.getHours() + 1);
|
---|
| 34 | return newStartTime < existingEndTime && newEndTime > existingStartTime;
|
---|
| 35 | });
|
---|
| 36 | }
|
---|
| 37 | async function getExistingAppointmentsMapped() {
|
---|
| 38 | let existingAppointments;
|
---|
| 39 | try {
|
---|
| 40 | const response = await fetch(`/api/appointments/getAllAppointments`);
|
---|
| 41 | if (!response.ok) {
|
---|
| 42 | throw new Error('Failed to fetch appointments');
|
---|
| 43 | }
|
---|
| 44 | existingAppointments = await response.json();
|
---|
| 45 | console.log(existingAppointments);
|
---|
| 46 | } catch (error) {
|
---|
| 47 | console.error(error);
|
---|
| 48 | }
|
---|
| 49 |
|
---|
| 50 | const appointmentMap = new Map();
|
---|
| 51 | existingAppointments.forEach(appointment => {
|
---|
| 52 | const dateTime = new Date(appointment.term);
|
---|
| 53 | const date = dateTime.toISOString().split('T')[0];
|
---|
| 54 | const time = dateTime.toTimeString().substring(0, 5);
|
---|
| 55 | if (appointmentMap.has(date)) {
|
---|
| 56 | appointmentMap.get(date).push(time);
|
---|
| 57 | } else {
|
---|
| 58 | appointmentMap.set(date, [time]);
|
---|
| 59 | }
|
---|
| 60 | });
|
---|
| 61 | return appointmentMap;
|
---|
| 62 | }
|
---|
| 63 | function createAppointments(startDate, endDate, startTime, endTime, interval) {
|
---|
| 64 | let appointments = [];
|
---|
| 65 | let currentDate = new Date(startDate);
|
---|
| 66 | let endDateObj = new Date(endDate);
|
---|
| 67 | const [startHour, startMinute] = startTime.split(':').map(Number);
|
---|
| 68 | const [endHour, endMinute] = endTime.split(':').map(Number);
|
---|
| 69 |
|
---|
| 70 | while (currentDate <= endDateObj) {
|
---|
| 71 | let currentStartTime = new Date(currentDate);
|
---|
| 72 | currentStartTime.setHours(startHour, startMinute, 0, 0);
|
---|
| 73 |
|
---|
| 74 | let currentEndTime = new Date(currentDate);
|
---|
| 75 | currentEndTime.setHours(endHour - 1, endMinute+interval, 0, 0);
|
---|
| 76 |
|
---|
| 77 | while (currentStartTime < currentEndTime) {
|
---|
| 78 | const formattedDate = currentDate.toISOString().split('T')[0];
|
---|
| 79 | appointments.push({
|
---|
| 80 | date: formattedDate,
|
---|
| 81 | time: currentStartTime.toTimeString().substring(0, 5)
|
---|
| 82 | });
|
---|
| 83 | currentStartTime.setMinutes(currentStartTime.getMinutes() + interval + 60);
|
---|
| 84 | }
|
---|
| 85 | currentDate.setDate(currentDate.getDate() + 1);
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | return appointments;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 | function formatConflictAlert(conflictingAppointments) {
|
---|
| 92 | const appointmentList = Array.isArray(conflictingAppointments) ? conflictingAppointments : [conflictingAppointments];
|
---|
| 93 | const formattedAppointments = appointmentList.map(appointment =>
|
---|
| 94 | `Датум: ${appointment.date}, Време: ${appointment.time}`
|
---|
| 95 | );
|
---|
| 96 |
|
---|
| 97 | const alertMessage = [
|
---|
| 98 | "Неуспешно креирање на термини:",
|
---|
| 99 | ...formattedAppointments
|
---|
| 100 | ].filter(Boolean).join('\n');
|
---|
| 101 |
|
---|
| 102 | return alertMessage.trim();
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | async function createAutoAppointments(appointments) {
|
---|
| 106 | const requestBody = appointments.map(appointment => ({
|
---|
| 107 | date: appointment.date,
|
---|
| 108 | time: appointment.time,
|
---|
| 109 | }));
|
---|
| 110 |
|
---|
| 111 | await fetch(`/api/appointments/create`, {
|
---|
| 112 | method: 'POST',
|
---|
| 113 | headers: {
|
---|
| 114 | 'Content-Type': 'application/json',
|
---|
| 115 | },
|
---|
| 116 | body: JSON.stringify(requestBody) // Send all appointments in one request
|
---|
| 117 | });
|
---|
| 118 | }
|
---|
| 119 | document.getElementById('create-appointments').addEventListener('click', async function () {
|
---|
| 120 | const startDate = document.getElementById('start-date').value;
|
---|
| 121 | const endDate = document.getElementById('end-date').value;
|
---|
| 122 | const startTime = document.getElementById('start-time').value;
|
---|
| 123 | const endTime = document.getElementById('end-time').value;
|
---|
| 124 | const interval = parseInt(document.getElementById('time-interval').value);
|
---|
| 125 |
|
---|
| 126 | if (!startDate || !endDate || !startTime || !endTime || !interval) {
|
---|
| 127 | alert("Please fill out all the fields.");
|
---|
| 128 | return;
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | const appointments = createAppointments(startDate, endDate, startTime, endTime, interval);
|
---|
| 132 | console.log('Generated Appointments:', appointments);
|
---|
| 133 |
|
---|
| 134 | const existingMapped = await getExistingAppointmentsMapped();
|
---|
| 135 | const conflictingAppointments = [];
|
---|
| 136 | const successfulAppointments = [];
|
---|
| 137 |
|
---|
| 138 | appointments.forEach(newAppointment => {
|
---|
| 139 | const { date, time } = newAppointment;
|
---|
| 140 |
|
---|
| 141 | if (existingMapped.has(date)) {
|
---|
| 142 | const existingTimes = existingMapped.get(date);
|
---|
| 143 | if (checkOverlap(existingTimes, time)) {
|
---|
| 144 | conflictingAppointments.push(newAppointment); // Add to conflict list if overlaps
|
---|
| 145 | } else {
|
---|
| 146 | successfulAppointments.push(newAppointment);
|
---|
| 147 | }
|
---|
| 148 | } else {
|
---|
| 149 | successfulAppointments.push(newAppointment);
|
---|
| 150 | }
|
---|
| 151 | });
|
---|
| 152 | console.log(conflictingAppointments);
|
---|
| 153 | console.log(successfulAppointments);
|
---|
| 154 | if(successfulAppointments.length>0){
|
---|
| 155 | await createAutoAppointments(successfulAppointments);
|
---|
| 156 | }
|
---|
| 157 | if (conflictingAppointments.length > 0) {
|
---|
| 158 | const alertMessage = formatConflictAlert(conflictingAppointments);
|
---|
| 159 | alert(alertMessage);
|
---|
| 160 | }
|
---|
| 161 | resetFields();
|
---|
| 162 | });
|
---|
| 163 |
|
---|
| 164 | cancelBtn.addEventListener('click', () => {
|
---|
| 165 | modal.style.display = 'none';
|
---|
| 166 | });
|
---|
| 167 |
|
---|
| 168 | closeSpan.addEventListener('click', () => {
|
---|
| 169 | modal.style.display = 'none';
|
---|
| 170 | });
|
---|
| 171 |
|
---|
| 172 | deleteBtn.addEventListener('click',()=>{
|
---|
| 173 | deleteAppointment(deleteBtn.getAttribute("term"),deleteBtn.getAttribute("type"));
|
---|
| 174 | })
|
---|
| 175 |
|
---|
| 176 | window.addEventListener('click', (event) => {
|
---|
| 177 | if (event.target === modal) {
|
---|
| 178 | modal.style.display = 'none';
|
---|
| 179 | }
|
---|
| 180 | });
|
---|
| 181 |
|
---|
| 182 | function cleanAssets() {
|
---|
| 183 | const ids = ['request-assets', 'appointment-assets'];
|
---|
| 184 | ids.forEach((id) => {
|
---|
| 185 | const element = document.getElementById(id);
|
---|
| 186 | if (element && element.style.display !== 'none') {
|
---|
| 187 | element.style.display = 'none';
|
---|
| 188 | }
|
---|
| 189 | });
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 |
|
---|
| 193 | async function isAppointmentReserved(dateTime) {
|
---|
| 194 | try {
|
---|
| 195 | const response = await fetch(`/api/appointments/isReserved?term=${dateTime}`);
|
---|
| 196 | return await response.json();
|
---|
| 197 | } catch (error) {
|
---|
| 198 | console.error('Error checking if appointment reserved:', error);
|
---|
| 199 | return false;
|
---|
| 200 | }
|
---|
| 201 | }
|
---|
| 202 | async function isAppointmentEmpty(dateTime) {
|
---|
| 203 | try {
|
---|
| 204 | const response = await fetch(`/api/requests/isEmpty?term=${dateTime}`);
|
---|
| 205 | return await response.json();
|
---|
| 206 | } catch (error) {
|
---|
| 207 | console.error('Error checking if no requests:', error);
|
---|
| 208 | return false;
|
---|
| 209 | }
|
---|
| 210 | }
|
---|
| 211 | function cleanData(bodyId){
|
---|
| 212 | const element = document.getElementById(bodyId);
|
---|
| 213 | while (element.firstChild) {
|
---|
| 214 | element.removeChild(element.firstChild);
|
---|
| 215 | }
|
---|
| 216 | }
|
---|
| 217 | function createLines(data,dateTime,whichOne){
|
---|
| 218 | cleanData(whichOne)
|
---|
| 219 | if(!Array.isArray(data)){
|
---|
| 220 | data=[data];
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | let requestedElement=document.getElementById(whichOne);
|
---|
| 224 | data.forEach(item => {
|
---|
| 225 | const requestedRow = document.createElement('tr');
|
---|
| 226 | const usernameTd = document.createElement('td');
|
---|
| 227 | usernameTd.textContent = item.username;
|
---|
| 228 | requestedRow.appendChild(usernameTd);
|
---|
| 229 | const nameTd = document.createElement('td');
|
---|
| 230 | nameTd.textContent = item.name;
|
---|
| 231 | requestedRow.appendChild(nameTd);
|
---|
| 232 | const surnameTd = document.createElement('td');
|
---|
| 233 | surnameTd.textContent = item.surname;
|
---|
| 234 | requestedRow.appendChild(surnameTd);
|
---|
| 235 | const additionalInfoTd = document.createElement('td');
|
---|
| 236 | additionalInfoTd.textContent = item.additionalInfo;
|
---|
| 237 | requestedRow.appendChild(additionalInfoTd);
|
---|
| 238 | const couponCodeTd = document.createElement('td');
|
---|
| 239 | couponCodeTd.textContent = item.couponCode;
|
---|
| 240 | requestedRow.appendChild(couponCodeTd);
|
---|
| 241 | requestedElement.appendChild(requestedRow);
|
---|
| 242 | displayDiv(dateTime);
|
---|
| 243 | })
|
---|
| 244 | }
|
---|
| 245 | function getAllRequests(dateTime,containerId){
|
---|
| 246 | let url;
|
---|
| 247 | if(containerId === "approved"){
|
---|
| 248 | url = `/api/appointments/listApprovedRequest?term=${dateTime}`;
|
---|
| 249 | } else {
|
---|
| 250 | url = `/api/requests/listRequests?term=${dateTime}`;
|
---|
| 251 | }
|
---|
| 252 |
|
---|
| 253 | fetch(url)
|
---|
| 254 | .then(response => response.json())
|
---|
| 255 | .then(data => {
|
---|
| 256 | createLines(data,dateTime,containerId)
|
---|
| 257 | })
|
---|
| 258 | .catch(error => {
|
---|
| 259 | console.error('Error fetching requests:', error);
|
---|
| 260 | });
|
---|
| 261 | }
|
---|
| 262 | function createActiveAppointments(data){
|
---|
| 263 | const frameElement=document.getElementById("frame");
|
---|
| 264 | frameElement.innerHTML = '';
|
---|
| 265 | document.getElementById("approved-table").style.display = 'none';
|
---|
| 266 | document.getElementById("requested-table").style.display = 'none';
|
---|
| 267 | data.forEach(item => {
|
---|
| 268 | const itemDiv = document.createElement('div');
|
---|
| 269 | itemDiv.style.border = '1px solid black';
|
---|
| 270 | itemDiv.style.padding = '20px';
|
---|
| 271 | itemDiv.style.display = 'inline-block';
|
---|
| 272 | itemDiv.style.marginRight = '10px';
|
---|
| 273 |
|
---|
| 274 | const appointmentDate = new Date(item.localDateTime);
|
---|
| 275 | const timeOptions = { hour: '2-digit', minute: '2-digit', hour12: false };
|
---|
| 276 | itemDiv.textContent = appointmentDate.toLocaleTimeString([], timeOptions);
|
---|
| 277 |
|
---|
| 278 | itemDiv.addEventListener('click', async () => {
|
---|
| 279 | try{
|
---|
| 280 |
|
---|
| 281 | const isReserved=await isAppointmentReserved(item.localDateTime);
|
---|
| 282 | const isEmpty=await isAppointmentEmpty(item.localDateTime);
|
---|
| 283 | cleanAssets();
|
---|
| 284 | cleanData("approved")
|
---|
| 285 | cleanData("requested")
|
---|
| 286 | if (isReserved) {
|
---|
| 287 | document.getElementById("approved-table").style.display = 'block';
|
---|
| 288 | document.getElementById("requested-table").style.display = 'none';
|
---|
| 289 | getAllRequests(item.localDateTime,"approved","");
|
---|
| 290 | document.getElementById("appointment-assets").style.display='block';
|
---|
| 291 | deleteBtn.style.display='block';
|
---|
| 292 | deleteBtn.setAttribute("term",item.localDateTime);
|
---|
| 293 | deleteBtn.setAttribute("type","cancelledAppointmentByAdmin");
|
---|
| 294 | //da go isprogramirash delete-approval
|
---|
| 295 | document.getElementById("delete-approval").addEventListener('click', function() {
|
---|
| 296 | removeAppointment(item.localDateTime,"cancelledAppointmentByAdmin");
|
---|
| 297 | });
|
---|
| 298 | document.getElementById("approve-carried-out").addEventListener('click', function() {
|
---|
| 299 | modal.style.display = 'flex';
|
---|
| 300 | approveBtn.addEventListener('click', () => {
|
---|
| 301 | const userInput = document.getElementById('userInput').value;
|
---|
| 302 | confirmCarriedOut(item.localDateTime,userInput);
|
---|
| 303 | modal.style.display = 'none';
|
---|
| 304 | });
|
---|
| 305 |
|
---|
| 306 | });
|
---|
| 307 | }
|
---|
| 308 | else if(!isEmpty){
|
---|
| 309 | document.getElementById("approved-table").style.display = 'none';
|
---|
| 310 | document.getElementById("requested-table").style.display = 'block';
|
---|
| 311 | getAllRequests(item.localDateTime,"requested","");
|
---|
| 312 | document.getElementById("request-assets").style.display='block';
|
---|
| 313 | deleteBtn.style.display='block';
|
---|
| 314 | deleteBtn.setAttribute("term",item.localDateTime);
|
---|
| 315 | deleteBtn.setAttribute("type","rejected");
|
---|
| 316 | }
|
---|
| 317 | else{
|
---|
| 318 | document.getElementById("approved-table").style.display = 'none';
|
---|
| 319 | document.getElementById("requested-table").style.display = 'none';
|
---|
| 320 | deleteBtn.style.display='block';
|
---|
| 321 | deleteBtn.setAttribute("term",item.localDateTime);
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 |
|
---|
| 325 | }
|
---|
| 326 | catch(error){
|
---|
| 327 | console.error('Error checking appointment reservation:', error);
|
---|
| 328 | }
|
---|
| 329 |
|
---|
| 330 | });
|
---|
| 331 |
|
---|
| 332 | frameElement.appendChild(itemDiv);
|
---|
| 333 | });
|
---|
| 334 | }
|
---|
| 335 | function fetchAppointments(date){
|
---|
| 336 | deleteBtn.style.display='none';
|
---|
| 337 | fetch(`/api/appointments/listAppointments?date=${date}`)
|
---|
| 338 | .then(response => response.json())
|
---|
| 339 | .then(data => {
|
---|
| 340 | createActiveAppointments(data);
|
---|
| 341 | })
|
---|
| 342 | .catch(error => {
|
---|
| 343 | console.error('Error fetching appointments:', error);
|
---|
| 344 | });
|
---|
| 345 | }
|
---|
| 346 |
|
---|
| 347 | const isLeapYear = (year) => {
|
---|
| 348 | return (year % 4 === 0 && year % 100 !== 0 && year % 400 !== 0) || (year % 100 === 0 && year % 400 ===0)
|
---|
| 349 | }
|
---|
| 350 |
|
---|
| 351 | const getFebDays = (year) => {
|
---|
| 352 | return isLeapYear(year) ? 29 : 28
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 |
|
---|
| 356 | const generateCalendar = (month, year) => {
|
---|
| 357 |
|
---|
| 358 | let calendar_days = calendar.querySelector('.calendar-days')
|
---|
| 359 | let calendar_header_year = calendar.querySelector('#year')
|
---|
| 360 |
|
---|
| 361 | let days_of_month = [31, getFebDays(year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
---|
| 362 |
|
---|
| 363 | calendar_days.innerHTML = ''
|
---|
| 364 |
|
---|
| 365 | let currDate = new Date()
|
---|
| 366 |
|
---|
| 367 | // if (!month) month = currDate.getMonth()
|
---|
| 368 | console.log(month);
|
---|
| 369 | if (typeof month !== 'number') month = currDate.getMonth();
|
---|
| 370 | if (!year) year = currDate.getFullYear()
|
---|
| 371 |
|
---|
| 372 | let curr_month = `${month_names[month]}`
|
---|
| 373 | month_picker.innerHTML = curr_month
|
---|
| 374 | calendar_header_year.innerHTML = year
|
---|
| 375 |
|
---|
| 376 | // get first day of month
|
---|
| 377 |
|
---|
| 378 | let first_day = new Date(year, month, 1)
|
---|
| 379 |
|
---|
| 380 | for (let i = 0; i <= days_of_month[month] + first_day.getDay() - 1; i++) {
|
---|
| 381 | let day = document.createElement('div')
|
---|
| 382 | if (i >= first_day.getDay()) {
|
---|
| 383 | day.classList.add('calendar-day-hover')
|
---|
| 384 | day.innerHTML = i - first_day.getDay() + 1;
|
---|
| 385 | day.innerHTML += `<span></span>
|
---|
| 386 | <span></span>
|
---|
| 387 | <span></span>
|
---|
| 388 | <span></span>`;
|
---|
| 389 | let selectedDate = `${year}-${(month + 1).toString().padStart(2, '0')}-${(i - first_day.getDay() + 1).toString().padStart(2, '0')}`;
|
---|
| 390 | if (i - first_day.getDay() + 1 === currDate.getDate() && year === currDate.getFullYear() && month === currDate.getMonth()) {
|
---|
| 391 | day.classList.add('curr-date')
|
---|
| 392 | importantDate=selectedDate;
|
---|
| 393 | document.getElementById("insert-date").innerText=importantDate;
|
---|
| 394 | fetchAppointments(importantDate);
|
---|
| 395 | }
|
---|
| 396 | day.addEventListener('click', () => {
|
---|
| 397 | let temp=document.getElementsByClassName('curr-date');
|
---|
| 398 | Array.from(temp).forEach(element => {
|
---|
| 399 | element.classList.remove('curr-date');
|
---|
| 400 | });
|
---|
| 401 | importantDate=selectedDate;
|
---|
| 402 | let daySpan= document.getElementById("insert-date");
|
---|
| 403 | daySpan.innerText="";
|
---|
| 404 | daySpan.innerText=importantDate;
|
---|
| 405 | day.classList.add('curr-date');
|
---|
| 406 | fetchAppointments(importantDate);
|
---|
| 407 | cleanAssets();
|
---|
| 408 | cleanData("approved")
|
---|
| 409 | cleanData("requested")
|
---|
| 410 | resetFields();
|
---|
| 411 | });
|
---|
| 412 | }
|
---|
| 413 | calendar_days.appendChild(day)
|
---|
| 414 | }
|
---|
| 415 | }
|
---|
| 416 |
|
---|
| 417 | let month_list = calendar.querySelector('.month-list')
|
---|
| 418 |
|
---|
| 419 | month_names.forEach((e, index) => {
|
---|
| 420 | let month = document.createElement('div')
|
---|
| 421 | month.innerHTML = `<div data-month="${index}">${e}</div>`
|
---|
| 422 | month.querySelector('div').onclick = () => {
|
---|
| 423 | month_list.classList.remove('show')
|
---|
| 424 | curr_month.value = index
|
---|
| 425 | generateCalendar(index, curr_year.value)
|
---|
| 426 | }
|
---|
| 427 | month_list.appendChild(month)
|
---|
| 428 | })
|
---|
| 429 |
|
---|
| 430 | let month_picker = calendar.querySelector('#month-picker')
|
---|
| 431 |
|
---|
| 432 | month_picker.onclick = () => {
|
---|
| 433 | month_list.classList.add('show')
|
---|
| 434 | }
|
---|
| 435 |
|
---|
| 436 | let currDate = new Date()
|
---|
| 437 |
|
---|
| 438 | let curr_month = {value: currDate.getMonth()}
|
---|
| 439 | let curr_year = {value: currDate.getFullYear()}
|
---|
| 440 |
|
---|
| 441 | generateCalendar(curr_month.value, curr_year.value)
|
---|
| 442 |
|
---|
| 443 | document.querySelector('#prev-year').onclick = () => {
|
---|
| 444 | --curr_year.value
|
---|
| 445 | generateCalendar(curr_month.value, curr_year.value)
|
---|
| 446 | }
|
---|
| 447 |
|
---|
| 448 | document.querySelector('#next-year').onclick = () => {
|
---|
| 449 | ++curr_year.value
|
---|
| 450 | generateCalendar(curr_month.value, curr_year.value)
|
---|
| 451 | }
|
---|
| 452 | function populateTimePicker() {
|
---|
| 453 | const timePicker = document.getElementById('timePicker');
|
---|
| 454 | const timePickerStart = document.getElementById('start-time');
|
---|
| 455 | const timePickerEnd = document.getElementById('end-time');
|
---|
| 456 |
|
---|
| 457 | const timePickerInterval = 10;
|
---|
| 458 | const otherPickersInterval = 30;
|
---|
| 459 |
|
---|
| 460 | for (let hour = 7; hour < 22; hour++) { // 0 to 23 for 24-hour format
|
---|
| 461 | for (let minutes = 0; minutes < 60; minutes++) {
|
---|
| 462 | const formattedHour = hour.toString().padStart(2, '0');
|
---|
| 463 | const formattedMinutes = minutes.toString().padStart(2, '0');
|
---|
| 464 |
|
---|
| 465 |
|
---|
| 466 | if (minutes % timePickerInterval === 0) {
|
---|
| 467 | let timeOption = document.createElement('option');
|
---|
| 468 | timeOption.value = `${formattedHour}:${formattedMinutes}`;
|
---|
| 469 | timeOption.text = `${formattedHour}:${formattedMinutes}`;
|
---|
| 470 | timePicker.appendChild(timeOption);
|
---|
| 471 | }
|
---|
| 472 |
|
---|
| 473 | if (minutes % otherPickersInterval === 0) {
|
---|
| 474 | let timeOptionStart = document.createElement('option');
|
---|
| 475 | timeOptionStart.value = `${formattedHour}:${formattedMinutes}`;
|
---|
| 476 | timeOptionStart.text = `${formattedHour}:${formattedMinutes}`;
|
---|
| 477 | timePickerStart.appendChild(timeOptionStart);
|
---|
| 478 |
|
---|
| 479 | let timeOptionEnd = document.createElement('option');
|
---|
| 480 | timeOptionEnd.value = `${formattedHour}:${formattedMinutes}`;
|
---|
| 481 | timeOptionEnd.text = `${formattedHour}:${formattedMinutes}`;
|
---|
| 482 | timePickerEnd.appendChild(timeOptionEnd);
|
---|
| 483 | }
|
---|
| 484 | }
|
---|
| 485 | }
|
---|
| 486 | }
|
---|
| 487 |
|
---|
| 488 | function createSeparateAppointment(data){
|
---|
| 489 | fetch('/api/appointments/add', {
|
---|
| 490 | method: 'POST',
|
---|
| 491 | headers: {
|
---|
| 492 | 'Content-Type': 'application/json',
|
---|
| 493 | },
|
---|
| 494 | body: JSON.stringify(data),
|
---|
| 495 | })
|
---|
| 496 | .then(response => {
|
---|
| 497 | if (!response.ok) {
|
---|
| 498 | return response.json().then(errorData => {
|
---|
| 499 | throw new Error(errorData.error || 'Unknown error');
|
---|
| 500 | });
|
---|
| 501 | }
|
---|
| 502 | return response.json();
|
---|
| 503 | })
|
---|
| 504 | .then(data => {
|
---|
| 505 | console.log(data.message);
|
---|
| 506 | })
|
---|
| 507 | .catch(error => {
|
---|
| 508 | console.error('Error:', error);
|
---|
| 509 | });
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | async function deleteFreeAppointments() {
|
---|
| 513 | const selectedDateFrom = document.getElementById('delete-date-from').value;
|
---|
| 514 | const selectedDateTo = document.getElementById('delete-date-to').value;
|
---|
| 515 | if (!selectedDateFrom && !selectedDateTo) {
|
---|
| 516 | alert("Please select dates!");
|
---|
| 517 | return;
|
---|
| 518 | }
|
---|
| 519 |
|
---|
| 520 | try {
|
---|
| 521 | const response = await fetch(`/api/appointments/deleteFree?startDate=${selectedDateFrom}&endDate=${selectedDateTo}`, {
|
---|
| 522 | method: 'DELETE',
|
---|
| 523 | });
|
---|
| 524 |
|
---|
| 525 | if (response.ok) {
|
---|
| 526 | alert("Free appointments for the selected date range were deleted.");
|
---|
| 527 | } else {
|
---|
| 528 | alert("An error occurred while trying to delete the appointments.");
|
---|
| 529 | }
|
---|
| 530 | } catch (error) {
|
---|
| 531 | console.error("Error deleting appointments:", error);
|
---|
| 532 | alert("A network error occurred while trying to delete the appointments.");
|
---|
| 533 | }
|
---|
| 534 | document.getElementById('delete-date-from').value='';
|
---|
| 535 | document.getElementById('delete-date-to').value='';
|
---|
| 536 | }
|
---|
| 537 |
|
---|
| 538 | populateTimePicker();
|
---|
| 539 | document.addEventListener('DOMContentLoaded', () => {
|
---|
| 540 | const today = new Date();
|
---|
| 541 | const formattedDate = today.toISOString().split('T')[0];
|
---|
| 542 | document.getElementById('start-date').setAttribute('min', formattedDate);
|
---|
| 543 | document.getElementById('end-date').setAttribute('min',formattedDate);
|
---|
| 544 | const addTermButton = document.getElementById('add-Term');
|
---|
| 545 | const timePicker = document.getElementById('timePicker');
|
---|
| 546 | timePicker.addEventListener('click',()=>{
|
---|
| 547 | document.getElementById('start-time').selectedIndex = 0;
|
---|
| 548 | document.getElementById('end-time').selectedIndex=0;
|
---|
| 549 | document.getElementById('time-interval').value = '';
|
---|
| 550 | document.getElementById('start-date').value = '';
|
---|
| 551 | document.getElementById('end-date').value='';
|
---|
| 552 | document.getElementById('delete-date-from').value='';
|
---|
| 553 | document.getElementById('delete-date-to').value='';
|
---|
| 554 | })
|
---|
| 555 | addTermButton.addEventListener('click',async () => {
|
---|
| 556 | const selectedTime = timePicker.value;
|
---|
| 557 | if (importantDate && selectedTime) {
|
---|
| 558 | console.log(`Selected Date: ${importantDate}`);
|
---|
| 559 | console.log(`Selected Time: ${selectedTime}`);
|
---|
| 560 |
|
---|
| 561 | const data = {
|
---|
| 562 | date: importantDate,
|
---|
| 563 | time: selectedTime
|
---|
| 564 | };
|
---|
| 565 |
|
---|
| 566 |
|
---|
| 567 | const mapped = await getExistingAppointmentsMapped();
|
---|
| 568 | if (mapped.has(importantDate)) {
|
---|
| 569 | const existingTimes = mapped.get(importantDate);
|
---|
| 570 | if (checkOverlap(existingTimes, selectedTime)) {
|
---|
| 571 | const alertMessage = formatConflictAlert(data);
|
---|
| 572 | alert(alertMessage);
|
---|
| 573 | } else {
|
---|
| 574 | createSeparateAppointment(data);
|
---|
| 575 | }
|
---|
| 576 | }
|
---|
| 577 | else {
|
---|
| 578 | createSeparateAppointment(data);
|
---|
| 579 | }
|
---|
| 580 | resetFields();
|
---|
| 581 | } else {
|
---|
| 582 | console.error('Please select a date and time.');
|
---|
| 583 | }
|
---|
| 584 | });
|
---|
| 585 |
|
---|
| 586 | let tempContainer=document.getElementsByClassName('appointment-section')[0];
|
---|
| 587 | tempContainer.addEventListener('click',()=>{
|
---|
| 588 | document.getElementById('timePicker').selectedIndex=0;
|
---|
| 589 | })
|
---|
| 590 | document.getElementById('delete-free-button').addEventListener('click', deleteFreeAppointments);
|
---|
| 591 | });
|
---|
| 592 |
|
---|
| 593 |
|
---|