2023-06-16 16:08:58 +00:00
import { create } from "zustand" ;
2022-12-14 13:36:10 +00:00
import dayjs from "@calcom/dayjs" ;
2023-06-16 16:08:58 +00:00
import type {
2022-12-14 13:36:10 +00:00
CalendarComponentProps ,
CalendarPublicActions ,
CalendarState ,
CalendarStoreProps ,
} from "../types/state" ;
import { mergeOverlappingDateRanges , weekdayDates } from "../utils" ;
const defaultState : CalendarComponentProps = {
view : "week" ,
startDate : weekdayDates ( 0 , new Date ( ) ) . startDate ,
endDate : weekdayDates ( 0 , new Date ( ) ) . endDate ,
events : [ ] ,
startHour : 0 ,
endHour : 23 ,
gridCellsPerHour : 4 ,
} ;
export const useCalendarStore = create < CalendarStoreProps > ( ( set ) = > ( {
. . . defaultState ,
setView : ( view : CalendarComponentProps [ "view" ] ) = > set ( { view } ) ,
setStartDate : ( startDate : CalendarComponentProps [ "startDate" ] ) = > set ( { startDate } ) ,
setEndDate : ( endDate : CalendarComponentProps [ "endDate" ] ) = > set ( { endDate } ) ,
setEvents : ( events : CalendarComponentProps [ "events" ] ) = > set ( { events } ) ,
// This looks a bit odd but init state only overrides the public props + actions as we don't want to override our internal state
initState : ( state : CalendarState & CalendarPublicActions ) = > {
// Handle sorting of events if required
let events = state . events ;
if ( state . sortEvents ) {
events = state . events . sort (
( a , b ) = > dayjs ( a . start ) . get ( "milliseconds" ) - dayjs ( b . start ) . get ( "milliseconds" )
) ;
}
const blockingDates = mergeOverlappingDateRanges ( state . blockingDates || [ ] ) ; // We merge overlapping dates so we don't get duplicate blocking "Cells" in the UI
set ( {
. . . state ,
blockingDates ,
events ,
} ) ;
} ,
setSelectedEvent : ( event ) = > set ( { selectedEvent : event } ) ,
handleDateChange : ( payload ) = >
set ( ( state ) = > {
const { startDate , endDate } = state ;
if ( payload === "INCREMENT" ) {
const newStartDate = dayjs ( startDate ) . add ( 1 , state . view ) . toDate ( ) ;
const newEndDate = dayjs ( endDate ) . add ( 1 , state . view ) . toDate ( ) ;
// Do nothing if
if (
( state . minDate && newStartDate < state . minDate ) ||
( state . maxDate && newEndDate > state . maxDate )
) {
return {
startDate ,
endDate ,
} ;
}
// We call this callback if we have it -> Allows you to change your state outside of the component
state . onDateChange && state . onDateChange ( newStartDate , newEndDate ) ;
return {
startDate : newStartDate ,
endDate : newEndDate ,
} ;
}
const newStartDate = dayjs ( startDate ) . subtract ( 1 , state . view ) . toDate ( ) ;
const newEndDate = dayjs ( endDate ) . subtract ( 1 , state . view ) . toDate ( ) ;
state . onDateChange && state . onDateChange ( newStartDate , newEndDate ) ;
return {
startDate : newStartDate ,
endDate : newEndDate ,
} ;
} ) ,
} ) ) ;