From 4fb8022c46d518e482e27d0ab0b564e16fb7ddb9 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sun, 14 Apr 2024 02:22:27 +0300 Subject: [PATCH] fix calendar popup --- components/availability/AvailabilityForm.js | 93 ++++++--------------- components/calendar/avcalendar.tsx | 78 ++++++++--------- pages/api/index.ts | 4 +- pages/cart/publishers/stats.tsx | 2 +- src/helpers/common.js | 6 +- 5 files changed, 70 insertions(+), 113 deletions(-) diff --git a/components/availability/AvailabilityForm.js b/components/availability/AvailabilityForm.js index 721df18..790223b 100644 --- a/components/availability/AvailabilityForm.js +++ b/components/availability/AvailabilityForm.js @@ -10,6 +10,8 @@ import { bgBG } from '../x-date-pickers/locales/bgBG'; import { ToastContainer } from 'react-toastify'; const common = require('src/helpers/common'); //todo import Availability type from prisma schema +import { isBefore, addMinutes, isAfter, isEqual, set, getHours, getMinutes, getSeconds } from 'date-fns'; + const fetchConfig = async () => { @@ -183,59 +185,6 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o return groupedIntervals; } - // // const firstSlotWithTransport = timeSlots[0].checked && timeSlots[0]?.isWithTransport; - // // const lastSlotWithTransport = timeSlots[timeSlots.length - 1].checked && timeSlots[timeSlots.length - 1]?.isWithTransport; - // function createAvailabilityFromGroup(group) { - // let startTime = new Date(day); - // startTime.setHours(group[0].startTime.getHours(), group[0].startTime.getMinutes(), group[0].startTime.getSeconds(), 0); - - // let endTime = new Date(day); - // endTime.setHours(group[group.length - 1].endTime.getHours(), group[group.length - 1].endTime.getMinutes(), group[group.length - 1].endTime.getSeconds(), 0); - - - // return { - // name: common.getTimeFomatted(startTime) + "-" + common.getTimeFomatted(endTime), - // publisherId: publisher.id, - // startTime: startTime, - // endTime: endTime, - // isWithTransportIn: group[0].isFirst && timeSlots[0].isWithTransport, - // isWithTransportOut: group[group.length - 1].isLast && timeSlots[timeSlots.length - 1].isWithTransport, - // dayofweek: common.getDayOfWeekNameEnEnumForDate(day.getDay()), - // repeatWeekly: doRepeat, - // dayOfMonth: doRepeat ? null : startTime.getDate(), - // endDate: doRepeat ? repeatUntil : null, - // dateOfEntry: new Date(), - // }; - // } - - // function updateAvailabilityFromGroup(availability, group) { - // availability.startTime.setTime(group[0].startTime); - // availability.endTime.setTime(group[group.length - 1].endTime); - // availability.name = common.getTimeFomatted(availability.startTime) + "-" + common.getTimeFomatted(availability.endTime); - - // availability.isWithTransportIn = group[0].isFirst && timeSlots[0].isWithTransport; - // availability.isWithTransportOut = group[group.length - 1].isLast && timeSlots[timeSlots.length - 1].isWithTransport; - - // delete availability.weekOfMonth; - // if (doRepeat) { - // availability.repeatWeekly = true; - // availability.dayOfMonth = null; - // availability.weekOfMonth = 0; - // availability.endDate = repeatUntil; - // } else { - // availability.repeatWeekly = false; - // availability.dayOfMonth = availability.startTime.getDate(); - // availability.endDate = null; - // } - - // availability.dateOfEntry = new Date(); - // if (availability.parentAvailabilityId) { - // availability.parentAvailability = { connect: { id: parentAvailabilityId } }; - // } - // delete availability.parentAvailabilityId; - - // return availability; - // } // Common function to set shared properties function setSharedAvailabilityProperties(availability, group, timeSlots) { let startTime = new Date(availability.startTime || day); @@ -332,22 +281,25 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o } // console.log("AvailabilityForm: publisherId: " + publisher.id + ", id: " + availabilit .id, ", inline: " + isInline); - + //ToDo: this is examplary function to be used in the future. replace all date/time related functions with this one const generateTimeSlots = (start, end, increment, items) => { const slots = []; - let currentTime = start.getTime(); + let currentTime = start; - const endTime = end.getTime(); + const baseDate = new Date(2000, 0, 1); // Use a constant date for all time comparisons - while (currentTime < endTime) { - let slotStart = new Date(currentTime); - let slotEnd = new Date(currentTime + increment * 60000); // increment is in minutes + while (isBefore(currentTime, end)) { + let slotStart = normalizeTime(currentTime, baseDate); + let slotEnd = normalizeTime(addMinutes(currentTime, increment), baseDate); - const isChecked = items.some(item => - item.startTime && item.endTime && - (slotStart.getTime() < item.endTime.getTime()) && - (slotEnd.getTime() > item.startTime.getTime()) - ); + const isChecked = items.some(item => { + let itemStart = item.startTime ? normalizeTime(new Date(item.startTime), baseDate) : null; + let itemEnd = item.endTime ? normalizeTime(new Date(item.endTime), baseDate) : null; + + return itemStart && itemEnd && + (slotStart.getTime() <= itemEnd.getTime()) && + (slotEnd.getTime() >= itemStart.getTime()); + }); slots.push({ startTime: slotStart, @@ -355,10 +307,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o isChecked: isChecked, }); - currentTime += increment * 60000; // Increment in milliseconds (minutes to milliseconds) + currentTime = addMinutes(currentTime, increment); } - // Optional: Add isFirst, isLast, and isWithTransport properties if (slots.length > 0 && items?.length > 0) { slots[0].isFirst = true; slots[slots.length - 1].isLast = true; @@ -369,6 +320,16 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o return slots; }; + // Normalize the time part of a date by using a base date + function normalizeTime(date, baseDate) { + return set(baseDate, { + hours: getHours(date), + minutes: getMinutes(date), + seconds: getSeconds(date), + milliseconds: 0 + }); + } + const TimeSlotCheckboxes = ({ slots, setSlots, items: [] }) => { const [allDay, setAllDay] = useState(slots.every(slot => slot.isChecked)); const handleAllDayChange = (e) => { diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx index a83d257..a7ab3b2 100644 --- a/components/calendar/avcalendar.tsx +++ b/components/calendar/avcalendar.tsx @@ -16,7 +16,12 @@ import { MdToday } from 'react-icons/md'; import { useSwipeable } from 'react-swipeable'; import axiosInstance from '../../src/axiosSecure'; -import { set } from 'date-fns'; +// import { set, format, addDays } from 'date-fns'; +import { isEqual, isSameDay, getHours, getMinutes } from 'date-fns'; +import { filter } from 'jszip'; + + + // Set moment to use the Bulgarian locale moment.locale('bg'); @@ -162,6 +167,31 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { occurrences.push(occurrence); } }; + const filterEvents = (evts, publisherId, startdate) => { + setDate(startdate); // Assuming setDate is a function that sets some state or context + + // Filter events based on the publisher ID and the start date/time + const existingEvents = evts?.filter(event => { + // Ensure the event belongs to the specified publisher + const isPublisherMatch = (event.publisher?.id || event.publisherId) === publisherId; + + let isDateMatch; + if (event.repeatWeekly && event.date) { + // Compare only the time part + const eventDate = new Date(event.startTime); + const isSameHour = getHours(eventDate) === getHours(startdate); + const isSameMinute = getMinutes(eventDate) === getMinutes(startdate); + isDateMatch = isSameHour && isSameMinute; + } else if (event.date) { + // Compare the full date + isDateMatch = isSameDay(new Date(event.date), startdate); + } + + return isPublisherMatch && isDateMatch; + }); + + return existingEvents; + }; // Define min and max times const minHour = 8; // 8:00 AM @@ -177,7 +207,8 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { const enddate = typeof end === 'string' ? new Date(end) : end; if (!start || !end) return; - if (startdate < new Date() || end < new Date() || startdate > end) return; + //readonly for past dates (ToDo: if not admin) + //if (startdate < new Date() || end < new Date() || startdate > end) return; // Check if start and end are on the same day if (startdate.toDateString() !== enddate.toDateString()) { @@ -198,52 +229,15 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { setDate(start); // get exising events for the selected date - const existingEvents = evts?.filter(event => (event.publisher?.id || event.publisherId) === publisherId && new Date(event.date).toDateString() === startdate.toDateString()); - // const existingEvents = evts?.filter(event => { - // return event.publisherId === publisherId && - // new Date(event.startTime).getFullYear() === start.getFullYear() && - // new Date(event.startTime).getMonth() === start.getMonth() && - // new Date(event.startTime).getDate() === start.getDate(); - // }); + const existingEvents = filterEvents(evts, publisherId, startdate); console.log("handleSelect: " + existingEvents); setSelectedEvents(existingEvents); - - // setSelectedEvent({ - // date: start, - // startTime: start, - // endTime: end, - // dayOfMonth: start.getDate(), - // isActive: true, - // publisherId: publisherId, - // // Add any other initial values needed - // //set dayOfMonth to null, so that we repeat the availability every week - // dayOfMonth: null, - - // }); - setIsModalOpen(true); + setIsModalOpen(true); }; const handleEventClick = (event) => { if (event.type === "assignment") return; handleSelect({ start: event.startTime, end: event.endTime }); - // Handle event click - // const eventForEditing = { - // ...event, - // startTime: new Date(event.startTime), - // endTime: new Date(event.endTime), - // publisherId: event.publisherId || event.publisher?.connect?.id, - // repeatWeekly: event.repeatWeekly || false, - // }; - // //strip title, start, end and allDay properties - // delete eventForEditing.title; - // delete eventForEditing.start; - // delete eventForEditing.end; - // delete eventForEditing.type; - // delete eventForEditing.publisher - // console.log("handleEventClick: " + eventForEditing); - // setSelectedEvents([eventForEditing]); - // setIsModalOpen(true); - }; const handleDialogClose = async (dialogEvent) => { @@ -256,10 +250,8 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { newEvents.forEach(event => { event.startTime = new Date(event.startTime); event.endTime = new Date(event.endTime); - }); setEvents(newEvents); - } console.log("handleSave: ", dialogEvent); diff --git a/pages/api/index.ts b/pages/api/index.ts index 538891d..a75d8ef 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -123,10 +123,10 @@ export default async function handler(req, res) { const availabilities = req.body; //! console.log("createAvailabilities: " + JSON.stringify(availabilities)); try { - await prisma.availability.createMany({ + let createResults = await prisma.availability.createMany({ data: availabilities }); - res.status(200).json({ "message": "ok" }); + res.status(200).json({ "message": "ok", "results": createResults }); } catch (error) { console.error("Error creating availabilities: " + error); res.status(500).json({ error }); diff --git a/pages/cart/publishers/stats.tsx b/pages/cart/publishers/stats.tsx index 5c55a68..b6ff171 100644 --- a/pages/cart/publishers/stats.tsx +++ b/pages/cart/publishers/stats.tsx @@ -24,7 +24,7 @@ function ContactsPage({ publishers, allPublishers }) {

Статистика

-
{publishers.length} участника с предпочитания (от {allPublishers.length} )
+
{publishers.length} участника с предпочитания за месеца (от {allPublishers.length} )