[743de55] | 1 | import { deleteAppointment, confirmCarriedOut, getUsersByTermExcept, removeRequestAndUpdateUser, removeAppointment, makeReservation ,displayDiv} from './shared.js';
|
---|
| 2 |
|
---|
[43c9090] | 3 | let lastClickedItem=null;
|
---|
[743de55] | 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 |
|
---|
[43c9090] | 112 | const response=await fetch(`/api/appointments/create`, {
|
---|
[743de55] | 113 | method: 'POST',
|
---|
| 114 | headers: {
|
---|
| 115 | 'Content-Type': 'application/json',
|
---|
| 116 | },
|
---|
[43c9090] | 117 | body: JSON.stringify(requestBody)
|
---|
[743de55] | 118 | });
|
---|
[43c9090] | 119 | if(response.ok){
|
---|
| 120 | location.reload();
|
---|
| 121 | }
|
---|
| 122 |
|
---|
[743de55] | 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 |
|
---|
[43c9090] | 131 | if (!startDate || !endDate || !startTime || !endTime || isNaN(interval)) {
|
---|
[743de55] | 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)) {
|
---|
[43c9090] | 149 | conflictingAppointments.push(newAppointment);
|
---|
[743de55] | 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 | })
|
---|
[43c9090] | 248 | displayDiv(dateTime);
|
---|
[743de55] | 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 () => {
|
---|
[43c9090] | 284 | document.getElementById("summary").style.display='none';
|
---|
[743de55] | 285 | try{
|
---|
[43c9090] | 286 | if(lastClickedItem){
|
---|
| 287 | lastClickedItem.style.backgroundColor="#f9f9f9";
|
---|
| 288 | }
|
---|
| 289 | lastClickedItem=itemDiv;
|
---|
| 290 | itemDiv.style.backgroundColor="grey";
|
---|
[743de55] | 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) {
|
---|
[43c9090] | 297 | document.getElementById("summary").style.display='block';
|
---|
[743de55] | 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){
|
---|
[43c9090] | 319 | document.getElementById("summary").style.display='block';
|
---|
[743de55] | 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{
|
---|
[43c9090] | 329 | document.getElementById("summary").style.display='none';
|
---|
[743de55] | 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', () => {
|
---|
[43c9090] | 407 | document.getElementById("summary").style.display='none';
|
---|
[743de55] | 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 |
|
---|
[43c9090] | 471 | for (let hour = 7; hour < 22; hour++) {
|
---|
[743de55] | 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);
|
---|
[43c9090] | 517 | location.reload();
|
---|
[743de55] | 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.");
|
---|
[43c9090] | 539 | location.reload();
|
---|
[743de55] | 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 |
|
---|