@@ -200,65 +221,102 @@ export default function PersonForm({ person, categories, onClose }: PersonFormPr
{/* Row 6: Mobile + Email */}
{/* Row 7: Phone */}
-
+
set('phone', e.target.value)}
placeholder="Landline / work number"
+ disabled={isShared('phone')}
+ className={isShared('phone') ? 'opacity-70 cursor-not-allowed' : ''}
/>
{/* Row 8: Address */}
-
- set('address', val)}
- onSelect={(result) => set('address', result.address || result.name)}
- placeholder="Search or enter address..."
- />
+
+ {isShared('address') ? (
+
+ ) : (
+ set('address', val)}
+ onSelect={(result) => set('address', result.address || result.name)}
+ placeholder="Search or enter address..."
+ />
+ )}
{/* Row 9: Company + Job Title */}
diff --git a/frontend/src/components/settings/SettingsPage.tsx b/frontend/src/components/settings/SettingsPage.tsx
index 6019c78..ba38b81 100644
--- a/frontend/src/components/settings/SettingsPage.tsx
+++ b/frontend/src/components/settings/SettingsPage.tsx
@@ -14,6 +14,7 @@ import {
Loader2,
Shield,
Blocks,
+ Ghost,
} from 'lucide-react';
import { useSettings } from '@/hooks/useSettings';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
@@ -24,6 +25,7 @@ import { cn } from '@/lib/utils';
import api from '@/lib/api';
import type { GeoLocation, UserProfile } from '@/types';
import { Switch } from '@/components/ui/switch';
+import CopyableField from '@/components/shared/CopyableField';
import TotpSetupSection from './TotpSetupSection';
import NtfySettingsSection from './NtfySettingsSection';
@@ -55,6 +57,24 @@ export default function SettingsPage() {
const [autoLockEnabled, setAutoLockEnabled] = useState(settings?.auto_lock_enabled ?? false);
const [autoLockMinutes, setAutoLockMinutes] = useState
(settings?.auto_lock_minutes ?? 5);
+ // Profile extension fields (stored on Settings model)
+ const [settingsPhone, setSettingsPhone] = useState(settings?.phone ?? '');
+ const [settingsMobile, setSettingsMobile] = useState(settings?.mobile ?? '');
+ const [settingsAddress, setSettingsAddress] = useState(settings?.address ?? '');
+ const [settingsCompany, setSettingsCompany] = useState(settings?.company ?? '');
+ const [settingsJobTitle, setSettingsJobTitle] = useState(settings?.job_title ?? '');
+
+ // Social settings
+ const [acceptConnections, setAcceptConnections] = useState(settings?.accept_connections ?? false);
+ const [sharePreferredName, setSharePreferredName] = useState(settings?.share_preferred_name ?? true);
+ const [shareEmail, setShareEmail] = useState(settings?.share_email ?? false);
+ const [sharePhone, setSharePhone] = useState(settings?.share_phone ?? false);
+ const [shareMobile, setShareMobile] = useState(settings?.share_mobile ?? false);
+ const [shareBirthday, setShareBirthday] = useState(settings?.share_birthday ?? false);
+ const [shareAddress, setShareAddress] = useState(settings?.share_address ?? false);
+ const [shareCompany, setShareCompany] = useState(settings?.share_company ?? false);
+ const [shareJobTitle, setShareJobTitle] = useState(settings?.share_job_title ?? false);
+
// Profile fields (stored on User model, fetched from /auth/profile)
const profileQuery = useQuery({
queryKey: ['profile'],
@@ -87,6 +107,20 @@ export default function SettingsPage() {
setFirstDayOfWeek(settings.first_day_of_week);
setAutoLockEnabled(settings.auto_lock_enabled);
setAutoLockMinutes(settings.auto_lock_minutes ?? 5);
+ setSettingsPhone(settings.phone ?? '');
+ setSettingsMobile(settings.mobile ?? '');
+ setSettingsAddress(settings.address ?? '');
+ setSettingsCompany(settings.company ?? '');
+ setSettingsJobTitle(settings.job_title ?? '');
+ setAcceptConnections(settings.accept_connections);
+ setSharePreferredName(settings.share_preferred_name);
+ setShareEmail(settings.share_email);
+ setSharePhone(settings.share_phone);
+ setShareMobile(settings.share_mobile);
+ setShareBirthday(settings.share_birthday);
+ setShareAddress(settings.share_address);
+ setShareCompany(settings.share_company);
+ setShareJobTitle(settings.share_job_title);
}
}, [settings?.id]); // only re-sync on initial load (settings.id won't change)
@@ -248,6 +282,29 @@ export default function SettingsPage() {
}
};
+ const handleSettingsFieldSave = async (field: string, value: string) => {
+ const trimmed = value.trim();
+ const currentVal = (settings as any)?.[field] || '';
+ if (trimmed === (currentVal || '')) return;
+ try {
+ await updateSettings({ [field]: trimmed || null } as any);
+ toast.success('Profile updated');
+ } catch {
+ toast.error('Failed to update profile');
+ }
+ };
+
+ const handleSocialToggle = async (field: string, checked: boolean, setter: (v: boolean) => void) => {
+ const previous = (settings as any)?.[field];
+ setter(checked);
+ try {
+ await updateSettings({ [field]: checked } as any);
+ } catch {
+ setter(previous);
+ toast.error('Failed to update setting');
+ }
+ };
+
const handleAutoLockMinutesSave = async () => {
const raw = typeof autoLockMinutes === 'string' ? parseInt(autoLockMinutes) : autoLockMinutes;
const clamped = Math.max(1, Math.min(60, isNaN(raw) ? 5 : raw));
@@ -363,6 +420,75 @@ export default function SettingsPage() {
onKeyDown={(e) => { if (e.key === 'Enter') handleProfileSave('date_of_birth'); }}
/>
@@ -586,9 +712,77 @@ export default function SettingsPage() {