Jamjar/src/app/settings/page.tsx
2025-02-09 02:39:02 +02:00

154 lines
4.4 KiB
TypeScript

"use client";
import Editor from "@/components/editor";
import sanitizeHtml from "sanitize-html";
import { getCookie, hasCookie } from "@/helpers/cookie";
import { UserType } from "@/types/UserType";
import { Avatar, Button, Form, Input } from "@nextui-org/react";
import { redirect, usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { LoaderCircle } from "lucide-react";
import Image from "next/image";
import { getSelf, updateUser } from "@/requests/user";
export default function UserPage() {
const [user, setUser] = useState<UserType>();
const [profilePicture, setProfilePicture] = useState("");
const [name, setName] = useState("");
const [bannerPicture, setBannerPicture] = useState("");
const [bio, setBio] = useState("");
const [errors] = useState({});
const pathname = usePathname();
const [waitingSave, setWaitingSave] = useState(false);
useEffect(() => {
loadUser();
async function loadUser() {
if (!hasCookie("token")) {
setUser(undefined);
redirect("/");
return;
}
const response = await getSelf();
if (response.status == 200) {
const data = await response.json();
setUser(data);
setProfilePicture(data.profilePicture ?? "");
setBannerPicture(data.bannerPicture ?? "");
setBio(data.bio ?? "");
setName(data.name ?? "");
} else {
setUser(undefined);
}
}
}, [pathname]);
return (
<div className="flex items-center justify-center">
{!user ? (
"Loading settings..."
) : (
<Form
className="w-full max-w-2xl flex flex-col gap-4"
validationErrors={errors}
onReset={() => {
setProfilePicture(user.profilePicture ?? "");
setBannerPicture(user.bannerPicture ?? "");
setBio(user.bio ?? "");
setName(user.name ?? "");
}}
onSubmit={async (e) => {
e.preventDefault();
const sanitizedBio = sanitizeHtml(bio);
if (!name) {
toast.error("You need to enter a name");
return;
}
setWaitingSave(true);
const response = await updateUser(user.slug, name, sanitizedBio, profilePicture, bannerPicture);
if (response.ok) {
toast.success("Changed settings");
setUser(await response.json());
setWaitingSave(false);
} else {
toast.error("Failed to update settings");
setWaitingSave(false);
}
}}
>
<p className="text-3xl">Settings</p>
<Input
label="Name"
labelPlacement="outside"
name="name"
placeholder="Enter a name"
type="text"
value={name}
onValueChange={setName}
/>
<p>Bio</p>
<Editor content={bio} setContent={setBio} />
<Input
label="Profile Picture"
labelPlacement="outside"
name="profilePicture"
placeholder="Enter a url to an image"
type="text"
value={profilePicture}
onValueChange={setProfilePicture}
/>
{profilePicture && <Avatar src={profilePicture} />}
<Input
label="Banner Picture"
labelPlacement="outside"
name="bannerPicture"
placeholder="Enter a url to an image"
type="text"
value={bannerPicture}
onValueChange={setBannerPicture}
/>
{bannerPicture &&
bannerPicture.startsWith("https://") &&
bannerPicture.length > 8 && (
<div className="bg-[#222222] h-28 w-full relative">
<Image
src={bannerPicture}
alt={`${user.name}'s profile banner`}
className="object-cover"
fill
/>
</div>
)}
<div className="flex gap-2">
<Button color="primary" type="submit">
{waitingSave ? (
<LoaderCircle className="animate-spin" size={16} />
) : (
<p>Save</p>
)}
</Button>
<Button type="reset" variant="flat">
Reset
</Button>
</div>
</Form>
)}
</div>
);
}