import type { ActionFunction, LinksFunction, MetaFunction } from "remix"; import { useActionData, json, Link, useSearchParams, Form } from "remix"; import { db } from "~/utils/db.server"; import { createUserSession, register } from "~/utils/session.server"; import Header from "../components/Header"; export const links: LinksFunction = () => { return []; }; export const meta: MetaFunction = () => { return { title: "Explit | Sign in", description: "Sign in to track and split your expenses!", }; }; function validateUsername(username: unknown) { if (typeof username !== "string" || username.length < 3) { return `Usernames must be at least 3 characters long`; } } 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; fieldErrors?: { username: string | undefined; password: string | undefined; teamId: string | undefined; confirmPassword: string | undefined; icon: string | undefined; }; fields?: { username: string; password: string; confirmPassword: string; teamId?: string; icon?: string; }; }; const badRequest = (data: ActionData) => json(data, { status: 400 }); export const action: ActionFunction = async ({ request }) => { const form = await request.formData(); const username = form.get("username"); const password = form.get("password"); const confirmPassword = form.get("confirmPassword"); const icon = form.get("icon") ?? (typeof username === "string" ? username[0] : undefined); const teamId = form.get("teamId"); const redirectTo = form.get("redirectTo") || "/expenses"; if ( typeof username !== "string" || typeof password !== "string" || typeof confirmPassword !== "string" || typeof teamId !== "string" || typeof redirectTo !== "string" ) { return badRequest({ formError: `Form not submitted correctly.`, }); } const fields = { username, password, confirmPassword, teamId }; const fieldErrors = { username: validateUsername(username), password: validatePassword(password), confirmPassword: validateConfirmPassword(confirmPassword, password), icon: validateIcon(icon), teamId: validateTeamId(teamId), }; if (Object.values(fieldErrors).some(Boolean)) return badRequest({ fieldErrors, fields }); const userExists = await db.user.findFirst({ where: { username }, }); if (userExists) { console.error(userExists); return badRequest({ fields, formError: `User with username ${username} already exists`, }); } const user = await register({ username, password, icon, teamId }); if (!user) { return badRequest({ fields, formError: `Something went wrong trying to create a new user.`, }); } return createUserSession(user.id, redirectTo); }; export default function Login() { const actionData = useActionData(); const [searchParams] = useSearchParams(); return ( <>

Sign In

{actionData?.fieldErrors?.username && (
)}
{actionData?.fieldErrors?.icon && (
)}
{actionData?.fieldErrors?.password && (
)}
{actionData?.fieldErrors?.confirmPassword && (
)}
{actionData?.fieldErrors?.teamId && (
)}
{actionData?.formError && (
)}
); }