diff --git a/src/components/clients/client-form.tsx b/src/components/clients/client-form.tsx index c4a2a2cd..666491b3 100644 --- a/src/components/clients/client-form.tsx +++ b/src/components/clients/client-form.tsx @@ -27,6 +27,7 @@ import { DedupSuggestionPanel } from '@/components/clients/dedup-suggestion-pane import { apiFetch } from '@/lib/api/client'; import { createClientSchema, type CreateClientInput } from '@/lib/validators/clients'; import type { CountryCode } from '@/lib/i18n/countries'; +import { primaryTimezoneFor } from '@/lib/i18n/timezones'; interface ClientFormProps { open: boolean; @@ -84,6 +85,17 @@ export function ClientForm({ open, onOpenChange, client, onUseExistingClient }: const { fields, append, remove } = useFieldArray({ control, name: 'contacts' }); const tagIds = watch('tagIds') ?? []; + // When the rep picks a country and no timezone is set yet, pre-fill the + // timezone with the country's primary IANA zone. Skips when the user has + // already chosen a zone explicitly so we never clobber a deliberate pick. + const watchedNationality = watch('nationalityIso'); + const watchedTimezone = watch('timezone'); + useEffect(() => { + if (!watchedNationality || watchedTimezone) return; + const primary = primaryTimezoneFor(watchedNationality as CountryCode); + if (primary) setValue('timezone', primary); + }, [watchedNationality, watchedTimezone, setValue]); + // Populate form when editing useEffect(() => { if (client && open) { @@ -287,11 +299,17 @@ export function ClientForm({ open, onOpenChange, client, onUseExistingClient }:
- +
diff --git a/src/components/settings/user-settings.tsx b/src/components/settings/user-settings.tsx index 2220cae1..c023ca30 100644 --- a/src/components/settings/user-settings.tsx +++ b/src/components/settings/user-settings.tsx @@ -11,6 +11,7 @@ import { Switch } from '@/components/ui/switch'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { PageHeader } from '@/components/shared/page-header'; import { CountryCombobox } from '@/components/shared/country-combobox'; +import { PhoneInput, type PhoneInputValue } from '@/components/shared/phone-input'; import { TimezoneCombobox } from '@/components/shared/timezone-combobox'; import { ImageCropperDialog } from '@/components/shared/image-cropper-dialog'; import { apiFetch } from '@/lib/api/client'; @@ -74,12 +75,24 @@ export function UserSettings() { setEmail(res.data.user?.email ?? ''); setOriginalEmail(res.data.user?.email ?? ''); setCountry(res.data.preferences?.country ?? null); - setTimezone(res.data.preferences?.timezone ?? null); + // Fall back to the browser-detected zone when no value has been saved + // yet — first-time users land on a sensible default rather than an + // empty picker. Doesn't overwrite an explicit choice. + setTimezone(res.data.preferences?.timezone ?? detectedTz ?? null); const fid = res.data.profile?.avatarFileId ?? null; setAvatarFileId(fid); setAvatarUrl(fid ? `/api/v1/files/${fid}/preview` : null); } + // When the user picks a country and no timezone is set, suggest the + // primary zone for that country. Doesn't fight an explicit timezone + // selection — only fires while the timezone slot is empty. + useEffect(() => { + if (!country || timezone) return; + const primary = primaryTimezoneFor(country as CountryCode); + if (primary) setTimezone(primary); + }, [country, timezone]); + function handleAvatarPicked(e: React.ChangeEvent) { const file = e.target.files?.[0] ?? null; if (!file) return; @@ -261,12 +274,11 @@ export function UserSettings() {
- setPhone(e.target.value)} - placeholder="+1 555-0123" + value={phone ? ({ e164: phone, country: (country as never) ?? 'US' } as PhoneInputValue) : null} + onChange={(next) => setPhone(next.e164 ?? '')} + placeholder="555 0123" />
diff --git a/src/components/yachts/yacht-form.tsx b/src/components/yachts/yacht-form.tsx index ed848af0..a5429c0e 100644 --- a/src/components/yachts/yacht-form.tsx +++ b/src/components/yachts/yacht-form.tsx @@ -19,6 +19,7 @@ import { } from '@/components/ui/select'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet'; import { Separator } from '@/components/ui/separator'; +import { CountryCombobox } from '@/components/shared/country-combobox'; import { OwnerPicker, type OwnerRef } from '@/components/shared/owner-picker'; import { TagPicker } from '@/components/shared/tag-picker'; import { apiFetch } from '@/lib/api/client'; @@ -185,7 +186,12 @@ export function YachtForm({ open, onOpenChange, yacht, initialOwner }: YachtForm
- + setValue('flag', iso ?? undefined)} + placeholder="Select flag country…" + clearable + />