This commit is contained in:
Alex Holliday committed 2026-02-06 21:35:25 +00:00
1 parent 514570da78
commit 8f2072e497
6 files changed
+3 -222

No files matched your search

@@ -1,22 +0,0 @@
// Hook to avoid double submits and manage loading state
import { useState, useCallback } from "react";
const useLoadingSubmit = () => {
const [submitting, setSubmitting] = useState(false);
const executeSubmit = useCallback(
async (submitFunction) => {
if (submitting) return;
setSubmitting(true);
try {
return await submitFunction();
} finally {
setSubmitting(false);
}
},
[submitting]
);
return { submitting, executeSubmit };
};
export default useLoadingSubmit;
@@ -1,19 +0,0 @@
import { useState } from "react";
const useLoginForm = () => {
const [form, setForm] = useState({
email: "",
password: "",
});
const onChange = (e) => {
let { name, value } = e.target;
if (name === "email") {
value = value.toLowerCase();
}
const updatedForm = { ...form, [name]: value };
setForm(updatedForm);
};
return [form, onChange];
};
export default useLoginForm;
@@ -1,40 +0,0 @@
import { useDispatch } from "react-redux";
import { login } from "../../../../Features/Auth/authSlice.js";
import { useNavigate } from "react-router-dom";
import { createToast } from "../../../../Utils/toastUtils.jsx";
import { useTranslation } from "react-i18next";
const useLoginSubmit = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { t } = useTranslation();
const handleLoginSubmit = async (form, setErrors) => {
const action = await dispatch(login(form));
if (action.payload.success) {
navigate("/uptime");
createToast({
body: t("auth.login.toasts.success"),
});
} else {
if (action.payload) {
if (action.payload.msg === "Incorrect password")
setErrors({
password: t("auth.login.errors.password.incorrect"),
});
// dispatch errors
createToast({
body: t("auth.login.toasts.incorrectPassword"),
});
} else {
// unknown errors
createToast({
body: t("common.toasts.unknownError"),
});
}
}
};
return [handleLoginSubmit];
};
export default useLoginSubmit;
@@ -1,31 +0,0 @@
import { useState } from "react";
import { loginCredentials } from "../../../../Validation/validation.js";
const useValidateLoginForm = () => {
const [errors, setErrors] = useState({
email: "",
password: "",
});
const validateField = (name, value) => {
const { error } = loginCredentials.validate({ [name]: value });
setErrors((prev) => ({
...prev,
[name]: error?.details?.[0]?.message || "",
}));
};
const validateForm = (form) => {
const { error } = loginCredentials.validate(form, { abortEarly: false });
if (error) {
const formErrors = {};
for (const err of error.details) {
formErrors[err.path[0]] = err.message;
}
setErrors(formErrors);
return false;
}
return true;
};
return [errors, setErrors, validateField, validateForm];
};
export default useValidateLoginForm;
+3 -8
View File
@@ -19,7 +19,7 @@ const LoginPage = () => {
const { schema, defaults } = useLoginForm();
const { control, handleSubmit, setError } = useForm<LoginFormData>({
const { control, handleSubmit } = useForm<LoginFormData>({
resolver: zodResolver(schema),
defaultValues: defaults,
});
@@ -30,13 +30,8 @@ const LoginPage = () => {
const result = await post("/auth/login", data);
if (result?.success) {
console.log(result);
// dispatch(setAuthState(result));
// navigate("/uptime");
} else if (result?.msg === "Incorrect password") {
setError("password", {
message: "auth.login.errors.password.incorrect",
});
dispatch(setAuthState(result));
navigate("/uptime");
}
};
-102
View File
@@ -1,102 +0,0 @@
// Components
import Stack from "@mui/material/Stack";
import Button from "@mui/material/Button";
import TextInput from "@/Components/v1/Inputs/TextInput/index.jsx";
import { PasswordEndAdornment } from "@/Components/v1/Inputs/TextInput/Adornments/index.jsx";
import TextLink from "@/Components/v1/TextLink/index.jsx";
import AuthPageWrapper from "../components/AuthPageWrapper.jsx";
// Utils
import { useTheme } from "@mui/material/styles";
import { useTranslation } from "react-i18next";
import useLoginForm from "./hooks/useLoginForm.jsx";
import useValidateLoginForm from "./hooks/useValidateLoginForm.jsx";
import useLoginSubmit from "./hooks/useLoginSubmit.jsx";
import useLoadingSubmit from "./hooks/useLoadingSubmit.jsx";
const Login = () => {
// Hooks
const { t } = useTranslation();
const theme = useTheme();
const [form, onChange] = useLoginForm();
const [errors, setErrors, validateField, validateForm] = useValidateLoginForm();
const [handleLoginSubmit] = useLoginSubmit();
const { submitting, executeSubmit } = useLoadingSubmit();
// Handlers
const handleChange = (e) => {
onChange(e);
validateField(e.target.name, e.target.value);
};
const onSubmit = async (e) => {
e.preventDefault();
const isValid = validateForm(form);
if (!isValid) return;
await executeSubmit(() => handleLoginSubmit(form, setErrors));
};
return (
<AuthPageWrapper
welcome={t("auth.login.welcome")}
heading={t("auth.login.heading")}
>
<Stack
component="form"
width="100%"
padding={theme.spacing(8)}
gap={theme.spacing(12)}
onSubmit={onSubmit}
sx={{
width: {
sm: "80%",
md: "70%",
lg: "65%",
xl: "65%",
},
}}
>
<TextInput
type="email"
name="email"
label={t("auth.common.inputs.email.label")}
placeholder={t("auth.common.inputs.email.placeholder")}
autoComplete="email"
value={form.email}
onChange={handleChange}
error={errors.email ? true : false}
helperText={errors.email ? t(errors.email) : ""} // Localization keys are in validation.js
/>
<TextInput
type="password"
name="password"
label={t("auth.common.inputs.password.label")}
placeholder="••••••••••"
autoComplete="current-password"
value={form.password}
onChange={handleChange}
error={errors.password ? true : false}
helperText={errors.password ? t(errors.password) : ""} // Localization keys are in validation.js
endAdornment={<PasswordEndAdornment />}
/>
<Button
variant="contained"
color="accent"
type="submit"
sx={{ width: "100%", alignSelf: "center", fontWeight: 700 }}
loading={submitting}
>
Login
</Button>
</Stack>
<TextLink
text={t("auth.login.links.forgotPassword")}
linkText={t("auth.login.links.forgotPasswordLink")}
href="/forgot-password"
/>
<TextLink
text={t("auth.login.links.register")}
linkText={t("auth.login.links.registerLink")}
href="/register"
/>
</AuthPageWrapper>
);
};
export default Login;