diff --git a/components/pages/calendar/EventCalendar.tsx b/components/pages/calendar/EventCalendar.tsx index da81a8f..7aac708 100644 --- a/components/pages/calendar/EventCalendar.tsx +++ b/components/pages/calendar/EventCalendar.tsx @@ -1,315 +1,337 @@ -import React, {useCallback, useEffect, useMemo, useState} from "react"; -import {Calendar} from "react-native-big-calendar"; -import {ActivityIndicator, StyleSheet, View, ViewStyle} from "react-native"; -import {useGetEvents} from "@/hooks/firebase/useGetEvents"; -import {useAtom, useSetAtom} from "jotai"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { Calendar } from "react-native-big-calendar"; +import { ActivityIndicator, StyleSheet, View, ViewStyle } from "react-native"; +import { useGetEvents } from "@/hooks/firebase/useGetEvents"; +import { useAtom, useSetAtom } from "jotai"; import { - editVisibleAtom, - eventForEditAtom, - modeAtom, - selectedDateAtom, - selectedNewEventDateAtom, + editVisibleAtom, + eventForEditAtom, + isAllDayAtom, + modeAtom, + selectedDateAtom, + selectedNewEventDateAtom, } from "@/components/pages/calendar/atoms"; -import {useAuthContext} from "@/contexts/AuthContext"; -import {CalendarEvent} from "@/components/pages/calendar/interfaces"; -import {Text} from "react-native-ui-lib"; -import {addDays, compareAsc, isWithinInterval, subDays} from "date-fns"; +import { useAuthContext } from "@/contexts/AuthContext"; +import { CalendarEvent } from "@/components/pages/calendar/interfaces"; +import { Text } from "react-native-ui-lib"; +import { addDays, compareAsc, isWithinInterval, subDays } from "date-fns"; interface EventCalendarProps { - calendarHeight: number; - // WAS USED FOR SCROLLABLE CALENDARS, PERFORMANCE WAS NOT OPTIMAL - calendarWidth: number; + calendarHeight: number; + // WAS USED FOR SCROLLABLE CALENDARS, PERFORMANCE WAS NOT OPTIMAL + calendarWidth: number; } const getTotalMinutes = () => { - const date = new Date(); - return Math.abs(date.getUTCHours() * 60 + date.getUTCMinutes() - 200); + const date = new Date(); + return Math.abs(date.getUTCHours() * 60 + date.getUTCMinutes() - 200); }; export const EventCalendar: React.FC = React.memo( - ({calendarHeight}) => { - const {data: events, isLoading} = useGetEvents(); - const {profileData} = useAuthContext(); - const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom); - const [mode, setMode] = useAtom(modeAtom); + ({ calendarHeight }) => { + const { data: events, isLoading } = useGetEvents(); + const { profileData } = useAuthContext(); + const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom); + const [mode, setMode] = useAtom(modeAtom); - const setEditVisible = useSetAtom(editVisibleAtom); - const setEventForEdit = useSetAtom(eventForEditAtom); - const setSelectedNewEndDate = useSetAtom(selectedNewEventDateAtom); + const setEditVisible = useSetAtom(editVisibleAtom); + const [isAllDay, setIsAllDay] = useAtom(isAllDayAtom); + const setEventForEdit = useSetAtom(eventForEditAtom); + const setSelectedNewEndDate = useSetAtom(selectedNewEventDateAtom); - const [offsetMinutes, setOffsetMinutes] = useState(getTotalMinutes()); + const [offsetMinutes, setOffsetMinutes] = useState(getTotalMinutes()); - const todaysDate = new Date(); + const todaysDate = new Date(); - const handlePressEvent = useCallback( - (event: CalendarEvent) => { - if (mode === "day" || mode === "week") { - setEditVisible(true); - console.log({event}); - setEventForEdit(event); - } else { - setMode("day"); - setSelectedDate(event.start); - } - }, - [setEditVisible, setEventForEdit, mode] - ); - - const handlePressCell = useCallback( - (date: Date) => { - if (mode === "day" || mode === "week") { - setSelectedNewEndDate(date); - } else { - setMode("day"); - setSelectedDate(date); - } - }, - [mode, setSelectedNewEndDate, setSelectedDate] - ); - - const handleSwipeEnd = useCallback( - (date: Date) => { - setSelectedDate(date); - }, - [setSelectedDate] - ); - - const memoizedEventCellStyle = useCallback( - (event: CalendarEvent) => ({backgroundColor: event.eventColor}), - [] - ); - - const memoizedWeekStartsOn = useMemo( - () => (profileData?.firstDayOfWeek === "Mondays" ? 1 : 0), - [profileData] - ); - - console.log({memoizedWeekStartsOn, profileData: profileData?.firstDayOfWeek}) - - const isSameDate = useCallback((date1: Date, date2: Date) => { - return ( - date1.getDate() === date2.getDate() && - date1.getMonth() === date2.getMonth() && - date1.getFullYear() === date2.getFullYear() - ); - }, []); - - const dayHeaderColor = useMemo(() => { - return isSameDate(todaysDate, selectedDate) ? "white" : "#4d4d4d"; - }, [selectedDate, mode]); - - const dateStyle = useMemo(() => { - if (mode === "week") return undefined; - return isSameDate(todaysDate, selectedDate) && mode === "day" - ? styles.dayHeader - : styles.otherDayHeader; - }, [selectedDate, mode]); - - const memoizedHeaderContentStyle = useMemo(() => { - if (mode === "day") { - return styles.dayModeHeader; - } else if (mode === "week") { - return styles.weekModeHeader; - } else if (mode === "month") { - return styles.monthModeHeader; - } else { - return {}; - } - }, [mode]); - - - const {enrichedEvents, filteredEvents} = useMemo(() => { - const startTime = Date.now(); // Start timer - - const startOffset = mode === "month" ? 40 : mode === "week" ? 10 : 1; - const endOffset = mode === "month" ? 40 : mode === "week" ? 10 : 1; - - const filteredEvents = events?.filter(event => - event.start && event.end && - isWithinInterval(event.start, { - start: subDays(selectedDate, startOffset), - end: addDays(selectedDate, endOffset) - }) && - isWithinInterval(event.end, { - start: subDays(selectedDate, startOffset), - end: addDays(selectedDate, endOffset) - }) - ) ?? []; - - const enrichedEvents = filteredEvents.reduce((acc, event) => { - const dateKey = event.start.toISOString().split('T')[0]; - acc[dateKey] = acc[dateKey] || []; - acc[dateKey].push({ - ...event, - overlapPosition: false, - overlapCount: 0 - }); - - acc[dateKey].sort((a, b) => compareAsc(a.start, b.start)); - - return acc; - }, {} as Record); - - const endTime = Date.now(); - console.log("memoizedEvents computation time:", endTime - startTime, "ms"); - - return {enrichedEvents, filteredEvents}; - }, [events, selectedDate, mode]); - - const renderCustomDateForMonth = (date: Date) => { - const circleStyle = useMemo( - () => ({ - width: 30, - height: 30, - justifyContent: "center", - alignItems: "center", - borderRadius: 15, - }), - [] - ); - - const defaultStyle = useMemo( - () => ({ - ...circleStyle, - }), - [circleStyle] - ); - - const currentDateStyle = useMemo( - () => ({ - ...circleStyle, - backgroundColor: "#4184f2", - }), - [circleStyle] - ); - - const renderDate = useCallback( - (date: Date) => { - const isCurrentDate = isSameDate(todaysDate, date); - const appliedStyle = isCurrentDate ? currentDateStyle : defaultStyle; - - return ( - - - - {date.getDate()} - - - - ); - }, - [todaysDate, currentDateStyle, defaultStyle] // dependencies - ); - - return renderDate(date); - }; - - useEffect(() => { - setOffsetMinutes(getTotalMinutes()); - }, [events, mode]); - - if (isLoading) { - return ( - - - - ); + const handlePressEvent = useCallback( + (event: CalendarEvent) => { + if (mode === "day" || mode === "week") { + setEditVisible(true); + console.log({ event }); + setEventForEdit(event); + } else { + setMode("day"); + setSelectedDate(event.start); } + }, + [setEditVisible, setEventForEdit, mode] + ); - // console.log(enrichedEvents, filteredEvents) + const handlePressCell = useCallback( + (date: Date) => { + if (mode === "day" || mode === "week") { + setSelectedNewEndDate(date); + } else { + setMode("day"); + setSelectedDate(date); + } + }, + [mode, setSelectedNewEndDate, setSelectedDate] + ); - return ( - - ); + const handlePressDayHeader = useCallback( + (date: Date) => { + setIsAllDay(true); + console.log(isAllDay); + setSelectedNewEndDate(date); + setEditVisible(true); + }, + [setSelectedNewEndDate] + ); + + const handleSwipeEnd = useCallback( + (date: Date) => { + setSelectedDate(date); + }, + [setSelectedDate] + ); + + const memoizedEventCellStyle = useCallback( + (event: CalendarEvent) => ({ backgroundColor: event.eventColor }), + [] + ); + + const memoizedWeekStartsOn = useMemo( + () => (profileData?.firstDayOfWeek === "Mondays" ? 1 : 0), + [profileData] + ); + + console.log({ + memoizedWeekStartsOn, + profileData: profileData?.firstDayOfWeek, + }); + + const isSameDate = useCallback((date1: Date, date2: Date) => { + return ( + date1.getDate() === date2.getDate() && + date1.getMonth() === date2.getMonth() && + date1.getFullYear() === date2.getFullYear() + ); + }, []); + + const dayHeaderColor = useMemo(() => { + return isSameDate(todaysDate, selectedDate) ? "white" : "#4d4d4d"; + }, [selectedDate, mode]); + + const dateStyle = useMemo(() => { + if (mode === "week") return undefined; + return isSameDate(todaysDate, selectedDate) && mode === "day" + ? styles.dayHeader + : styles.otherDayHeader; + }, [selectedDate, mode]); + + const memoizedHeaderContentStyle = useMemo(() => { + if (mode === "day") { + return styles.dayModeHeader; + } else if (mode === "week") { + return styles.weekModeHeader; + } else if (mode === "month") { + return styles.monthModeHeader; + } else { + return {}; + } + }, [mode]); + + const { enrichedEvents, filteredEvents } = useMemo(() => { + const startTime = Date.now(); // Start timer + + const startOffset = mode === "month" ? 40 : mode === "week" ? 10 : 1; + const endOffset = mode === "month" ? 40 : mode === "week" ? 10 : 1; + + const filteredEvents = + events?.filter( + (event) => + event.start && + event.end && + isWithinInterval(event.start, { + start: subDays(selectedDate, startOffset), + end: addDays(selectedDate, endOffset), + }) && + isWithinInterval(event.end, { + start: subDays(selectedDate, startOffset), + end: addDays(selectedDate, endOffset), + }) + ) ?? []; + + const enrichedEvents = filteredEvents.reduce((acc, event) => { + const dateKey = event.start.toISOString().split("T")[0]; + acc[dateKey] = acc[dateKey] || []; + acc[dateKey].push({ + ...event, + overlapPosition: false, + overlapCount: 0, + }); + + acc[dateKey].sort((a, b) => compareAsc(a.start, b.start)); + + return acc; + }, {} as Record); + + const endTime = Date.now(); + console.log( + "memoizedEvents computation time:", + endTime - startTime, + "ms" + ); + + return { enrichedEvents, filteredEvents }; + }, [events, selectedDate, mode]); + + const renderCustomDateForMonth = (date: Date) => { + const circleStyle = useMemo( + () => ({ + width: 30, + height: 30, + justifyContent: "center", + alignItems: "center", + borderRadius: 15, + }), + [] + ); + + const defaultStyle = useMemo( + () => ({ + ...circleStyle, + }), + [circleStyle] + ); + + const currentDateStyle = useMemo( + () => ({ + ...circleStyle, + backgroundColor: "#4184f2", + }), + [circleStyle] + ); + + const renderDate = useCallback( + (date: Date) => { + const isCurrentDate = isSameDate(todaysDate, date); + const appliedStyle = isCurrentDate ? currentDateStyle : defaultStyle; + + return ( + + + + {date.getDate()} + + + + ); + }, + [todaysDate, currentDateStyle, defaultStyle] // dependencies + ); + + return renderDate(date); + }; + + useEffect(() => { + setOffsetMinutes(getTotalMinutes()); + }, [events, mode]); + + if (isLoading) { + return ( + + + + ); } + + // console.log(enrichedEvents, filteredEvents) + + return ( + + ); + } ); const styles = StyleSheet.create({ - segmentslblStyle: { - fontSize: 12, - fontFamily: "Manrope_600SemiBold", - }, - calHeader: { - borderWidth: 0, - }, - dayModeHeader: { - alignSelf: "flex-start", - justifyContent: "space-between", - alignContent: "center", - width: 38, - right: 42, - height: 13, - }, - weekModeHeader: {}, - monthModeHeader: {}, - loadingContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - }, - dayHeader: { - backgroundColor: "#4184f2", - aspectRatio: 1, - borderRadius: 100, - alignItems: "center", - justifyContent: "center", - }, - otherDayHeader: { - backgroundColor: "transparent", - color: "#919191", - aspectRatio: 1, - borderRadius: 100, - alignItems: "center", - justifyContent: "center", - }, - hourStyle: { - color: "#5f6368", - fontSize: 12, - fontFamily: "Manrope_500Medium", - }, + segmentslblStyle: { + fontSize: 12, + fontFamily: "Manrope_600SemiBold", + }, + calHeader: { + borderWidth: 0, + }, + dayModeHeader: { + alignSelf: "flex-start", + justifyContent: "space-between", + alignContent: "center", + width: 38, + right: 42, + height: 13, + }, + weekModeHeader: {}, + monthModeHeader: {}, + loadingContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + }, + dayHeader: { + backgroundColor: "#4184f2", + aspectRatio: 1, + borderRadius: 100, + alignItems: "center", + justifyContent: "center", + }, + otherDayHeader: { + backgroundColor: "transparent", + color: "#919191", + aspectRatio: 1, + borderRadius: 100, + alignItems: "center", + justifyContent: "center", + }, + hourStyle: { + color: "#5f6368", + fontSize: 12, + fontFamily: "Manrope_500Medium", + }, }); diff --git a/components/pages/calendar/ManuallyAddEventModal.tsx b/components/pages/calendar/ManuallyAddEventModal.tsx index 2bd41ee..4a50b94 100644 --- a/components/pages/calendar/ManuallyAddEventModal.tsx +++ b/components/pages/calendar/ManuallyAddEventModal.tsx @@ -1,673 +1,731 @@ import { - Button, - ButtonSize, - Colors, - DateTimePicker, - LoaderScreen, - Modal, - Picker, - PickerModes, - Switch, - Text, - TextField, - TextFieldRef, - TouchableOpacity, - View, + Button, + ButtonSize, + Colors, + DateTimePicker, + LoaderScreen, + Modal, + Picker, + PickerModes, + Switch, + Text, + TextField, + TextFieldRef, + TouchableOpacity, + View, } from "react-native-ui-lib"; -import {ScrollView} from "react-native-gesture-handler"; -import {useSafeAreaInsets} from "react-native-safe-area-context"; -import {useEffect, useRef, useState} from "react"; -import {AntDesign, Feather, Ionicons} from "@expo/vector-icons"; -import {PickerMultiValue} from "react-native-ui-lib/src/components/picker/types"; -import {useCreateEvent} from "@/hooks/firebase/useCreateEvent"; -import {EventData} from "@/hooks/firebase/types/eventData"; -import {addHours} from "date-fns"; +import { ScrollView } from "react-native-gesture-handler"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { useEffect, useRef, useState } from "react"; +import { AntDesign, Feather, Ionicons } from "@expo/vector-icons"; +import { PickerMultiValue } from "react-native-ui-lib/src/components/picker/types"; +import { useCreateEvent } from "@/hooks/firebase/useCreateEvent"; +import { EventData } from "@/hooks/firebase/types/eventData"; +import { addHours } from "date-fns"; import DropModalIcon from "@/assets/svgs/DropModalIcon"; -import {StyleSheet} from "react-native"; +import { StyleSheet } from "react-native"; import ClockIcon from "@/assets/svgs/ClockIcon"; import LockIcon from "@/assets/svgs/LockIcon"; import MenuIcon from "@/assets/svgs/MenuIcon"; import CameraIcon from "@/assets/svgs/CameraIcon"; import AssigneesDisplay from "@/components/shared/AssigneesDisplay"; -import {useAtom} from "jotai"; -import {eventForEditAtom, selectedNewEventDateAtom,} from "@/components/pages/calendar/atoms"; -import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers"; +import { useAtom, useAtomValue } from "jotai"; +import { + eventForEditAtom, + selectedNewEventDateAtom, + isAllDayAtom, +} from "@/components/pages/calendar/atoms"; +import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers"; import BinIcon from "@/assets/svgs/BinIcon"; import DeleteEventDialog from "./DeleteEventDialog"; -import {useDeleteEvent} from "@/hooks/firebase/useDeleteEvent"; +import { useDeleteEvent } from "@/hooks/firebase/useDeleteEvent"; const daysOfWeek = [ - {label: "Monday", value: "monday"}, - {label: "Tuesday", value: "tuesday"}, - {label: "Wednesday", value: "wednesday"}, - {label: "Thursday", value: "thursday"}, - {label: "Friday", value: "friday"}, - {label: "Saturday", value: "saturday"}, - {label: "Sunday", value: "sunday"}, + { label: "Monday", value: "monday" }, + { label: "Tuesday", value: "tuesday" }, + { label: "Wednesday", value: "wednesday" }, + { label: "Thursday", value: "thursday" }, + { label: "Friday", value: "friday" }, + { label: "Saturday", value: "saturday" }, + { label: "Sunday", value: "sunday" }, ]; export const ManuallyAddEventModal = () => { - const insets = useSafeAreaInsets(); + const insets = useSafeAreaInsets(); - const [selectedNewEventDate, setSelectedNewEndDate] = useAtom( - selectedNewEventDateAtom - ); - const [editEvent, setEditEvent] = useAtom(eventForEditAtom); - const [deleteModalVisible, setDeleteModalVisible] = useState(false); - const {mutateAsync: deleteEvent, isLoading: isDeleting} = useDeleteEvent() + const [selectedNewEventDate, setSelectedNewEndDate] = useAtom( + selectedNewEventDateAtom + ); + const [editEvent, setEditEvent] = useAtom(eventForEditAtom); + const [allDayAtom, setAllDayAtom] = useAtom(isAllDayAtom); + const [deleteModalVisible, setDeleteModalVisible] = useState(false); + const { mutateAsync: deleteEvent, isLoading: isDeleting } = useDeleteEvent(); - const {show, close, initialDate} = { - show: !!selectedNewEventDate || !!editEvent, - close: () => { - setDeleteModalVisible(false); - setSelectedNewEndDate(undefined); - setEditEvent(undefined); - }, - initialDate: selectedNewEventDate || editEvent?.start, + const { show, close, initialDate } = { + show: !!selectedNewEventDate || !!editEvent, + close: () => { + setDeleteModalVisible(false); + setSelectedNewEndDate(undefined); + setEditEvent(undefined); + }, + initialDate: selectedNewEventDate || editEvent?.start, + }; + + const detailsRef = useRef(null); + + const [title, setTitle] = useState(editEvent?.title || ""); + const [details, setDetails] = useState(editEvent?.notes || ""); + const [isAllDay, setIsAllDay] = useState(editEvent?.allDay || false); + const [isPrivate, setIsPrivate] = useState( + editEvent?.private || false + ); + + useEffect(() => { + console.log(allDayAtom); + return () => { + setAllDayAtom(false); }; + }, []); - const detailsRef = useRef(null); + const [startTime, setStartTime] = useState(() => { + const date = initialDate ?? new Date(); + if ( + date.getMinutes() > 0 || + date.getSeconds() > 0 || + date.getMilliseconds() > 0 + ) { + date.setHours(date.getHours() + 1); + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + return date; + }); - const [title, setTitle] = useState(editEvent?.title || ""); - const [details, setDetails] = useState(editEvent?.notes || ""); - const [isAllDay, setIsAllDay] = useState(editEvent?.allDay || false); - const [isPrivate, setIsPrivate] = useState( - editEvent?.private || false - ); - const [startTime, setStartTime] = useState(() => { - const date = initialDate ?? new Date(); - date.setSeconds(0, 0); - return date; - }); - const [endTime, setEndTime] = useState(() => { - if (editEvent?.end) { - const date = new Date(editEvent.end); - date.setSeconds(0, 0); - return date; - } - const date = - editEvent?.end ?? initialDate - ? addHours(editEvent?.end ?? initialDate!, 1) - : addHours(new Date(), 1); - date.setSeconds(0, 0); - return date; - }); - const [startDate, setStartDate] = useState(initialDate ?? new Date()); - const [endDate, setEndDate] = useState( - editEvent?.end ?? initialDate ?? new Date() - ); - const [selectedAttendees, setSelectedAttendees] = useState( - editEvent?.participants ?? [] - ); - const [repeatInterval, setRepeatInterval] = useState([]); - - const {mutateAsync: createEvent, isLoading: isAdding, isError} = useCreateEvent(); - const {data: members} = useGetFamilyMembers(true); - const titleRef = useRef(null) - - const isLoading = isDeleting || isAdding - - useEffect(() => { - setTitle(editEvent?.title || ""); - setDetails(editEvent?.notes || ""); - setIsAllDay(editEvent?.allDay || false); - setIsPrivate(editEvent?.private || false); - setStartTime(() => { - const date = initialDate ?? new Date(); - date.setSeconds(0, 0); - return date; - }); - setEndTime(() => { - if (editEvent?.end) { - const date = new Date(editEvent.end); - date.setSeconds(0, 0); - return date; - } - const date = - editEvent?.end ?? initialDate - ? addHours(editEvent?.end ?? initialDate!, 1) - : addHours(new Date(), 1); - date.setSeconds(0, 0); - return date; - }); - setStartDate(initialDate ?? new Date()); - setEndDate(editEvent?.end ?? initialDate ?? new Date()); - setSelectedAttendees(editEvent?.participants ?? []); - setRepeatInterval([]); - }, [editEvent, selectedNewEventDate]); - - useEffect(() => { - if(show && !editEvent) { - setTimeout(() => { - titleRef?.current?.focus() - }, 500); - } - }, [selectedNewEventDate]); - - if (!show) return null; - - const formatDateTime = (date?: Date | string) => { - if (!date) return undefined; - return new Date(date).toLocaleDateString("en-US", { - weekday: "long", - month: "short", - day: "numeric", - }); - }; - - const showDeleteEventModal = () => { - setDeleteModalVisible(true); - }; - - const handleDeleteEvent = async () => { - await deleteEvent({eventId: `${editEvent?.id}`}) - close() - }; - - const hideDeleteEventModal = () => { - setDeleteModalVisible(false); - }; - - const combineDateAndTime = (date: Date, time: Date): Date => { - const combined = new Date(date); - combined.setHours(time.getHours()); - combined.setMinutes(time.getMinutes()); - combined.setSeconds(0); - combined.setMilliseconds(0); - return combined; - }; - - const handleSave = async () => { - let finalStartDate: Date; - let finalEndDate: Date; - - if (isAllDay) { - finalStartDate = new Date(startDate.setHours(0, 0, 0, 0)); - finalEndDate = new Date(startDate.setHours(0, 0, 0, 0)); - } else { - finalStartDate = combineDateAndTime(startDate, startTime); - finalEndDate = combineDateAndTime(endDate, endTime); - } - - const eventData: Partial = { - title: title, - startDate: finalStartDate, - endDate: finalEndDate, - allDay: isAllDay, - attendees: selectedAttendees, - notes: details, - }; - - if (editEvent?.id) eventData.id = editEvent?.id; - - await createEvent(eventData); - setEditEvent(undefined); - - close(); - }; - - const getRepeatLabel = () => { - const selectedDays = repeatInterval; - const allDays = [ - "sunday", - "monday", - "tuesday", - "wednesday", - "thursday", - "friday", - "saturday", - ]; - const workDays = ["monday", "tuesday", "wednesday", "thursday", "friday"]; - - const isEveryWorkDay = workDays.every((day) => selectedDays.includes(day)); - - const isEveryDay = allDays.every((day) => selectedDays.includes(day)); - - if (isEveryDay) { - return "Every day"; - } else if ( - isEveryWorkDay && - !selectedDays.includes("saturday") && - !selectedDays.includes("sunday") - ) { - return "Every work day"; - } else { - return selectedDays - .map((item) => daysOfWeek.find((day) => day.value === item)?.label) - .join(", "); - } - }; - - if (isLoading && !isError) { - return ( - - - - ); + const [endTime, setEndTime] = useState(() => { + if (editEvent?.end) { + const date = new Date(editEvent.end); + date.setSeconds(0, 0); + return date; } + const baseDate = editEvent?.end ?? initialDate ?? new Date(); + const date = new Date(baseDate); + + if ( + date.getMinutes() > 0 || + date.getSeconds() > 0 || + date.getMilliseconds() > 0 + ) { + date.setHours(date.getHours() + 1); + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + + date.setHours(date.getHours() + 1); + return date; + }); + const [startDate, setStartDate] = useState(initialDate ?? new Date()); + const [endDate, setEndDate] = useState( + editEvent?.end ?? initialDate ?? new Date() + ); + const [selectedAttendees, setSelectedAttendees] = useState( + editEvent?.participants ?? [] + ); + const [repeatInterval, setRepeatInterval] = useState([]); + + const { + mutateAsync: createEvent, + isLoading: isAdding, + isError, + } = useCreateEvent(); + const { data: members } = useGetFamilyMembers(true); + const titleRef = useRef(null); + + const isLoading = isDeleting || isAdding; + + useEffect(() => { + setTitle(editEvent?.title || ""); + setDetails(editEvent?.notes || ""); + setIsAllDay(editEvent?.allDay || false); + setIsPrivate(editEvent?.private || false); + + setStartTime(() => { + const date = new Date(initialDate ?? new Date()); + const minutes = date.getMinutes(); + date.setMinutes(0, 0, 0); + if (minutes >= 30) { + date.setHours(date.getHours() + 1); + } + return date; + }); + + setEndTime(() => { + if (editEvent?.end) { + const date = new Date(editEvent.end); + date.setSeconds(0, 0); + return date; + } + + const baseDate = editEvent?.end ?? initialDate ?? new Date(); + const date = new Date(baseDate); + + if ( + date.getMinutes() > 0 || + date.getSeconds() > 0 || + date.getMilliseconds() > 0 + ) { + date.setHours(date.getHours() + 1); + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + + date.setHours(date.getHours() + 1); + return date; + }); + + setStartDate(initialDate ?? new Date()); + setEndDate(editEvent?.end ?? initialDate ?? new Date()); + setSelectedAttendees(editEvent?.participants ?? []); + setRepeatInterval([]); + }, [editEvent, selectedNewEventDate]); + + useEffect(() => { + if (show && !editEvent) { + setTimeout(() => { + titleRef?.current?.focus(); + }, 500); + } + }, [selectedNewEventDate]); + + if (!show) return null; + + const formatDateTime = (date?: Date | string) => { + if (!date) return undefined; + return new Date(date).toLocaleDateString("en-US", { + weekday: "long", + month: "short", + day: "numeric", + }); + }; + + const showDeleteEventModal = () => { + setDeleteModalVisible(true); + }; + + const handleDeleteEvent = async () => { + await deleteEvent({ eventId: `${editEvent?.id}` }); + close(); + }; + + const hideDeleteEventModal = () => { + setDeleteModalVisible(false); + }; + + const combineDateAndTime = (date: Date, time: Date): Date => { + const combined = new Date(date); + combined.setHours(time.getHours()); + combined.setMinutes(time.getMinutes()); + combined.setSeconds(0); + combined.setMilliseconds(0); + return combined; + }; + + const handleSave = async () => { + let finalStartDate: Date; + let finalEndDate: Date; + + if (isAllDay) { + finalStartDate = new Date(startDate.setHours(0, 0, 0, 0)); + finalEndDate = new Date(startDate.setHours(0, 0, 0, 0)); + } else { + finalStartDate = combineDateAndTime(startDate, startTime); + finalEndDate = combineDateAndTime(endDate, endTime); + } + + const eventData: Partial = { + title: title, + startDate: finalStartDate, + endDate: finalEndDate, + allDay: isAllDay, + attendees: selectedAttendees, + notes: details, + }; + + if (editEvent?.id) eventData.id = editEvent?.id; + + await createEvent(eventData); + setEditEvent(undefined); + + close(); + }; + + const getRepeatLabel = () => { + const selectedDays = repeatInterval; + const allDays = [ + "sunday", + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + ]; + const workDays = ["monday", "tuesday", "wednesday", "thursday", "friday"]; + + const isEveryWorkDay = workDays.every((day) => selectedDays.includes(day)); + + const isEveryDay = allDays.every((day) => selectedDays.includes(day)); + + if (isEveryDay) { + return "Every day"; + } else if ( + isEveryWorkDay && + !selectedDays.includes("saturday") && + !selectedDays.includes("sunday") + ) { + return "Every work day"; + } else { + return selectedDays + .map((item) => daysOfWeek.find((day) => day.value === item)?.label) + .join(", "); + } + }; + + if (isLoading && !isError) { return ( - - - {/*{editEvent ? (*/} - {/* <>*/} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* }*/} - {/* onPress={close}*/} - {/* />*/} - {/* */} - {/* }*/} - {/* onPress={handleSave}*/} - {/* />*/} - {/* }*/} - {/* onPress={() => {*/} - {/* showDeleteEventModal();*/} - {/* }}*/} - {/* />*/} - {/* */} - {/* */} - {/* */} - {/*) : (*/} - - - - Cancel - - - - - - - - - Save - - - {editEvent && ( -