Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | import React, {ChangeEvent, FormEvent, ReactElement, useCallback, useEffect, useState} from "react"; import {Button, Form, FormGroup} from "react-bootstrap"; import check_svg from "../../../assets/images/icons/material.io/check_circle-24px.svg"; import info_svg from "../../../assets/images/icons/material.io/info-24px.svg"; import error_svg from "../../../assets/images/icons/material.io/error-24px.svg"; import {biggerMaxStrLength, notMinStrLength} from "../../../background/methods/checkInput"; import {deleteSpaces} from "../../../background/methods/strings"; import {DEFAULT_ALERT_DURATION, MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH} from "../../../background/constants"; export interface UserInformationInputInterface { username: string, password: string, passwordConfirmation?: string } type UserInformationInputProps = { triggerAlert(duration: number, color: "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark", message: string): void, submitFunction(newUser: UserInformationInputInterface): void, presets?: UserInformationInputInterface } export default function UserInformationInput(props: UserInformationInputProps): ReactElement { let {triggerAlert, submitFunction, presets} = props; const [username, setUsername] = useState<string>(presets?.username ?? ""); const [password, setPassword] = useState<string>(presets?.password ?? ""); const [passwordConfirmation, setPasswordConfirmation] = useState<string>(presets?.password ?? ""); const [passwordInformationLength, setPasswordInformationLength] = useState<boolean>(false); const [passwordInformationLowercase, setPasswordInformationLowercase] = useState<boolean>(false); const [passwordInformationUppercase, setPasswordInformationUppercase] = useState<boolean>(false); const [passwordInformationNumber, setPasswordInformationNumber] = useState<boolean>(false); const [passwordsMatch, setPasswordsMatch] = useState<boolean>(true); const reviewPasswordMatch = useCallback((): void => { setPasswordsMatch(password === passwordConfirmation); }, [password, passwordConfirmation]); useEffect(() => { reviewPasswordMatch() }, [reviewPasswordMatch]) const makePasswordInputFitRules = (input: string): [string, boolean] => { input = deleteSpaces(input); if (biggerMaxStrLength(input, MAX_PASSWORD_LENGTH)) { triggerAlert(DEFAULT_ALERT_DURATION, "warning", "Maximum password length exceeded. Input was undone."); return [input, false]; } return [input, true]; } const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => { event.preventDefault(); let newValue: string; let [stringValue, isOK]: [string, boolean] = makePasswordInputFitRules(event.target.value); if (!isOK) { newValue = password; } else { newValue = stringValue } setPasswordInformationLength(!notMinStrLength(newValue, MIN_PASSWORD_LENGTH)); setPasswordInformationLowercase(newValue.match(/[a-z]/) !== null); setPasswordInformationUppercase(newValue.match(/[A-Z]/) !== null); setPasswordInformationNumber(newValue.match(/\d/) !== null); setPassword(newValue) } const handlePasswordConfirmationChange = async (event: ChangeEvent<HTMLInputElement>) => { event.preventDefault(); let newValue: string; const [stringValue, isOK]: [string, boolean] = makePasswordInputFitRules(event.target.value); if (!isOK) { newValue = passwordConfirmation; } else { newValue = stringValue } setPasswordConfirmation(newValue); } const handleSubmit = async (event: FormEvent) => { event.preventDefault(); console.log("[UserInformationInput] handleSubmit") reviewPasswordMatch(); let newUser = {username: username, password: password, passwordConfirmation: passwordConfirmation} submitFunction(newUser) } return ( <Form onSubmit={handleSubmit}> <FormGroup controlId="formBasicUsername"> <Form.Label>Username</Form.Label> <Form.Control type={"name"} value={username} onChange={event => setUsername(event.target.value)}/> </FormGroup> <Form.Group controlId="formBasicPassword"> <Form.Label>Password</Form.Label> <Form.Control type="password" placeholder="Must contain one number, uppercase & lowercase letter each" value={password} onChange={(event: ChangeEvent<HTMLInputElement>) => handlePasswordChange(event)}/> <div> <img alt={"status icon password length"} src={passwordInformationLength ? check_svg : info_svg}/> <span className={"sr-only"}>{passwordInformationLength ? "Done: " : "Missing: "}</span> <span className={passwordInformationLength ? "text-success" : "text-muted"}>Passwords must be between 8 and 20 characters.</span> </div> <div> <img alt={"status icon password contains uppercase character"} src={passwordInformationUppercase ? check_svg : info_svg}/> <span className={"sr-only"}>{passwordInformationUppercase ? "Done: " : "Missing: "}</span> <span className={passwordInformationUppercase ? "text-success" : "text-muted"}>Passwords must be at least contain 1 uppercase character.</span> </div> <div> <img alt={"status icon password contains lowercase character"} src={passwordInformationLowercase ? check_svg : info_svg}/> <span className={"sr-only"}>{passwordInformationLowercase ? "Done: " : "Missing: "}</span> <span className={passwordInformationLowercase ? "text-success" : "text-muted"}>Passwords must be at least contain 1 lowercase character.</span> </div> <div> <img alt={"status icon password contains number"} src={passwordInformationNumber ? check_svg : info_svg}/> <span className={"sr-only"}>{passwordInformationNumber ? "Done: " : "Missing: "}</span> <span className={passwordInformationNumber ? "text-success" : "text-muted"}>Passwords must be at least contain 1 number.</span> </div> </Form.Group> <Form.Group controlId="formConfirmPassword"> <Form.Label>Re-enter password</Form.Label> <Form.Control type="password" value={passwordConfirmation} onChange={(event: ChangeEvent<HTMLInputElement>) => handlePasswordConfirmationChange(event)}/> <div> <img alt={"status icon passwords match"} src={!passwordConfirmation ? info_svg : passwordsMatch ? check_svg : error_svg}/> <span className={"sr-only"}>{passwordsMatch ? "Done: " : "Missing: "}</span> <span className={!passwordConfirmation ? "text-muted" : passwordsMatch ? "text-success" : "text-danger"}>Passwords must match.</span> </div> </Form.Group> <Button variant="primary" type="submit"> Submit </Button> </Form> ) } |