From a25c54970f6219ffce09a01da8230a7672a6f76b Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Sun, 2 Aug 2026 17:31:34 +0000 Subject: [PATCH] feat(CC-084): add Professional Identity settings (bio/role/links/locale via workspace PATCH) --- src/app/dashboard/settings/identity/page.tsx | 152 +++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/app/dashboard/settings/identity/page.tsx diff --git a/src/app/dashboard/settings/identity/page.tsx b/src/app/dashboard/settings/identity/page.tsx new file mode 100644 index 0000000..494f811 --- /dev/null +++ b/src/app/dashboard/settings/identity/page.tsx @@ -0,0 +1,152 @@ +'use client'; + +import { useMemo, useState, useEffect } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { apiFetch } from '../../../../lib/api'; +import { useSession } from '../../../../components/session-provider'; + +interface Workspace { + id: string; name: string; slug: string | null; settings: Record | null; + logoUrl: string | null; timezone: string | null; locale: string | null; createdAt: string; +} + +const TIMEZONES = [ + 'Europe/Bucharest', 'Europe/Berlin', 'Europe/London', 'Europe/Paris', + 'America/New_York', 'America/Chicago', 'America/Los_Angeles', + 'Asia/Kolkata', 'Asia/Tokyo', 'UTC', +]; + +const LOCALES = [ + { value: 'ro-RO', label: 'Română (RO)' }, + { value: 'de-DE', label: 'Deutsch (DE)' }, + { value: 'en-US', label: 'English (US)' }, + { value: 'es-ES', label: 'Español (ES)' }, +]; + +export default function SettingsIdentityPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + + const { data: ws, isLoading } = useQuery({ + queryKey: ['ws-identity', tenantId], + queryFn: () => apiFetch('/v1/workspace', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + + const [form, setForm] = useState({ name: '', slug: '', timezone: '', locale: '', bio: '', website: '', linkedin: '', role: '' }); + const [saved, setSaved] = useState(false); + + useEffect(() => { + if (ws) { + const s = (ws.settings ?? {}) as Record; + setForm({ + name: ws.name ?? '', + slug: ws.slug ?? '', + timezone: ws.timezone ?? 'Europe/Bucharest', + locale: ws.locale ?? 'ro-RO', + bio: s.bio ?? '', + website: s.website ?? '', + linkedin: s.linkedin ?? '', + role: s.role ?? '', + }); + } + }, [ws]); + + const saveMut = useMutation({ + mutationFn: () => apiFetch('/v1/workspace', { tenantId, method: 'PATCH', body: { + name: form.name, slug: form.slug || undefined, + timezone: form.timezone, locale: form.locale, + settings: { bio: form.bio, website: form.website, linkedin: form.linkedin, role: form.role }, + }}), + onSuccess: () => { qc.invalidateQueries({ queryKey: ['ws-identity', tenantId] }); setSaved(true); setTimeout(() => setSaved(false), 3000); }, + }); + + if (isLoading) return
Se încarcă…
; + + return ( +
+
+

Identitate Profesională

+

Profilul și setările de bază ale workspace-ului CEO OS.

+
+ + {/* Identity */} +
+

Informații de bază

+
+
+ + setForm((p) => ({ ...p, name: e.target.value }))} + className="w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+
+ + setForm((p) => ({ ...p, slug: e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '') }))} + placeholder="ex: valentin-ion" + className="w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink font-mono focus:outline-none focus:ring-2 focus:ring-ring" /> +
+
+ + setForm((p) => ({ ...p, role: e.target.value }))} + placeholder="ex: CTO & AI Strategist" + className="w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+
+ +