Files
element-call/src/auth/RegisterPage.tsx
T

256 lines
8.4 KiB
TypeScript
Raw Normal View History

2021-08-20 16:23:12 -07:00
/*
Copyright 2021-2024 New Vector Ltd.
2021-08-20 16:23:12 -07:00
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
2021-08-20 16:23:12 -07:00
*/
import {
2022-08-09 11:44:46 +02:00
ChangeEvent,
2022-05-27 16:48:38 -04:00
FC,
FormEvent,
useCallback,
useEffect,
useRef,
useState,
} from "react";
2022-01-05 16:34:01 -08:00
import { useHistory, useLocation } from "react-router-dom";
import { captureException } from "@sentry/react";
import { sleep } from "matrix-js-sdk/src/utils";
2022-10-10 09:19:10 -04:00
import { Trans, useTranslation } from "react-i18next";
2023-09-25 18:04:34 +01:00
import { logger } from "matrix-js-sdk/src/logger";
import { Button } from "@vector-im/compound-web";
2022-05-27 16:48:38 -04:00
2022-01-05 17:27:01 -08:00
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
2023-06-30 16:43:28 +01:00
import { useClientLegacy } from "../ClientContext";
2022-01-05 16:47:53 -08:00
import { useInteractiveRegistration } from "./useInteractiveRegistration";
2021-12-10 12:46:18 -08:00
import styles from "./LoginPage.module.css";
2023-09-27 19:06:10 -04:00
import Logo from "../icons/LogoLarge.svg?react";
2022-01-05 16:34:01 -08:00
import { LoadingView } from "../FullScreenView";
import { useRecaptcha } from "./useRecaptcha";
import { Caption, Link } from "../typography/Typography";
2022-02-02 15:02:40 -08:00
import { usePageTitle } from "../usePageTitle";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
2022-12-20 17:26:45 +00:00
import { Config } from "../config/Config";
2021-08-20 16:23:12 -07:00
2022-05-27 16:48:38 -04:00
export const RegisterPage: FC = () => {
2022-10-10 09:19:10 -04:00
const { t } = useTranslation();
2023-11-20 13:00:43 +00:00
usePageTitle(t("action.register"));
2022-02-02 15:02:40 -08:00
2023-06-30 16:43:28 +01:00
const { loading, authenticated, passwordlessUser, client, setClient } =
useClientLegacy();
const confirmPasswordRef = useRef<HTMLInputElement>(null);
2021-08-20 16:23:12 -07:00
const history = useHistory();
const location = useLocation();
const [registering, setRegistering] = useState(false);
2022-05-27 16:48:38 -04:00
const [error, setError] = useState<Error>();
2021-12-15 11:10:38 -08:00
const [password, setPassword] = useState("");
const [passwordConfirmation, setPasswordConfirmation] = useState("");
const { recaptchaKey, register } = useInteractiveRegistration(client);
2022-01-05 16:34:01 -08:00
const { execute, reset, recaptchaId } = useRecaptcha(recaptchaKey);
2021-08-20 16:23:12 -07:00
const onSubmitRegisterForm = useCallback(
2022-05-27 16:48:38 -04:00
(e: FormEvent<HTMLFormElement>) => {
2021-08-20 16:23:12 -07:00
e.preventDefault();
2022-05-27 16:48:38 -04:00
const data = new FormData(e.target as HTMLFormElement);
const userName = data.get("userName") as string;
const password = data.get("password") as string;
const passwordConfirmation = data.get("passwordConfirmation") as string;
2022-05-27 16:48:38 -04:00
if (password !== passwordConfirmation) return;
2023-09-22 18:05:13 -04:00
const submit = async (): Promise<void> => {
2021-12-20 15:56:39 -08:00
setRegistering(true);
2022-02-15 12:46:58 -08:00
const recaptchaResponse = await execute();
const [newClient, session] = await register(
2022-02-15 12:46:58 -08:00
userName,
password,
userName,
2023-06-30 16:43:28 +01:00
recaptchaResponse,
2023-10-11 10:42:04 -04:00
passwordlessUser,
2022-02-15 12:46:58 -08:00
);
if (client && client?.groupCallEventHandler && passwordlessUser) {
2022-05-27 16:48:38 -04:00
// Migrate the user's rooms
for (const groupCall of client.groupCallEventHandler.groupCalls.values()) {
const roomId = groupCall.room.roomId;
2022-02-15 12:46:58 -08:00
try {
await newClient.joinRoom(roomId);
} catch (error) {
2023-06-30 16:43:28 +01:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (error.errcode === "M_LIMIT_EXCEEDED") {
2023-06-30 16:43:28 +01:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await sleep(error.data.retry_after_ms);
await newClient.joinRoom(roomId);
} else {
captureException(error);
2023-09-25 18:04:34 +01:00
logger.error(`Couldn't join room ${roomId}`, error);
}
2022-02-15 12:46:58 -08:00
}
}
2021-12-20 15:56:39 -08:00
}
setClient?.({ client: newClient, session });
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
2022-05-27 16:48:38 -04:00
};
2022-01-05 16:34:01 -08:00
submit()
.then(() => {
2023-06-30 16:43:28 +01:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
2022-05-27 16:48:38 -04:00
if (location.state?.from) {
2023-06-30 16:43:28 +01:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
2022-08-02 00:46:16 +02:00
history.push(location.state?.from);
2022-01-05 16:34:01 -08:00
} else {
history.push("/");
}
})
.catch((error) => {
setError(error);
setRegistering(false);
reset();
});
2021-08-20 16:23:12 -07:00
},
2022-05-27 16:48:38 -04:00
[
register,
location,
history,
2023-06-30 16:43:28 +01:00
passwordlessUser,
2022-05-27 16:48:38 -04:00
reset,
execute,
client,
setClient,
2023-10-11 10:42:04 -04:00
],
2021-08-20 16:23:12 -07:00
);
2021-12-15 11:10:38 -08:00
useEffect(() => {
if (password && passwordConfirmation && password !== passwordConfirmation) {
2023-11-20 13:00:43 +00:00
confirmPasswordRef.current?.setCustomValidity(
t("register.passwords_must_match"),
);
2021-12-15 11:10:38 -08:00
} else {
2022-05-27 16:48:38 -04:00
confirmPasswordRef.current?.setCustomValidity("");
2021-12-15 11:10:38 -08:00
}
2022-10-10 09:19:10 -04:00
}, [password, passwordConfirmation, t]);
2021-12-15 11:10:38 -08:00
useEffect(() => {
2023-06-30 16:43:28 +01:00
if (!loading && authenticated && !passwordlessUser && !registering) {
history.push("/");
}
2023-06-30 16:43:28 +01:00
}, [loading, history, authenticated, passwordlessUser, registering]);
if (loading) {
return <LoadingView />;
} else {
PosthogAnalytics.instance.eventSignup.cacheSignupStart(new Date());
}
2021-08-20 16:23:12 -07:00
return (
<>
2021-12-10 12:46:18 -08:00
<div className={styles.container}>
<div className={styles.content}>
<div className={styles.formContainer}>
<Logo width="auto" height="auto" className={styles.logo} />
2023-11-22 20:07:15 +00:00
<h2>{t("register_heading")}</h2>
2021-12-10 12:46:18 -08:00
<form onSubmit={onSubmitRegisterForm}>
<FieldRow>
<InputField
type="text"
name="userName"
placeholder={t("common.username")}
label={t("common.username")}
2021-12-10 12:46:18 -08:00
autoCorrect="off"
autoCapitalize="none"
2021-12-15 10:54:01 -08:00
prefix="@"
2022-12-20 17:26:45 +00:00
suffix={`:${Config.defaultServerName()}`}
data-testid="register_username"
2021-12-10 12:46:18 -08:00
/>
</FieldRow>
<FieldRow>
<InputField
2021-12-15 11:10:38 -08:00
required
name="password"
2021-12-10 12:46:18 -08:00
type="password"
2023-09-22 18:05:13 -04:00
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
2022-08-09 11:44:46 +02:00
setPassword(e.target.value)
}
2021-12-15 11:10:38 -08:00
value={password}
placeholder={t("common.password")}
label={t("common.password")}
data-testid="register_password"
2021-12-10 12:46:18 -08:00
/>
</FieldRow>
2021-12-15 11:10:38 -08:00
<FieldRow>
<InputField
required
type="password"
name="passwordConfirmation"
2023-09-22 18:05:13 -04:00
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
2022-08-09 11:44:46 +02:00
setPasswordConfirmation(e.target.value)
}
2021-12-15 11:10:38 -08:00
value={passwordConfirmation}
2023-11-20 13:00:43 +00:00
placeholder={t("register_confirm_password_label")}
label={t("register_confirm_password_label")}
2021-12-15 11:10:38 -08:00
ref={confirmPasswordRef}
data-testid="register_confirm_password"
2021-12-15 11:10:38 -08:00
/>
</FieldRow>
2022-02-15 12:46:58 -08:00
<Caption>
2023-11-20 13:00:43 +00:00
<Trans i18nKey="recaptcha_caption">
2022-10-10 09:19:10 -04:00
This site is protected by ReCAPTCHA and the Google{" "}
<Link href="https://www.google.com/policies/privacy/">
Privacy Policy
</Link>{" "}
and{" "}
<Link href="https://policies.google.com/terms">
Terms of Service
</Link>{" "}
apply.
<br />
By clicking "Register", you agree to our{" "}
2023-07-06 08:53:57 +02:00
<Link href={Config.get().eula}>
2023-07-06 08:43:00 +02:00
End User Licensing Agreement (EULA)
</Link>
2022-10-10 09:19:10 -04:00
</Trans>
2022-02-15 12:46:58 -08:00
</Caption>
2021-12-10 12:46:18 -08:00
{error && (
2021-08-20 16:23:12 -07:00
<FieldRow>
2022-10-10 09:19:10 -04:00
<ErrorMessage error={error} />
2021-08-20 16:23:12 -07:00
</FieldRow>
2021-12-10 12:46:18 -08:00
)}
<FieldRow>
<Button
type="submit"
disabled={registering}
data-testid="register_register"
>
2023-11-20 13:00:43 +00:00
{registering
? t("register.registering")
: t("action.register")}
2021-12-10 12:46:18 -08:00
</Button>
</FieldRow>
2022-01-05 16:34:01 -08:00
<div id={recaptchaId} />
2021-12-10 12:46:18 -08:00
</form>
</div>
<div className={styles.authLinks}>
2023-11-20 13:00:43 +00:00
<Trans i18nKey="register_auth_links">
2022-10-10 09:19:10 -04:00
<p>Already have an account?</p>
<p>
<Link to="/login">Log in</Link>
{" Or "}
<Link to="/">Access as a guest</Link>
</p>
</Trans>
2021-12-10 12:46:18 -08:00
</div>
</div>
</div>
2021-08-20 16:23:12 -07:00
</>
);
2022-05-27 16:48:38 -04:00
};