ファイル
btrc-hub/frontend/src/components/common/DateTimeField.tsx
T
2026-06-05 01:59:46 +09:00

61 行
1.6 KiB
TypeScript

import { useEffect, useState } from 'react'
import { cn } from '@/lib/utils'
import type { ComponentPropsWithoutRef, FC, FocusEvent } from 'react'
const pad = (n: number): string => n.toString ().padStart (2, '0')
const toDateTimeLocalValue = (d: Date) => {
const y = d.getFullYear ()
const m = pad (d.getMonth () + 1)
const day = pad (d.getDate ())
const h = pad (d.getHours ())
const min = pad (d.getMinutes ())
return `${ y }-${ m }-${ day }T${ h }:${ min }:00`
}
type Props = Omit<ComponentPropsWithoutRef<'input'>, 'onChange'> & {
value?: string
onChange?: (isoUTC: string | null) => void
className?: string
onBlur?: (ev: FocusEvent<HTMLInputElement>) => void
invalid?: boolean }
const DateTimeField: FC<Props> = ({ value, onChange, className, onBlur, invalid, ...rest }) => {
const [local, setLocal] = useState ('')
useEffect (() => {
setLocal (value ? toDateTimeLocalValue (new Date (value)) : '')
}, [value])
return (
<input
{...rest}
className={cn ('border rounded p-2',
(invalid
? ['border-red-500 bg-red-50 text-red-900',
'focus:border-red-500 focus:outline-none',
'focus:ring-2 focus:ring-red-200',
'dark:border-red-500 dark:bg-red-950/30 dark:text-red-100']
: ['border-gray-300',
'focus:border-blue-500 focus:outline-none',
'focus:ring-2 focus:ring-blue-200']),
className)}
type="datetime-local"
value={local}
aria-invalid={invalid}
onChange={ev => {
const v = ev.target.value
setLocal (v)
onChange?.(v ? (new Date (v)).toISOString () : null)
}}
onBlur={onBlur}/>)
}
export default DateTimeField