Refactor auth pages
This commit is contained in:
parent
71986f6001
commit
8a452d80e2
8 changed files with 60 additions and 143 deletions
|
|
@ -19,8 +19,8 @@ import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { OverlayProvider } from "@react-aria/overlays";
|
import { OverlayProvider } from "@react-aria/overlays";
|
||||||
import { HomePage } from "./home/HomePage";
|
import { HomePage } from "./home/HomePage";
|
||||||
import { LoginPage } from "./LoginPage";
|
import { LoginPage } from "./auth/LoginPage";
|
||||||
import { RegisterPage } from "./RegisterPage";
|
import { RegisterPage } from "./auth/RegisterPage";
|
||||||
import { RoomPage } from "./room/RoomPage";
|
import { RoomPage } from "./room/RoomPage";
|
||||||
import { RoomRedirect } from "./room/RoomRedirect";
|
import { RoomRedirect } from "./room/RoomRedirect";
|
||||||
import { ClientProvider } from "./ConferenceCallManagerHooks";
|
import { ClientProvider } from "./ConferenceCallManagerHooks";
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import React, { useEffect, useRef } from "react";
|
|
||||||
|
|
||||||
export function RecaptchaInput({ publicKey, onResponse }) {
|
|
||||||
const containerRef = useRef();
|
|
||||||
const recaptchaRef = useRef();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const onRecaptchaLoaded = () => {
|
|
||||||
if (!recaptchaRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.grecaptcha.render(recaptchaRef.current, {
|
|
||||||
sitekey: publicKey,
|
|
||||||
callback: (response) => {
|
|
||||||
if (!recaptchaRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onResponse(response);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof window.grecaptcha !== "undefined" &&
|
|
||||||
typeof window.grecaptcha.render === "function"
|
|
||||||
) {
|
|
||||||
onRecaptchaLoaded();
|
|
||||||
} else {
|
|
||||||
window.mxOnRecaptchaLoaded = onRecaptchaLoaded;
|
|
||||||
const scriptTag = document.createElement("script");
|
|
||||||
scriptTag.setAttribute(
|
|
||||||
"src",
|
|
||||||
`https://www.recaptcha.net/recaptcha/api.js?onload=mxOnRecaptchaLoaded&render=explicit`
|
|
||||||
);
|
|
||||||
containerRef.current.appendChild(scriptTag);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={containerRef}>
|
|
||||||
<div ref={recaptchaRef} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -16,14 +16,14 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useCallback, useRef, useState, useMemo } from "react";
|
import React, { useCallback, useRef, useState, useMemo } from "react";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { useHistory, useLocation, Link } from "react-router-dom";
|
||||||
import { ReactComponent as Logo } from "./icons/LogoLarge.svg";
|
import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
|
||||||
import { FieldRow, InputField, ErrorMessage } from "./Input";
|
import { FieldRow, InputField, ErrorMessage } from "../Input";
|
||||||
import { Button } from "./button";
|
import { Button } from "../button";
|
||||||
import {
|
import {
|
||||||
defaultHomeserver,
|
defaultHomeserver,
|
||||||
defaultHomeserverHost,
|
defaultHomeserverHost,
|
||||||
useInteractiveLogin,
|
useInteractiveLogin,
|
||||||
} from "./ConferenceCallManagerHooks";
|
} from "../ConferenceCallManagerHooks";
|
||||||
import styles from "./LoginPage.module.css";
|
import styles from "./LoginPage.module.css";
|
||||||
|
|
||||||
export function LoginPage() {
|
export function LoginPage() {
|
||||||
|
|
@ -15,18 +15,19 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import { FieldRow, InputField, ErrorMessage, Field } from "./Input";
|
import { FieldRow, InputField, ErrorMessage } from "../Input";
|
||||||
import { Button } from "./button";
|
import { Button } from "../button";
|
||||||
import {
|
import {
|
||||||
useClient,
|
useClient,
|
||||||
defaultHomeserverHost,
|
defaultHomeserverHost,
|
||||||
useInteractiveRegistration,
|
useInteractiveRegistration,
|
||||||
} from "./ConferenceCallManagerHooks";
|
} from "../ConferenceCallManagerHooks";
|
||||||
import styles from "./LoginPage.module.css";
|
import styles from "./LoginPage.module.css";
|
||||||
import { ReactComponent as Logo } from "./icons/LogoLarge.svg";
|
import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
|
||||||
import { LoadingView } from "./FullScreenView";
|
import { LoadingView } from "../FullScreenView";
|
||||||
import { RecaptchaInput } from "./RecaptchaInput";
|
import { useRecaptcha } from "./useRecaptcha";
|
||||||
|
import { Caption, Link } from "../typography/Typography";
|
||||||
|
|
||||||
export function RegisterPage() {
|
export function RegisterPage() {
|
||||||
const {
|
const {
|
||||||
|
|
@ -37,17 +38,15 @@ export function RegisterPage() {
|
||||||
isPasswordlessUser,
|
isPasswordlessUser,
|
||||||
} = useClient();
|
} = useClient();
|
||||||
const confirmPasswordRef = useRef();
|
const confirmPasswordRef = useRef();
|
||||||
const acceptTermsRef = useRef();
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [registering, setRegistering] = useState(false);
|
const [registering, setRegistering] = useState(false);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [passwordConfirmation, setPasswordConfirmation] = useState("");
|
const [passwordConfirmation, setPasswordConfirmation] = useState("");
|
||||||
const [acceptTerms, setAcceptTerms] = useState(false);
|
|
||||||
const [{ privacyPolicyUrl, recaptchaKey }, register] =
|
const [{ privacyPolicyUrl, recaptchaKey }, register] =
|
||||||
useInteractiveRegistration();
|
useInteractiveRegistration();
|
||||||
const [recaptchaResponse, setRecaptchaResponse] = useState();
|
const { execute, reset, recaptchaId } = useRecaptcha(recaptchaKey);
|
||||||
|
|
||||||
const onSubmitRegisterForm = useCallback(
|
const onSubmitRegisterForm = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
|
@ -56,16 +55,23 @@ export function RegisterPage() {
|
||||||
const userName = data.get("userName");
|
const userName = data.get("userName");
|
||||||
const password = data.get("password");
|
const password = data.get("password");
|
||||||
const passwordConfirmation = data.get("passwordConfirmation");
|
const passwordConfirmation = data.get("passwordConfirmation");
|
||||||
const acceptTerms = data.get("acceptTerms");
|
|
||||||
|
|
||||||
if (isPasswordlessUser) {
|
|
||||||
if (password !== passwordConfirmation) {
|
if (password !== passwordConfirmation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
setRegistering(true);
|
setRegistering(true);
|
||||||
|
|
||||||
changePassword(password)
|
if (isPasswordlessUser) {
|
||||||
|
changePassword(password);
|
||||||
|
} else {
|
||||||
|
const recaptchaResponse = await execute();
|
||||||
|
await register(userName, password, recaptchaResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
submit()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (location.state && location.state.from) {
|
if (location.state && location.state.from) {
|
||||||
history.push(location.state.from);
|
history.push(location.state.from);
|
||||||
|
|
@ -76,31 +82,8 @@ export function RegisterPage() {
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setError(error);
|
setError(error);
|
||||||
setRegistering(false);
|
setRegistering(false);
|
||||||
|
reset();
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
password !== passwordConfirmation ||
|
|
||||||
!acceptTerms ||
|
|
||||||
!recaptchaResponse
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setRegistering(true);
|
|
||||||
|
|
||||||
register(userName, password, recaptchaResponse)
|
|
||||||
.then(() => {
|
|
||||||
if (location.state && location.state.from) {
|
|
||||||
history.push(location.state.from);
|
|
||||||
} else {
|
|
||||||
history.push("/");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setError(error);
|
|
||||||
setRegistering(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
register,
|
register,
|
||||||
|
|
@ -108,7 +91,8 @@ export function RegisterPage() {
|
||||||
location,
|
location,
|
||||||
history,
|
history,
|
||||||
isPasswordlessUser,
|
isPasswordlessUser,
|
||||||
recaptchaResponse,
|
reset,
|
||||||
|
execute,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -124,20 +108,6 @@ export function RegisterPage() {
|
||||||
}
|
}
|
||||||
}, [password, passwordConfirmation]);
|
}, [password, passwordConfirmation]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!acceptTermsRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!acceptTerms) {
|
|
||||||
acceptTermsRef.current.setCustomValidity(
|
|
||||||
"You must accept the terms to continue."
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
acceptTermsRef.current.setCustomValidity("");
|
|
||||||
}
|
|
||||||
}, [acceptTerms]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && isAuthenticated && !isPasswordlessUser) {
|
if (!loading && isAuthenticated && !isPasswordlessUser) {
|
||||||
history.push("/");
|
history.push("/");
|
||||||
|
|
@ -198,28 +168,20 @@ export function RegisterPage() {
|
||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
{!isPasswordlessUser && (
|
{!isPasswordlessUser && (
|
||||||
<FieldRow>
|
<Caption>
|
||||||
<InputField
|
This site is protected by ReCAPTCHA and the Google{" "}
|
||||||
id="acceptTerms"
|
<Link href="https://www.google.com/policies/privacy/">
|
||||||
type="checkbox"
|
|
||||||
name="acceptTerms"
|
|
||||||
onChange={(e) => setAcceptTerms(e.target.checked)}
|
|
||||||
checked={acceptTerms}
|
|
||||||
label="Accept Privacy Policy"
|
|
||||||
ref={acceptTermsRef}
|
|
||||||
/>
|
|
||||||
<a target="_blank" href={privacyPolicyUrl}>
|
|
||||||
Privacy Policy
|
Privacy Policy
|
||||||
</a>
|
</Link>{" "}
|
||||||
</FieldRow>
|
and{" "}
|
||||||
)}
|
<Link href="https://policies.google.com/terms">
|
||||||
{!isPasswordlessUser && recaptchaKey && (
|
Terms of Service
|
||||||
<FieldRow>
|
</Link>{" "}
|
||||||
<RecaptchaInput
|
apply.
|
||||||
publicKey={recaptchaKey}
|
<br />
|
||||||
onResponse={setRecaptchaResponse}
|
By clicking "Go", you agree to our{" "}
|
||||||
/>
|
<Link href={privacyPolicyUrl}>Terms and conditions</Link>
|
||||||
</FieldRow>
|
</Caption>
|
||||||
)}
|
)}
|
||||||
{error && (
|
{error && (
|
||||||
<FieldRow>
|
<FieldRow>
|
||||||
|
|
@ -231,6 +193,7 @@ export function RegisterPage() {
|
||||||
{registering ? "Registering..." : "Register"}
|
{registering ? "Registering..." : "Register"}
|
||||||
</Button>
|
</Button>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
|
<div id={recaptchaId} />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.authLinks}>
|
<div className={styles.authLinks}>
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
} from "../ConferenceCallManagerHooks";
|
} from "../ConferenceCallManagerHooks";
|
||||||
import { useModalTriggerState } from "../Modal";
|
import { useModalTriggerState } from "../Modal";
|
||||||
import { JoinExistingCallModal } from "../JoinExistingCallModal";
|
import { JoinExistingCallModal } from "../JoinExistingCallModal";
|
||||||
import { useRecaptcha } from "../useRecaptcha";
|
import { useRecaptcha } from "../auth/useRecaptcha";
|
||||||
import { Body, Caption, Link, Headline } from "../typography/Typography";
|
import { Body, Caption, Link, Headline } from "../typography/Typography";
|
||||||
import { Form } from "../form/Form";
|
import { Form } from "../form/Form";
|
||||||
import styles from "./UnauthenticatedView.module.css";
|
import styles from "./UnauthenticatedView.module.css";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { Button } from "../button";
|
||||||
import { Body, Caption, Link, Headline } from "../typography/Typography";
|
import { Body, Caption, Link, Headline } from "../typography/Typography";
|
||||||
import { Header, HeaderLogo, LeftNav, RightNav } from "../Header";
|
import { Header, HeaderLogo, LeftNav, RightNav } from "../Header";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useRecaptcha } from "../useRecaptcha";
|
import { useRecaptcha } from "../auth/useRecaptcha";
|
||||||
import { FieldRow, InputField, ErrorMessage } from "../Input";
|
import { FieldRow, InputField, ErrorMessage } from "../Input";
|
||||||
import { randomString } from "matrix-js-sdk/src/randomstring";
|
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||||
import { useInteractiveRegistration } from "../ConferenceCallManagerHooks";
|
import { useInteractiveRegistration } from "../ConferenceCallManagerHooks";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue