|
Lines 468-486
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 468 |
continue; |
468 |
continue; |
| 469 |
} |
469 |
} |
| 470 |
|
470 |
|
| 471 |
let start_date = flatpickr.parseDate( |
471 |
// Parse and normalize dates to start-of-day for consistent comparison |
| 472 |
booking.start_date |
472 |
let start_date = dayjs(booking.start_date) |
| 473 |
); |
473 |
.startOf("day") |
| 474 |
let end_date = flatpickr.parseDate( |
474 |
.toDate(); |
| 475 |
booking.end_date |
475 |
let end_date = dayjs(booking.end_date) |
| 476 |
); |
476 |
.startOf("day") |
|
|
477 |
.toDate(); |
| 477 |
|
478 |
|
| 478 |
// patron has selected a start date (end date checks) |
479 |
// patron has selected a start date (end date checks) |
| 479 |
if (selectedDates[0]) { |
480 |
if (selectedDates[0]) { |
|
|
481 |
// Normalize selected date to start-of-day for comparison |
| 482 |
let selectedStart = dayjs(selectedDates[0]) |
| 483 |
.startOf("day") |
| 484 |
.toDate(); |
| 485 |
|
| 480 |
// new booking start date is between existing booking start and end dates |
486 |
// new booking start date is between existing booking start and end dates |
| 481 |
if ( |
487 |
if ( |
| 482 |
selectedDates[0] >= start_date && |
488 |
selectedStart >= start_date && |
| 483 |
selectedDates[0] <= end_date |
489 |
selectedStart <= end_date |
| 484 |
) { |
490 |
) { |
| 485 |
if (booking.item_id) { |
491 |
if (booking.item_id) { |
| 486 |
if ( |
492 |
if ( |
|
Lines 506-562
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 506 |
} |
512 |
} |
| 507 |
|
513 |
|
| 508 |
// new booking end date would be between existing booking start and end dates |
514 |
// new booking end date would be between existing booking start and end dates |
| 509 |
else if ( |
515 |
else if (date) { |
| 510 |
date >= start_date && |
516 |
let selectedEnd = dayjs(date) |
| 511 |
date <= end_date |
517 |
.startOf("day") |
| 512 |
) { |
518 |
.toDate(); |
| 513 |
if (booking.item_id) { |
519 |
if ( |
| 514 |
if ( |
520 |
selectedEnd >= start_date && |
| 515 |
unavailable_items.indexOf( |
521 |
selectedEnd <= end_date |
| 516 |
booking.item_id |
522 |
) { |
| 517 |
) === -1 |
523 |
if (booking.item_id) { |
| 518 |
) { |
524 |
if ( |
| 519 |
unavailable_items.push( |
525 |
unavailable_items.indexOf( |
| 520 |
booking.item_id |
526 |
booking.item_id |
| 521 |
); |
527 |
) === -1 |
| 522 |
} |
528 |
) { |
| 523 |
} else { |
529 |
unavailable_items.push( |
| 524 |
if ( |
530 |
booking.item_id |
| 525 |
biblio_bookings.indexOf( |
531 |
); |
| 526 |
booking.booking_id |
532 |
} |
| 527 |
) === -1 |
533 |
} else { |
| 528 |
) { |
534 |
if ( |
| 529 |
biblio_bookings.push( |
535 |
biblio_bookings.indexOf( |
| 530 |
booking.booking_id |
536 |
booking.booking_id |
| 531 |
); |
537 |
) === -1 |
|
|
538 |
) { |
| 539 |
biblio_bookings.push( |
| 540 |
booking.booking_id |
| 541 |
); |
| 542 |
} |
| 532 |
} |
543 |
} |
| 533 |
} |
544 |
} |
| 534 |
} |
|
|
| 535 |
|
545 |
|
| 536 |
// new booking would span existing booking |
546 |
// new booking would span existing booking |
| 537 |
else if ( |
547 |
else if ( |
| 538 |
selectedDates[0] <= start_date && |
548 |
selectedStart <= start_date && |
| 539 |
date >= end_date |
549 |
selectedEnd >= end_date |
| 540 |
) { |
550 |
) { |
| 541 |
if (booking.item_id) { |
551 |
if (booking.item_id) { |
| 542 |
if ( |
552 |
if ( |
| 543 |
unavailable_items.indexOf( |
553 |
unavailable_items.indexOf( |
| 544 |
booking.item_id |
554 |
booking.item_id |
| 545 |
) === -1 |
555 |
) === -1 |
| 546 |
) { |
556 |
) { |
| 547 |
unavailable_items.push( |
557 |
unavailable_items.push( |
| 548 |
booking.item_id |
558 |
booking.item_id |
| 549 |
); |
559 |
); |
| 550 |
} |
560 |
} |
| 551 |
} else { |
561 |
} else { |
| 552 |
if ( |
562 |
if ( |
| 553 |
biblio_bookings.indexOf( |
563 |
biblio_bookings.indexOf( |
| 554 |
booking.booking_id |
564 |
booking.booking_id |
| 555 |
) === -1 |
565 |
) === -1 |
| 556 |
) { |
566 |
) { |
| 557 |
biblio_bookings.push( |
567 |
biblio_bookings.push( |
| 558 |
booking.booking_id |
568 |
booking.booking_id |
| 559 |
); |
569 |
); |
|
|
570 |
} |
| 560 |
} |
571 |
} |
| 561 |
} |
572 |
} |
| 562 |
} |
573 |
} |
|
Lines 777-786
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 777 |
// Range set, update hidden fields and set available items |
788 |
// Range set, update hidden fields and set available items |
| 778 |
else if (selectedDates[0] && selectedDates[1]) { |
789 |
else if (selectedDates[0] && selectedDates[1]) { |
| 779 |
// set form fields from picker |
790 |
// set form fields from picker |
| 780 |
let picker_start = dayjs(selectedDates[0]); |
791 |
// Ensure dates are normalized to start/end of day in browser timezone |
|
|
792 |
let picker_start = dayjs( |
| 793 |
selectedDates[0] |
| 794 |
).startOf("day"); |
| 781 |
let picker_end = dayjs(selectedDates[1]).endOf( |
795 |
let picker_end = dayjs(selectedDates[1]).endOf( |
| 782 |
"day" |
796 |
"day" |
| 783 |
); |
797 |
); |
|
|
798 |
// toISOString() converts to RFC3339 format with timezone offset |
| 784 |
$("#booking_start_date").val( |
799 |
$("#booking_start_date").val( |
| 785 |
picker_start.toISOString() |
800 |
picker_start.toISOString() |
| 786 |
); |
801 |
); |
|
Lines 791-808
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 791 |
// set available items in select2 |
806 |
// set available items in select2 |
| 792 |
let booked_items = bookings.filter( |
807 |
let booked_items = bookings.filter( |
| 793 |
function (booking) { |
808 |
function (booking) { |
| 794 |
let start_date = flatpickr.parseDate( |
809 |
// Parse and normalize dates to start-of-day for consistent comparison |
|
|
810 |
let start_date = dayjs( |
| 795 |
booking.start_date |
811 |
booking.start_date |
| 796 |
); |
812 |
) |
| 797 |
let end_date = flatpickr.parseDate( |
813 |
.startOf("day") |
| 798 |
booking.end_date |
814 |
.toDate(); |
| 799 |
); |
815 |
let end_date = dayjs(booking.end_date) |
|
|
816 |
.startOf("day") |
| 817 |
.toDate(); |
| 818 |
let selectedStart = dayjs( |
| 819 |
selectedDates[0] |
| 820 |
) |
| 821 |
.startOf("day") |
| 822 |
.toDate(); |
| 823 |
let selectedEnd = dayjs( |
| 824 |
selectedDates[1] |
| 825 |
) |
| 826 |
.startOf("day") |
| 827 |
.toDate(); |
| 828 |
|
| 800 |
// This booking ends before the start of the new booking |
829 |
// This booking ends before the start of the new booking |
| 801 |
if (end_date <= selectedDates[0]) { |
830 |
if (end_date < selectedStart) { |
| 802 |
return false; |
831 |
return false; |
| 803 |
} |
832 |
} |
| 804 |
// This booking starts after then end of the new booking |
833 |
// This booking starts after the end of the new booking |
| 805 |
if (start_date >= selectedDates[1]) { |
834 |
if (start_date > selectedEnd) { |
| 806 |
return false; |
835 |
return false; |
| 807 |
} |
836 |
} |
| 808 |
// This booking overlaps |
837 |
// This booking overlaps |
|
Lines 869-879
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 869 |
const item_id = booking.item_id; |
898 |
const item_id = booking.item_id; |
| 870 |
|
899 |
|
| 871 |
// Iterate through each date within the range of start_date and end_date |
900 |
// Iterate through each date within the range of start_date and end_date |
| 872 |
let currentDate = new Date(start_date); |
901 |
// Use dayjs to maintain browser timezone consistency |
| 873 |
while (currentDate <= end_date) { |
902 |
let currentDate = dayjs(start_date).startOf("day"); |
| 874 |
const currentDateStr = currentDate |
903 |
const endDate = dayjs(end_date).endOf("day"); |
| 875 |
.toISOString() |
904 |
|
| 876 |
.split("T")[0]; |
905 |
while (currentDate <= endDate) { |
|
|
906 |
// Format in browser timezone - no UTC conversion |
| 907 |
const currentDateStr = currentDate.format("YYYY-MM-DD"); |
| 877 |
|
908 |
|
| 878 |
// If the date key doesn't exist in the hash, create an empty array for it |
909 |
// If the date key doesn't exist in the hash, create an empty array for it |
| 879 |
if (!bookingsByDate[currentDateStr]) { |
910 |
if (!bookingsByDate[currentDateStr]) { |
|
Lines 884-890
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 884 |
bookingsByDate[currentDateStr].push(item_id); |
915 |
bookingsByDate[currentDateStr].push(item_id); |
| 885 |
|
916 |
|
| 886 |
// Move to the next day |
917 |
// Move to the next day |
| 887 |
currentDate.setDate(currentDate.getDate() + 1); |
918 |
currentDate = currentDate.add(1, "day"); |
| 888 |
} |
919 |
} |
| 889 |
}); |
920 |
}); |
| 890 |
|
921 |
|
|
Lines 896-904
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 896 |
periodPicker.config.onDayCreate.push( |
927 |
periodPicker.config.onDayCreate.push( |
| 897 |
function dayCreate(dObj, dStr, instance, dayElem) { |
928 |
function dayCreate(dObj, dStr, instance, dayElem) { |
| 898 |
const currentDate = dayElem.dateObj; |
929 |
const currentDate = dayElem.dateObj; |
| 899 |
const dateString = currentDate |
930 |
// Format in browser timezone to match bookingsByDate keys |
| 900 |
.toISOString() |
931 |
const dateString = |
| 901 |
.split("T")[0]; |
932 |
dayjs(currentDate).format("YYYY-MM-DD"); |
| 902 |
|
933 |
|
| 903 |
const isBold = boldDates.some( |
934 |
const isBold = boldDates.some( |
| 904 |
boldDate => |
935 |
boldDate => |
| 905 |
- |
|
|