Skip to content

Commit e3faffe

Browse files
Merge pull request #2175 from matuzalemsteles/issue-2106
refactor(@clayui/time-picker): rewrites the timer to mimic browser time behavior
2 parents 2968282 + 5444307 commit e3faffe

File tree

12 files changed

+1330
-160
lines changed

12 files changed

+1330
-160
lines changed

packages/clay-date-picker/src/Hooks.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,28 @@ const useCurrentTime = (format: string) => {
3535
.format(format)
3636
);
3737

38-
function setCurrentTime(hours: number, minutes: number): void {
39-
set(
40-
moment()
38+
function setCurrentTime(
39+
hours: number | string,
40+
minutes: number | string
41+
): void {
42+
if (typeof hours !== 'string') {
43+
hours = moment()
4144
.set('h', hours)
45+
.format('H');
46+
}
47+
48+
if (typeof minutes !== 'string') {
49+
minutes = moment()
4250
.set('m', minutes)
43-
.format(format)
44-
);
51+
.format('m');
52+
}
53+
54+
set(`${hours}:${minutes}`);
4555
}
4656

4757
return [currentTime, setCurrentTime] as [
4858
string,
49-
(hours: number, minutes: number) => void
59+
(hours: number | string, minutes: number | string) => void
5060
];
5161
};
5262

packages/clay-date-picker/src/TimePicker.tsx

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,66 @@
44
* SPDX-License-Identifier: BSD-3-Clause
55
*/
66

7-
import ClayTimePicker from '@clayui/time-picker';
8-
import Icon from '@clayui/icon';
9-
import moment from 'moment';
10-
import React, {ChangeEventHandler, FunctionComponent} from 'react';
7+
import ClayTimePicker, {Input} from '@clayui/time-picker';
8+
import React, {useEffect, useState} from 'react';
119

1210
interface IProps {
1311
currentTime: string;
14-
onTimeChange: (hours: number, minutes: number) => void;
12+
onTimeChange: (hours: number | string, minutes: number | string) => void;
1513
spritemap: string;
16-
timeFormat: string;
1714
timezone?: string;
1815
}
1916

20-
const ClayDatePickerTimePicker: FunctionComponent<IProps> = ({
17+
const DEFAULT_VALUE = '--';
18+
19+
const ClayDatePickerTimePicker: React.FunctionComponent<IProps> = ({
2120
currentTime,
2221
onTimeChange,
2322
spritemap,
24-
timeFormat,
2523
timezone,
2624
}) => {
25+
const [values, setValues] = useState<Input>({
26+
ampm: DEFAULT_VALUE,
27+
hours: DEFAULT_VALUE,
28+
minutes: DEFAULT_VALUE,
29+
});
30+
2731
/**
2832
* Handles the control time picker
2933
*/
30-
const handleOnChange: ChangeEventHandler<HTMLInputElement> = event => {
31-
const date = moment(event.target.value, timeFormat);
32-
onTimeChange(date.hours(), date.minutes());
34+
const handleOnChange = (values: Input) => {
35+
const hours =
36+
values.hours === DEFAULT_VALUE
37+
? DEFAULT_VALUE
38+
: Number(values.hours);
39+
const minutes =
40+
values.minutes === DEFAULT_VALUE
41+
? DEFAULT_VALUE
42+
: Number(values.minutes);
43+
44+
setValues(values);
45+
onTimeChange(hours, minutes);
3346
};
3447

48+
useEffect(() => {
49+
const time = currentTime.split(':');
50+
51+
setValues(prevValues => ({
52+
...prevValues,
53+
hours: String(time[0]),
54+
minutes: String(time[1]),
55+
}));
56+
}, [currentTime]);
57+
3558
return (
3659
<div className="time-picker">
37-
<div className="input-group">
38-
<div className="input-group-item input-group-item-shrink">
39-
<span className="input-group-text">
40-
<Icon spritemap={spritemap} symbol="time" />
41-
</span>
42-
</div>
43-
<ClayTimePicker
44-
name="timer"
45-
onChange={handleOnChange}
46-
timezone={timezone}
47-
value={currentTime}
48-
wrapTime={false}
49-
/>
50-
</div>
60+
<ClayTimePicker
61+
icon
62+
onInputChange={handleOnChange}
63+
spritemap={spritemap}
64+
timezone={timezone}
65+
values={values}
66+
/>
5167
</div>
5268
);
5369
};

packages/clay-date-picker/src/__tests__/IncrementalInteractions.tsx

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,9 @@ describe('IncrementalInteractions', () => {
357357
);
358358

359359
const input: any = getByLabelText(ariaLabels.input);
360-
const inputTimePicker: any = getByTestId('time-picker-input');
360+
const hoursEl = getByTestId('hours') as HTMLInputElement;
361361

362-
fireEvent.change(inputTimePicker, {
363-
target: {
364-
value: '00:20',
365-
},
366-
});
362+
fireEvent.keyDown(hoursEl, {key: '10'});
367363

368364
expect(input.value).toBe('');
369365
});
@@ -381,17 +377,13 @@ describe('IncrementalInteractions', () => {
381377

382378
const input: any = getByLabelText(ariaLabels.input);
383379
const dayNumber = getByLabelText('2019 04 24');
384-
const inputTimePicker: any = getByTestId('time-picker-input');
380+
const hoursEl = getByTestId('hours') as HTMLInputElement;
385381

386382
fireEvent.click(dayNumber);
387383

388-
fireEvent.change(inputTimePicker, {
389-
target: {
390-
value: '00:20',
391-
},
392-
});
384+
fireEvent.keyDown(hoursEl, {key: '10'});
393385

394-
expect(input.value).toBe('2019-04-24 00:20');
386+
expect(input.value).toBe('2019-04-24 10:0');
395387
});
396388

397389
it('value entered in the input value must be reflected in the time picker', () => {
@@ -406,15 +398,17 @@ describe('IncrementalInteractions', () => {
406398
);
407399

408400
const input: any = getByLabelText(ariaLabels.input);
409-
const inputTimePicker: any = getByTestId('time-picker-input');
401+
const hoursEl = getByTestId('hours') as HTMLInputElement;
402+
const minutesEl = getByTestId('minutes') as HTMLInputElement;
410403

411404
fireEvent.change(input, {
412405
target: {
413406
value: '2019-04-18 01:20',
414407
},
415408
});
416409

417-
expect(inputTimePicker.value).toBe('01:20');
410+
expect(hoursEl.value).toBe('1');
411+
expect(minutesEl.value).toBe('20');
418412
});
419413
});
420414
});

packages/clay-date-picker/src/__tests__/__snapshots__/BasicRendering.tsx.snap

Lines changed: 119 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,43 +1609,130 @@ exports[`BasicRendering renders date picker with time 1`] = `
16091609
class="time-picker"
16101610
>
16111611
<div
1612-
class="input-group"
1612+
class="clay-time"
16131613
>
16141614
<div
1615-
class="input-group-item input-group-item-shrink"
1615+
class="input-group"
16161616
>
1617-
<span
1618-
class="input-group-text"
1617+
<div
1618+
class="input-group-item input-group-item-shrink"
16191619
>
1620-
<svg
1621-
class="lexicon-icon lexicon-icon-time"
1622-
role="presentation"
1620+
<div
1621+
class="input-group-text"
16231622
>
1624-
<use
1625-
xlink:href="icons.svg#time"
1626-
/>
1627-
</svg>
1628-
</span>
1629-
</div>
1630-
<div
1631-
class="input-group-item"
1632-
>
1633-
<input
1634-
class="form-control"
1635-
data-testid="time-picker-input"
1636-
name="timer"
1637-
type="time"
1638-
value="00:00"
1639-
/>
1640-
</div>
1641-
<div
1642-
class="input-group-item input-group-item-shrink"
1643-
>
1644-
<span
1645-
class="input-group-text"
1646-
>
1647-
(GMT+01:00)
1648-
</span>
1623+
<svg
1624+
class="lexicon-icon lexicon-icon-time"
1625+
role="presentation"
1626+
>
1627+
<use
1628+
xlink:href="icons.svg#time"
1629+
/>
1630+
</svg>
1631+
</div>
1632+
</div>
1633+
<div
1634+
class="input-group-item input-group-item-shrink"
1635+
>
1636+
<div
1637+
class="form-control"
1638+
data-testid="formControl"
1639+
>
1640+
<div
1641+
class="clay-time-edit"
1642+
>
1643+
<input
1644+
class="clay-time-hours form-control-inset"
1645+
data-testid="hours"
1646+
maxlength="2"
1647+
type="text"
1648+
value="0"
1649+
/>
1650+
<span
1651+
class="clay-time-divider"
1652+
>
1653+
:
1654+
</span>
1655+
<input
1656+
class="clay-time-minutes form-control-inset"
1657+
data-testid="minutes"
1658+
maxlength="2"
1659+
type="text"
1660+
value="0"
1661+
/>
1662+
</div>
1663+
<div
1664+
class="clay-time-action-group"
1665+
>
1666+
<div
1667+
class="clay-time-action-group-item"
1668+
data-testid="containerReset"
1669+
style="opacity: 0; pointer-events: none;"
1670+
>
1671+
<button
1672+
class="clay-time-clear-btn btn btn-unstyled"
1673+
type="button"
1674+
>
1675+
<svg
1676+
class="lexicon-icon lexicon-icon-times-circle"
1677+
role="presentation"
1678+
>
1679+
<use
1680+
xlink:href="icons.svg#times-circle"
1681+
/>
1682+
</svg>
1683+
</button>
1684+
</div>
1685+
<div
1686+
class="clay-time-action-group-item"
1687+
data-testid="containerSpin"
1688+
style="opacity: 0;"
1689+
>
1690+
<div
1691+
class="btn-group-vertical clay-time-inner-spin"
1692+
role="group"
1693+
>
1694+
<button
1695+
class="clay-time-inner-spin-btn clay-time-inner-spin-btn-inc btn btn-secondary"
1696+
data-testid="spinInc"
1697+
type="button"
1698+
>
1699+
<svg
1700+
class="lexicon-icon lexicon-icon-angle-up"
1701+
role="presentation"
1702+
>
1703+
<use
1704+
xlink:href="icons.svg#angle-up"
1705+
/>
1706+
</svg>
1707+
</button>
1708+
<button
1709+
class="clay-time-inner-spin-btn clay-time-inner-spin-btn-dec btn btn-secondary"
1710+
data-testid="spinDec"
1711+
type="button"
1712+
>
1713+
<svg
1714+
class="lexicon-icon lexicon-icon-angle-down"
1715+
role="presentation"
1716+
>
1717+
<use
1718+
xlink:href="icons.svg#angle-down"
1719+
/>
1720+
</svg>
1721+
</button>
1722+
</div>
1723+
</div>
1724+
</div>
1725+
</div>
1726+
</div>
1727+
<div
1728+
class="input-group-item input-group-item-shrink"
1729+
>
1730+
<span
1731+
class="input-group-text"
1732+
>
1733+
(GMT+01:00)
1734+
</span>
1735+
</div>
16491736
</div>
16501737
</div>
16511738
</div>

0 commit comments

Comments
 (0)