feat(profile): add privacy controls and progressive photo gallery
This commit is contained in:
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>
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user