137 lines
4.3 KiB
TypeScript
137 lines
4.3 KiB
TypeScript
"use client"
|
|
import { parseDate } from "@internationalized/date"
|
|
import {
|
|
DateInput,
|
|
DatePicker,
|
|
DateSegment,
|
|
Group,
|
|
} from "react-aria-components"
|
|
import { useController, useFormContext, useWatch } from "react-hook-form"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { dt } from "@/lib/dt"
|
|
|
|
import Select from "@/components/TempDesignSystem/Select"
|
|
import { rangeArray } from "@/utils/rangeArray"
|
|
|
|
import { DateName } from "./date"
|
|
|
|
import styles from "./date.module.css"
|
|
|
|
import type { Key } from "react-aria-components"
|
|
|
|
import type { DateProps } from "./date"
|
|
|
|
/** TODO: Get selecting with Enter-key to work */
|
|
export default function DateSelect({ name, registerOptions }: DateProps) {
|
|
const { formatMessage } = useIntl()
|
|
const d = useWatch({ name })
|
|
const { control, setValue } = useFormContext()
|
|
const { field } = useController({
|
|
control,
|
|
name,
|
|
rules: registerOptions,
|
|
})
|
|
const currentYear = new Date().getFullYear()
|
|
const months = rangeArray(1, 12).map((month) => ({
|
|
value: month,
|
|
label: `${month}`,
|
|
}))
|
|
const years = rangeArray(1900, currentYear)
|
|
.reverse()
|
|
.map((year) => ({ value: year, label: `${year}` }))
|
|
|
|
function createOnSelect(selector: DateName) {
|
|
/**
|
|
* Months are 0 index based and therefore we
|
|
* must subtract by 1 to get the selected month
|
|
*/
|
|
return (select: Key) => {
|
|
if (selector === DateName.month) {
|
|
select = Number(select) - 1
|
|
}
|
|
const newDate = dt(d).set(selector, Number(select))
|
|
setValue(name, newDate.format("YYYY-MM-DD"))
|
|
}
|
|
}
|
|
|
|
const dayLabel = formatMessage({ id: "Day" })
|
|
const monthLabel = formatMessage({ id: "Month" })
|
|
const yearLabel = formatMessage({ id: "Year" })
|
|
|
|
return (
|
|
<DatePicker
|
|
aria-label={formatMessage({ id: "Select date of birth" })}
|
|
granularity="day"
|
|
isRequired={!!registerOptions.required}
|
|
name={name}
|
|
ref={field.ref}
|
|
value={parseDate(d)}
|
|
>
|
|
<Group>
|
|
<DateInput className={styles.container}>
|
|
{(segment) => {
|
|
switch (segment.type) {
|
|
case "day":
|
|
let days = []
|
|
if (segment.maxValue && segment.minValue) {
|
|
days = rangeArray(segment.minValue, segment.maxValue).map(
|
|
(day) => ({ value: day, label: `${day}` })
|
|
)
|
|
} else {
|
|
days = Array.from(Array(segment.maxValue).keys()).map(
|
|
(i) => ({ value: i + 1, label: `${i + 1}` })
|
|
)
|
|
}
|
|
return (
|
|
<DateSegment className={styles.day} segment={segment}>
|
|
<Select
|
|
aria-label={dayLabel}
|
|
items={days}
|
|
label={dayLabel}
|
|
name={DateName.date}
|
|
onSelect={createOnSelect(DateName.date)}
|
|
placeholder="DD"
|
|
value={segment.value}
|
|
/>
|
|
</DateSegment>
|
|
)
|
|
case "month":
|
|
return (
|
|
<DateSegment className={styles.month} segment={segment}>
|
|
<Select
|
|
aria-label={monthLabel}
|
|
items={months}
|
|
label={monthLabel}
|
|
name={DateName.month}
|
|
onSelect={createOnSelect(DateName.month)}
|
|
placeholder="MM"
|
|
value={segment.value}
|
|
/>
|
|
</DateSegment>
|
|
)
|
|
case "year":
|
|
return (
|
|
<DateSegment className={styles.year} segment={segment}>
|
|
<Select
|
|
aria-label={yearLabel}
|
|
items={years}
|
|
label={yearLabel}
|
|
name={DateName.year}
|
|
onSelect={createOnSelect(DateName.year)}
|
|
placeholder="YYYY"
|
|
value={segment.value}
|
|
/>
|
|
</DateSegment>
|
|
)
|
|
default:
|
|
/** DateInput forces return of ReactElement */
|
|
return <></>
|
|
}
|
|
}}
|
|
</DateInput>
|
|
</Group>
|
|
</DatePicker>
|
|
)
|
|
}
|