feat(profile): add privacy controls and progressive photo gallery
CI / check (push) Failing after 53s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-11 00:31:29 +02:00
1 parent ba9c61d808
commit 74223984dc
13 files changed
+764 -167

No files matched your search

@@ -0,0 +1,60 @@
import { getTranslations } from "next-intl/server";
import { saveProfilePrivacy } from "@/actions/profile-privacy";
import { SurfaceCard } from "@/components/surface-card";
import {
loadProfilePrivacy,
profilePrivacyKeys,
} from "@/lib/services/profile-privacy";
export default async function ProfilePrivacySettings({
userId,
status,
}: {
userId: number;
status?: string;
}) {
const [privacy, t] = await Promise.all([
loadProfilePrivacy(userId),
getTranslations("pages.profile.privacy"),
]);
return (
<section id="profile-privacy">
<SurfaceCard title={t("title")} bodyClassName="p-5">
<p className="muted">{t("hint")}</p>
{status === "saved" && <p role="status">{t("saved")}</p>}
{(privacy.unavailable || status === "error") && (
<p role="alert">{t("error")}</p>
)}
<form action={saveProfilePrivacy}>
<fieldset
disabled={privacy.unavailable}
style={{
display: "grid",
gap: 12,
margin: "16px 0",
border: 0,
padding: 0,
}}
>
<legend className="sr-only">{t("title")}</legend>
{profilePrivacyKeys.map((key) => (
<label
key={key}
style={{ display: "flex", gap: 10, alignItems: "center" }}
>
<input
type="checkbox"
name={key}
defaultChecked={privacy.values[key]}
/>
{t(key)}
</label>
))}
<button type="submit" className="btn btn-primary">
{t("save")}
</button>
</fieldset>
</form>
</SurfaceCard>
</section>
);
}
+8 -1
View File
@@ -10,7 +10,13 @@ import { auth } from "@/lib/auth";
import { db, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format";
export default async function SettingsPage() {
import ProfilePrivacySettings from "./ProfilePrivacySettings";
export default async function SettingsPage({
searchParams,
}: {
searchParams: Promise<{ privacy?: string }>;
}) {
const { privacy } = await searchParams;
const t = await getTranslations("pages.settings");
const session = await auth();
if (!session?.user?.id) redirect("/login");
@@ -45,6 +51,7 @@ export default async function SettingsPage() {
return (
<div className="mx-auto flex w-full max-w-5xl flex-col gap-6 pb-14">
<ProfilePrivacySettings userId={id} status={privacy} />
{/* Header */}
<Reveal>
<SurfaceCard