diff --git a/libs/ui/src/lib/input/AmharicDatePicker.tsx b/libs/ui/src/lib/input/AmharicDatePicker.tsx index 040700c75..a9db1b2e4 100644 --- a/libs/ui/src/lib/input/AmharicDatePicker.tsx +++ b/libs/ui/src/lib/input/AmharicDatePicker.tsx @@ -6,6 +6,7 @@ import { Group, MantineSize, Popover, + Select, TextInput, } from '@mantine/core'; import { TimeInput } from '@mantine/dates'; @@ -51,6 +52,40 @@ function toAmharicDisplay(date: Date): string { } } +export type EthPeriod = 'lelit' | 'tewat' | 'ken' | 'mata'; + +// Ethiopian day starts at 6am. Period is picked from the 24h hour; the +// displayed hour is the Western hour shifted 6, wrapped onto a 12-hour dial. +// Each period only spans 6 hours (not 12): ጠዋት/ማታ show 12,1..5, ቀን/ሌሊት show +// 6..11 — offering all 12 hours in every period would let a user pick e.g. +// "ጠዋት 7", which has no 06:00–11:59 preimage. +const ETH_PERIODS: { value: EthPeriod; label: string; hours: number[] }[] = [ + { value: 'tewat', label: 'ጠዋት', hours: [12, 1, 2, 3, 4, 5] }, // 06:00–11:59 + { value: 'ken', label: 'ቀን', hours: [6, 7, 8, 9, 10, 11] }, // 12:00–17:59 + { value: 'mata', label: 'ማታ', hours: [12, 1, 2, 3, 4, 5] }, // 18:00–23:59 + { value: 'lelit', label: 'ሌሊት', hours: [6, 7, 8, 9, 10, 11] }, // 00:00–05:59 +]; + +export function toEthTime(h24: number): { period: EthPeriod; hour: number } { + const period: EthPeriod = + h24 < 6 ? 'lelit' : h24 < 12 ? 'tewat' : h24 < 18 ? 'ken' : 'mata'; + return { period, hour: ((h24 + 6) % 12) || 12 }; +} + +export function fromEthTime(period: EthPeriod, hour: number): number { + // Inverse of the shift, then re-add the 12h that %12 discarded for the + // afternoon/night pair of periods. + const pm = period === 'ken' || period === 'mata'; + return ((hour + 6) % 12) + (pm ? 12 : 0); +} + +function ethTimeLabel(date: Date): string { + const { period, hour } = toEthTime(date.getHours()); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const label = ETH_PERIODS.find((p) => p.value === period)?.label ?? ''; + return `${hour}:${minutes} ${label}`; +} + // react-day-picker calls these with the Gregorian Date it tracks internally; // override so the caption/dropdown show Amharic month names instead of the // library's Latin transliteration (triggered by numerals="latn" below). @@ -215,7 +250,9 @@ export function AmharicDatePicker({ : ''; const timeLabel = withTime && selected - ? ` ${selected.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}` + ? calendarType === 'AMH' + ? ` ${ethTimeLabel(selected)}` + : ` ${selected.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}` : ''; const displayValue = dateLabel + timeLabel; @@ -329,7 +366,61 @@ export function AmharicDatePicker({ /> )} - {withTime && ( + {withTime && calendarType === 'AMH' && (() => { + const { period, hour } = selected ? toEthTime(selected.getHours()) : { period: 'tewat' as EthPeriod, hour: 12 }; + const minute = selected ? selected.getMinutes() : 0; + const periodHours = ETH_PERIODS.find((p) => p.value === period)?.hours ?? ETH_PERIODS[0].hours; + const setTime = (h24: number, m: number) => + onChange?.( + formatWireValue(mergeDateTime(selected, undefined, { hours: h24, minutes: m }), dateFormat, true), + ); + return ( + + ({ value: String(h), label: String(h) }))} + allowDeselect={false} + onChange={(next) => { + if (!next) return; + setTime(fromEthTime(period, Number(next)), minute); + }} + /> +