fix(ui): prefill empty date/time picker with now
This commit is contained in:
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. This projec
|
|||||||
- Mobile admin shell and lists: wide tables no longer expand/clip the page. The shared ScrollArea constrains content width, tables scroll horizontally inside their card, and list Create / pagination actions stay visible in the mobile viewport.
|
- Mobile admin shell and lists: wide tables no longer expand/clip the page. The shared ScrollArea constrains content width, tables scroll horizontally inside their card, and list Create / pagination actions stay visible in the mobile viewport.
|
||||||
- Form and detail layouts wrap more cleanly on narrow screens (action bars, label/value rows).
|
- Form and detail layouts wrap more cleanly on narrow screens (action bars, label/value rows).
|
||||||
- Date/time picker in dark mode: replaced the native time input (invisible clock icon + always-light popup) with themed hour/minute selects and a visible Clock icon; set `color-scheme` on light/dark themes so remaining native date controls follow the UI.
|
- Date/time picker in dark mode: replaced the native time input (invisible clock icon + always-light popup) with themed hour/minute selects and a visible Clock icon; set `color-scheme` on light/dark themes so remaining native date controls follow the UI.
|
||||||
|
- Empty date/time fields open prefilled with the current date and time so the calendar and hour/minute selects start on a useful default.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Negative account disk-usage values (stale Stalwart quota counters) are shown in red with an info tooltip that explains how to recalculate usage via Tasks (Perform account maintenance operations → Recalculate storage quota usage, or store-wide Reset all user quotas).
|
- Negative account disk-usage values (stale Stalwart quota counters) are shown in red with an info tooltip that explains how to recalculate usage via Tasks (Perform account maintenance operations → Recalculate storage quota usage, or store-wide Reset all user quotas).
|
||||||
|
|||||||
@@ -924,6 +924,19 @@ function DateTimeField({ value, onChange, readOnly, nullable }: DateTimeFieldPro
|
|||||||
onChange(next.toISOString());
|
onChange(next.toISOString());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatClock = (d: Date): string =>
|
||||||
|
`${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
/** Empty fields open on "now" so the calendar and time selects start useful. */
|
||||||
|
const handleOpenChange = (next: boolean) => {
|
||||||
|
setOpen(next);
|
||||||
|
if (next && !parsed) {
|
||||||
|
const now = new Date();
|
||||||
|
now.setSeconds(0, 0);
|
||||||
|
onChange(now.toISOString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (readOnly) {
|
if (readOnly) {
|
||||||
if (!strValue) {
|
if (!strValue) {
|
||||||
return <span className="text-sm text-muted-foreground italic">{t('field.notSet', 'Not set')}</span>;
|
return <span className="text-sm text-muted-foreground italic">{t('field.notSet', 'Not set')}</span>;
|
||||||
@@ -944,7 +957,7 @@ function DateTimeField({ value, onChange, readOnly, nullable }: DateTimeFieldPro
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Popover open={open} onOpenChange={setOpen} modal={false}>
|
<Popover open={open} onOpenChange={handleOpenChange} modal={false}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -971,17 +984,17 @@ function DateTimeField({ value, onChange, readOnly, nullable }: DateTimeFieldPro
|
|||||||
<Calendar
|
<Calendar
|
||||||
mode="single"
|
mode="single"
|
||||||
selected={parsed ?? undefined}
|
selected={parsed ?? undefined}
|
||||||
defaultMonth={parsed ?? undefined}
|
defaultMonth={parsed ?? new Date()}
|
||||||
onSelect={(day) => {
|
onSelect={(day) => {
|
||||||
if (!day) return;
|
if (!day) return;
|
||||||
commit(day, timeValue || '00:00');
|
commit(day, timeValue || formatClock(new Date()));
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center gap-2 border-t bg-background p-3">
|
<div className="flex items-center gap-2 border-t bg-background p-3">
|
||||||
<Clock className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden="true" />
|
<Clock className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden="true" />
|
||||||
<DateTimeTimeSelect
|
<DateTimeTimeSelect
|
||||||
value={timeValue || '00:00'}
|
value={timeValue || formatClock(new Date())}
|
||||||
disabled={!parsed}
|
disabled={!parsed}
|
||||||
onChange={(next) => {
|
onChange={(next) => {
|
||||||
if (parsed) commit(parsed, next);
|
if (parsed) commit(parsed, next);
|
||||||
|
|||||||
Reference in New Issue
Block a user