// Components import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import TextInput from "../../../Components/Inputs/TextInput"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import PasswordTooltip from "../components/PasswordTooltip"; // Utils import { useTheme } from "@emotion/react"; import { useTranslation } from "react-i18next"; import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { useDispatch, useSelector } from "react-redux"; import { useParams } from "react-router-dom"; import { networkService } from "../../../main"; import { newOrChangedCredentials } from "../../../Validation/validation"; import { register } from "../../../Features/Auth/authSlice"; import AuthPageWrapper from "../components/AuthPageWrapper"; import { createToast } from "../../../Utils/toastUtils"; import PropTypes from "prop-types"; const getFeedbackStatus = (form, errors, field, criteria) => { const fieldErrors = errors?.[field]; const isFieldEmpty = form?.[field]?.length === 0; const hasError = fieldErrors?.includes(criteria) || fieldErrors?.includes("empty"); const isCorrect = !isFieldEmpty && !hasError; if (isCorrect) { return "success"; } else if (hasError) { return "error"; } else { return "info"; } }; const Register = ({ superAdminExists }) => { // Redux const { isLoading } = useSelector((state) => state.auth); // Local state const [form, setForm] = useState({ firstName: "", lastName: "", email: "", password: "", confirm: "", role: [], teamId: "", }); const [errors, setErrors] = useState({}); const [feedback, setFeedback] = useState({}); // Hooks const theme = useTheme(); const { t } = useTranslation(); const { token } = useParams(); const navigate = useNavigate(); const dispatch = useDispatch(); // Effects useEffect(() => { const fetchInvite = async () => { if (token !== undefined) { try { const res = await networkService.verifyInvitationToken(token); const invite = res.data.data; const { email } = invite; setForm((prevForm) => { if (!prevForm.email) { return { ...prevForm, email }; } return prevForm; }); } catch (error) { navigate("/register", { replace: true }); } } }; fetchInvite(); }, [form, token, navigate]); // Handlers const onChange = (e) => { let { name, value } = e.target; if (name === "email") value = value.toLowerCase(); const updatedForm = { ...form, [name]: value }; const { error } = newOrChangedCredentials.validate( { [name]: value }, { abortEarly: false, context: { password: form.password } } ); setErrors((prev) => ({ ...prev, [name]: error?.details?.[0]?.message || "", })); setForm(updatedForm); }; const onPasswordChange = (e) => { const { name, value } = e.target; const updatedForm = { ...form, [name]: value }; setForm(updatedForm); const validateValue = { [name]: value }; const validateOptions = { abortEarly: false, context: { password: form.password } }; if (name === "password" && form.confirm.length > 0) { validateValue.confirm = form.confirm; validateOptions.context = { password: value }; } else if (name === "confirm") { validateValue.password = form.password; } const { error } = newOrChangedCredentials.validate(validateValue, validateOptions); const pwdErrors = error?.details.map((error) => ({ path: error.path[0], type: error.type, })); const errorsByPath = pwdErrors && pwdErrors.reduce((acc, { path, type }) => { if (!acc[path]) { acc[path] = []; } acc[path].push(type); return acc; }, {}); const oldErrors = { ...errors }; if (name === "password") { oldErrors.password = undefined; } else if (name === "confirm") { oldErrors.confirm = undefined; } const newErrors = { ...oldErrors, ...errorsByPath }; setErrors(newErrors); const newFeedback = { length: getFeedbackStatus(updatedForm, errorsByPath, "password", "string.min"), special: getFeedbackStatus(updatedForm, errorsByPath, "password", "special"), number: getFeedbackStatus(updatedForm, errorsByPath, "password", "number"), uppercase: getFeedbackStatus(updatedForm, errorsByPath, "password", "uppercase"), lowercase: getFeedbackStatus(updatedForm, errorsByPath, "password", "lowercase"), confirm: getFeedbackStatus(updatedForm, errorsByPath, "confirm", "different"), }; setFeedback(newFeedback); }; const onSubmit = async (e) => { e.preventDefault(); const toSubmit = { ...form, role: superAdminExists ? form.role : ["superadmin"], inviteToken: token ? token : "", }; const { error } = newOrChangedCredentials.validate(toSubmit, { abortEarly: false, context: { password: form.password }, }); if (error) { const formErrors = {}; for (const err of error.details) { formErrors[err.path[0]] = err.message; } setErrors(formErrors); return; } delete toSubmit.confirm; const action = await dispatch(register(toSubmit)); if (action.payload.success) { navigate("/uptime"); createToast({ body: t("auth.registration.toasts.success"), }); } else { if (action.payload) { createToast({ body: action.payload.msg, }); } else { createToast({ body: t("common.toasts.unknownError"), }); } } }; return ( {superAdminExists ? t("auth.registration.description.user") : t("auth.registration.description.superAdmin")} (e.target.value = e.target.value.toLowerCase())} onChange={onChange} error={errors.email ? true : false} helperText={errors.email ? t(errors.email) : ""} // Localization keys are in validation.js /> ); }; Register.propTypes = { superAdminExists: PropTypes.bool, }; export default Register;