Skip to content
Clone
main
85 lines 3.2 KB
import { IconChevronDown as ChevronDown } from '@tabler/icons-react'
import { t } from '@/shared/i18n'
export interface BirthValue {
year: string
month: string
day: string
}
export const emptyBirth: BirthValue = { year: '', month: '', day: '' }
export function BirthDate({
value,
onChange,
error,
disabled = false,
helper = t('ui.birth.helper'),
}: {
value: BirthValue
onChange: (value: BirthValue) => void
error?: string
disabled?: boolean
helper?: string
}) {
const days =
value.year && value.month ? new Date(Date.UTC(Number(value.year), Number(value.month), 0)).getUTCDate() : 31
const currentYear = new Date().getUTCFullYear()
const options = [
Array.from({ length: currentYear - 1899 }, (_, i) => currentYear - i),
Array.from({ length: 12 }, (_, i) => i + 1),
Array.from({ length: days }, (_, i) => i + 1),
]
const parts = ['year', 'month', 'day'] as const
return (
<fieldset className="flex min-w-0 flex-col gap-2" disabled={disabled}>
<legend className="mb-2 text-sm font-medium">{t('ui.birth.legend')}</legend>
<div className="flex gap-2">
{parts.map((part, index) => (
<div key={part} className="relative min-w-0 flex-1">
<select
id={index === 0 ? 'birth' : `birth-${part}`}
aria-label={t(
index === 0 ? 'ui.birth.aria.year' : index === 1 ? 'ui.birth.aria.month' : 'ui.birth.aria.day',
)}
aria-invalid={!!error}
aria-describedby="birth-description"
value={value[part]}
onChange={(event) => {
const next = { ...value, [part]: event.currentTarget.value }
if (
next.year &&
next.month &&
Number(next.day) > new Date(Date.UTC(Number(next.year), Number(next.month), 0)).getUTCDate()
)
next.day = ''
onChange(next)
}}
className={`h-12 w-full appearance-none rounded-lg border bg-field pr-8 pl-3 text-base outline-none focus:border-focus focus:ring-1 focus:ring-focus disabled:cursor-not-allowed disabled:bg-disabled ${value[part] ? 'text-ink' : 'text-muted'} ${error ? 'border-danger' : 'border-control-border'}`}
>
<option value="">
{t(
index === 0
? 'ui.birth.placeholder.year'
: index === 1
? 'ui.birth.placeholder.month'
: 'ui.birth.placeholder.day',
)}
</option>
{options[index].map((number) => (
<option key={number} value={String(number)}>
{number}
{index > 0 ? t(index === 1 ? 'ui.birth.unit.month' : 'ui.birth.unit.day') : ''}
</option>
))}
</select>
<ChevronDown size={16} className="pointer-events-none absolute top-4 right-3 text-icon" />
</div>
))}
</div>
<p id="birth-description" className={`text-xs leading-normal ${error ? 'text-danger' : 'text-muted'}`}>
{error || helper}
</p>
</fieldset>
)
}