gluestick/src/app/me/AboutMe.tsx

292 lines
8.5 KiB
TypeScript
Raw Normal View History

2023-04-26 13:56:59 -04:00
/* eslint-disable @next/next/no-img-element */
"use client";
import { UserInfo } from "@/ldap";
2023-04-27 13:47:30 -04:00
import React from "react";
2023-04-26 13:56:59 -04:00
import styles from "./AboutMe.module.css";
2023-04-26 22:59:17 -04:00
import AvatarChanger from "@/components/AvatarChanger";
2023-04-28 11:53:58 -04:00
import Input, { Label } from "@/components/Input";
2023-04-26 22:59:17 -04:00
import { Form, Formik, FormikHelpers } from "formik";
import {
AboutMeFormValues,
PasswordUpdateFormValues,
aboutMeSchema,
passwordUpdateSchema
} from "@/schemas";
import PrettyForm from "@/components/PrettyForm";
2023-04-26 23:22:49 -04:00
import Toast from "@/components/Toast";
import { AuthProviderState } from "@/auth/AuthProvider";
2023-04-28 11:53:58 -04:00
import inputStyles from "@/components/Input.module.css";
import Connection from "@/components/Connection";
2023-04-28 16:09:12 -04:00
import DiscordIcon from "@/components/icons/DiscordIcon";
import GitHubIcon from "@/components/icons/GitHubIcon";
2023-04-26 13:56:59 -04:00
type UpdateResponse = {
ok: boolean;
error?: string;
};
export default function AboutMe({
info,
2023-04-28 11:53:58 -04:00
providers: [discordState, githubState]
}: {
info: UserInfo;
providers: AuthProviderState[];
}) {
2023-04-28 11:53:58 -04:00
// TODO: Reimplement password changing.
2023-04-26 22:59:17 -04:00
const [globalError, setGlobalError] = React.useState<string | null>(null);
2023-04-26 23:22:49 -04:00
const [madeProfileChanges, setMadeChanges] = React.useState(false);
const [madePasswordChanges, setMadePasswordChanges] = React.useState(false);
2023-04-26 22:59:17 -04:00
const initialValues: AboutMeFormValues = {
username: info.username,
displayName: info.displayName,
email: info.email,
avatar: info.avatar
};
async function handleFormSubmit(
{ displayName, email, avatar }: AboutMeFormValues,
{ setSubmitting }: FormikHelpers<AboutMeFormValues>
) {
2023-04-26 23:22:49 -04:00
setMadeChanges(false);
2023-04-26 22:59:17 -04:00
setSubmitting(true);
const req = await fetch("/api/update", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
displayName,
email,
avatar: avatar != null ? avatar.split(",")[1] : null
})
});
setSubmitting(false);
try {
const res: UpdateResponse = await req.json();
if (!res.ok && res.error !== null) {
switch (res.error) {
case "avatarBig":
break;
}
}
2023-04-26 23:22:49 -04:00
setMadeChanges(true);
2023-04-26 22:59:17 -04:00
} catch {
console.error(req);
}
}
const [passwordError, setPasswordError] = React.useState<string | null>(null);
const initialPasswordValues: PasswordUpdateFormValues = {
password: "",
newPassword: "",
confirmPassword: ""
};
async function handlePasswordSubmit(
{ password, newPassword }: PasswordUpdateFormValues,
{ setFieldError, setSubmitting }: FormikHelpers<PasswordUpdateFormValues>
) {
2023-04-26 23:22:49 -04:00
setMadePasswordChanges(false);
2023-04-26 22:59:17 -04:00
setSubmitting(true);
const req = await fetch("/api/changePassword", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
currentPassword: password,
newPassword: newPassword
})
});
setSubmitting(false);
try {
const res: UpdateResponse = await req.json();
if (!res.ok && res.error !== null) {
switch (res.error) {
case "incorrectPassword":
setFieldError("password", "Incorrect password.");
break;
}
}
2023-04-26 23:22:49 -04:00
setMadePasswordChanges(true);
2023-04-26 22:59:17 -04:00
} catch {
console.error(req);
}
}
2023-04-26 13:56:59 -04:00
return (
<div className={styles.content}>
2023-04-26 22:59:17 -04:00
<PrettyForm globalError={globalError}>
<Formik
initialValues={initialValues}
onSubmit={handleFormSubmit}
validationSchema={aboutMeSchema}
>
{({ isSubmitting }) => (
<Form className={styles.profileGrid}>
2023-04-28 11:53:58 -04:00
<div className={styles.profileTower}>
<Input
type="file"
name="avatar"
customRender={(fieldProps) => (
<AvatarChanger
currentAvatarBlob={fieldProps.field.value}
onChange={(newBlob) =>
fieldProps.form.setFieldValue("avatar", newBlob)
}
vertical
/>
)}
/>
</div>
2023-04-26 22:59:17 -04:00
2023-04-28 11:53:58 -04:00
<div>
<h2 className={styles.userName}>{info.username}</h2>
<div className={styles.rightGrid}>
<div>
{madeProfileChanges ? (
<Toast>Saved your changes.</Toast>
) : null}
<Input
type="text"
name="username"
label="Username"
defaultValue={info.username}
disabled
hint="This can&rsquo;t be changed."
/>
<Input
type="text"
name="displayName"
label="Display name"
defaultValue={info.displayName}
/>
2023-04-26 22:59:17 -04:00
2023-04-28 11:53:58 -04:00
<Input
type="email"
name="email"
label="Email"
defaultValue={info.email}
/>
<div className={inputStyles.formRow}>
<button type="button">Change Password</button>
</div>
<div className={inputStyles.formRow}>
<button
type="button"
onClick={async () => {
document.cookie =
"ticket=; expires=" +
new Date().toUTCString() +
"; path=/";
window.location.href = "/";
}}
>
Log out
</button>
</div>
<input
type="submit"
value="Save"
className={styles.fancyInput}
disabled={isSubmitting}
/>
</div>
<div className={styles.connections}>
<Label>Connections</Label>
2023-04-28 16:09:12 -04:00
<Connection
service="Discord"
authState={discordState}
icon={DiscordIcon}
/>
<Connection
service="GitHub"
authState={githubState}
icon={GitHubIcon}
/>
2023-04-28 11:53:58 -04:00
<Connection service="Tailscale" unavailable />
<Connection service="Migadu" unavailable />
</div>
</div>
</div>
2023-04-26 22:59:17 -04:00
</Form>
)}
</Formik>
</PrettyForm>
2023-04-28 11:53:58 -04:00
{/*<PrettyForm globalError={passwordError}>
2023-04-26 22:59:17 -04:00
<Formik
initialValues={initialPasswordValues}
onSubmit={handlePasswordSubmit}
validationSchema={passwordUpdateSchema}
>
{({ isSubmitting }) => (
2023-04-26 23:22:49 -04:00
<Form>
{madePasswordChanges ? (
<Toast>Changed your password.</Toast>
) : null}
2023-04-26 22:59:17 -04:00
<Input
type="password"
name="password"
label="Current"
minLength={12}
required
/>
<Input
type="password"
name="newPassword"
label="New"
minLength={12}
required
/>
<Input
type="password"
name="confirmPassword"
label="Confirm"
minLength={12}
required
/>
<input
type="submit"
value="Save"
className={styles.fancyInput}
disabled={isSubmitting}
/>
</Form>
)}
</Formik>
</PrettyForm>
2023-04-26 23:32:52 -04:00
<h2 className={styles.header}>Connections</h2>
<div className={styles.authProviderList}>
{providers.map((provider) => (
<AuthProviderEntry provider={provider} key={provider.name} />
))}
2023-04-26 23:32:52 -04:00
</div>
2023-04-26 22:59:17 -04:00
<input
type="button"
value="Log out"
className={styles.logout}
onClick={async () => {
document.cookie =
"ticket=; expires=" + new Date().toUTCString() + "; path=/";
window.location.href = "/";
}}
2023-04-28 11:53:58 -04:00
/>*/}
2023-04-26 13:56:59 -04:00
</div>
);
}