intelicoreact 0.0.5 → 0.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.
Files changed (58) hide show
  1. package/dist/Atomic/FormElements/Calendar/Calendar.js +20 -9
  2. package/dist/Atomic/FormElements/Calendar/Calendar.scss +1 -1
  3. package/dist/Atomic/FormElements/Calendar/Calendar.stories.js +12 -54
  4. package/dist/Atomic/FormElements/DateTime/DateTime.stories.js +1 -1
  5. package/dist/Atomic/FormElements/Input/Input.js +8 -7
  6. package/dist/Atomic/FormElements/Input/Input.stories.js +5 -1
  7. package/dist/Atomic/FormElements/InputCalendar/InputCalendar.js +89 -0
  8. package/dist/Atomic/FormElements/InputCalendar/InputCalendar.stories.js +46 -0
  9. package/dist/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +238 -0
  10. package/dist/Atomic/FormElements/InputDateRange/components/Datepicker.js +468 -0
  11. package/dist/Atomic/FormElements/InputDateRange/components/InputDateRange.js +248 -0
  12. package/dist/Atomic/FormElements/InputDateRange/components/InputDateRange.scss +598 -0
  13. package/dist/Atomic/FormElements/InputDateRange/components/OpenedPart.js +147 -0
  14. package/dist/Atomic/FormElements/InputDateRange/components/SelectItem.js +38 -0
  15. package/dist/Atomic/FormElements/InputDateRange/index.js +248 -0
  16. package/dist/Atomic/FormElements/Modal/Modal.stories.js +64 -18
  17. package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.js +162 -0
  18. package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.scss +101 -0
  19. package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.stories.js +81 -0
  20. package/dist/Atomic/UI/Arrow/Arrow.js +80 -0
  21. package/dist/Atomic/UI/Arrow/Arrow.scss +22 -0
  22. package/dist/Atomic/UI/Arrow/Arrow.stories.js +46 -0
  23. package/dist/Atomic/UI/Button/Button.js +4 -2
  24. package/dist/Atomic/UI/Button/Button.scss +26 -0
  25. package/dist/Atomic/UI/Button/Button.stories.js +2 -2
  26. package/dist/Atomic/UI/Calendar/Calendar.js +145 -0
  27. package/dist/Atomic/UI/Calendar/Calendar.scss +544 -0
  28. package/dist/Atomic/UI/Calendar/Calendar.stories.js +37 -0
  29. package/dist/Functions/utils.js +10 -2
  30. package/package.json +7 -5
  31. package/src/Atomic/FormElements/DateTime/DateTime.stories.js +1 -1
  32. package/src/Atomic/FormElements/Input/Input.js +8 -7
  33. package/src/Atomic/FormElements/Input/Input.stories.js +3 -1
  34. package/src/Atomic/FormElements/InputCalendar/InputCalendar.js +43 -0
  35. package/src/Atomic/FormElements/InputCalendar/InputCalendar.stories.js +27 -0
  36. package/src/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +142 -0
  37. package/src/Atomic/FormElements/InputDateRange/components/Datepicker.js +394 -0
  38. package/src/Atomic/FormElements/InputDateRange/components/InputDateRange.js +230 -0
  39. package/src/Atomic/FormElements/InputDateRange/components/InputDateRange.scss +598 -0
  40. package/src/Atomic/FormElements/InputDateRange/components/OpenedPart.js +109 -0
  41. package/src/Atomic/FormElements/InputDateRange/components/SelectItem.js +22 -0
  42. package/src/Atomic/FormElements/InputDateRange/index.js +157 -0
  43. package/src/Atomic/FormElements/Modal/Modal.stories.js +60 -15
  44. package/src/Atomic/FormElements/RangeCalendar/RangeCalendar.js +143 -0
  45. package/src/Atomic/FormElements/RangeCalendar/RangeCalendar.scss +101 -0
  46. package/src/Atomic/FormElements/RangeCalendar/RangeCalendar.stories.js +54 -0
  47. package/src/Atomic/UI/Arrow/Arrow.js +41 -0
  48. package/src/Atomic/UI/Arrow/Arrow.scss +22 -0
  49. package/src/Atomic/UI/Arrow/Arrow.stories.js +32 -0
  50. package/src/Atomic/UI/Button/Button.js +3 -3
  51. package/src/Atomic/UI/Button/Button.scss +26 -0
  52. package/src/Atomic/UI/Button/Button.stories.js +4 -3
  53. package/src/Atomic/{FormElements → UI}/Calendar/Calendar.js +13 -10
  54. package/src/Atomic/UI/Calendar/Calendar.scss +544 -0
  55. package/src/Atomic/UI/Calendar/Calendar.stories.js +23 -0
  56. package/src/Functions/utils.js +6 -0
  57. package/src/Atomic/FormElements/Calendar/Calendar.scss +0 -543
  58. package/src/Atomic/FormElements/Calendar/Calendar.stories.js +0 -38
@@ -0,0 +1,394 @@
1
+ // eslint-disable-next-line no-unused-vars
2
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
3
+ import moment from 'moment-timezone';
4
+ import cn from 'classnames';
5
+
6
+ import SelectInput from '../../Dropdown/Dropdown';
7
+ import TextInput from '../../Input/Input';
8
+ import Btn from '../../../UI/Button/Button';
9
+ // import Switcher from '../../Switcher/Switcher';
10
+ import Calendar from '../../RangeCalendar/RangeCalendar';
11
+
12
+ const padTime = time => {
13
+ return `${time.toString().padStart(2, '0')}:00`;
14
+ };
15
+
16
+ const handleDateInputOnChange = value => {
17
+ const replace = val => val.replace(/[^0-9\/]/g, '');
18
+
19
+ const input = replace(value);
20
+ const lastSymbol = input ? input.slice(-1) : '';
21
+ const previousValue = input ? input.slice(0, input.length - 1) : '';
22
+
23
+ if (value.length > 10 || lastSymbol === '/') return previousValue;
24
+ return previousValue.length === 2 || previousValue.length === 5 ? previousValue + '/' + lastSymbol : input;
25
+ };
26
+
27
+ const Datepicker = props => {
28
+ const {
29
+ txt,
30
+ className,
31
+ values = {},
32
+ onChange,
33
+ onChangeCompare,
34
+ onCancel,
35
+ getSelectedMode,
36
+ onChangeInterval,
37
+ isCompareHidden,
38
+ limitRange,
39
+ } = props;
40
+ const { start = null, end = null, compare = false } = values;
41
+ const startDateInputRef = useRef(null);
42
+ const endDateInputRef = useRef(null);
43
+
44
+ const [startDate, setStartDate] = useState(start);
45
+ const [endDate, setEndDate] = useState(end);
46
+ const dateInterval = getSelectedMode({ start: startDate, end: endDate });
47
+
48
+ const [startDateInput, setStartDateInput] = useState(start);
49
+ const [endDateInput, setEndDateInput] = useState(end);
50
+ const [startHour, setStartHour] = useState(start ? moment(start).hour() : 0);
51
+ const [endHour, setEndHour] = useState(end ? moment(end).hour() : 0);
52
+ // eslint-disable-next-line no-unused-vars
53
+ const [isCompare, setIsCompare] = useState(compare);
54
+ const [date1, setDate1] = useState(start ? moment(start).toDate() : moment().subtract(1, 'month').toDate());
55
+ const [date2, setDate2] = useState(end ? moment(end).toDate() : moment().toDate());
56
+ const [isStartFocused, setIsStartFocused] = useState(false);
57
+ const [isEndFocused, setIsEndFocused] = useState(false);
58
+ const [hoverStatus, setHoverStatus] = useState(null);
59
+
60
+ const isNearby = useMemo(() => moment(date2).subtract(1, 'month').isSame(moment(date1), 'month'), [date1, date2]);
61
+
62
+ const isPreviousPeriodShowed = useMemo(
63
+ () => isCompare && !isCompareHidden && startDate && endDate,
64
+ [startDate, endDate, isCompare],
65
+ );
66
+
67
+ const prevEndHour = useRef(endHour);
68
+
69
+ const getStartHourItems = () =>
70
+ [...Array(24).keys()].map(hour => ({
71
+ label: padTime(hour),
72
+ value: hour,
73
+ disabled: moment(startDate).isSame(endDate, 'day') && endHour <= hour,
74
+ }));
75
+ const getEndHourItems = () =>
76
+ [...Array(24).keys()].map(hour => ({
77
+ label: padTime(hour + 1),
78
+ value: hour === 23 ? 0 : hour + 1,
79
+ disabled:
80
+ (moment(startDate).isSame(endDate, 'day') ||
81
+ (moment(startDate).isSame(moment(endDate).subtract(1, 'days'), 'day') && endHour === 0)) &&
82
+ hour < startHour,
83
+ }));
84
+
85
+ const startPrevDate = useMemo(() => {
86
+ if (isPreviousPeriodShowed) {
87
+ const intervalHoursCount = moment(endDate).diff(startDate, 'hours');
88
+ return moment(startDate).subtract(intervalHoursCount, 'hours').toDate();
89
+ } else return null;
90
+ }, [startDate, endDate, isCompare]);
91
+
92
+ const endPrevDate = useMemo(() => {
93
+ if (isPreviousPeriodShowed) {
94
+ return startDate;
95
+ } else return null;
96
+ }, [startDate, endDate, isCompare]);
97
+
98
+ const title = useMemo(() => {
99
+ if (isCompare && !isCompareHidden && startDate && endDate) {
100
+ return `${moment(startPrevDate).format('ll')} (${moment(startPrevDate).format('HH:mm')}) - ${moment(
101
+ endPrevDate,
102
+ ).format('ll')} (${moment(endPrevDate).format('HH:mm')})`;
103
+ } else return '';
104
+ }, [startDate, endDate, isCompare]);
105
+
106
+ const subtractDay = date => (endHour === 0 ? moment(date).subtract(1, 'days') : date);
107
+ const addDay = date => (endHour === 0 ? moment(date).add(1, 'days') : date);
108
+
109
+ useEffect(() => {
110
+ if (moment(startDate).isSameOrAfter(endDate)) {
111
+ setStartDate(moment(endDate).subtract(1, 'd').toDate());
112
+ setDate1(moment(endDate).subtract(1, 'd'));
113
+ }
114
+ }, [startDate]);
115
+
116
+ useEffect(() => {
117
+ if (moment(endDate).isSameOrBefore(startDate)) {
118
+ setEndDate(moment(startDate).add(1, 'd').toDate());
119
+ setDate2(moment(startDate).add(1, 'd'));
120
+ }
121
+ }, [endDate]);
122
+
123
+ useEffect(() => {
124
+ setStartDateInput(startDate);
125
+ setEndDateInput(endDate);
126
+ if (moment(startDate).isBefore(moment(endDate), 'month')) {
127
+ setDate1(moment(startDate));
128
+ setDate2(moment(endDate));
129
+ }
130
+ }, [startDate, endDate]);
131
+
132
+ useEffect(() => {
133
+ if (moment(date1).isSameOrAfter(moment(date2), 'month')) {
134
+ setDate1(moment(date2).subtract(1, 'month'));
135
+ }
136
+ }, [date1, date2]);
137
+
138
+ useEffect(() => {
139
+ onChangeInterval(dateInterval);
140
+ }, [dateInterval]);
141
+
142
+ const handleClick = date => {
143
+ prevEndHour.current = 0;
144
+ if (
145
+ !startDate ||
146
+ (startDate && endDate && !(moment(startDate).add(1, 'd').isSame(endDate, 'day') && endHour === 0))
147
+ ) {
148
+ setStartDate(moment(date).startOf('day').toDate());
149
+ setEndDate(moment(date).add(1, 'd').startOf('day').toDate());
150
+ setStartHour(0);
151
+ setEndHour(0);
152
+ } else if (moment(date).isBefore(moment(startDate), 'day')) {
153
+ setEndDate(moment(startDate).add(1, 'd').startOf('day').toDate());
154
+ setStartDate(moment(date).set('hour', parseInt(startHour, 10)).toDate());
155
+ } else if (moment(date).isAfter(moment(startDate), 'day')) {
156
+ setEndDate(moment(date).add(1, 'd').startOf('day').toDate());
157
+ }
158
+ setHoverStatus(null);
159
+ };
160
+
161
+ let timerId;
162
+
163
+ const handleHover = date => {
164
+ if (!date) {
165
+ timerId = setTimeout(() => {
166
+ setHoverStatus(null);
167
+ }, 400);
168
+ return;
169
+ }
170
+ if (timerId) clearTimeout(timerId);
171
+ if (moment(startDate).add(1, 'd').isSame(endDate, 'day') && endHour === 0) {
172
+ if (moment(date).isAfter(moment(startDate), 'day')) setHoverStatus('end');
173
+ else if (moment(date).isBefore(moment(startDate), 'day')) setHoverStatus('start');
174
+ else setHoverStatus(null);
175
+ } else {
176
+ setHoverStatus('start');
177
+ }
178
+ };
179
+
180
+ const handleChangeStartHour = val => {
181
+ setStartHour(+val);
182
+ setStartDate(
183
+ moment(startDate)
184
+ .set('hour', +val)
185
+ .toDate(),
186
+ );
187
+ };
188
+
189
+ const handleChangeEndHour = val => {
190
+ const newHour = +val;
191
+ setEndHour(newHour);
192
+ let newEndDate;
193
+ if (prevEndHour.current === 0 && newHour !== 0) {
194
+ newEndDate = moment(endDate).subtract(1, 'days');
195
+ } else if (prevEndHour.current !== 0 && newHour === 0) {
196
+ newEndDate = moment(endDate).add(1, 'days');
197
+ } else {
198
+ newEndDate = endDate;
199
+ }
200
+ prevEndHour.current = newHour;
201
+ setEndDate(moment(newEndDate).set('hour', newHour).toDate());
202
+ };
203
+
204
+ const renderButtons = () => (
205
+ <>
206
+ <Btn className="date-picker__button" onClick={() => onCancel()} variant="ellipse-cancel">
207
+ {txt?.buttons?.cancel || 'cancel'}
208
+ </Btn>
209
+ <Btn
210
+ className="date-picker__button"
211
+ variant="ellipse-apply"
212
+ disabled={!startDate || !endDate}
213
+ onClick={() =>
214
+ onChange({
215
+ start: startDate,
216
+ end: endDate,
217
+ startPrevDate,
218
+ endPrevDate,
219
+ compare: isCompare,
220
+ })
221
+ }
222
+ >
223
+ {txt?.buttons?.apply || 'apply'}
224
+ </Btn>
225
+ </>
226
+ );
227
+
228
+ const renderPreviousPeriod = () => (
229
+ <>
230
+ {txt.labels.previousPeriod}: <span className="date-picker__previous-period-interval">{title}</span>
231
+ </>
232
+ );
233
+
234
+ const doBlur = (type, e) => {
235
+ const executor = type === 'start' ? setIsStartFocused : setIsEndFocused;
236
+ e.target.blur();
237
+ executor(false);
238
+ };
239
+
240
+ const handleStartDateFocus = e => {
241
+ setIsStartFocused(true);
242
+ setStartDateInput(moment(startDate).format('L'));
243
+ setTimeout(() => e.target.select(), 0);
244
+ };
245
+
246
+ const handleStartDateBlur = e => {
247
+ let newDate;
248
+ if (moment(startDateInput).isValid()) {
249
+ newDate = moment(startDateInput).set('hour', parseInt(startHour, 10)).toDate();
250
+ setStartDate(newDate);
251
+ } else {
252
+ newDate = startDate;
253
+ setStartDateInput(newDate);
254
+ }
255
+ doBlur('start', e);
256
+ setDate1(
257
+ moment(newDate).isSameOrAfter(moment(date2), 'month') ? moment(date2).subtract(1, 'month') : moment(newDate),
258
+ );
259
+ };
260
+
261
+ const handleEndDateFocus = e => {
262
+ setIsEndFocused(true);
263
+ setEndDateInput(moment(subtractDay(endDateInput)).format('L'));
264
+ setTimeout(() => e.target.select(), 0);
265
+ };
266
+
267
+ const handleEndDateBlur = e => {
268
+ let newDate;
269
+ if (moment(endDateInput).isValid()) {
270
+ newDate = moment(endDateInput).set('hour', parseInt(endHour, 10)).toDate();
271
+ setEndDate(addDay(newDate));
272
+ } else {
273
+ newDate = endDate;
274
+ setEndDateInput(newDate);
275
+ }
276
+ doBlur('end', e);
277
+ setDate2(newDate);
278
+ setEndDateInput();
279
+ };
280
+
281
+ const handleKeyPressed = (code, e, type) => {
282
+ if (code === 13) (type === 'start' ? handleStartDateBlur : handleEndDateBlur)(e);
283
+ if (code === 27) doBlur(type, e);
284
+ };
285
+
286
+ return (
287
+ <div className={cn('date-picker', className)}>
288
+ <div className="date-picker__header">
289
+ <div className="date-picker__inputs-block">
290
+ <TextInput
291
+ dataTest="datepicker_start-date-input"
292
+ className={cn('date-picker__date-input', { 'date-picker__date-input_active': hoverStatus === 'start' })}
293
+ value={isStartFocused ? startDateInput : moment(startDate).format('ll')}
294
+ disabled={!startDate}
295
+ onChange={value => setStartDateInput(handleDateInputOnChange(value))}
296
+ onFocus={handleStartDateFocus}
297
+ onBlur={handleStartDateBlur}
298
+ onKeyUp={(code, e) => handleKeyPressed(code, e, 'start')}
299
+ ref={startDateInputRef}
300
+ // mask={moment(startDate).format('L').replace(/[0-9]/g, '9')}
301
+ />
302
+ <SelectInput
303
+ dataTest="datepicker_start-hour-select-input"
304
+ className={cn('date-picker__hour-select-input')}
305
+ onChange={value => handleChangeStartHour(value)}
306
+ value={startHour}
307
+ options={getStartHourItems()}
308
+ disabled={!startDate}
309
+ short
310
+ />
311
+ <div className="date-picker__inputs-separator date-picker__header--gray">—</div>
312
+ <TextInput
313
+ dataTest="datepicker_end-date-input"
314
+ className={cn('date-picker__date-input', { 'date-picker__date-input_active': hoverStatus === 'end' })}
315
+ value={isEndFocused ? endDateInput : moment(subtractDay(endDate)).format('ll')}
316
+ disabled={!endDate}
317
+ onChange={value => setEndDateInput(handleDateInputOnChange(value))}
318
+ onFocus={handleEndDateFocus}
319
+ onBlur={handleEndDateBlur}
320
+ onKeyUp={(code, e) => handleKeyPressed(code, e, 'end')}
321
+ ref={endDateInputRef}
322
+ />
323
+ <SelectInput
324
+ dataTest="datepicker_end-hour-select-input"
325
+ className={cn('date-picker__hour-select-input')}
326
+ onChange={value => handleChangeEndHour(value)}
327
+ value={endHour}
328
+ options={getEndHourItems()}
329
+ disabled={!endDate}
330
+ short
331
+ />
332
+ </div>
333
+ {isCompare && !isCompareHidden && startDate && endDate && (
334
+ <div className="date-picker__previous-period">
335
+ {renderPreviousPeriod()}
336
+ </div>
337
+ )}
338
+ </div>
339
+
340
+
341
+ <div className="date-picker__calendars">
342
+ <Calendar
343
+ className="date-picker__calendar"
344
+ date={date1}
345
+ setDate={setDate1}
346
+ allowNext={!isNearby}
347
+ startDate={startDate}
348
+ endDate={endDate}
349
+ startPrevDate={startPrevDate}
350
+ endPrevDate={endPrevDate}
351
+ onClick={handleClick}
352
+ onHover={handleHover}
353
+ limitRange={limitRange}
354
+ />
355
+ <Calendar
356
+ className="date-picker__calendar"
357
+ date={date2}
358
+ setDate={setDate2}
359
+ allowPrev={!isNearby}
360
+ startDate={startDate}
361
+ endDate={endDate}
362
+ startPrevDate={startPrevDate}
363
+ endPrevDate={endPrevDate}
364
+ onClick={handleClick}
365
+ onHover={handleHover}
366
+ />
367
+ </div>
368
+ <div className={cn('date-picker__footer', {
369
+ 'date-picker__footer_once-element': isCompareHidden
370
+ })}>
371
+ {/* {!isCompareHidden ? (
372
+ <div className="date-picker__compare-block">
373
+ <div className="mr5">
374
+ <Switcher
375
+ dataTest="datepicker_compare"
376
+ label={txt.labels.compare}
377
+ isSwitchOn={isCompare}
378
+ onChange={() => {
379
+ onChangeCompare(!isCompare);
380
+ setIsCompare(state => !state);
381
+ }}
382
+ />
383
+ </div>
384
+ </div>
385
+ ) : (
386
+ <div />
387
+ )} */}
388
+ <div className="date-picker__buttons-block">{renderButtons()}</div>
389
+ </div>
390
+ </div>
391
+ );
392
+ };
393
+
394
+ export default Datepicker;
@@ -0,0 +1,230 @@
1
+ import React, { useState, useEffect, useRef, useMemo } from 'react';
2
+ import cn from 'classnames';
3
+ import moment from 'moment-timezone';
4
+
5
+ import { useClickOutside, useToggle, getActualDateRange, INTERVALS, ALL_TIME_KEY, CUSTOM_INTERVAL_KEY_TEXT } from '..';
6
+
7
+ import OpenedPart from './OpenedPart';
8
+ import Arrow from '../../../UI/Arrow/Arrow';
9
+
10
+ import './InputDateRange.scss'
11
+
12
+ const InputDateRange = props => {
13
+ const {
14
+ txt,
15
+ id,
16
+ label,
17
+ className,
18
+ value,
19
+ onChange = () => {},
20
+ error,
21
+ disabled,
22
+ isHoverable,
23
+ short,
24
+ isCompact = false,
25
+ // isFocused = false,
26
+ isIntervalsHidden = false,
27
+ isCompareHidden = false,
28
+ hideArrows = false,
29
+ isOptionsRight,
30
+ limitRange,
31
+ isUseAbs,
32
+ absTooltip,
33
+ } = props;
34
+
35
+ const actualValues = getActualDateRange(value);
36
+ const { isToggled, toggle, toggleOn, toggleOff } = useToggle(false);
37
+ const [current, setCurrent] = useState(actualValues?.intervalKey);
38
+ const [isCompare, setIsCompare] = useState(actualValues?.compare);
39
+
40
+ const ref = !isUseAbs ? useClickOutside(toggleOff) : useRef(null);
41
+ const internalContainerRef = useRef(null);
42
+ const isEndDateNearFuture = moment(actualValues?.end).isSameOrAfter(moment());
43
+
44
+ const Range = () => {
45
+ const SYMBOLS_QUANTITY_IF_TIME_ADDED = 13;
46
+ const { start, end } = actualValues;
47
+ if (!start || !end) return null;
48
+
49
+ const startTime = moment(start).format('HH:mm');
50
+ const endTime = moment(end).format('HH:mm');
51
+
52
+ const firstPart = `${moment(start).format('ll')} ${startTime !== '00:00' ? `(${startTime})` : ''}`;
53
+ const secondPart = `${(endTime !== '00:00' ? moment(end) : moment(end).subtract(1, 'days')).format('ll')} ${
54
+ endTime !== '00:00' ? `(${endTime})` : ''
55
+ }`;
56
+
57
+ const getClasses = base => cn('date-range-input__range-text', {
58
+ 'date-range-input__range-text_little': base.length > SYMBOLS_QUANTITY_IF_TIME_ADDED
59
+ });
60
+
61
+ return (
62
+ <>
63
+ <span className={getClasses(firstPart)}>
64
+ {firstPart}
65
+ {endTime === '00:00' && moment(end).isSame(moment(start).add(1, 'days'), 'day') ? '' : ` - `}
66
+ </span>
67
+ {endTime === '00:00' && moment(end).isSame(moment(start).add(1, 'days'), 'day')
68
+ ? null
69
+ :<span className={getClasses(secondPart)}>{secondPart}</span>
70
+
71
+ }
72
+ </>
73
+ )
74
+ }
75
+
76
+ const slideInterval = (direction = 'forward') => {
77
+ const { start, end } = actualValues;
78
+ const intervalHoursCount = moment(end).diff(start, 'hours');
79
+ console.log(intervalHoursCount);
80
+ let newEnd, newStart;
81
+ const endHours = moment(end).hours();
82
+ const startHours = moment(start).hours();
83
+ if (direction === 'forward') {
84
+ newStart = moment(end)
85
+ .add(endHours === 0 ? 0 : 1, 'day')
86
+ .hours(startHours)
87
+ .toDate();
88
+ newEnd = moment(newStart).add(intervalHoursCount, 'hours');
89
+ } else {
90
+ newEnd = moment(start)
91
+ .subtract(endHours === 0 ? 0 : 1, 'day')
92
+ .hours(endHours)
93
+ .toDate();
94
+ newStart = moment(newEnd).subtract(intervalHoursCount, 'hours');
95
+ }
96
+ const startPrevDate = moment(newStart).subtract(intervalHoursCount, 'hours').subtract(1, 'seconds');
97
+ const endPrevDate = moment(newEnd).subtract(1, 'seconds');
98
+ onChange({
99
+ ...value,
100
+ intervalKey: getActualDateRange({
101
+ start: newStart,
102
+ end: newEnd,
103
+ })?.intervalKey,
104
+ start: newStart,
105
+ end: newEnd,
106
+ startPrevDate,
107
+ endPrevDate,
108
+ });
109
+ };
110
+
111
+ const handleArrowClick = type => {
112
+ slideInterval(type === 'right' ? 'forward' : 'back');
113
+ toggleOff();
114
+ };
115
+
116
+ const absData = useMemo(
117
+ () => ({
118
+ body: OpenedPart,
119
+ props: {
120
+ ...props,
121
+ key: `${actualValues.start}-${actualValues.end}-${actualValues.intervalKey}-${current}-${isCompare}`,
122
+ actualValues,
123
+ current,
124
+ setCurrent,
125
+ isCompare,
126
+ setIsCompare,
127
+ toggleOff,
128
+ onChange,
129
+ },
130
+ clickOutsideCallback: () => toggleOff(),
131
+ top: internalContainerRef.current?.getBoundingClientRect()?.bottom || 0,
132
+ left: internalContainerRef.current?.getBoundingClientRect()?.left || 0,
133
+ }),
134
+ [isToggled, value, actualValues, current, isCompare],
135
+ );
136
+
137
+ useEffect(() => {
138
+ if (current && isUseAbs && absTooltip) onChange(current, 'absTooltip/props/current');
139
+ }, [current]);
140
+
141
+ useEffect(() => {
142
+ if (isUseAbs) onChange(isToggled ? absData : null, 'absTooltip');
143
+ }, [isToggled]);
144
+
145
+ return (
146
+ <div
147
+ ref={internalContainerRef}
148
+ className={cn('date-range-input', className, {
149
+ 'date-range-input_compact': isCompact,
150
+ 'date-range-input_hide-arrows': hideArrows,
151
+ 'date-range-input_focused': isToggled,
152
+ 'date-range-input_error': error,
153
+ 'date-range-input_disabled': disabled,
154
+ })}
155
+ >
156
+ <span className="date-range-input__label" >{label}</span>
157
+ <div
158
+ className="date-range-input__wraper"
159
+ ref={ref}
160
+ onMouseEnter={isHoverable && toggleOn}
161
+ onMouseLeave={isHoverable && toggleOff}
162
+ >
163
+ <div className={cn('date-range-input__absolut-wraper', {
164
+ 'date-range-input__absolut-wraper_right-position': isOptionsRight,
165
+ })}>
166
+ <div className={cn('date-range-input__static-part')}>
167
+ <button
168
+ id={id}
169
+ className={cn('date-range-input__toggle-button')}
170
+ // className={cn(
171
+ // 'date-range-input__toggle-button',
172
+ // { 'form-select__input--disabled': disabled },
173
+ // { 'form-select__input--opened': isToggled },
174
+ // { 'form-select__input--focused': isToggled },
175
+ // className,
176
+ // )}
177
+ disabled={disabled}
178
+ onClick={!disabled && !isHoverable ? toggle : undefined}
179
+ >
180
+ <div className="date-range-input__interval-key">
181
+ <span>
182
+ {(txt?.labels && txt.labels[actualValues?.intervalKey]) ?? (INTERVALS[actualValues?.intervalKey]?.label || CUSTOM_INTERVAL_KEY_TEXT)}
183
+ </span>
184
+ {current !== ALL_TIME_KEY && <span>:</span>}
185
+ </div>
186
+ {!isCompact && <div className={cn('date-range-input__range', {})}><Range /></div>}
187
+ </button>
188
+ {!isCompact && !hideArrows && (
189
+ <div className={cn('date-range-input__arrows-block')}>
190
+ <Arrow
191
+ type="left"
192
+ className="date-range-input__arrow"
193
+ onClick={() => handleArrowClick("left")}
194
+ disabled={disabled || actualValues?.intervalKey === ALL_TIME_KEY}
195
+ />
196
+ <Arrow
197
+ type="right"
198
+ className="date-range-input__arrow"
199
+ onClick={() => handleArrowClick("right")}
200
+ disabled={
201
+ disabled ||
202
+ actualValues?.intervalKey === ALL_TIME_KEY ||
203
+ actualValues?.intervalKey === 'today' ||
204
+ moment(actualValues?.end).add(moment(actualValues?.end).diff(actualValues?.start, 'hours'), 'hours').isSameOrAfter(moment())
205
+ }
206
+ />
207
+ </div>
208
+ )}
209
+ </div>
210
+ {isToggled && !isUseAbs && (
211
+ <OpenedPart
212
+ {...props}
213
+ ref={internalContainerRef}
214
+ actualValues={actualValues}
215
+ current={current}
216
+ setCurrent={setCurrent}
217
+ isCompare={isCompare}
218
+ setIsCompare={setIsCompare}
219
+ toggleOff={toggleOff}
220
+ onChange={onChange}
221
+ />
222
+ )}
223
+ </div>
224
+ </div>
225
+ {error && <span className="date-range-input__error-block">{error}</span>}
226
+ </div>
227
+ );
228
+ };
229
+
230
+ export default React.memo(InputDateRange);