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() {