fix(ui): commit date-picker selections immediately instead of on confirm (#6122)

* fix(ui): commit date-picker selections immediately instead of on confirm

With showTime, Ant Design's DatePicker stages a clicked date until the
OK button confirms it. Closing the dropdown any other way - clicking
elsewhere in the form or hitting Create/Save directly - discarded the
staged date without a hint, so an inbound saved this way ended up with
expiryTime=0 (never expires). The Now shortcut commits in one click,
which made it look like only the current time could ever be set.

Drop the confirm step (needConfirm=false) and propagate every calendar
selection through onCalendarChange, so the picked date reaches the form
state the moment it is clicked and can no longer be lost to a race with
the submit button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(ui): pin calendar clicks committing without a confirm press

A clicked day cell must reach onChange with the exact selected
timestamp while the dropdown is still open, and the footer must not
render a confirm button. Pins the needConfirm-free behavior so a picker
dependency bump cannot silently bring the staged-value discard back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
PathGao
2026-07-29 02:57:46 +08:00
committed by GitHub
parent b6473004ac
commit 604986598f
2 changed files with 45 additions and 0 deletions

View File

@@ -121,7 +121,9 @@ export default function DateTimePicker({
<DatePicker
value={value}
onChange={(next) => onChange(next || null)}
onCalendarChange={(next) => onChange((Array.isArray(next) ? next[0] : next) || null)}
showTime={showTime ? { format: 'HH:mm:ss' } : false}
needConfirm={false}
format={format}
placeholder={placeholder}
disabled={disabled}

View File

@@ -0,0 +1,43 @@
import { fireEvent } from '@testing-library/react';
import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { describe, expect, it, vi } from 'vitest';
import DateTimePicker from '@/components/form/DateTimePicker';
import { renderWithProviders } from './test-utils';
function openPicker(): void {
const input = document.querySelector('.ant-picker input');
if (!input) throw new Error('picker input not rendered');
fireEvent.mouseDown(input);
fireEvent.click(input);
}
function clickDayCell(title: string): void {
const cell = document.querySelector(`.ant-picker-cell[title="${title}"] .ant-picker-cell-inner`);
if (!cell) throw new Error(`day cell ${title} not rendered`);
fireEvent.click(cell);
}
describe('DateTimePicker', () => {
it('commits a clicked calendar date without an OK press', () => {
const onChange = vi.fn<(next: Dayjs | null) => void>();
renderWithProviders(<DateTimePicker value={null} onChange={onChange} />);
openPicker();
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');
clickDayCell(tomorrow);
expect(onChange).toHaveBeenCalled();
const committed = onChange.mock.calls.at(-1)?.[0];
expect(committed?.format('YYYY-MM-DD HH:mm:ss')).toBe(`${tomorrow} 00:00:00`);
});
it('renders no OK confirm button in the picker footer', () => {
renderWithProviders(<DateTimePicker value={null} onChange={vi.fn()} />);
openPicker();
expect(document.querySelector('.ant-picker-ok')).toBeNull();
});
});