import type { User, Team } from "@prisma/client"; import type { LinksFunction, LoaderFunction, ActionFunction } from "remix"; import { Link, useLoaderData, useActionData, Form, redirect, useCatch, json, } from "remix"; import { getUser, updateUser } from "~/utils/session.server"; import { db } from "~/utils/db.server"; import Check from "~/icons/Check"; export const links: LinksFunction = () => { return []; }; type LoaderData = { user: (User & { team: Team & { members: User[] } }) | null; }; export const loader: LoaderFunction = async ({ request }) => { const user = await getUser(request); if (!user?.id) { return redirect("/login"); } const data: LoaderData = { user, }; return data; }; const badRequest = (data: ActionData) => json(data, { status: 400 }); const success = (data: ActionData) => json(data, { status: 200 }); function validatePassword(password: unknown) { if (typeof password === "string" && password.length < 6) { return `Passwords must be at least 6 characters long`; } } function validateConfirmPassword(confirmPassword: unknown, password: string) { if (typeof confirmPassword === "string" && confirmPassword !== password) { return `Passwords must match`; } } function validateIcon(icon: unknown) { if (typeof icon === "string" && icon.length > 2) { return `Icons must be a single character, e.g. "A" or "😎"`; } } function validateTeamId(teamId: unknown) { if (typeof teamId === "string" && teamId.length < 1) { return "You must indicate an arbitrary team ID"; } } type ActionData = { formError?: string; success?: string; fieldErrors?: { icon: string | undefined; teamId: string | undefined; password: string | undefined; confirmPassword: string | undefined; }; fields?: { password?: string; confirmPassword?: string; teamId?: string; icon?: string; }; }; export const action: ActionFunction = async ({ request }) => { // @ts-ignore const user = await getUser(request); if (!user) return badRequest({ formError: "You must be logged in to change your settings", }); const form = await request.formData(); const password = form.get("password"); const confirmPassword = form.get("confirmPassword"); const icon = form.get("icon") ?? (user ? user.username[0] : undefined); const teamId = form.get("teamId"); const fields = { icon: typeof icon === "string" ? icon : undefined, password: typeof password === "string" ? password : undefined, confirmPassword: typeof confirmPassword === "string" ? confirmPassword : undefined, teamId: typeof teamId === "string" ? teamId : undefined, }; const fieldErrors = { password: validatePassword(password), confirmPassword: validateConfirmPassword( confirmPassword, typeof password === "string" ? password : "" ), icon: validateIcon(icon), teamId: validateTeamId(teamId), }; if (Object.values(fieldErrors).some(Boolean)) return badRequest({ fieldErrors, fields }); const nonEmptyFields = Object.entries(fields).reduce((acc, [key, value]) => { if (typeof value === "string" && key !== "confirmPassword") return { ...acc, [key]: value ?? undefined }; else return acc; }, {}); const userUpdated = await updateUser({ id: user.id, ...nonEmptyFields, }); if (!userUpdated) { return badRequest({ fields, formError: `Something went wrong trying to update user.`, }); } return success({ success: "Your settings have been updated.", }); }; export default function AccountPreferencesRoute() { const data = useLoaderData(); const actionData = useActionData(); return ( <>
Preferences Manage
{actionData?.fieldErrors?.icon && (
)}
{actionData?.fieldErrors?.password && (
)}
{actionData?.fieldErrors?.confirmPassword && (
)}
{actionData?.fieldErrors?.teamId && (
)} {actionData?.success && (
)}

Do you really want to delete your account? All your data will be permanently deleted.

); } export function CatchBoundary() { const caught = useCatch(); if (caught.status === 401) { return (

You must be logged in to set your preferences.

Login
); } } export function ErrorBoundary() { return (
Something unexpected went wrong. Sorry about that.
); }