pixel-react 1.0.4 → 1.0.6
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/lib/assets/utils/functionUtils.d.ts +3 -0
- package/lib/components/DatePicker/DatePicker.d.ts +5 -0
- package/lib/components/DatePicker/DatePicker.stories.d.ts +9 -0
- package/lib/components/DatePicker/Timepicker.d.ts +4 -0
- package/lib/components/DatePicker/index.d.ts +1 -0
- package/lib/components/DatePicker/types.d.ts +81 -0
- package/lib/components/IconButton/IconButton.d.ts +5 -0
- package/lib/components/IconButton/IconButton.stories.d.ts +6 -0
- package/lib/components/IconButton/index.d.ts +1 -0
- package/lib/components/IconButton/types.d.ts +5 -0
- package/lib/components/InputWithDropdown/InputWithDropdown.d.ts +1 -1
- package/lib/components/InputWithDropdown/types.d.ts +3 -7
- package/lib/components/TableTree/TableTree.d.ts +1 -1
- package/lib/index.d.ts +68 -10
- package/lib/index.esm.js +8556 -224
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +8558 -224
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/src/assets/Themes/BaseTheme.scss +7 -0
- package/src/assets/Themes/DarkTheme.scss +7 -1
- package/src/assets/icons/add_variable_icon.svg +5 -0
- package/src/assets/icons/calendar_icon.svg +9 -0
- package/src/assets/icons/clock_icon.svg +11 -0
- package/src/assets/icons/info_icon.svg +4 -0
- package/src/assets/icons/left_arrow_icon.svg +3 -0
- package/src/assets/icons/right_arrow_icon.svg +4 -0
- package/src/assets/styles/_mixins.scss +1 -0
- package/src/assets/utils/functionUtils.ts +37 -0
- package/src/components/DatePicker/DatePicker.scss +387 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +161 -0
- package/src/components/DatePicker/DatePicker.tsx +438 -0
- package/src/components/DatePicker/Timepicker.tsx +372 -0
- package/src/components/DatePicker/index.ts +1 -0
- package/src/components/DatePicker/types.ts +100 -0
- package/src/components/Drawer/Drawer.scss +0 -1
- package/src/components/Drawer/Drawer.tsx +10 -14
- package/src/components/Icon/iconList.ts +17 -9
- package/src/components/{AddButton/AddButton.scss → IconButton/IconButton.scss} +6 -2
- package/src/components/IconButton/IconButton.stories.tsx +25 -0
- package/src/components/{AddButton/AddButton.tsx → IconButton/IconButton.tsx} +10 -7
- package/src/components/IconButton/index.ts +1 -0
- package/src/components/{AddButton → IconButton}/types.ts +3 -2
- package/src/components/InputWithDropdown/InputWithDropdown.scss +1 -1
- package/src/components/InputWithDropdown/InputWithDropdown.stories.tsx +10 -13
- package/src/components/InputWithDropdown/InputWithDropdown.tsx +10 -8
- package/src/components/InputWithDropdown/types.ts +4 -7
- package/src/components/RadioButton/RadioButton.scss +3 -3
- package/src/components/Select/Select.scss +1 -1
- package/src/components/StateDropdown/StateDropdown.tsx +10 -15
- package/src/components/TableTree/TableTree.tsx +4 -0
- package/src/index.ts +5 -0
- package/src/assets/icons/expired_license_icon.svg +0 -3
- package/src/assets/icons/expiringSoon_license_icon.svg +0 -3
- package/src/components/AddButton/AddButton.stories.tsx +0 -24
- package/src/components/AddButton/index.ts +0 -1
@@ -0,0 +1,161 @@
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
2
|
+
import CustomDatePicker from './DatePicker';
|
3
|
+
import { useState } from 'react';
|
4
|
+
|
5
|
+
const meta: Meta<typeof CustomDatePicker> = {
|
6
|
+
title: 'Components/DatePicker',
|
7
|
+
component: CustomDatePicker,
|
8
|
+
parameters: {
|
9
|
+
layout: 'centered',
|
10
|
+
docs: {
|
11
|
+
description: {
|
12
|
+
component:
|
13
|
+
'A custom date picker component with built-in calendar and input field.',
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
tags: ['autodocs'],
|
18
|
+
argTypes: {
|
19
|
+
minDate: {
|
20
|
+
description: 'The minimum selectable date',
|
21
|
+
control: {
|
22
|
+
type: 'date',
|
23
|
+
},
|
24
|
+
},
|
25
|
+
maxDate: {
|
26
|
+
description: 'The maximum selectable date',
|
27
|
+
control: {
|
28
|
+
type: 'date',
|
29
|
+
},
|
30
|
+
},
|
31
|
+
value: {
|
32
|
+
description: 'Selected date value',
|
33
|
+
control: {
|
34
|
+
type: 'date',
|
35
|
+
},
|
36
|
+
},
|
37
|
+
onChange: {
|
38
|
+
description: 'Function to handle date selection',
|
39
|
+
action: 'changed',
|
40
|
+
},
|
41
|
+
placeholder: {
|
42
|
+
description: 'Placeholder text for the input field',
|
43
|
+
control: 'text',
|
44
|
+
},
|
45
|
+
disabled: {
|
46
|
+
description: 'Disables the date picker',
|
47
|
+
control: 'boolean',
|
48
|
+
},
|
49
|
+
dateFormat: {
|
50
|
+
description: 'Date format to display',
|
51
|
+
control: 'text',
|
52
|
+
},
|
53
|
+
timeFormat: {
|
54
|
+
description: 'time format to display',
|
55
|
+
control: 'text',
|
56
|
+
},
|
57
|
+
timezone: {
|
58
|
+
description: 'Timezone for date formatting',
|
59
|
+
control: 'text',
|
60
|
+
},
|
61
|
+
calendarWidth: {
|
62
|
+
description: 'Custom width for the calendar in pixel',
|
63
|
+
control: "number"
|
64
|
+
},
|
65
|
+
error: {
|
66
|
+
description: 'Displays the input field in an error state',
|
67
|
+
control: 'boolean',
|
68
|
+
},
|
69
|
+
helperText: {
|
70
|
+
description: 'Helper text to show below the input, often used for error messages',
|
71
|
+
control: 'text',
|
72
|
+
},
|
73
|
+
},
|
74
|
+
};
|
75
|
+
|
76
|
+
export default meta;
|
77
|
+
|
78
|
+
type Story = StoryObj<typeof CustomDatePicker>;
|
79
|
+
|
80
|
+
// Default story for DatePicker
|
81
|
+
export const Default: Story = {
|
82
|
+
render: (args) => {
|
83
|
+
const [date, setDate] = useState<Date | undefined>();
|
84
|
+
|
85
|
+
return(
|
86
|
+
<CustomDatePicker
|
87
|
+
{...args}
|
88
|
+
value={date}
|
89
|
+
onChange={setDate}
|
90
|
+
/>
|
91
|
+
)
|
92
|
+
}
|
93
|
+
};
|
94
|
+
|
95
|
+
// Start Date Filter story
|
96
|
+
export const StartDateFilter: Story = {
|
97
|
+
render: (args) => {
|
98
|
+
const [startDate, setStartDate] = useState<Date | undefined>();
|
99
|
+
|
100
|
+
return (
|
101
|
+
<CustomDatePicker
|
102
|
+
{...args}
|
103
|
+
value={startDate}
|
104
|
+
onChange={setStartDate}
|
105
|
+
calendarWidth = {240}
|
106
|
+
maxDate={new Date()} // Disable future dates for start date picker
|
107
|
+
/>
|
108
|
+
);
|
109
|
+
},
|
110
|
+
};
|
111
|
+
|
112
|
+
// End Date Input story
|
113
|
+
export const EndDateInput: Story = {
|
114
|
+
render: (args) => {
|
115
|
+
const [startDate, setStartDate] = useState<Date | undefined>();
|
116
|
+
const [endDate, setEndDate] = useState<Date | undefined>();
|
117
|
+
|
118
|
+
return (
|
119
|
+
<>
|
120
|
+
<p>Select Start Date:</p>
|
121
|
+
<CustomDatePicker
|
122
|
+
{...args}
|
123
|
+
value={startDate}
|
124
|
+
onChange={setStartDate}
|
125
|
+
maxDate={new Date()} // Disable future dates for start date picker
|
126
|
+
/>
|
127
|
+
|
128
|
+
<p>Select End Date:</p>
|
129
|
+
<CustomDatePicker
|
130
|
+
{...args}
|
131
|
+
value={endDate}
|
132
|
+
onChange={setEndDate}
|
133
|
+
disabled={!startDate}
|
134
|
+
minDate={startDate || undefined} // Restrict the end date based on selected start date
|
135
|
+
maxDate={new Date()} // Disable future dates for end date picker
|
136
|
+
/>
|
137
|
+
</>
|
138
|
+
);
|
139
|
+
},
|
140
|
+
};
|
141
|
+
|
142
|
+
// Schedule Date Input story
|
143
|
+
export const ScheduleDateInput: Story = {
|
144
|
+
args: {
|
145
|
+
error: false,
|
146
|
+
helperText: "Error"
|
147
|
+
},
|
148
|
+
|
149
|
+
render: (args) => {
|
150
|
+
const [selectDate, setSelectDate] = useState<Date | undefined>(new Date());
|
151
|
+
|
152
|
+
return (
|
153
|
+
<CustomDatePicker
|
154
|
+
{...args}
|
155
|
+
value={selectDate}
|
156
|
+
onChange={setSelectDate}
|
157
|
+
minDate={new Date()} // Set minimum date to today
|
158
|
+
/>
|
159
|
+
);
|
160
|
+
}
|
161
|
+
};
|
@@ -0,0 +1,438 @@
|
|
1
|
+
import React, { useEffect, useState, useRef } from 'react';
|
2
|
+
import { DayPicker } from 'react-day-picker';
|
3
|
+
import { formatInTimeZone } from 'date-fns-tz';
|
4
|
+
import TimePicker from './Timepicker';
|
5
|
+
import Icon from '../Icon';
|
6
|
+
import './DatePicker.scss';
|
7
|
+
import {
|
8
|
+
DatePickerProps,
|
9
|
+
CustomCaptionProps,
|
10
|
+
CustomCalenderButtonProps,
|
11
|
+
} from './types';
|
12
|
+
import Button from '../Button';
|
13
|
+
import Typography from '../Typography';
|
14
|
+
import classNames from 'classnames';
|
15
|
+
|
16
|
+
const CustomDatePicker: React.FC<DatePickerProps> = ({
|
17
|
+
minDate,
|
18
|
+
maxDate,
|
19
|
+
value,
|
20
|
+
onChange,
|
21
|
+
placeholder = 'Select a date',
|
22
|
+
disabled = false,
|
23
|
+
dateFormat = 'EEEE, dd MMM yyyy',
|
24
|
+
calendarWidth,
|
25
|
+
timezone = 'Asia/Kolkata',
|
26
|
+
timeFormat = 'hh:mm a',
|
27
|
+
error,
|
28
|
+
helperText = '',
|
29
|
+
}) => {
|
30
|
+
const [timeValue, setTimeValue] = useState<string>('');
|
31
|
+
const [selectedDate, setSelectedDate] = useState<Date | undefined>();
|
32
|
+
const [isPickerOpen, setIsPickerOpen] = useState<boolean>(false);
|
33
|
+
const [timeError, setTimeError] = useState<boolean>(false);
|
34
|
+
const [selectedMonth, setSelectedMonth] = useState<Date | undefined>(
|
35
|
+
new Date()
|
36
|
+
);
|
37
|
+
const [view, setView] = useState<string>('days');
|
38
|
+
const [startYear, setStartYear] = useState(() => {
|
39
|
+
const currentYear =
|
40
|
+
selectedMonth?.getFullYear() ?? new Date().getFullYear();
|
41
|
+
return currentYear - (currentYear % 12); // Set to the first year in the 12-year range
|
42
|
+
});
|
43
|
+
const [datePickerPosition, setDatePickerPosition] = useState<
|
44
|
+
'top' | 'bottom'
|
45
|
+
>('bottom');
|
46
|
+
const pickerRef = useRef<HTMLDivElement>(null); // Ref to track the picker
|
47
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
48
|
+
|
49
|
+
useEffect(() => {
|
50
|
+
if (value) {
|
51
|
+
setTimeValue(formatTimeStr(value));
|
52
|
+
setSelectedDate(value);
|
53
|
+
}
|
54
|
+
}, [value, isPickerOpen]);
|
55
|
+
|
56
|
+
const formatTimeStr = (date: Date): string => {
|
57
|
+
const hours = date.getHours().toString().padStart(2, '0');
|
58
|
+
const minutes = date.getMinutes().toString().padStart(2, '0');
|
59
|
+
return `${hours}:${minutes}`;
|
60
|
+
};
|
61
|
+
|
62
|
+
// Convert minDate and maxDate to "hh:mm" for the TimePicker if the dates match
|
63
|
+
const minTime =
|
64
|
+
selectedDate &&
|
65
|
+
minDate &&
|
66
|
+
selectedDate.toDateString() === minDate.toDateString()
|
67
|
+
? formatTimeStr(minDate)
|
68
|
+
: undefined;
|
69
|
+
|
70
|
+
const maxTime =
|
71
|
+
selectedDate &&
|
72
|
+
maxDate &&
|
73
|
+
selectedDate.toDateString() === maxDate.toDateString()
|
74
|
+
? formatTimeStr(maxDate)
|
75
|
+
: undefined;
|
76
|
+
|
77
|
+
useEffect(() => {
|
78
|
+
const adjustPosition = () => {
|
79
|
+
if (containerRef.current && pickerRef.current) {
|
80
|
+
const relativeRect = containerRef.current.getBoundingClientRect();
|
81
|
+
const absoluteRect = pickerRef.current.getBoundingClientRect();
|
82
|
+
|
83
|
+
const spaceBelow = window.innerHeight - relativeRect.bottom;
|
84
|
+
const spaceAbove = relativeRect.top;
|
85
|
+
|
86
|
+
// Check if there is more space above than below
|
87
|
+
if (
|
88
|
+
spaceBelow < absoluteRect.height &&
|
89
|
+
spaceAbove >= absoluteRect.height
|
90
|
+
) {
|
91
|
+
setDatePickerPosition('top');
|
92
|
+
} else {
|
93
|
+
setDatePickerPosition('bottom');
|
94
|
+
}
|
95
|
+
}
|
96
|
+
};
|
97
|
+
|
98
|
+
// Initial check
|
99
|
+
adjustPosition();
|
100
|
+
|
101
|
+
// Adjust position on window resize
|
102
|
+
window.addEventListener('resize', adjustPosition);
|
103
|
+
return () => window.removeEventListener('resize', adjustPosition);
|
104
|
+
}, []);
|
105
|
+
|
106
|
+
const calendarStyle = {
|
107
|
+
'--rdp-day-width': calendarWidth ? `${calendarWidth / 7 - 4}px` : undefined,
|
108
|
+
} as React.CSSProperties;
|
109
|
+
|
110
|
+
const handleTimeChange = (time: string) => {
|
111
|
+
setTimeValue(time);
|
112
|
+
if (selectedDate) {
|
113
|
+
const [hoursStr, minutesStr] = time.split(':');
|
114
|
+
const newSelectedDate = new Date(selectedDate);
|
115
|
+
newSelectedDate.setHours(parseInt(hoursStr ? hoursStr : '0', 10));
|
116
|
+
newSelectedDate.setMinutes(
|
117
|
+
parseInt(minutesStr ? minutesStr : '0', 10) || 0
|
118
|
+
);
|
119
|
+
setSelectedDate(newSelectedDate);
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
123
|
+
const handleDaySelect = (date: Date | undefined) => {
|
124
|
+
if (!timeValue || !date) {
|
125
|
+
// if need to set time to current time in case no time selected
|
126
|
+
const now = new Date();
|
127
|
+
date?.setHours(now.getHours(), now.getMinutes(), now.getSeconds());
|
128
|
+
|
129
|
+
setSelectedDate(date);
|
130
|
+
} else {
|
131
|
+
const [hoursStr, minutesStr] = timeValue.split(':');
|
132
|
+
date.setHours(parseInt(hoursStr ? hoursStr : '0', 10) || 0);
|
133
|
+
date.setMinutes(parseInt(minutesStr ? minutesStr : '0', 10) || 0);
|
134
|
+
setSelectedDate(date);
|
135
|
+
}
|
136
|
+
};
|
137
|
+
|
138
|
+
const handleSave = () => {
|
139
|
+
onChange(selectedDate);
|
140
|
+
resetAndCloseDatePicker();
|
141
|
+
};
|
142
|
+
|
143
|
+
const handleDateInputClick = () => {
|
144
|
+
setIsPickerOpen((prev) => !prev);
|
145
|
+
setView('days');
|
146
|
+
setSelectedMonth(value ?? new Date());
|
147
|
+
};
|
148
|
+
|
149
|
+
const handleClickOutside = (event: MouseEvent) => {
|
150
|
+
if (
|
151
|
+
pickerRef.current &&
|
152
|
+
!pickerRef.current.contains(event.target as Node)
|
153
|
+
) {
|
154
|
+
resetAndCloseDatePicker();
|
155
|
+
}
|
156
|
+
};
|
157
|
+
|
158
|
+
const handleCancel = () => {
|
159
|
+
resetAndCloseDatePicker();
|
160
|
+
};
|
161
|
+
|
162
|
+
const resetAndCloseDatePicker = () => {
|
163
|
+
setIsPickerOpen(false); // Close the picker if the click was outside
|
164
|
+
setView('days'); // Return to default day view on close of day picker
|
165
|
+
setSelectedMonth(value ?? new Date());
|
166
|
+
};
|
167
|
+
|
168
|
+
useEffect(() => {
|
169
|
+
if (isPickerOpen) {
|
170
|
+
document.addEventListener('mousedown', handleClickOutside);
|
171
|
+
} else {
|
172
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
173
|
+
}
|
174
|
+
return () => {
|
175
|
+
document.removeEventListener('mousedown', handleClickOutside); // Clean up the event listener
|
176
|
+
};
|
177
|
+
}, [isPickerOpen]);
|
178
|
+
|
179
|
+
const months = Array.from({ length: 12 }, (_, i) =>
|
180
|
+
new Date(0, i).toLocaleString('default', { month: 'long' })
|
181
|
+
);
|
182
|
+
const years = Array.from({ length: 12 }, (_, i) => startYear + i);
|
183
|
+
|
184
|
+
const handleMonthClick = () => setView('months');
|
185
|
+
const handleYearClick = () => setView('years');
|
186
|
+
|
187
|
+
const handleMonthSelect = (monthIndex: number) => {
|
188
|
+
const newDate = new Date(selectedMonth || '');
|
189
|
+
newDate.setMonth(monthIndex);
|
190
|
+
setSelectedMonth(newDate);
|
191
|
+
setView('days');
|
192
|
+
};
|
193
|
+
|
194
|
+
const handleYearSelect = (year: number) => {
|
195
|
+
const newDate = new Date(selectedMonth || '');
|
196
|
+
newDate.setFullYear(year);
|
197
|
+
setSelectedMonth(newDate);
|
198
|
+
setView('days');
|
199
|
+
};
|
200
|
+
|
201
|
+
const handleNextClick = () => {
|
202
|
+
if (view === 'years') {
|
203
|
+
setStartYear((prev) => prev + 12);
|
204
|
+
}
|
205
|
+
};
|
206
|
+
|
207
|
+
const handlePrevClick = () => {
|
208
|
+
if (view === 'years') {
|
209
|
+
setStartYear((prev) => prev - 12);
|
210
|
+
}
|
211
|
+
};
|
212
|
+
|
213
|
+
useEffect(() => {
|
214
|
+
if (isPickerOpen && view === 'years') {
|
215
|
+
const currentYear =
|
216
|
+
selectedMonth?.getFullYear() ?? new Date().getFullYear();
|
217
|
+
setStartYear(currentYear - (currentYear % 12)); // Reset to the first year in the range that contains the selected year
|
218
|
+
}
|
219
|
+
}, [isPickerOpen, selectedMonth, view]);
|
220
|
+
|
221
|
+
// Custom Caption Component
|
222
|
+
const CustomCaption: React.FC<CustomCaptionProps> = ({ children }) => {
|
223
|
+
// If children is a React node (like an element), render it directly
|
224
|
+
if (React.isValidElement(children)) {
|
225
|
+
return <div>{children}</div>;
|
226
|
+
}
|
227
|
+
|
228
|
+
const [month = '', year = ''] = String(children).split(' ');
|
229
|
+
|
230
|
+
return (
|
231
|
+
<Typography
|
232
|
+
as="div"
|
233
|
+
fontWeight="medium"
|
234
|
+
lineHeight="16.8px"
|
235
|
+
className="ff-calendar-haeder"
|
236
|
+
>
|
237
|
+
<span onClick={handleMonthClick} className="ff-cursor-pointer">
|
238
|
+
{month}
|
239
|
+
</span>
|
240
|
+
<span onClick={handleYearClick} className="ff-cursor-pointer">
|
241
|
+
{year}
|
242
|
+
</span>
|
243
|
+
</Typography>
|
244
|
+
);
|
245
|
+
};
|
246
|
+
|
247
|
+
// Custom MonthGrid Component
|
248
|
+
const CustomMonthGrid: React.FC = () => {
|
249
|
+
return (
|
250
|
+
<div className="ff-custom-month_grid">
|
251
|
+
{months.map((month: string, index: number) => (
|
252
|
+
<div
|
253
|
+
key={index}
|
254
|
+
onClick={() => handleMonthSelect(index)}
|
255
|
+
className={classNames('ff-custom-month', {
|
256
|
+
'ff-custom-month--selected': index === selectedMonth?.getMonth(),
|
257
|
+
})}
|
258
|
+
>
|
259
|
+
<Typography>{month}</Typography>
|
260
|
+
</div>
|
261
|
+
))}
|
262
|
+
</div>
|
263
|
+
);
|
264
|
+
};
|
265
|
+
|
266
|
+
const CustomPrevButton: React.FC<CustomCalenderButtonProps> = ({
|
267
|
+
disabled,
|
268
|
+
onClick,
|
269
|
+
}) => {
|
270
|
+
return (
|
271
|
+
<button
|
272
|
+
className="ff-calendar-nav-button"
|
273
|
+
onClick={onClick}
|
274
|
+
disabled={disabled}
|
275
|
+
>
|
276
|
+
<Icon name="left_arrow_icon" height={12} width={12} />
|
277
|
+
</button>
|
278
|
+
);
|
279
|
+
};
|
280
|
+
const CustomNextButton: React.FC<CustomCalenderButtonProps> = ({
|
281
|
+
disabled,
|
282
|
+
onClick,
|
283
|
+
}) => {
|
284
|
+
return (
|
285
|
+
<button
|
286
|
+
className="ff-calendar-nav-button"
|
287
|
+
onClick={onClick}
|
288
|
+
disabled={disabled}
|
289
|
+
>
|
290
|
+
<Icon name="right_arrow_icon" height={12} width={12} />
|
291
|
+
</button>
|
292
|
+
);
|
293
|
+
};
|
294
|
+
|
295
|
+
// Custom YearGrid Component
|
296
|
+
const CustomYearGrid: React.FC = () => {
|
297
|
+
return (
|
298
|
+
<div className="ff-custom-year_grid">
|
299
|
+
{years.map((year: number) => (
|
300
|
+
<div
|
301
|
+
key={year}
|
302
|
+
onClick={() => handleYearSelect(year)}
|
303
|
+
className={classNames('ff-custom-year', {
|
304
|
+
'ff-custom-year--selected': year === selectedMonth?.getFullYear(),
|
305
|
+
})}
|
306
|
+
>
|
307
|
+
<Typography>{year}</Typography>
|
308
|
+
</div>
|
309
|
+
))}
|
310
|
+
</div>
|
311
|
+
);
|
312
|
+
};
|
313
|
+
|
314
|
+
return (
|
315
|
+
<div className="ff-date-picker" ref={containerRef}>
|
316
|
+
<div className="ff-datepicker-input-container">
|
317
|
+
<div className="ff-input-with-icon ff-date-input-field">
|
318
|
+
<Icon
|
319
|
+
name={'calendar_icon'}
|
320
|
+
hoverEffect={false}
|
321
|
+
className="ff-calendar-icon"
|
322
|
+
/>
|
323
|
+
<input
|
324
|
+
type="text"
|
325
|
+
value={value ? formatInTimeZone(value, timezone, dateFormat) : ''}
|
326
|
+
readOnly
|
327
|
+
placeholder={placeholder}
|
328
|
+
className="ff-date-input"
|
329
|
+
disabled={disabled}
|
330
|
+
onClick={handleDateInputClick}
|
331
|
+
/>
|
332
|
+
{helperText && error && (
|
333
|
+
<span
|
334
|
+
className={classNames('ff-date-input-message', {
|
335
|
+
'ff-date-input-message--danger': !!error,
|
336
|
+
})}
|
337
|
+
>
|
338
|
+
{helperText}
|
339
|
+
</span>
|
340
|
+
)}
|
341
|
+
</div>
|
342
|
+
|
343
|
+
<div className="ff-input-with-icon ff-time-input-field">
|
344
|
+
<Icon
|
345
|
+
name={'clock_icon'}
|
346
|
+
hoverEffect={false}
|
347
|
+
className="ff-clock-icon"
|
348
|
+
/>
|
349
|
+
<input
|
350
|
+
type="text"
|
351
|
+
placeholder="Select time"
|
352
|
+
className="ff-time-input"
|
353
|
+
value={value ? formatInTimeZone(value, timezone, timeFormat) : ''}
|
354
|
+
disabled={disabled}
|
355
|
+
onClick={handleDateInputClick}
|
356
|
+
readOnly
|
357
|
+
/>
|
358
|
+
</div>
|
359
|
+
</div>
|
360
|
+
|
361
|
+
{isPickerOpen && (
|
362
|
+
<div
|
363
|
+
className="ff-date-picker-container"
|
364
|
+
ref={pickerRef}
|
365
|
+
style={{
|
366
|
+
top: datePickerPosition === 'top' ? 'auto' : '110%',
|
367
|
+
bottom: datePickerPosition === 'top' ? '110%' : 'auto',
|
368
|
+
}}
|
369
|
+
>
|
370
|
+
<div className="ff-calendar-container">
|
371
|
+
<DayPicker
|
372
|
+
style={calendarStyle}
|
373
|
+
className="ff-calendar"
|
374
|
+
mode="single"
|
375
|
+
selected={selectedDate}
|
376
|
+
onSelect={handleDaySelect}
|
377
|
+
month={selectedMonth}
|
378
|
+
onMonthChange={(month) => {
|
379
|
+
if (view === 'days') {
|
380
|
+
setSelectedMonth(month);
|
381
|
+
}
|
382
|
+
}}
|
383
|
+
onNextClick={handleNextClick}
|
384
|
+
onPrevClick={handlePrevClick}
|
385
|
+
disableNavigation={view === 'months'}
|
386
|
+
disabled={[
|
387
|
+
{
|
388
|
+
before: new Date(minDate ? minDate : ''),
|
389
|
+
after: new Date(maxDate ? maxDate : ''),
|
390
|
+
},
|
391
|
+
]}
|
392
|
+
timeZone={timezone}
|
393
|
+
components={{
|
394
|
+
CaptionLabel: (props) => <CustomCaption {...props} />,
|
395
|
+
PreviousMonthButton: (props) => <CustomPrevButton {...props} />,
|
396
|
+
NextMonthButton: (props) => <CustomNextButton {...props} />,
|
397
|
+
...(view === 'months'
|
398
|
+
? {
|
399
|
+
MonthGrid: () => <CustomMonthGrid />,
|
400
|
+
}
|
401
|
+
: {}),
|
402
|
+
...(view === 'years'
|
403
|
+
? {
|
404
|
+
MonthGrid: () => <CustomYearGrid />,
|
405
|
+
}
|
406
|
+
: {}),
|
407
|
+
}}
|
408
|
+
/>
|
409
|
+
<TimePicker
|
410
|
+
value={timeValue}
|
411
|
+
onChange={handleTimeChange}
|
412
|
+
minTime={minTime}
|
413
|
+
maxTime={maxTime}
|
414
|
+
onErrorChange={setTimeError}
|
415
|
+
/>
|
416
|
+
</div>
|
417
|
+
<div className="ff-date-picker-controls">
|
418
|
+
<Button
|
419
|
+
className="ff-date-picker-button"
|
420
|
+
variant="secondary"
|
421
|
+
onClick={handleCancel}
|
422
|
+
label="Cancel"
|
423
|
+
/>
|
424
|
+
<Button
|
425
|
+
className="ff-date-picker-button"
|
426
|
+
variant="primary"
|
427
|
+
onClick={handleSave}
|
428
|
+
label="Save"
|
429
|
+
disabled={timeError}
|
430
|
+
/>
|
431
|
+
</div>
|
432
|
+
</div>
|
433
|
+
)}
|
434
|
+
</div>
|
435
|
+
);
|
436
|
+
};
|
437
|
+
|
438
|
+
export default CustomDatePicker;
|