import React, {Fragment, useState, useContext} from "react"; import {Link} from "react-router-dom"; import Card from "components/card/Card.jsx"; import Button from "components/button/Button.jsx"; import Darken from "components/darken/Darken.jsx"; import Loading from "components/loading/Loading.jsx"; import Input from "components/input/Input.jsx"; import {UserContext} from "contexts/UserContext.jsx"; import {maybeAuthFromCookie} from "helpers/Auth.jsx"; import {getFieldError, correctFieldAnimate} from "helpers/Input.jsx"; import styles from "./Login.css"; const validateEmail = (email) => getFieldError(email?.target?.value, [3, 254]); const validatePassword = (password) => getFieldError(password?.target?.value, [8, 64]); function RequestButton({email, password, apiPath, promise, setPromise, setEmail, setPassword, setLoginActive, setError, children}) { const userState = useContext(UserContext); const onClick = () => { if (promise != null) { return; } setError(null); // We don't want to send a worthless request, we should animate the bad values. const emailErrors = validateEmail(email); const passwordErrors = validatePassword(password); if (emailErrors != null || passwordErrors != null) { correctFieldAnimate(email, setEmail, emailErrors); correctFieldAnimate(password, setPassword, passwordErrors); return; } const init = { method: "POST", headers: { 'Content-Type': "application/json" }, body: JSON.stringify({ "email": email.target.value, "password": password.target.value }), referrer: "same-origin", }; setPromise(fetch(apiPath, init) .then((response) => { if (response.ok) { if (!maybeAuthFromCookie(userState)) { throw new Error("rejected authentication token"); } setLoginActive(false); return; } return response.json() .then((json) => { if ("error" in json) { throw new Error(json.error); } throw new Error("unexpected data received"); }) }) .catch((error) => { console.log(error); setError(error.message); }) .finally(() => { setPromise(null); }) ); }; // I'm not worried about this object becoming unmounted mid promise because // our website design removes this possibility. return ( ); } function CardError({active, text}) { return (

{text}

); } function FormContents(props) { const {setLoginActive, isRegister, setIsRegister, title, prompt, linkContents, apiPath} = props; const [error, setError] = useState(null); // Email and password .value's are null here to represent the state where the user // has not typed in anything yet. This is to only validate after at least some // input has been received. const [email, setEmail] = useState(null); const [password, setPassword] = useState(null); const [promise, setPromise] = useState(null); return (

{title}

{prompt}
{promise == null ? title : } { if (promise != null) { // disallow mid transaction change return; } setIsRegister(!isRegister); setError(null); setEmail({...email, value: null, animating: false}); setPassword({...password, value: null, animating: false});}}> {linkContents}
); }; function RegisterPrompt() { return (

By registering, you agree to both our privacy policy and to waive all rights of basic privacy and security.

); } function LoginPrompt(props) { const {setLoginActive} = props; return (
setLoginActive(false)}> Can't log in?
); } function Prompt(props) { const {setLoginActive} = props; const [isRegister, setIsRegister] = useState(true); return ( : } linkContents={isRegister ? "Already have an account?" : "Don't have an account?"} apiPath={isRegister ? "/api/signup" : "/api/login"} /> ); } // A popup which asks for login/register info. export default function Login(props) { const {active, setActive} = props; return ( setActive(false)} className={styles.darken} />
); }