import { useState } from "react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { LogOut, ShieldCheck } from "lucide-react"; import { updateMember, logout } from "@/lib/api"; import { useAuth } from "@/context/Auth"; import { Card, CardHeader, Button, Field, Input, PageHeader, LoadingState } from "@/components/ui"; import { classNames } from "@/lib/format"; // 계정 설정: 표시 이름·알림·화면 환경설정 + 로그아웃. 비밀번호/2단계 인증 등 계정 보안은 // Keycloak이 담당하며, 계정 생성/삭제도 Keycloak에서 이뤄집니다. export function AccountSettingsPage() { const { me, loading } = useAuth(); const qc = useQueryClient(); const member = me?.member; const [displayName, setDisplayName] = useState(member?.displayName ?? ""); const save = useMutation({ mutationFn: () => updateMember(member!.id, { displayName }), onSuccess: () => qc.invalidateQueries({ queryKey: ["me"] }), }); // 알림/화면 환경설정 (클라이언트 보관) const [prefs, setPrefs] = useState(() => ({ notifyProject: localStorage.getItem("spin.notify.project") !== "0", notifyWork: localStorage.getItem("spin.notify.work") !== "0", notifyIncentive: localStorage.getItem("spin.notify.incentive") !== "0", sidebarCollapsed: localStorage.getItem("spin.sidebarCollapsed") === "1", })); const setPref = (k: keyof typeof prefs, key: string, v: boolean) => { setPrefs((p) => ({ ...p, [k]: v })); localStorage.setItem(key, v ? "1" : "0"); }; if (loading) return ; if (!member) return 구성원 정보가 없습니다. 관리자에게 문의하세요.; return (
save.mutate()} disabled={save.isPending}>저장} />
setDisplayName(e.target.value)} />
setPref("notifyProject", "spin.notify.project", v)} /> setPref("notifyWork", "spin.notify.work", v)} /> setPref("notifyIncentive", "spin.notify.incentive", v)} />
setPref("sidebarCollapsed", "spin.sidebarCollapsed", v)} />

비밀번호 변경·2단계 인증 등 계정 보안과 계정 생성/삭제는 Keycloak 계정에서 관리됩니다.

); } function ToggleRow({ label, desc, on, onChange }: { label: string; desc?: string; on: boolean; onChange: (v: boolean) => void }) { return (
{label}
{desc &&
{desc}
}
); }