willba-component-library 0.2.23 → 0.2.25

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "willba-component-library",
3
- "version": "0.2.23",
3
+ "version": "0.2.25",
4
4
  "description": "A custom UI component library",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.esm.js",
@@ -87,7 +87,8 @@
87
87
 
88
88
  /* Tooltip */
89
89
  .will-root .will-calendar-filter-container .will-calendar-tooltip,
90
- .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out {
90
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out,
91
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-overlapping-date {
91
92
  position: absolute;
92
93
  top: -42px;
93
94
  transform: translateX(calc(-50% + 20px));
@@ -96,7 +97,8 @@
96
97
  z-index: 2;
97
98
  }
98
99
  .will-root .will-calendar-filter-container .will-calendar-tooltip > div,
99
- .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out> div {
100
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out > div,
101
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-overlapping-date > div {
100
102
  background-color: white;
101
103
  position: relative;
102
104
  padding: 5px 10px;
@@ -105,7 +107,8 @@
105
107
  }
106
108
 
107
109
  .will-root .will-calendar-filter-container .will-calendar-tooltip::before,
108
- .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out::before {
110
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-check-out::before,
111
+ .will-root .will-calendar-filter-container .will-calendar-tooltip-overlapping-date::before {
109
112
  content: "";
110
113
  width: 10px;
111
114
  height: 10px;
@@ -119,7 +122,8 @@
119
122
  }
120
123
 
121
124
  .will-root .will-calendar-filter-container .rdp-cell:hover .will-calendar-tooltip,
122
- .will-root .will-calendar-filter-container .rdp-cell:hover .will-calendar-tooltip-check-out {
125
+ .will-root .will-calendar-filter-container .rdp-cell:hover .will-calendar-tooltip-check-out,
126
+ .will-root .will-calendar-filter-container .rdp-cell:hover .will-calendar-tooltip-overlapping-date {
123
127
  display: block;
124
128
  }
125
129
 
@@ -145,8 +149,22 @@
145
149
 
146
150
  /* No active selection */
147
151
 
148
- .will-root .will-calendar-filter-container .no-active-selection {
149
- background-color: lightgrey;
152
+ .will-root .will-calendar-filter-container .rdp-day_selected.rdp-day_range_start.no-active-selection,
153
+ .will-root .will-calendar-filter-container .rdp-day_selected.rdp-day_range_middle.no-active-selection,
154
+ .will-root .will-calendar-filter-container .rdp-day_selected.rdp-day_range_end.no-active-selection {
155
+ background-color: var(--will-grey);
156
+ }
157
+
158
+ /* Overlapping date */
159
+
160
+ .will-root .will-calendar-filter-container .overlapping-date {
161
+ user-select: none;
162
+ pointer-events: none;
163
+
164
+ }
165
+
166
+ .will-root .will-calendar-filter-container .overlapping-date:hover {
167
+ cursor: not-allowed;
150
168
  }
151
169
 
152
170
 
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useEffect } from 'react'
1
+ import React, { forwardRef, useEffect, useMemo, useState } from 'react'
2
2
  import { addDays, startOfDay, format } from 'date-fns'
3
3
  import { fi, enUS } from 'date-fns/locale'
4
4
  import { useTranslation } from 'react-i18next'
@@ -36,19 +36,61 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
36
36
  const today = startOfDay(new Date())
37
37
  const selectedStartDate = calendarRange?.from
38
38
 
39
+ // Handle loading spinner
39
40
  useEffect(() => {
40
- if (!calendarRange) {
41
- setCalendarRange(undefined)
42
- } else if (calendarRange.from && calendarRange.to) {
43
- handleSelectedCheckIn({
44
- range: calendarRange,
45
- disableCalendarDates,
46
- setCalendarRange,
47
- setDisabledDates,
48
- calendarRange,
41
+ if (typeof document === 'undefined') return
42
+ const loadingSpinner: HTMLElement | null = document.querySelector(
43
+ '.will-filter-bar-calendar .will-calendar-spinner'
44
+ )
45
+ if (loadingData) {
46
+ if (loadingSpinner) loadingSpinner.style.display = 'flex'
47
+ } else {
48
+ if (loadingSpinner) loadingSpinner.style.display = 'none'
49
+ }
50
+ }, [loadingData])
51
+
52
+ // Handle overlapping availableDates.lastCheckOut and disabledDates.start
53
+ const [overlappingDate, setOverlappingDate] = useState<
54
+ DateRange | undefined
55
+ >(undefined)
56
+
57
+ useMemo(() => {
58
+ if (disableCalendarDates?.availableDates) {
59
+ const dateFormat = 'dd-MM-yyyy'
60
+
61
+ const availableDateMap = new Map()
62
+ disableCalendarDates.availableDates?.forEach((available) => {
63
+ availableDateMap.set(
64
+ format(available.lastCheckOut, dateFormat),
65
+ available
66
+ )
49
67
  })
68
+
69
+ const updatedDisabledDates = disableCalendarDates.disabledDates?.map(
70
+ (dateRange) => {
71
+ const formattedFromDate = format(dateRange.from, dateFormat)
72
+ if (availableDateMap.has(formattedFromDate)) {
73
+ setOverlappingDate(dateRange)
74
+
75
+ return {
76
+ ...dateRange,
77
+ from: addDays(dateRange.from, 1),
78
+ }
79
+ }
80
+ return dateRange
81
+ }
82
+ )
83
+
84
+ disableCalendarDates.disabledDates = updatedDisabledDates
50
85
  }
51
- }, [disableCalendarDates, calendarRange])
86
+ }, [disableCalendarDates])
87
+
88
+ // Handle disable dates by page
89
+ const disabledDatesByPage = handleDisabledDatesByPage({
90
+ today,
91
+ selectedPath,
92
+ disableCalendarDates,
93
+ })
52
94
 
53
95
  // Handle tooltip
54
96
  useEffect(() => {
@@ -58,6 +100,11 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
58
100
  const calendarTooltipCheckOut = document.querySelector(
59
101
  '.will-calendar-tooltip-check-out'
60
102
  )
103
+
104
+ const calendarTooltipOverlappingDate = document.querySelector(
105
+ '.will-calendar-tooltip-overlapping-date'
106
+ )
107
+
61
108
  const loadingSpinner = document.querySelector(
62
109
  '.will-filter-bar-calendar .will-calendar-spinner'
63
110
  )
@@ -70,6 +117,13 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
70
117
  const calendarMonthContainer = document.querySelector(
71
118
  '.will-filter-bar-calendar .rdp-months'
72
119
  )
120
+ const calendarOverlappingDate = document.querySelector(
121
+ '.will-filter-bar-calendar .rdp-cell:has(.overlapping-date)'
122
+ )
123
+ const appendedOverlappingDateTooltip: HTMLElement | null =
124
+ document.querySelector(
125
+ '.will-filter-bar-calendar .rdp-cell .will-calendar-tooltip-overlapping-date'
126
+ )
73
127
 
74
128
  const tooltipClones: Element[] = []
75
129
  const tooltipClonesCheckOut: Element[] = []
@@ -98,61 +152,24 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
98
152
  calendarMonthContainer.appendChild(loadingSpinner)
99
153
  }
100
154
 
155
+ if (
156
+ calendarOverlappingDate &&
157
+ calendarTooltipOverlappingDate &&
158
+ !appendedOverlappingDateTooltip &&
159
+ !calendarRange
160
+ ) {
161
+ calendarOverlappingDate.appendChild(calendarTooltipOverlappingDate)
162
+ } else if (calendarRange && appendedOverlappingDateTooltip) {
163
+ appendedOverlappingDateTooltip.style.visibility = 'hidden'
164
+ } else if (!calendarRange && appendedOverlappingDateTooltip) {
165
+ appendedOverlappingDateTooltip.style.visibility = 'visible'
166
+ }
167
+
101
168
  return () => {
102
169
  tooltipClones.forEach((clone) => clone.remove())
103
170
  tooltipClonesCheckOut.forEach((clone) => clone.remove())
104
171
  }
105
- }, [calendarRange, updateCalendar])
106
-
107
- // Handle loading spinner
108
- useEffect(() => {
109
- if (typeof document === 'undefined') return
110
- const loadingSpinner: HTMLElement | null = document.querySelector(
111
- '.will-filter-bar-calendar .will-calendar-spinner'
112
- )
113
- if (loadingData) {
114
- if (loadingSpinner) loadingSpinner.style.display = 'flex'
115
- } else {
116
- if (loadingSpinner) loadingSpinner.style.display = 'none'
117
- }
118
- }, [loadingData])
119
-
120
- // Handle overlapping availableDates.lastCheckOut and disabledDates.start
121
- useEffect(() => {
122
- if (disableCalendarDates) {
123
- const dateFormat = 'dd-MM-yyyy'
124
-
125
- const availableDateMap = new Map()
126
- disableCalendarDates.availableDates?.forEach((available) => {
127
- availableDateMap.set(
128
- format(available.lastCheckOut, dateFormat),
129
- available
130
- )
131
- })
132
-
133
- const updatedDisabledDates = disableCalendarDates.disabledDates?.map(
134
- (dateRange) => {
135
- const formattedFromDate = format(dateRange.from, dateFormat)
136
- if (availableDateMap.has(formattedFromDate)) {
137
- return {
138
- ...dateRange,
139
- from: addDays(dateRange.from, 1),
140
- }
141
- }
142
- return dateRange
143
- }
144
- )
145
-
146
- disableCalendarDates.disabledDates = updatedDisabledDates
147
- }
148
- }, [disableCalendarDates])
149
-
150
- // Handle disable dates by page
151
- const disabledDatesByPage = handleDisabledDatesByPage({
152
- today,
153
- selectedPath,
154
- disableCalendarDates,
155
- })
172
+ }, [calendarRange, updateCalendar, overlappingDate])
156
173
 
157
174
  return (
158
175
  <div className="will-filter-bar-calendar" ref={ref}>
@@ -171,14 +188,9 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
171
188
  setCalendarRange,
172
189
  setDisabledDates,
173
190
  calendarRange,
191
+ overlappingDate,
174
192
  })
175
193
  }
176
- modifiersClassNames={{
177
- today: 'my-today',
178
- booked: 'booked',
179
- disabledAfterCheckIn: 'disabled-after-check-in',
180
- noActiveSelection: 'no-active-selection',
181
- }}
182
194
  captionLayout="dropdown-buttons"
183
195
  defaultMonth={
184
196
  selectedStartDate ||
@@ -199,6 +211,19 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
199
211
  ? (requestDates(val), setUpdateCalendar((prev) => !prev))
200
212
  : null
201
213
  }}
214
+ modifiersClassNames={{
215
+ today: 'my-today',
216
+ booked: 'booked',
217
+ disabledAfterCheckIn: 'disabled-after-check-in',
218
+ overlappingDate: 'overlapping-date',
219
+
220
+ noActiveSelectionStart:
221
+ 'rdp-day_selected rdp-day_range_start no-active-selection ',
222
+ noActiveSelectionMid:
223
+ 'rdp-day_selected rdp-day_range_middle no-active-selection',
224
+ noActiveSelectionEnd:
225
+ 'rdp-day_selected rdp-day_range_end no-active-selection',
226
+ }}
202
227
  modifiers={{
203
228
  booked: disabledDatesByPage.length
204
229
  ? disabledDatesByPage
@@ -210,9 +235,26 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
210
235
  ? [{ after: calendarRange.from }]
211
236
  : [],
212
237
 
213
- noActiveSelection: !calendarRange
214
- ? initialCalendarRange || []
238
+ noActiveSelectionStart: !calendarRange
239
+ ? initialCalendarRange?.from || []
240
+ : [],
241
+ noActiveSelectionMid:
242
+ !calendarRange &&
243
+ initialCalendarRange?.from &&
244
+ initialCalendarRange?.to
245
+ ? [
246
+ {
247
+ after: initialCalendarRange?.from,
248
+ before: initialCalendarRange?.to,
249
+ },
250
+ ]
251
+ : [],
252
+ noActiveSelectionEnd: !calendarRange
253
+ ? initialCalendarRange?.to || []
215
254
  : [],
255
+
256
+ overlappingDate:
257
+ (!calendarRange?.from && overlappingDate?.from) || [],
216
258
  }}
217
259
  />
218
260
 
@@ -222,6 +264,9 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarTypes>(
222
264
  <div className={'will-calendar-tooltip-check-out'}>
223
265
  <div>{t('noCheckOut')}</div>
224
266
  </div>
267
+ <div className={'will-calendar-tooltip-overlapping-date'}>
268
+ <div>{t('checkOutOnly')}</div>
269
+ </div>
225
270
  <div className={'will-calendar-spinner'}>Loading...</div>
226
271
  </div>
227
272
  </div>
@@ -237,12 +282,14 @@ const handleSelectedCheckIn = ({
237
282
  setCalendarRange,
238
283
  setDisabledDates,
239
284
  calendarRange,
285
+ overlappingDate,
240
286
  }: {
241
287
  range: DateRange | undefined
242
288
  disableCalendarDates?: DisableCalendarDates
243
289
  setCalendarRange: (range: DateRange | undefined) => void
244
290
  setDisabledDates: ((arg: Matcher[]) => void) | undefined
245
291
  calendarRange?: DateRange
292
+ overlappingDate?: DateRange
246
293
  }) => {
247
294
  // Calendar dates select logic
248
295
  const dateFormat = 'dd-MM-yyyy'
@@ -255,6 +302,10 @@ const handleSelectedCheckIn = ({
255
302
  ? format(calendarRange?.to, dateFormat)
256
303
  : null
257
304
 
305
+ const overlappingDateFrom = overlappingDate?.from
306
+ ? format(overlappingDate.from, dateFormat)
307
+ : null
308
+
258
309
  const checkOutRange = disableCalendarDates?.availableDates?.length
259
310
  ? disableCalendarDates.availableDates.find(
260
311
  (checkInDate) =>
@@ -270,19 +321,6 @@ const handleSelectedCheckIn = ({
270
321
  format(checkIn, dateFormat) ===
271
322
  format(checkOutRange.firstCheckOut, dateFormat)
272
323
 
273
- // Handle overlapping availableDates.lastCheckOut and disabledDates.start
274
- // const filteredDisabledCalendarDates =
275
- // disableCalendarDates?.disabledDates?.map((dateRange) => {
276
- // if (
277
- // dateRange.from &&
278
- // format(dateRange.from, dateFormat) ===
279
- // format(checkOutRange.lastCheckOut, dateFormat)
280
- // ) {
281
- // return { ...dateRange, from: addDays(checkOutRange.lastCheckOut, 1) }
282
- // }
283
- // return dateRange
284
- // })
285
-
286
324
  setDisabledDates([
287
325
  // { before: findCheckOutRange?.checkIn },
288
326
 
@@ -299,7 +337,8 @@ const handleSelectedCheckIn = ({
299
337
 
300
338
  if (
301
339
  (rangeTo && rangeFrom && rangeFrom === rangeTo) ||
302
- (!rangeTo && !rangeFrom)
340
+ (!rangeTo && !rangeFrom) ||
341
+ rangeFrom === overlappingDateFrom
303
342
  ) {
304
343
  setCalendarRange(undefined)
305
344
  setDisabledDates && setDisabledDates([])
@@ -345,34 +384,3 @@ const handleDisabledDatesByPage = ({
345
384
  ]
346
385
  : []
347
386
  }
348
-
349
- // const handleOverlappingDates = ({
350
- // disableCalendarDates,
351
- // }: {
352
- // disableCalendarDates?: DisableCalendarDates
353
- // }): DisableCalendarDates | undefined => {
354
- // if (!disableCalendarDates) return undefined
355
-
356
- // const dateFormat = 'dd-MM-yyyy'
357
-
358
- // disableCalendarDates.disabledDates = disableCalendarDates.disabledDates?.map(
359
- // (dateRange) => {
360
- // const overlappingDate = disableCalendarDates.availableDates?.find(
361
- // (available) =>
362
- // format(available.lastCheckOut, dateFormat) ===
363
- // format(dateRange.from, dateFormat)
364
- // )
365
-
366
- // if (overlappingDate) {
367
- // return {
368
- // ...dateRange,
369
- // from: addDays(dateRange.from, 1),
370
- // }
371
- // }
372
-
373
- // return dateRange
374
- // }
375
- // )
376
-
377
- // return disableCalendarDates
378
- // }
@@ -7,5 +7,6 @@
7
7
  "apply": "Apply",
8
8
  "clearDates": "Clear dates",
9
9
  "noCheckIn": "Room not available",
10
- "noCheckOut": "Check-out not available"
10
+ "noCheckOut": "Check-out not available",
11
+ "checkOutOnly": "Check-out only"
11
12
  }
@@ -7,6 +7,7 @@
7
7
  "apply": "Aseta",
8
8
  "clearDates": "Tyhjennä",
9
9
  "noCheckIn": "Huone ei saatavilla",
10
- "noCheckOut": "Uloskirjaus ei saatavilla"
10
+ "noCheckOut": "Uloskirjaus ei saatavilla",
11
+ "checkOutOnly": "Vain uloskirjaus"
11
12
  }
12
13