diff --git a/app/lib/profile.ts b/app/lib/profile.ts index ac454d0..4ce734f 100644 --- a/app/lib/profile.ts +++ b/app/lib/profile.ts @@ -1,23 +1,16 @@ -// Local user preferences — title, signature, default agent, plus a cache -// mirror of the resolved avatar URL. Persisted in localStorage; reactive -// across tabs. Identity (name, email) is owned by the arcadia session -// (~/lib/session.ts); the public profile (bio, phone, location, timezone) -// is server-backed via /api/v1/profile (~/lib/arcadia/profiles.ts). +// Local mirror of the resolved avatar URL, so the appbar can render the +// avatar before the profile fetch resolves on next mount. The real +// profile (name, email, bio, phone, location, timezone, avatar) is +// server-backed — see ~/lib/arcadia/profiles.ts. import { useEffect, useSyncExternalStore } from "react" export type Profile = { - title: string - signature: string avatarUrl: string - defaultAgentId: string } export const DEFAULT_PROFILE: Profile = { - title: "", - signature: "", avatarUrl: "", - defaultAgentId: "", } const STORAGE_KEY = "crema.profile" @@ -30,20 +23,10 @@ function readFromStorage(): Profile { if (!raw) return DEFAULT_PROFILE const parsed = JSON.parse(raw) as Partial return { - title: - typeof parsed.title === "string" ? parsed.title : DEFAULT_PROFILE.title, - signature: - typeof parsed.signature === "string" - ? parsed.signature - : DEFAULT_PROFILE.signature, avatarUrl: typeof parsed.avatarUrl === "string" ? parsed.avatarUrl : DEFAULT_PROFILE.avatarUrl, - defaultAgentId: - typeof parsed.defaultAgentId === "string" - ? parsed.defaultAgentId - : DEFAULT_PROFILE.defaultAgentId, } } catch { return DEFAULT_PROFILE diff --git a/app/routes/profile.tsx b/app/routes/profile.tsx index c4e83f9..85dde38 100644 --- a/app/routes/profile.tsx +++ b/app/routes/profile.tsx @@ -15,19 +15,11 @@ import { CardHeader, CardTitle, } from "~/components/ui/card" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "~/components/ui/dropdown-menu" import { Input } from "~/components/ui/input" import { Textarea } from "~/components/ui/textarea" -import { useAgents } from "~/lib/agents" import { pageTitle } from "~/lib/page-meta" import { profileInitials, - resetProfile, saveProfile, useProfile, type Profile, @@ -54,15 +46,14 @@ export default function ProfileRoute() { const session = useSession() const arcadia = useArcadiaClient() const profile = useProfile() - const agents = useAgents() - // Local preferences (avatar, title, bio, signature, default agent). + // Mirror of the resolved avatar URL — kept in localStorage so the + // in the appbar can render before the profile fetch + // resolves on next mount. const [prefs, setPrefs] = useState(profile) - const [prefsSavedAt, setPrefsSavedAt] = useState(null) useEffect(() => { setPrefs(profile) }, [profile]) - const prefsDirty = JSON.stringify(prefs) !== JSON.stringify(profile) // Arcadia account. const [account, setAccount] = useState(null) @@ -260,20 +251,11 @@ export default function ProfileRoute() { } } - // Save the local-prefs mirror (separate from `savePrefs`, which only - // runs on the explicit "Save" button — avatar changes auto-persist - // because the server already accepted them). + // Mirror the avatar URL into localStorage so it survives reloads. const savePrefsLocal = (next: Profile) => { saveProfile(next) } - const savePrefs = () => { - saveProfile(prefs) - setPrefsSavedAt(Date.now()) - } - - const defaultAgent = agents.find((a) => a.id === prefs.defaultAgentId) ?? null - return ( @@ -517,167 +499,50 @@ export default function ProfileRoute() { - Preferences + Avatar - Avatar uploads land in your tenant's storage backend; the rest - (title, signature, default persona) stays local to this browser. + Uploads land in your tenant's storage backend. - -
- Avatar - {avatarError ? ( - {avatarError} - ) : null} -
- - {prefs.avatarUrl && !avatarUploading && ( - - )} -
- - PNG, JPG, or SVG. Stored locally as a data URL. - -
- -
- - - setPrefs((d) => ({ ...d, title: e.target.value })) - } - placeholder="e.g. Platform admin" + + {avatarError ? ( + {avatarError} + ) : null} +
+
- - -