Kyoo/front/src/ui/login/register.tsx
2025-06-07 19:32:55 +02:00

103 lines
3.2 KiB
TypeScript

import { type QueryPage, login } from "@kyoo/models";
import { A, Button, H1, Input, P, ts } from "@kyoo/primitives";
import { useEffect, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { Platform } from "react-native";
import { useRouter } from "solito/router";
import { percent, px, useYoshiki } from "yoshiki/native";
import { DefaultLayout } from "../../../packages/ui/src/layout";
import { FormPage } from "./form";
import { OidcLogin } from "./oidc";
import { PasswordInput } from "./password-input";
export const RegisterPage: QueryPage<{ apiUrl?: string }> = ({ apiUrl }) => {
const { data } = useFetch({
path: ["info"],
parser: ServerInfoP,
});
const [email, setEmail] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [confirm, setConfirm] = useState("");
const [error, setError] = useState<string | undefined>(undefined);
const router = useRouter();
const { t } = useTranslation();
const { css } = useYoshiki();
useEffect(() => {
if (!apiUrl && Platform.OS !== "web")
router.replace("/server-url", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
});
}, [apiUrl, router]);
return (
<FormPage apiUrl={apiUrl}>
<H1>{t("login.register")}</H1>
<OidcLogin apiUrl={apiUrl} hideOr={!data?.passwordLoginEnabled} />
{data?.registrationEnabled && (
<>
<P {...css({ paddingLeft: ts(1) })}>{t("login.username")}</P>
<Input
autoComplete="username"
variant="big"
onChangeText={(value) => setUsername(value)}
/>
<P {...css({ paddingLeft: ts(1) })}>{t("login.email")}</P>
<Input autoComplete="email" variant="big" onChangeText={(value) => setEmail(value)} />
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
<PasswordInput
autoComplete="password-new"
variant="big"
onChangeText={(value) => setPassword(value)}
/>
<P {...css({ paddingLeft: ts(1) })}>{t("login.confirm")}</P>
<PasswordInput
autoComplete="password-new"
variant="big"
onChangeText={(value) => setConfirm(value)}
/>
{password !== confirm && (
<P {...css({ color: (theme) => theme.colors.red })}>{t("login.password-no-match")}</P>
)}
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
<Button
text={t("login.register")}
disabled={password !== confirm}
onPress={async () => {
const { error } = await login("register", { email, username, password, apiUrl });
setError(error);
if (error) return;
router.replace("/", undefined, {
experimental: { nativeBehavior: "stack-replace", isNestedNavigator: false },
});
}}
{...css({
m: ts(1),
width: px(250),
maxWidth: percent(100),
alignSelf: "center",
mY: ts(3),
})}
/>
</>
)}
<P>
<Trans i18nKey="login.or-login">
Have an account already? <A href={{ pathname: "/login", query: { apiUrl } }}>Log in</A>.
</Trans>
</P>
</FormPage>
);
};
RegisterPage.getFetchUrls = () => [OidcLogin.query()];
RegisterPage.isPublic = true;
RegisterPage.getLayout = DefaultLayout;