121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* /settings — the settings hub.
|
|
*
|
|
* A plain entry menu: one tappable row per setting type, each routing to its
|
|
* own dedicated page. This keeps the top level uncluttered — the actual
|
|
* controls live on the sub-pages (`/settings/reading`, `/settings/notifications`,
|
|
* `/settings/account`, `/settings/legal`) plus the existing
|
|
* `/settings/profile` editor. The "Offline" row is a direct shortcut to the
|
|
* device-local download library at `/downloads` (no intermediate page).
|
|
*
|
|
* Sign out is an action rather than a destination, so it sits on its own
|
|
* below the menu.
|
|
*/
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import {
|
|
Bell,
|
|
BookOpenText,
|
|
DownloadCloud,
|
|
LogOut,
|
|
MessageSquareText,
|
|
Scale,
|
|
ShieldCheck,
|
|
UserRound,
|
|
} from "lucide-react";
|
|
import { useAuth } from "@/components/auth/auth-provider";
|
|
import {
|
|
NavList,
|
|
NavRow,
|
|
SettingsShell,
|
|
} from "@/components/settings/settings-ui";
|
|
|
|
export default function SettingsPage() {
|
|
return (
|
|
<SettingsShell backHref="/u/me" backLabel="Back to profile" title="Settings">
|
|
<NavList>
|
|
<NavRow
|
|
href="/settings/profile"
|
|
icon={<UserRound className="size-5" />}
|
|
label="Profile"
|
|
description="Name, handle, bio, and avatar."
|
|
/>
|
|
<NavRow
|
|
href="/settings/reading"
|
|
icon={<BookOpenText className="size-5" />}
|
|
label="Reading preferences"
|
|
description="Theme, palette, font, and size — synced across devices."
|
|
/>
|
|
<NavRow
|
|
href="/settings/notifications"
|
|
icon={<Bell className="size-5" />}
|
|
label="Notifications"
|
|
description="What reaches you, and on which channels."
|
|
/>
|
|
<NavRow
|
|
href="/downloads"
|
|
icon={<DownloadCloud className="size-5" />}
|
|
label="Offline downloads"
|
|
description="Manage pages and lectures saved to this device."
|
|
/>
|
|
<NavRow
|
|
href="/settings/account"
|
|
icon={<ShieldCheck className="size-5" />}
|
|
label="Account & security"
|
|
description="Connected accounts, email, and password."
|
|
/>
|
|
<NavRow
|
|
href="/settings/feedbacks"
|
|
icon={<MessageSquareText className="size-5" />}
|
|
label="My feedback"
|
|
description="Your submissions, their status, and our responses."
|
|
/>
|
|
<NavRow
|
|
href="/settings/legal"
|
|
icon={<Scale className="size-5" />}
|
|
label="Legal"
|
|
description="Terms, privacy, and data deletion."
|
|
/>
|
|
</NavList>
|
|
|
|
<SignOut />
|
|
</SettingsShell>
|
|
);
|
|
}
|
|
|
|
function SignOut() {
|
|
const { logOut } = useAuth();
|
|
const router = useRouter();
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
async function onSignOut() {
|
|
setBusy(true);
|
|
try {
|
|
await logOut();
|
|
router.push("/");
|
|
router.refresh();
|
|
} catch {
|
|
// Logout errors are silent — the cookie is cleared on the server
|
|
// either way and the next protected request will redirect anyway.
|
|
setBusy(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onSignOut}
|
|
disabled={busy}
|
|
className="w-full flex items-center justify-between gap-4 rounded-xl border border-border bg-card px-4 py-3.5 group transition-colors hover:bg-muted/50 disabled:opacity-60"
|
|
>
|
|
<span className="text-sm font-medium text-foreground group-hover:text-destructive transition-colors">
|
|
{busy ? "Signing out…" : "Sign out from this device"}
|
|
</span>
|
|
<LogOut className="size-4 shrink-0 text-muted-foreground group-hover:text-destructive transition-colors" />
|
|
</button>
|
|
);
|
|
}
|