willba-component-library 0.2.56 → 0.2.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,4 @@
1
- import {
2
- addDays,
3
- startOfDay,
4
- format,
5
- isAfter,
6
- isBefore,
7
- endOfDay,
8
- } from 'date-fns'
1
+ import { addDays, isAfter, isBefore, endOfDay, isEqual } from 'date-fns'
9
2
  import { DateRange, Matcher } from 'react-day-picker'
10
3
 
11
4
  import { DisableCalendarDates, RangeContext } from '../CalendarTypes'
@@ -33,30 +26,31 @@ export const calendarSelectionRules = ({
33
26
  rangeContext,
34
27
  }: Props) => {
35
28
  // Get and parse needed data
36
- const dateFormat = 'dd-MM-yyyy'
37
- const rangeFrom = range?.from ? format(range.from, dateFormat) : null
38
- const rangeTo = range?.to ? format(range.to, dateFormat) : null
39
- const calendarFrom = calendarRange?.from
40
- ? format(calendarRange?.from, dateFormat)
41
- : null
42
- const calendarTo = calendarRange?.to
43
- ? format(calendarRange?.to, dateFormat)
29
+ const rangeFrom = range?.from ? endOfDay(range.from) : null
30
+ const rangeTo = range?.to ? endOfDay(range.to) : null
31
+ const calendarRangeFrom = calendarRange?.from
32
+ ? endOfDay(calendarRange.from)
44
33
  : null
34
+ const calendarRangeTo = calendarRange?.to ? endOfDay(calendarRange.to) : null
35
+
45
36
  const rangeContextFrom = rangeContext?.from
46
- ? format(rangeContext.from, dateFormat)
37
+ ? endOfDay(rangeContext.from)
47
38
  : null
39
+ const rangeContextTo = rangeContext?.to ? endOfDay(rangeContext.to) : null
48
40
 
49
41
  const overlappingDateFrom = overlappingDate?.length
50
42
  ? overlappingDate.find((date) =>
51
- date.from ? format(date.from, dateFormat) === rangeFrom : false
43
+ !!(date.from && rangeFrom)
44
+ ? isEqual(endOfDay(date.from), rangeFrom)
45
+ : false
52
46
  )
53
47
  : null
54
48
 
55
49
  const checkOutRange = newDisableCalendarDates?.availableDates?.length
56
- ? newDisableCalendarDates.availableDates.find(
57
- (checkInDate) =>
58
- format(checkInDate.checkIn || 1, dateFormat) ===
59
- format(range?.from || 1, dateFormat)
50
+ ? newDisableCalendarDates.availableDates.find((checkInDate) =>
51
+ !!(checkInDate.checkIn && rangeFrom)
52
+ ? isEqual(endOfDay(checkInDate.checkIn), rangeFrom)
53
+ : false
60
54
  )
61
55
  : null
62
56
 
@@ -65,57 +59,85 @@ export const calendarSelectionRules = ({
65
59
  rangeFrom,
66
60
  checkOutRange,
67
61
  setDisabledDates,
68
- dateFormat,
69
62
  newDisableCalendarDates,
70
63
  })
71
64
 
72
- // Calendar selection rules
73
- switch (true) {
74
- case !!overlappingDateFrom:
75
- // Clear the selection when overlapping dates are detected
76
- return setCalendarRange(undefined)
77
-
78
- case !!((!rangeTo && !rangeFrom && calendarFrom) || rangeTo === rangeFrom):
79
- // Handle double-click on the same date
80
- return setCalendarRange({ from: calendarRange?.from, to: undefined })
81
-
82
- case range?.to &&
83
- calendarRange?.to &&
84
- isAfter(endOfDay(range.to), endOfDay(calendarRange.to)) &&
85
- !(
86
- range?.to &&
87
- rangeContext?.to &&
88
- isAfter(startOfDay(range.to), startOfDay(rangeContext.to))
89
- ):
90
- // Handle checkout selection greater than current checkout
91
- return setCalendarRange({ from: range?.to, to: undefined })
92
-
93
- case calendarFrom && rangeFrom && rangeFrom !== calendarFrom:
94
- // Handle check-in selection prior to current check-in
95
- return setCalendarRange({ from: range?.from, to: undefined })
96
-
97
- case checkOutRange && range?.to && checkOutRange.lastCheckOut < range.to:
98
- return setCalendarRange({ from: range?.to, to: undefined })
99
-
100
- // Handle checkout selection between the range context and first passible check-in
101
- case range?.to &&
102
- rangeContext?.from &&
103
- isBefore(startOfDay(range.to), startOfDay(rangeContext.from)):
104
- return setCalendarRange({ from: range?.to, to: undefined })
105
-
106
- case range?.from &&
107
- rangeContext?.to &&
108
- isAfter(startOfDay(range.from), startOfDay(rangeContext.to)):
109
- return (
110
- setCalendarRange(undefined),
111
- setCalendarHasError && setCalendarHasError(true)
112
- )
113
- //
65
+ // Calendar selection rules: The cases are handled sequentially, starting from simple selections to more complex contextual selections.
66
+ // The rules are processed in a specific order, so one case is handled before another.
67
+ // Changing the order will cause the rules to break or not work properly.
68
+
69
+ if (!!overlappingDateFrom) {
70
+ // 1. If dates overlap, clear the selection.
71
+ return setCalendarRange(undefined)
72
+ }
114
73
 
115
- default:
116
- // Apply the given range
117
- return setCalendarRange(range)
74
+ if (
75
+ // 2. If selected "start" is after "range context end", clear selection and display error
76
+ (rangeFrom && rangeContextTo && isAfter(rangeFrom, rangeContextTo)) ||
77
+ (calendarRangeFrom &&
78
+ calendarRangeTo &&
79
+ rangeContextTo &&
80
+ rangeTo &&
81
+ isAfter(rangeTo, rangeContextTo))
82
+ ) {
83
+ setCalendarHasError && setCalendarHasError(true)
84
+ return setCalendarRange(undefined)
118
85
  }
86
+
87
+ if (rangeFrom && rangeTo && isEqual(rangeFrom, rangeTo)) {
88
+ // 3. If "start" is selected and the same date is clicked again, keep the current "start" selection.
89
+ return setCalendarRange({ from: rangeFrom, to: undefined })
90
+ }
91
+
92
+ if (calendarRangeFrom && calendarRangeTo && !range) {
93
+ // 4. If "calendarRange" has dates selected and the same "start" date is clicked, the "range" will become undefined.
94
+ // Set the current selection (calendarRange) to the initial "start" of calendarRange.
95
+ return setCalendarRange({ from: calendarRangeFrom, to: undefined })
96
+ }
97
+
98
+ // 5. Handle gap selection backwards and forwards
99
+ if (
100
+ // Enforce on every date selection before current "start", mark as "start" selection
101
+ rangeFrom &&
102
+ calendarRangeFrom &&
103
+ isBefore(rangeFrom, calendarRangeFrom)
104
+ ) {
105
+ return setCalendarRange({ from: rangeFrom, to: undefined })
106
+ }
107
+
108
+ if (
109
+ // Every date selection that is after selected "start" last checkout, mark as "start"
110
+ rangeTo &&
111
+ checkOutRange?.lastCheckOut &&
112
+ isAfter(rangeTo, endOfDay(checkOutRange.lastCheckOut))
113
+ ) {
114
+ return setCalendarRange({ from: rangeTo, to: undefined })
115
+ }
116
+
117
+ if (
118
+ calendarRangeFrom &&
119
+ rangeFrom &&
120
+ !isEqual(calendarRangeFrom, rangeFrom)
121
+ ) {
122
+ // 6. If "calendarRange" has selected dates and the new selection "start" differs from the current "calendarRange start", reset and make a new "start" selection.
123
+ return setCalendarRange({ from: rangeFrom, to: undefined })
124
+ } else if (calendarRangeTo && rangeTo && !isEqual(calendarRangeTo, rangeTo)) {
125
+ // 7. If "calendarRange" has selected dates and the new selection "end" differs from the current "calendarRange end", reset and make a new "start" selection.
126
+ return setCalendarRange({ from: rangeTo, to: undefined })
127
+ }
128
+
129
+ if (
130
+ // 8. If selected "end" is before "context start", mark as "start" and display error
131
+ rangeFrom &&
132
+ rangeTo &&
133
+ rangeContextFrom &&
134
+ isBefore(rangeTo, rangeContextFrom)
135
+ ) {
136
+ setCalendarHasError && setCalendarHasError(true)
137
+ return setCalendarRange({ from: rangeTo, to: undefined })
138
+ }
139
+
140
+ setCalendarRange(range)
119
141
  }
120
142
 
121
143
  /////////
@@ -124,26 +146,20 @@ const disableFutureDates = ({
124
146
  rangeFrom,
125
147
  checkOutRange,
126
148
  setDisabledDates,
127
- dateFormat,
128
149
  newDisableCalendarDates,
129
150
  }: {
130
- rangeFrom: string | null
151
+ rangeFrom: Date | null
131
152
  checkOutRange?:
132
153
  | NonNullable<DisableCalendarDates['availableDates']>['0']
133
154
  | null
134
155
  setDisabledDates?: (arg: Matcher[]) => void
135
- dateFormat: string
136
156
  newDisableCalendarDates?: DisableCalendarDates
137
157
  }) => {
138
158
  if (rangeFrom && checkOutRange && setDisabledDates) {
139
159
  // Get and parse data
140
160
  const checkIn = addDays(checkOutRange.checkIn, 1)
141
161
  const firstCheckOut = addDays(checkOutRange.firstCheckOut, -1)
142
- const noDatesRange =
143
- format(checkIn, dateFormat) ===
144
- format(checkOutRange.firstCheckOut, dateFormat)
145
-
146
- // -------------------
162
+ const noDatesRange = isEqual(checkIn, checkOutRange.firstCheckOut)
147
163
 
148
164
  setDisabledDates([
149
165
  // Will disable all dates before the check-in date