Skip to content

Commit 2a37c3e

Browse files
authored
fix: 2.7.x dynamic disabledTime should be correct (#673)
1 parent 27b83a9 commit 2a37c3e

File tree

3 files changed

+139
-30
lines changed

3 files changed

+139
-30
lines changed

src/hooks/useTimeSelection.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { GenerateConfig } from '../generate';
2+
import type { Unit } from '../panels/TimePanel/TimeUnitColumn';
3+
import { setTime as utilSetTime } from '../utils/timeUtil';
4+
5+
export default function useTimeSelection<DateType>({
6+
value,
7+
generateConfig,
8+
disabledMinutes,
9+
disabledSeconds,
10+
minutes,
11+
seconds,
12+
use12Hours,
13+
}: {
14+
value: DateType;
15+
generateConfig: GenerateConfig<DateType>;
16+
disabledMinutes: (hour: number) => number[];
17+
disabledSeconds: (hour: number, minute: number) => number[];
18+
minutes: Unit[];
19+
seconds: Unit[];
20+
use12Hours: boolean;
21+
}) {
22+
const setTime = (
23+
isNewPM: boolean | undefined,
24+
newHour: number,
25+
newMinute: number,
26+
newSecond: number,
27+
) => {
28+
let newDate = value || generateConfig.getNow();
29+
30+
const mergedHour = Math.max(0, newHour);
31+
let mergedMinute = Math.max(0, newMinute);
32+
let mergedSecond = Math.max(0, newSecond);
33+
34+
const newDisabledMinutes = disabledMinutes && disabledMinutes(mergedHour);
35+
if (newDisabledMinutes?.includes(mergedMinute)) {
36+
// find the first available minute in minutes
37+
const availableMinute = minutes.find((i) => !newDisabledMinutes.includes(i.value));
38+
if (availableMinute) {
39+
mergedMinute = availableMinute.value;
40+
} else {
41+
return null;
42+
}
43+
}
44+
const newDisabledSeconds = disabledSeconds && disabledSeconds(mergedHour, mergedMinute);
45+
if (newDisabledSeconds?.includes(mergedSecond)) {
46+
// find the first available second in seconds
47+
const availableSecond = seconds.find((i) => !newDisabledSeconds.includes(i.value));
48+
if (availableSecond) {
49+
mergedSecond = availableSecond.value;
50+
} else {
51+
return null;
52+
}
53+
}
54+
55+
newDate = utilSetTime(
56+
generateConfig,
57+
newDate,
58+
!use12Hours || !isNewPM ? mergedHour : mergedHour + 12,
59+
mergedMinute,
60+
mergedSecond,
61+
);
62+
63+
return newDate;
64+
};
65+
66+
return setTime;
67+
}

src/panels/TimePanel/TimeBody.tsx

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import * as React from 'react';
21
import useMemo from 'rc-util/lib/hooks/useMemo';
2+
import * as React from 'react';
3+
import type { SharedTimeProps } from '.';
34
import type { GenerateConfig } from '../../generate';
5+
import useTimeSelection from '../../hooks/useTimeSelection';
46
import type { Locale, OnSelect } from '../../interface';
7+
import { leftPad } from '../../utils/miscUtil';
58
import type { Unit } from './TimeUnitColumn';
69
import TimeUnitColumn from './TimeUnitColumn';
7-
import { leftPad } from '../../utils/miscUtil';
8-
import type { SharedTimeProps } from '.';
9-
import { setTime as utilSetTime } from '../../utils/timeUtil';
1010

1111
function shouldUnitsUpdate(prevUnits: Unit[], nextUnits: Unit[]) {
1212
if (prevUnits.length !== nextUnits.length) return true;
@@ -102,30 +102,6 @@ function TimeBody<DateType>(props: TimeBodyProps<DateType>) {
102102
return [disabledHours, disabledMinutes, disabledSeconds];
103103
}, [disabledHours, disabledMinutes, disabledSeconds, disabledTime, now]);
104104

105-
// Set Time
106-
const setTime = (
107-
isNewPM: boolean | undefined,
108-
newHour: number,
109-
newMinute: number,
110-
newSecond: number,
111-
) => {
112-
let newDate = value || generateConfig.getNow();
113-
114-
const mergedHour = Math.max(0, newHour);
115-
const mergedMinute = Math.max(0, newMinute);
116-
const mergedSecond = Math.max(0, newSecond);
117-
118-
newDate = utilSetTime(
119-
generateConfig,
120-
newDate,
121-
!use12Hours || !isNewPM ? mergedHour : mergedHour + 12,
122-
mergedMinute,
123-
mergedSecond,
124-
);
125-
126-
return newDate;
127-
};
128-
129105
// ========================= Unit =========================
130106
const rawHours = generateUnits(0, 23, hourStep, mergedDisabledHours && mergedDisabledHours());
131107

@@ -182,6 +158,17 @@ function TimeBody<DateType>(props: TimeBodyProps<DateType>) {
182158
mergedDisabledSeconds && mergedDisabledSeconds(originHour, minute),
183159
);
184160

161+
// Set Time
162+
const setTime = useTimeSelection({
163+
value,
164+
generateConfig,
165+
disabledMinutes: mergedDisabledMinutes,
166+
disabledSeconds: mergedDisabledSeconds,
167+
minutes,
168+
seconds,
169+
use12Hours,
170+
});
171+
185172
// ====================== Operations ======================
186173
operationRef.current = {
187174
onUpDown: (diff) => {

tests/disabledTime.spec.tsx

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React from 'react';
21
import type { Moment } from 'moment';
32
import { resetWarned } from 'rc-util/lib/warning';
4-
import { mount, getMoment, isSame, MomentPicker, MomentRangePicker } from './util/commonUtil';
3+
import { getMoment, isSame, MomentPicker, MomentRangePicker, mount } from './util/commonUtil';
54

65
describe('Picker.DisabledTime', () => {
76
it('disabledTime on TimePicker', () => {
@@ -90,6 +89,62 @@ describe('Picker.DisabledTime', () => {
9089
wrapper.closePicker(1);
9190
});
9291

92+
it('dynamic disabledTime should be correct', () => {
93+
const wrapper = mount(
94+
<MomentPicker
95+
open
96+
picker="time"
97+
disabledTime={() => ({
98+
disabledHours: () => [0, 1],
99+
disabledMinutes: (selectedHour) => {
100+
if (selectedHour === 2) {
101+
return [0, 1];
102+
} else {
103+
return [];
104+
}
105+
},
106+
disabledSeconds: (_, selectMinute) => {
107+
if (selectMinute === 2) {
108+
return [0, 1];
109+
} else {
110+
return [];
111+
}
112+
},
113+
})}
114+
/>,
115+
);
116+
117+
wrapper
118+
.find('.rc-picker-time-panel-column')
119+
.first()
120+
.find('.rc-picker-time-panel-cell')
121+
.at(2)
122+
.simulate('click');
123+
124+
wrapper
125+
.find('.rc-picker-time-panel-column')
126+
.at(1)
127+
.find('.rc-picker-time-panel-cell')
128+
.first()
129+
.simulate('click');
130+
131+
wrapper
132+
.find('.rc-picker-time-panel-column')
133+
.at(2)
134+
.find('.rc-picker-time-panel-cell')
135+
.first()
136+
.simulate('click');
137+
138+
wrapper
139+
.find('.rc-picker-time-panel-column')
140+
.first()
141+
.find('.rc-picker-time-panel-cell')
142+
.at(1)
143+
.simulate('click');
144+
145+
expect(wrapper.find('input').prop('value')).toEqual('02:02:02');
146+
});
147+
93148
describe('warning for legacy props', () => {
94149
it('single', () => {
95150
resetWarned();

0 commit comments

Comments
 (0)