@@ -16,7 +16,7 @@ export type DatePickerProps = {
1616 /** which day of the week to render the calendar. Usually Sunday (=0) or Monday (=1) - default: Sunday */
1717 weekStart ?: 0 | 1 | 2 | 3 | 4 | 5 | 6 ;
1818 /** Fires whenever a selected date is changed. */
19- onChange : ( date : Dayjs ) => void ;
19+ onChange : ( date : Dayjs | null ) => void ;
2020 /** Fires when the month is changed. */
2121 onMonthChange ?: ( date : Dayjs ) => void ;
2222 /** which date or dates are currently selected (not tracked from here) */
@@ -30,7 +30,7 @@ export type DatePickerProps = {
3030 /** Defaults to [], which dates are not bookable. Array of valid dates like: ["2022-04-23", "2022-04-24"] */
3131 excludedDates ?: string [ ] ;
3232 /** defaults to all, which dates are bookable (inverse of excludedDates) */
33- includedDates ?: string [ ] ;
33+ includedDates ?: string [ ] | null ;
3434 /** allows adding classes to the container */
3535 className ?: string ;
3636 /** Shows a small loading spinner next to the month name */
@@ -121,7 +121,7 @@ const Days = ({
121121 // Create placeholder elements for empty days in first week
122122 const weekdayOfFirst = browsingDate . date ( 1 ) . day ( ) ;
123123 const currentDate = minDate . utcOffset ( browsingDate . utcOffset ( ) ) ;
124- const availableDates = ( includedDates : string [ ] | undefined ) => {
124+ const availableDates = ( includedDates : string [ ] | undefined | null ) => {
125125 const dates = [ ] ;
126126 const lastDateOfMonth = browsingDate . date ( daysInMonth ( browsingDate ) ) ;
127127 for (
@@ -148,6 +148,21 @@ const Days = ({
148148 days . push ( date ) ;
149149 }
150150
151+ const daysToRenderForTheMonth = days . map ( ( day ) => {
152+ if ( ! day ) return { day : null , disabled : true } ;
153+ return {
154+ day : day ,
155+ disabled :
156+ ( includedDates && ! includedDates . includes ( yyyymmdd ( day ) ) ) || excludedDates . includes ( yyyymmdd ( day ) ) ,
157+ } ;
158+ } ) ;
159+
160+ useHandleInitialDateSelection ( {
161+ daysToRenderForTheMonth,
162+ selected,
163+ onChange : props . onChange ,
164+ } ) ;
165+
151166 const [ selectedDatesAndTimes ] = useBookerStore ( ( state ) => [ state . selectedDatesAndTimes ] , shallow ) ;
152167
153168 const isActive = ( day : dayjs . Dayjs ) => {
@@ -177,7 +192,7 @@ const Days = ({
177192
178193 return (
179194 < >
180- { days . map ( ( day , idx ) => (
195+ { daysToRenderForTheMonth . map ( ( { day, disabled } , idx ) => (
181196 < div key = { day === null ? `e-${ idx } ` : `day-${ day . format ( ) } ` } className = "relative w-full pt-[100%]" >
182197 { day === null ? (
183198 < div key = { `e-${ idx } ` } />
@@ -194,10 +209,7 @@ const Days = ({
194209 onClick = { ( ) => {
195210 props . onChange ( day ) ;
196211 } }
197- disabled = {
198- ( includedDates && ! includedDates . includes ( yyyymmdd ( day ) ) ) ||
199- excludedDates . includes ( yyyymmdd ( day ) )
200- }
212+ disabled = { disabled }
201213 active = { isActive ( day ) }
202214 />
203215 ) }
@@ -293,4 +305,41 @@ const DatePicker = ({
293305 ) ;
294306} ;
295307
308+ /**
309+ * Takes care of selecting a valid date in the month if the selected date is not available in the month
310+ */
311+ const useHandleInitialDateSelection = ( {
312+ daysToRenderForTheMonth,
313+ selected,
314+ onChange,
315+ } : {
316+ daysToRenderForTheMonth : { day : Dayjs | null ; disabled : boolean } [ ] ;
317+ selected : Dayjs | Dayjs [ ] | null | undefined ;
318+ onChange : ( date : Dayjs | null ) => void ;
319+ } ) => {
320+ // Let's not do something for now in case of multiple selected dates as behaviour is unclear and it's not needed at the moment
321+ if ( selected instanceof Array ) {
322+ return ;
323+ }
324+ const firstAvailableDateOfTheMonth = daysToRenderForTheMonth . find ( ( day ) => ! day . disabled ) ?. day ;
325+
326+ const isSelectedDateAvailable = selected
327+ ? daysToRenderForTheMonth . some ( ( { day, disabled } ) => {
328+ if ( day && yyyymmdd ( day ) === yyyymmdd ( selected ) && ! disabled ) return true ;
329+ } )
330+ : false ;
331+
332+ if ( firstAvailableDateOfTheMonth ) {
333+ // If selected date not available in the month, select the first available date of the month
334+ if ( ! isSelectedDateAvailable ) {
335+ onChange ( firstAvailableDateOfTheMonth ) ;
336+ }
337+ } else {
338+ // No date is available and if we were asked to select something inform that it couldn't be selected. This would actually help in not showing the timeslots section(with No Time Available) when no date in the month is available
339+ if ( selected ) {
340+ onChange ( null ) ;
341+ }
342+ }
343+ } ;
344+
296345export default DatePicker ;
0 commit comments