diff --git a/frontend/src/components/ui/date-picker.tsx b/frontend/src/components/ui/date-picker.tsx index 1ad42b3..7997e69 100644 --- a/frontend/src/components/ui/date-picker.tsx +++ b/frontend/src/components/ui/date-picker.tsx @@ -34,7 +34,7 @@ function to24Hour(h12: number, ampm: string): number { return isPM ? h12 + 12 : h12; } -/** ISO string → user-friendly display: DD/MM/YYYY or DD/MM/YYYY h:mm AM/PM */ +/** ISO string → user-friendly display: DD/MM/YYYY or DD/MM/YYYY hh:mm AM */ function isoToDisplay(iso: string, mode: 'date' | 'datetime'): string { if (!iso) return ''; const parts = iso.split('T'); @@ -47,20 +47,20 @@ function isoToDisplay(iso: string, mode: 'date' | 'datetime'): string { const h = parseInt(tp[0], 10); if (isNaN(h)) return dateStr; const { hour: h12, ampm } = to12Hour(h); - return `${dateStr} ${h12}:${tp[1].slice(0, 2)} ${ampm}`; + return `${dateStr} ${pad(h12)}:${tp[1].slice(0, 2)} ${ampm}`; } /** User-friendly display → ISO string, or null if incomplete/invalid */ function displayToIso(display: string, mode: 'date' | 'datetime'): string | null { if (!display) return null; if (mode === 'date') { - const m = display.match(/^(\d{2})\/(\d{2})\/(\d{4})$/); + const m = display.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/); if (!m) return null; const d = parseInt(m[1], 10), mo = parseInt(m[2], 10), y = parseInt(m[3], 10); if (mo < 1 || mo > 12 || d < 1 || d > getDaysInMonth(y, mo - 1)) return null; - return `${m[3]}-${m[2]}-${m[1]}`; + return `${m[3]}-${pad(mo)}-${pad(d)}`; } - const m = display.match(/^(\d{2})\/(\d{2})\/(\d{4})\s+(\d{1,2}):(\d{2})\s*(AM|PM)$/i); + const m = display.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{2})\s*(AM|PM)$/i); if (!m) return null; const d = parseInt(m[1], 10), mo = parseInt(m[2], 10), y = parseInt(m[3], 10); if (mo < 1 || mo > 12 || d < 1 || d > getDaysInMonth(y, mo - 1)) return null; @@ -68,7 +68,7 @@ function displayToIso(display: string, mode: 'date' | 'datetime'): string | null const min = parseInt(m[5], 10); if (h < 1 || h > 12 || min < 0 || min > 59) return null; h = to24Hour(h, m[6]); - return `${m[3]}-${m[2]}-${m[1]}T${pad(h)}:${pad(min)}`; + return `${m[3]}-${pad(mo)}-${pad(d)}T${pad(h)}:${pad(min)}`; } const MONTH_NAMES = [ @@ -152,7 +152,7 @@ const DatePicker = React.forwardRef( const [hour, setHour] = React.useState(parsed?.hour ?? 0); const [minute, setMinute] = React.useState(parsed?.minute ?? 0); - // Input variant: user-friendly display string (DD/MM/YYYY or DD/MM/YYYY h:mm AM/PM) + // Input variant: user-friendly display string (DD/MM/YYYY or DD/MM/YYYY hh:mm AM) const [displayValue, setDisplayValue] = React.useState(() => variant === 'input' ? isoToDisplay(value, mode) : '' ); @@ -520,7 +520,7 @@ const DatePicker = React.forwardRef( }} required={required} disabled={disabled} - placeholder={placeholder || (mode === 'datetime' ? 'DD/MM/YYYY h:mm AM/PM' : 'DD/MM/YYYY')} + placeholder={placeholder || (mode === 'datetime' ? 'DD/MM/YYYY hh:mm AM' : 'DD/MM/YYYY')} className={cn( 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pr-9 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', className