import { ArrowLeft, LogOut, MoonStar, Palette, Sparkles, Upload, UserRoundPen, X } from "lucide-react"; import { type ChangeEvent, type FormEvent, useEffect, useMemo, useState } from "react"; import type { PageComponentProps } from "../contracts/page"; import { defaultPageForUser } from "../routes/routes"; import { applyBackgroundImage, applyThemePalette, loadThemeState, persistBackgroundImage, persistThemePalette, themePalettes, type ThemePaletteId, type WorkspaceThemeState } from "../theme/tokens"; import { cx } from "../utils/classes"; import { PageFrame } from "../components/PageFrame"; import { ResultBadge } from "../components/StateViews"; type SaveState = { status: "pending" | "succeeded" | "failed"; label: string }; export function ProfileSettingsPage({ session, onNavigate, onLogout, onProfileSave, onThemePreferenceSave }: PageComponentProps) { const [themeState, setThemeState] = useState(() => loadThemeState()); const [profileResult, setProfileResult] = useState(); const [themeResult, setThemeResult] = useState(); const [profileDraft, setProfileDraft] = useState({ displayName: session.displayName, avatarUrl: session.profile.avatarUrl ?? "", phone: session.profile.phone ?? "", qq: session.profile.qq ?? "", contactNote: session.profile.contactNote ?? "" }); useEffect(() => { setProfileDraft({ displayName: session.displayName, avatarUrl: session.profile.avatarUrl ?? "", phone: session.profile.phone ?? "", qq: session.profile.qq ?? "", contactNote: session.profile.contactNote ?? "" }); }, [session]); const activePalette = useMemo(() => themePalettes.find((palette) => palette.id === themeState.paletteId) ?? themePalettes[0], [themeState.paletteId]); const hasCustomBackground = Boolean(themeState.backgroundImage); const backgroundMetricValue = hasCustomBackground ? "已上传" : "主题配色"; async function saveProfile(event: FormEvent) { event.preventDefault(); setProfileResult({ status: "pending", label: "正在保存个人资料" }); try { const saved = await onProfileSave({ displayName: profileDraft.displayName.trim(), avatarUrl: profileDraft.avatarUrl.trim(), phone: profileDraft.phone.trim(), qq: profileDraft.qq.trim(), contactNote: profileDraft.contactNote.trim() }); setProfileResult({ status: saved.source === "api" ? "succeeded" : "failed", label: saved.source === "api" ? "个人资料已保存到数据库" : "个人资料 API 暂不可用,已保留在本地会话" }); } catch (error) { setProfileResult({ status: "failed", label: error instanceof Error ? error.message : "个人资料保存失败" }); } } async function persistThemePreference(nextState: WorkspaceThemeState) { setThemeResult({ status: "pending", label: "正在保存界面偏好" }); try { const response = await onThemePreferenceSave({ paletteId: nextState.paletteId, backgroundPresetId: nextState.backgroundPresetId, backgroundImage: nextState.backgroundImage }); setThemeResult({ status: response.persistence === "api" ? "succeeded" : "failed", label: response.persistence === "api" ? "界面偏好已保存到数据库" : "界面偏好 API 暂不可用,已本地保存" }); } catch (error) { setThemeResult({ status: "failed", label: error instanceof Error ? error.message : "界面偏好保存失败" }); } } function selectPalette(paletteId: ThemePaletteId) { applyThemePalette(paletteId); persistThemePalette(paletteId); setThemeState((current) => { const nextState = { ...current, paletteId }; void persistThemePreference(nextState); return nextState; }); } function handleBackgroundUpload(event: ChangeEvent) { const file = event.target.files?.[0]; event.target.value = ""; if (!file) { return; } const reader = new FileReader(); reader.onload = () => { const dataUrl = typeof reader.result === "string" ? reader.result : null; applyBackgroundImage(dataUrl); persistBackgroundImage(dataUrl); setThemeState((current) => { const nextState = { ...current, backgroundImage: dataUrl }; void persistThemePreference(nextState); return nextState; }); }; reader.readAsDataURL(file); } function clearBackground() { applyBackgroundImage(null); persistBackgroundImage(null); setThemeState((current) => { const nextState = { ...current, backgroundImage: null }; void persistThemePreference(nextState); return nextState; }); } return (

{profileDraft.displayName || session.displayName}

{session.email ?? session.id}

{session.status}

个人资料

{profileResult && }