@cleartrip/ct-design-calendar 4.0.0 → 5.0.0

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.
Files changed (119) hide show
  1. package/dist/Arrow/LeftArrow.d.ts +3 -0
  2. package/dist/Arrow/LeftArrow.d.ts.map +1 -0
  3. package/dist/Arrow/RightArrow.d.ts +3 -0
  4. package/dist/Arrow/RightArrow.d.ts.map +1 -0
  5. package/dist/BaseCalendar.d.ts +4 -0
  6. package/dist/BaseCalendar.d.ts.map +1 -0
  7. package/dist/Calendar.d.ts +4 -0
  8. package/dist/Calendar.d.ts.map +1 -0
  9. package/dist/Calendar.native.d.ts +4 -0
  10. package/dist/Calendar.native.d.ts.map +1 -0
  11. package/dist/CalendarBody/LazyMonthList.d.ts +4 -0
  12. package/dist/CalendarBody/LazyMonthList.d.ts.map +1 -0
  13. package/dist/CalendarBody/PlaceholderMonth.d.ts +5 -0
  14. package/dist/CalendarBody/PlaceholderMonth.d.ts.map +1 -0
  15. package/dist/CalendarBody/index.d.ts +4 -0
  16. package/dist/CalendarBody/index.d.ts.map +1 -0
  17. package/dist/CalendarDayElements/CalendarDate.d.ts +4 -0
  18. package/dist/CalendarDayElements/CalendarDate.d.ts.map +1 -0
  19. package/dist/CalendarDayElements/CalendarDot.d.ts +4 -0
  20. package/dist/CalendarDayElements/CalendarDot.d.ts.map +1 -0
  21. package/dist/CalendarDayElements/CalendarDotWrapper.d.ts +5 -0
  22. package/dist/CalendarDayElements/CalendarDotWrapper.d.ts.map +1 -0
  23. package/dist/CalendarDayElements/CalendarRange.d.ts +4 -0
  24. package/dist/CalendarDayElements/CalendarRange.d.ts.map +1 -0
  25. package/dist/CalendarDayElements/index.d.ts +4 -0
  26. package/dist/CalendarDayElements/index.d.ts.map +1 -0
  27. package/dist/CalendarDayElements/useForceRerender.d.ts +5 -0
  28. package/dist/CalendarDayElements/useForceRerender.d.ts.map +1 -0
  29. package/dist/CalendarMonth/CalendarMonthBody.d.ts +4 -0
  30. package/dist/CalendarMonth/CalendarMonthBody.d.ts.map +1 -0
  31. package/dist/CalendarMonth/CalendarMonthFooter.d.ts +5 -0
  32. package/dist/CalendarMonth/CalendarMonthFooter.d.ts.map +1 -0
  33. package/dist/CalendarMonth/CalendarMonthHeader.d.ts +4 -0
  34. package/dist/CalendarMonth/CalendarMonthHeader.d.ts.map +1 -0
  35. package/dist/CalendarMonth/index.d.ts +12 -0
  36. package/dist/CalendarMonth/index.d.ts.map +1 -0
  37. package/dist/Caption/index.d.ts +4 -0
  38. package/dist/Caption/index.d.ts.map +1 -0
  39. package/dist/DayPicker.d.ts +62 -0
  40. package/dist/DayPicker.d.ts.map +1 -0
  41. package/dist/Footer/CheckinCheckout.d.ts +11 -0
  42. package/dist/Footer/CheckinCheckout.d.ts.map +1 -0
  43. package/dist/Footer/LongWeekend.d.ts +5 -0
  44. package/dist/Footer/LongWeekend.d.ts.map +1 -0
  45. package/dist/Footer/constants.d.ts +7 -0
  46. package/dist/Footer/constants.d.ts.map +1 -0
  47. package/dist/Footer/index.d.ts +14 -0
  48. package/dist/Footer/index.d.ts.map +1 -0
  49. package/dist/WeekDays.d.ts +3 -0
  50. package/dist/WeekDays.d.ts.map +1 -0
  51. package/dist/constants.d.ts +13 -0
  52. package/dist/constants.d.ts.map +1 -0
  53. package/dist/ct-design-calendar.browser.cjs.js +2 -0
  54. package/dist/ct-design-calendar.browser.cjs.js.map +1 -0
  55. package/dist/ct-design-calendar.browser.esm.js +2 -0
  56. package/dist/ct-design-calendar.browser.esm.js.map +1 -0
  57. package/dist/ct-design-calendar.cjs.js +67 -0
  58. package/dist/ct-design-calendar.cjs.js.map +1 -0
  59. package/dist/ct-design-calendar.esm.js +61 -0
  60. package/dist/ct-design-calendar.esm.js.map +1 -0
  61. package/dist/ct-design-calendar.umd.js +70 -0
  62. package/dist/ct-design-calendar.umd.js.map +1 -0
  63. package/dist/event/EventEmitter/index.d.ts +10 -0
  64. package/dist/event/EventEmitter/index.d.ts.map +1 -0
  65. package/dist/event/EventEmitter/type.d.ts +10 -0
  66. package/dist/event/EventEmitter/type.d.ts.map +1 -0
  67. package/dist/event/constants.d.ts +6 -0
  68. package/dist/event/constants.d.ts.map +1 -0
  69. package/dist/event/index.d.ts +8 -0
  70. package/dist/event/index.d.ts.map +1 -0
  71. package/dist/globalStyle.d.ts +2 -0
  72. package/dist/globalStyle.d.ts.map +1 -0
  73. package/dist/index.d.ts +4 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/style.d.ts +2 -0
  76. package/dist/style.d.ts.map +1 -0
  77. package/dist/styles.d.ts +570 -0
  78. package/dist/styles.d.ts.map +1 -0
  79. package/dist/type.d.ts +58 -0
  80. package/dist/type.d.ts.map +1 -0
  81. package/dist/util.d.ts +22 -0
  82. package/dist/util.d.ts.map +1 -0
  83. package/package.json +32 -5
  84. package/src/Arrow/LeftArrow.tsx +13 -0
  85. package/src/Arrow/RightArrow.tsx +13 -0
  86. package/src/BaseCalendar.tsx +189 -0
  87. package/src/Calendar.native.tsx +99 -0
  88. package/src/Calendar.tsx +13 -0
  89. package/src/CalendarBody/LazyMonthList.tsx +45 -0
  90. package/src/CalendarBody/PlaceholderMonth.tsx +20 -0
  91. package/src/CalendarBody/index.tsx +159 -0
  92. package/src/CalendarDayElements/CalendarDate.tsx +34 -0
  93. package/src/CalendarDayElements/CalendarDot.tsx +11 -0
  94. package/src/CalendarDayElements/CalendarDotWrapper.tsx +17 -0
  95. package/src/CalendarDayElements/CalendarRange.tsx +54 -0
  96. package/src/CalendarDayElements/index.tsx +77 -0
  97. package/src/CalendarDayElements/useForceRerender.ts +14 -0
  98. package/src/CalendarMonth/CalendarMonthBody.tsx +39 -0
  99. package/src/CalendarMonth/CalendarMonthFooter.tsx +70 -0
  100. package/src/CalendarMonth/CalendarMonthHeader.tsx +15 -0
  101. package/src/CalendarMonth/index.tsx +43 -0
  102. package/src/Caption/index.tsx +39 -0
  103. package/src/DayPicker.tsx +324 -0
  104. package/src/Footer/CheckinCheckout.tsx +196 -0
  105. package/src/Footer/LongWeekend.tsx +98 -0
  106. package/src/Footer/constants.ts +7 -0
  107. package/src/Footer/index.tsx +84 -0
  108. package/src/WeekDays.tsx +20 -0
  109. package/src/constants.ts +54 -0
  110. package/src/event/EventEmitter/index.ts +34 -0
  111. package/src/event/EventEmitter/type.ts +10 -0
  112. package/src/event/constants.ts +5 -0
  113. package/src/event/index.tsx +21 -0
  114. package/src/globalStyle.ts +351 -0
  115. package/src/index.ts +3 -0
  116. package/src/style.ts +333 -0
  117. package/src/styles.ts +167 -0
  118. package/src/type.ts +66 -0
  119. package/src/util.ts +114 -0
@@ -0,0 +1,324 @@
1
+ import { CSSProperties, useEffect, useMemo } from 'react';
2
+ import dayjs from 'dayjs';
3
+ import {
4
+ DayPicker,
5
+ DayContent,
6
+ DayContentProps,
7
+ DateFormatter,
8
+ DayClickEventHandler,
9
+ DayPickerDefaultProps,
10
+ DayPickerMultipleProps,
11
+ DayPickerRangeProps,
12
+ DayPickerSingleProps,
13
+ Matcher,
14
+ ModifiersClassNames,
15
+ ModifiersStyles,
16
+ SelectMultipleModifiers,
17
+ SelectRangeEventHandler,
18
+ SelectRangeModifiers,
19
+ WeekNumberFormatter,
20
+ FooterProps,
21
+ } from 'react-day-picker';
22
+ import { WEEK_DAY_LABEL } from '@cleartrip/ct-design-common-constants';
23
+ import { getNestedField } from '@cleartrip/ct-design-common-utils';
24
+ import { Container } from '@cleartrip/ct-design-container';
25
+ import { useTheme } from '@cleartrip/ct-design-theme';
26
+ import { Typography } from '@cleartrip/ct-design-typography';
27
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
28
+
29
+ import { Caption } from './Caption';
30
+ import './globalStyle';
31
+
32
+ type DayPickerType = DayPickerDefaultProps | DayPickerSingleProps | DayPickerMultipleProps | DayPickerRangeProps;
33
+
34
+ type DayPickerProps = Pick<DayPickerType, 'mode'>;
35
+
36
+ export interface IDate {
37
+ from: Date;
38
+ to: Date;
39
+ }
40
+
41
+ type CustomDay = {
42
+ dots?: {
43
+ showDots?: boolean;
44
+ dotsData?: string[];
45
+ styleProps?: CSSProperties;
46
+ };
47
+ dayFooter?: {
48
+ showDayFooter?: boolean;
49
+ dayFooterData?: { date?: string; text?: string }[]; // TODO(@Om @Kanishk): fix type for this later
50
+ styleProps?: CSSProperties;
51
+ };
52
+ };
53
+
54
+ export interface DateRangeProps extends DayPickerProps {
55
+ /**
56
+ * props to format the dates.
57
+ */
58
+ labelFormat?: string;
59
+ /**
60
+ *
61
+ * @param day
62
+ * @returns dateclick callback and below is for the range date click.
63
+ */
64
+ onDayClick?: DayClickEventHandler;
65
+ onDateSelect: SelectRangeEventHandler;
66
+
67
+ selectedDays?: { from: Date; to: Date };
68
+ /**
69
+ * total number of months need to render
70
+ */
71
+ noOfMonths: number;
72
+ /**
73
+ * Incase any required changes come to modify header to show icons along with month name.
74
+ */
75
+ customHeader?: React.FC;
76
+ min?: number;
77
+ max?: number;
78
+ disabledDays?: Matcher | Matcher[];
79
+ /**
80
+ * modifiersStyles specifies styles to those dates.
81
+ */
82
+ modifierStyles?: ModifiersStyles;
83
+ modifiersClassName?: ModifiersClassNames;
84
+ fromMonth?: Date;
85
+ toDate?: Date;
86
+ defaultMonth?: Date;
87
+ /**
88
+ *
89
+ * @returns this props is for scrolling to selected month.
90
+ */
91
+ setScrollToIndex?: () => void;
92
+ formatters?: DateFormatter | WeekNumberFormatter;
93
+ scrollToIndex?: React.RefObject<HTMLElement>;
94
+ /**
95
+ * props which provide the container width to calculate the table cell size.
96
+ */
97
+ containerWidth?: number;
98
+ /**
99
+ * modifiers are for modifiying the relevant dates
100
+ */
101
+ modifiers?: SelectRangeModifiers | SelectMultipleModifiers;
102
+
103
+ /**
104
+ * cellwidth is calculated based on the container width.
105
+ */
106
+ cellWidth?: number;
107
+ cellHeight?: number;
108
+ daySize?: number;
109
+ footer?: (props: FooterProps) => React.JSX.Element | null;
110
+
111
+ customDay?: CustomDay;
112
+
113
+ customSelectedDayProps?: {
114
+ dayHeight?: number;
115
+ dayWidth?: number;
116
+ borderRadius?: number;
117
+ };
118
+ /**
119
+ * If passed true, initial date scroll will happen using setTimeout.
120
+ */
121
+ asyncInitialScroll?: boolean;
122
+ }
123
+
124
+ const CALENDAR_ROOT_ID = 'react_day_picker_pwa';
125
+
126
+ const staticStyles = makeStyles((theme) => ({
127
+ mainContainer: {
128
+ display: 'flex',
129
+ alignItems: 'center',
130
+ paddingTop: theme.spacing[3],
131
+ overflowY: 'hidden',
132
+ },
133
+ customDayContainer: {
134
+ display: 'flex',
135
+ flexDirection: 'column',
136
+ alignItems: 'center',
137
+ justifyContent: 'center',
138
+ },
139
+ dotsContainer: {
140
+ position: 'absolute',
141
+ marginTop: -36,
142
+ marginRight: -18,
143
+ width: 6,
144
+ height: 6,
145
+ },
146
+ dayFooterContainer: {
147
+ position: 'absolute',
148
+ marginBottom: -32,
149
+ },
150
+ }));
151
+
152
+ const Calendar = ({
153
+ onDateSelect,
154
+ selectedDays,
155
+ noOfMonths,
156
+ footer,
157
+ customHeader,
158
+ disabledDays,
159
+ fromMonth,
160
+ cellWidth,
161
+ cellHeight,
162
+ onDayClick,
163
+ customDay,
164
+ customSelectedDayProps,
165
+ containerWidth,
166
+ modifiers,
167
+ modifierStyles,
168
+ }: DateRangeProps) => {
169
+ const theme = useTheme();
170
+ const { dots = {}, dayFooter = {} } = customDay || { dots: {}, dayFooter: {} };
171
+ const { showDots = false, dotsData = [] } = dots || {};
172
+ const { showDayFooter = false, dayFooterData = [] } = dayFooter || {};
173
+ const { dayHeight, dayWidth, borderRadius } = customSelectedDayProps || {};
174
+
175
+ const formatWeekdayName = (date: Date) => {
176
+ const day = date.getDay();
177
+ return (
178
+ <Typography variant='B3' color={day < 5 ? 'neutral' : 'warning'}>
179
+ {WEEK_DAY_LABEL[day as keyof typeof WEEK_DAY_LABEL]}
180
+ </Typography>
181
+ );
182
+ };
183
+
184
+ /**
185
+ *
186
+ * @param props
187
+ * @returns Here we are doing a customiesed day component which has red dot also available.
188
+ */
189
+ function CustomDayComponent(props: DayContentProps) {
190
+ const dateTime = dayjs(props.date).format('YYYY/MM/DD');
191
+
192
+ const dynamicDayStyles = useStyles(
193
+ (theme) => ({
194
+ customDay: {
195
+ width: dayWidth ? dayWidth : theme.size[10],
196
+ height: dayHeight ? dayHeight : theme.size[10],
197
+ },
198
+ dotsStyle: {
199
+ backgroundColor: theme.color.text.warning,
200
+ },
201
+ }),
202
+ [dayWidth, dayHeight],
203
+ );
204
+
205
+ return (
206
+ <Container
207
+ styleConfig={{
208
+ root: [staticStyles.customDayContainer, dynamicDayStyles.customDay],
209
+ }}
210
+ id={`Calendar${props.date.getMonth()}`}
211
+ >
212
+ {showDots && dotsData.includes(dateTime) && (
213
+ <Container
214
+ styleConfig={{
215
+ root: [staticStyles.dotsContainer, dynamicDayStyles.dotsStyle],
216
+ }}
217
+ ></Container>
218
+ )}
219
+ <time dateTime={dateTime}>
220
+ <DayContent {...props} />
221
+ </time>
222
+ {showDayFooter &&
223
+ dayFooterData.map((ele) => {
224
+ return ele?.date === dateTime;
225
+ }) && (
226
+ <Container
227
+ styleConfig={{
228
+ root: [staticStyles.dayFooterContainer],
229
+ }}
230
+ >
231
+ <Typography variant='B3' colorCode={theme.color.text.success}>
232
+ {dayFooterData.find((ele) => ele.date === dateTime)?.text}
233
+ </Typography>
234
+ </Container>
235
+ )}
236
+ </Container>
237
+ );
238
+ }
239
+
240
+ const formatWeekNumber = (weekNumber: number) => {
241
+ // Subtract 1 to make Monday as 0
242
+ return weekNumber - 1;
243
+ };
244
+
245
+ /**
246
+ * below one is to customise the calendar css as per need.
247
+ */
248
+
249
+ const styleConfigurableVariables = useMemo(
250
+ () => ({
251
+ '--rdp-cell-width': cellWidth ? `${cellWidth}px` : getNestedField(['size', '10'], theme) /* Cell width */,
252
+ '--rdp-cell-height': cellHeight ? `${cellHeight}px` : getNestedField(['size', '10'], theme) /* Cell height */,
253
+ '--rdp-day-size': cellWidth ? `${cellWidth}px` : getNestedField(['size', '10'], theme) /* Cell width */,
254
+ '--rdp-day-height-custom': dayHeight ? `${dayHeight}px` : getNestedField(['size', '10'], theme) /* Cell width */,
255
+ '--rdp-day-width-custom': dayWidth ? `${dayWidth}px` : getNestedField(['size', '10'], theme) /* Cell width */,
256
+ '--rdp-day-borderRadius-custom': borderRadius
257
+ ? `${borderRadius}%`
258
+ : getNestedField(['size', '10'], theme) /* Cell width */,
259
+ '--rdp-accent-color': getNestedField(['color', 'calendar', 'accent'], theme),
260
+ '--rdp-outline': `1.5px solid ${getNestedField(
261
+ ['color', 'calendar', 'borderColor'],
262
+ theme,
263
+ )}` /* Outline border for focused elements */,
264
+ '--rdp-selected-range-color': getNestedField(['color', 'calendar', 'background'], theme),
265
+ }),
266
+ // eslint-disable-next-line react-hooks/exhaustive-deps
267
+ [theme, getNestedField],
268
+ );
269
+
270
+ useEffect(() => {
271
+ const calendarElement = document.getElementById(CALENDAR_ROOT_ID);
272
+ if (calendarElement) {
273
+ Object.keys(styleConfigurableVariables).forEach((styleVar) => {
274
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
275
+ calendarElement?.style?.setProperty(styleVar, styleConfigurableVariables[styleVar]);
276
+ });
277
+ }
278
+ }, [styleConfigurableVariables]);
279
+
280
+ const dynamicMainStyles = useStyles(
281
+ () => ({
282
+ mainContainerWidth: {
283
+ width: containerWidth,
284
+ },
285
+ }),
286
+ [containerWidth],
287
+ );
288
+
289
+ return (
290
+ <Container
291
+ styleConfig={{
292
+ root: [staticStyles.mainContainer, dynamicMainStyles.mainContainerWidth],
293
+ }}
294
+ >
295
+ <DayPicker
296
+ ISOWeek
297
+ id={CALENDAR_ROOT_ID}
298
+ numberOfMonths={noOfMonths}
299
+ mode='range'
300
+ onDayClick={onDayClick}
301
+ selected={selectedDays}
302
+ onSelect={onDateSelect}
303
+ components={{
304
+ Footer: (...args) => {
305
+ return footer ? footer(...args) : null;
306
+ },
307
+ Caption: (...args) => {
308
+ return Caption(...args) || customHeader;
309
+ },
310
+ HeadRow: () => null,
311
+ Head: () => null,
312
+ DayContent: CustomDayComponent,
313
+ }}
314
+ fromMonth={dayjs().startOf('month').toDate() || fromMonth}
315
+ formatters={{ formatWeekdayName, formatWeekNumber }}
316
+ disabled={disabledDays}
317
+ modifiers={modifiers}
318
+ modifiersStyles={modifierStyles}
319
+ />
320
+ </Container>
321
+ );
322
+ };
323
+
324
+ export default Calendar;
@@ -0,0 +1,196 @@
1
+ import { Container } from '@cleartrip/ct-design-container';
2
+ import { Typography } from '@cleartrip/ct-design-typography';
3
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
4
+ import { Badge } from '@cleartrip/ct-design-badge';
5
+ import dayjs from 'dayjs';
6
+
7
+ import { DATE_TYPE, MONTHS } from './constants';
8
+
9
+ const pluralize = (value: number, text: string, suffix = 's') => (+value === 1 ? text : `${text}${suffix}`);
10
+ const pad = (s: number) => {
11
+ return s < 10 ? `0${s}` : s;
12
+ };
13
+
14
+ const formatDateCalendar = (date: Date) =>
15
+ `${pad(date.getDate())} ${MONTHS[date.getMonth()]} ‘${date.getFullYear().toString().substr(-2)}`;
16
+
17
+ interface CheckInCheckOutProps {
18
+ checkInDate?: Date | '';
19
+ checkOutDate?: Date | '';
20
+ stateDateType?: `${DATE_TYPE}`;
21
+ onCheckInTap?: () => void;
22
+ onCheckOutTap?: () => void;
23
+ }
24
+
25
+ // Static styles using makeStyles
26
+ const staticStyles = makeStyles((theme) => ({
27
+ root: {
28
+ display: 'flex',
29
+ flexDirection: 'row',
30
+ justifyContent: 'space-between',
31
+ gap: theme.spacing[3],
32
+ position: 'relative',
33
+ },
34
+ checkInContainer: {
35
+ paddingHorizontal: theme.spacing[4],
36
+ paddingVertical: theme.spacing[2],
37
+ backgroundColor: theme.color.background.neutral,
38
+ borderRadius: theme.border.radius[12],
39
+ justifyContent: 'center',
40
+ alignItems: 'center',
41
+ },
42
+ checkOutContainer: {
43
+ border: `1px solid ${theme.color.border.default}`,
44
+ borderRadius: theme.border.radius[12],
45
+ justifyContent: 'center',
46
+ alignItems: 'center',
47
+ },
48
+ checkOutContainerLayout: {
49
+ paddingHorizontal: 16,
50
+ paddingVertical: 8,
51
+ backgroundColor: '#f5f5f5',
52
+ borderRadius: 12,
53
+ flex: 1,
54
+ display: 'flex',
55
+ flexDirection: 'column',
56
+ },
57
+ dateLabelBase: {
58
+ color: '#B3B3B3',
59
+ transition: 'all 0.2s ease-in-out',
60
+ },
61
+ uncheckedCheckInContainer: {
62
+ fontSize: 16,
63
+ lineHeight: 22,
64
+ transform: 'translateY(8px)',
65
+ },
66
+ nightsTextContainer: {
67
+ top: '50%',
68
+ left: '50%',
69
+ transform: 'translate(-50%, -50%)',
70
+ },
71
+ nightsBadgeLayout: {
72
+ display: 'flex',
73
+ alignItems: 'center',
74
+ justifyContent: 'center',
75
+ position: 'absolute',
76
+ zIndex: 100,
77
+ },
78
+ containerBase: {
79
+ height: 56,
80
+ },
81
+ checkedCheckInContainer: {},
82
+ checkedInDateText: {
83
+ color: theme.color.text.neutral,
84
+ lineHeight: 22,
85
+ },
86
+ checkedOutDateText: {
87
+ color: '#171717',
88
+ lineHeight: 22,
89
+ },
90
+ }));
91
+
92
+ const CheckInCheckOut = ({
93
+ checkInDate,
94
+ checkOutDate,
95
+ onCheckInTap,
96
+ onCheckOutTap,
97
+ stateDateType,
98
+ }: CheckInCheckOutProps) => {
99
+ const dateDiff = dayjs(checkOutDate).diff(dayjs(checkInDate), 'day');
100
+
101
+ const checkInStyles = useStyles(
102
+ (theme) => ({
103
+ container: {
104
+ borderColor: stateDateType === DATE_TYPE.CHECK_IN ? theme.color.background.primary : theme.color.border.default,
105
+ borderWidth: stateDateType === DATE_TYPE.CHECK_IN ? 1.5 : 1,
106
+ },
107
+ }),
108
+ [stateDateType],
109
+ );
110
+
111
+ const checkOutStyles = useStyles(
112
+ (theme) => ({
113
+ checkoutContainer: {
114
+ borderColor:
115
+ stateDateType === DATE_TYPE.CHECK_OUT ? theme.color.background.primary : theme.color.border.default,
116
+ borderWidth: stateDateType === DATE_TYPE.CHECK_OUT ? 1.5 : 1,
117
+ },
118
+ dateLabel: {
119
+ color: '#B3B3B3',
120
+ transition: 'all 0.2s ease-in-out',
121
+ },
122
+ }),
123
+ [stateDateType],
124
+ );
125
+
126
+ return (
127
+ <Container styleConfig={{ root: [staticStyles.root] }}>
128
+ <Container
129
+ styleConfig={{ root: [checkInStyles.container, staticStyles.checkInContainer] }}
130
+ onClick={onCheckInTap}
131
+ >
132
+ <Typography
133
+ variant='B3'
134
+ styleConfig={{
135
+ root: [
136
+ staticStyles.dateLabelBase,
137
+ checkInDate ? staticStyles.checkedCheckInContainer : staticStyles.uncheckedCheckInContainer,
138
+ ],
139
+ }}
140
+ >
141
+ Check-in
142
+ </Typography>
143
+
144
+ {checkInDate && (
145
+ <Typography variant='B1' styleConfig={{ root: [staticStyles.checkedInDateText] }}>
146
+ {formatDateCalendar(checkInDate)}
147
+ </Typography>
148
+ )}
149
+ </Container>
150
+
151
+ {!!dateDiff && !isNaN(dateDiff) && dateDiff > 0 && (
152
+ <Container
153
+ styleConfig={{
154
+ root: [staticStyles.nightsTextContainer, staticStyles.nightsBadgeLayout],
155
+ }}
156
+ >
157
+ <Badge
158
+ variant='subtle'
159
+ colorScheme='default'
160
+ text={<Typography variant='TAG'>{`${dateDiff} ${pluralize(dateDiff, 'NIGHT', 'S')}`}</Typography>}
161
+ size='micro'
162
+ />
163
+ </Container>
164
+ )}
165
+
166
+ <Container
167
+ styleConfig={{
168
+ root: [
169
+ staticStyles.checkOutContainer,
170
+ staticStyles.containerBase,
171
+ staticStyles.checkOutContainerLayout,
172
+ checkOutStyles.checkoutContainer,
173
+ ],
174
+ }}
175
+ onClick={onCheckOutTap}
176
+ >
177
+ <Typography variant='B3' styleConfig={{ root: [checkOutStyles.dateLabel] }}>
178
+ Check-out
179
+ </Typography>
180
+
181
+ {checkOutDate && (
182
+ <Typography
183
+ variant='B1'
184
+ styleConfig={{
185
+ root: [staticStyles.checkedOutDateText],
186
+ }}
187
+ >
188
+ {formatDateCalendar(checkOutDate)}
189
+ </Typography>
190
+ )}
191
+ </Container>
192
+ </Container>
193
+ );
194
+ };
195
+
196
+ export default CheckInCheckOut;
@@ -0,0 +1,98 @@
1
+ import { Container } from '@cleartrip/ct-design-container';
2
+ import { Typography } from '@cleartrip/ct-design-typography';
3
+ import { Accordion } from '@cleartrip/ct-design-accordion';
4
+ import { makeStyles } from '@cleartrip/ct-design-style-manager';
5
+
6
+ import { ChevronDown } from '@cleartrip/ct-design-icons';
7
+
8
+ const isIndexType = (argument: unknown): argument is string | number => {
9
+ return (typeof argument === 'number' || typeof argument === 'string') && typeof argument !== 'undefined';
10
+ };
11
+
12
+ const staticStyles = makeStyles((theme) => ({
13
+ accordionRoot: {
14
+ paddingLeft: 0,
15
+ paddingRight: 0,
16
+ paddingTop: theme.spacing[2],
17
+ paddingBottom: theme.spacing[2],
18
+ },
19
+ accordionLabel: {
20
+ display: 'flex',
21
+ justifyContent: 'flex-start',
22
+ },
23
+ accordionChildrenContainer: {
24
+ paddingTop: theme.spacing[2],
25
+ },
26
+ accordionIcon: {
27
+ marginLeft: theme.spacing[1],
28
+ },
29
+ labelContainer: {
30
+ display: 'flex',
31
+ alignItems: 'center',
32
+ marginLeft: theme.spacing[4],
33
+ },
34
+ holidayIndicator: {
35
+ marginRight: theme.spacing[2],
36
+ height: theme.spacing[1.5],
37
+ width: theme.spacing[1.5],
38
+ backgroundColor: '#C83232', // TODO: Replace with theme.color when available
39
+ borderRadius: theme.border.radius[16],
40
+ },
41
+ holidaysContainer: {
42
+ width: 'calc(100% - 32px)' as unknown as number,
43
+ marginHorizontal: theme.spacing[4],
44
+ display: 'flex',
45
+ flexDirection: 'column',
46
+ gap: theme.spacing[1],
47
+ },
48
+ }));
49
+
50
+ const accordianStyleConfig = {
51
+ root: [staticStyles.accordionRoot],
52
+ label: [staticStyles.accordionLabel],
53
+ childrenContainer: [staticStyles.accordionChildrenContainer],
54
+ icon: [staticStyles.accordionIcon],
55
+ };
56
+
57
+ export function LongWeekendFooter(props: {
58
+ displayMonth?: Date;
59
+ holidayList: Record<string, Record<string, string[]>>;
60
+ }) {
61
+ const month = props.displayMonth?.getMonth();
62
+ const year = props.displayMonth?.getFullYear();
63
+
64
+ const holidays = isIndexType(month) && isIndexType(year) ? props.holidayList?.[year]?.[month] || [] : [];
65
+
66
+ if (holidays.length) {
67
+ return (
68
+ <tfoot>
69
+ {holidays.length ? (
70
+ <tr>
71
+ <td colSpan={8}>
72
+ <Accordion
73
+ expandIcon={<ChevronDown height={16} width={16} />}
74
+ styleConfig={accordianStyleConfig}
75
+ label={
76
+ <Container styleConfig={{ root: [staticStyles.labelContainer] }}>
77
+ <Container styleConfig={{ root: [staticStyles.holidayIndicator] }} />
78
+ <Typography variant='B3'>{holidays.length} Holidays</Typography>
79
+ </Container>
80
+ }
81
+ >
82
+ <Container styleConfig={{ root: [staticStyles.holidaysContainer] }}>
83
+ {holidays.map((holiday) => (
84
+ <Typography key={holiday} variant='P3'>
85
+ {holiday}
86
+ </Typography>
87
+ ))}
88
+ </Container>
89
+ </Accordion>
90
+ </td>
91
+ </tr>
92
+ ) : null}
93
+ </tfoot>
94
+ );
95
+ }
96
+
97
+ return null;
98
+ }
@@ -0,0 +1,7 @@
1
+ export const enum DATE_TYPE {
2
+ INIT = 'init',
3
+ CHECK_IN = 'checkIn',
4
+ CHECK_OUT = 'checkOut',
5
+ }
6
+
7
+ export const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
@@ -0,0 +1,84 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ import { Container } from '@cleartrip/ct-design-container';
4
+ import { Spacer } from '@cleartrip/ct-design-spacer';
5
+ import { Button } from '@cleartrip/ct-design-button';
6
+ import { makeStyles } from '@cleartrip/ct-design-style-manager';
7
+
8
+ import CheckInCheckOut from './CheckinCheckout';
9
+ import { DATE_TYPE } from './constants';
10
+
11
+ // Static styles using makeStyles
12
+ const staticStyles = makeStyles((theme) => ({
13
+ footerContainer: {
14
+ position: 'absolute',
15
+ bottom: 0,
16
+ padding: theme.spacing[4],
17
+ paddingBottom: theme.spacing[4],
18
+ paddingTop: theme.spacing[3],
19
+ zIndex: 100,
20
+ width: '100%',
21
+ backgroundColor: theme.color.background.neutral,
22
+ boxShadow: 'rgba(26, 26, 26, 0.08) 0px -4px 16px',
23
+ },
24
+ spacerMargin: {
25
+ marginBottom: theme.spacing[4],
26
+ },
27
+ }));
28
+
29
+ interface ICalendarFixedFooter {
30
+ checkInDate?: Date | '';
31
+ checkOutDate?: Date | '';
32
+ stateDateType?: `${DATE_TYPE}`;
33
+ onClick: () => void;
34
+ onCheckInTap: () => void;
35
+ onCheckOutTap: () => void;
36
+ primaryCtaTestId?: string;
37
+ }
38
+
39
+ const CalendarFixedFooter: React.FC<ICalendarFixedFooter> = ({
40
+ checkInDate,
41
+ checkOutDate,
42
+ stateDateType,
43
+ onClick,
44
+ onCheckInTap,
45
+ onCheckOutTap,
46
+ }) => {
47
+ const checkInRef = useRef<HTMLInputElement>(null);
48
+ const checkOutRef = useRef<HTMLInputElement>(null);
49
+
50
+ useEffect(() => {
51
+ if (!checkInDate) checkInRef.current?.focus();
52
+ else if (!checkOutDate) checkOutRef.current?.focus();
53
+ else if (stateDateType === DATE_TYPE.CHECK_IN || stateDateType === DATE_TYPE.INIT) checkInRef.current?.focus();
54
+ else if (stateDateType === DATE_TYPE.CHECK_OUT) checkOutRef.current?.focus();
55
+ }, [checkInDate, checkOutDate, stateDateType]);
56
+
57
+ const isPrimaryCtaDisabled = stateDateType === 'checkOut' || checkInDate?.toString() === checkOutDate?.toString();
58
+
59
+ return (
60
+ <Container
61
+ styleConfig={{
62
+ root: [staticStyles.footerContainer],
63
+ }}
64
+ >
65
+ <CheckInCheckOut
66
+ checkInDate={checkInDate}
67
+ checkOutDate={checkOutDate}
68
+ onCheckInTap={onCheckInTap}
69
+ onCheckOutTap={onCheckOutTap}
70
+ stateDateType={stateDateType}
71
+ />
72
+ <Spacer
73
+ styleConfig={{
74
+ root: [staticStyles.spacerMargin],
75
+ }}
76
+ />
77
+ <Button disabled={isPrimaryCtaDisabled} variant='contained' onClick={onClick} isFullWidth={true}>
78
+ Confirm
79
+ </Button>
80
+ </Container>
81
+ );
82
+ };
83
+
84
+ export default CalendarFixedFooter;