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