import { Check, ChevronLeft } from 'lucide-react'
import { useEffect, useId, useMemo, useState, type ReactNode } from 'react'
import { useNavigate } from 'react-router'
import { Button } from '../ui/Button.tsx'
import { Card } from '../ui/Card.tsx'
import { ErrorBanner } from '../ui/ErrorBanner.tsx'
import { Icon } from '../ui/Icon.tsx'
import { IconButton } from '../ui/IconButton.tsx'
import { Select } from '../ui/Select.tsx'
import { Sheet } from '../ui/Sheet.tsx'
import { Skeleton } from '../ui/Skeleton.tsx'
import { TextInput } from '../ui/TextInput.tsx'
import {
householdSettingsProblems,
useHouseholdSettings,
useSaveHouseholdSettings,
type HouseholdSettings,
type HouseholdSettingsField,
type HouseholdSettingsPatch,
} from './api.ts'
import styles from './HouseholdSettingsPage.module.css'
import { LeaveGuard } from './LeaveGuard.tsx'
import { matchesZone, timeZoneOptions, utcOffset, zoneLabel } from './timezones.ts'
// Days of the week as the server counts them, from Sunday = 0.
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] as const
// Settings · Household: the time zone and the times the household's
// reminders and weekly AI runs happen at. Every field is edited as a draft
// and saved together; only the changed fields are sent.
export function HouseholdSettingsPage() {
const [dirty, setDirty] = useState(false)
return (
Changes apply to everyone in the household.
)
}
type HouseholdSettingsProps = {
// Called with whether the form holds unsaved changes.
onDirtyChange: (dirty: boolean) => void
}
// HouseholdSettingsSections is the screen's form once its settings load,
// without the screen's header, so the desktop settings (mock 2e) can embed
// it.
export function HouseholdSettingsSections({ onDirtyChange }: HouseholdSettingsProps) {
const settings = useHouseholdSettings()
return (
<>
{settings.isPending && }
{settings.isError && (
void settings.refetch()}>
Household settings could not load: {settings.error.message}
)}
{settings.isSuccess && }
>
)
}
function Header() {
const navigate = useNavigate()
return (
void navigate('/settings')}>
Settings
Household
)
}
// patchOf is the PATCH body for the fields draft changes.
function patchOf(saved: HouseholdSettings, draft: HouseholdSettings): HouseholdSettingsPatch {
const patch: Record = {}
for (const field of Object.keys(saved) as HouseholdSettingsField[]) {
if (draft[field] !== saved[field]) patch[field] = draft[field]
}
return patch as HouseholdSettingsPatch
}
type HouseholdSettingsFormProps = HouseholdSettingsProps & {
saved: HouseholdSettings
}
function HouseholdSettingsForm({ saved, onDirtyChange }: HouseholdSettingsFormProps) {
const [draft, setDraft] = useState(saved)
const save = useSaveHouseholdSettings()
const patch = patchOf(saved, draft)
const dirty = Object.keys(patch).length > 0
const problems = save.isError ? householdSettingsProblems(save.error) : { fields: {}, other: [] }
useEffect(() => {
onDirtyChange(dirty)
}, [dirty, onDirtyChange])
useEffect(() => () => onDirtyChange(false), [onDirtyChange])
function edit(change: Partial) {
save.reset()
setDraft((current) => ({ ...current, ...change }))
}
function onSave() {
save.mutate(patch, { onSuccess: setDraft })
}
return (
)
}
function Section({ title, children }: { title: string; children: ReactNode }) {
const titleId = useId()
return (