Files
turnosxpress/txclient/src/app/components/Home/Login/Login.tsx
T
2026-07-16 20:48:43 -03:00

478 lines
22 KiB
TypeScript

"use client";
import { useSessionStore, useSessionTokenStore } from "@store/Sesion.Store";
import { ApiError } from "@models/Server.Error.model";
import { ISession } from "@models/Session.model";
import EvangelizeBanner from "@components/EvangelizeBanner/EvangelizeBanner";
import {
login,
loginAndVerificate,
recoveryAccountWithCode,
sendRecoveryCode,
} from "@services/Session.Login";
import Checkbox from "@mui/material/Checkbox";
import Textbox from "@components/Textbox/Textbox";
import Button from "@components/Button/Button";
import ButtonGoogle from "./LoginGoogle";
import { GoogleOAuthProvider } from "@react-oauth/google";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import * as Yup from "yup";
import { useAlert } from "@store/Alert.Store";
import Link from "next/link";
import AnimatedContainer from "@components/AnimatedConainer/AnimatedContainer";
import { LOGIN_ACTIONS, useLoginActionStore } from "@core/Store/LoginAction.Store";
import HeaderConfProvider from "../../HeaderConfProvider/HeaderConfProvider";
import { EVENT_TYPES, useEventHandlerStore } from "@core/Store/EventHandler.Store";
import { ScrollToTop } from "@core/app/components/ScrollTop";
import { useNavigation } from "@core/app/hooks/goto";
interface LoginProps {
verification?: boolean;
recovery?: boolean;
recoveryCode?: boolean;
}
export default function Login(props: LoginProps) {
const { verification = false, recovery = false, recoveryCode = false } = props;
const router = useRouter();
const loginAction = useLoginActionStore();
const SessionInfo = useSessionStore();
const SessionToken = useSessionTokenStore();
const alert = useAlert();
const eventHandler = useEventHandlerStore();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [verificationCode, setVerificationCode] = useState("");
const [checkReadTerms, setCheckReadTerms] = useState(false);
const clientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "";
const { goTo } = useNavigation();
const createSession = (userSession: ISession, msg: string) => {
SessionInfo.setUser(userSession);
SessionToken.setToken(userSession.userToken);
SessionInfo.setLoginState("success");
alert.showSuccess(msg);
};
const manageLoginActions = () => {
const toUrl = process.env.NEXT_PUBLIC_DEFAULT_PATH_AFTER_LOGIN || "/";
if (loginAction.action !== LOGIN_ACTIONS.NONE) {
goTo(loginAction.url);
loginAction.clear();
} else {
if (SessionInfo.subscription && SessionInfo.subscription.plan) {
goTo("/landing/dashboard");
return;
}
goTo(toUrl);
}
};
const clearSession = (msg: string) => {
SessionInfo.clear();
SessionToken.setToken("");
alert.showError(msg);
SessionInfo.setLoginState("error");
};
const verificateLogin = () => {
const schema = Yup.object().shape({
verificationCode: Yup.string()
.length(6, "El código de verificacion debe tener 6 digitos")
.required("El código de verificacion es obligatorio."),
password: Yup.string()
.min(8, "La contraseña debe tener al menos 8 caracteres.")
.required("El campo de contraseña es obligatorio."),
email: Yup.string()
.email("Debe ingresar un correo electrónico válido.")
.required("El campo de correo electrónico es obligatorio."),
});
eventHandler.setEventType(EVENT_TYPES.LOADING);
schema
.validate({ email, password, verificationCode }, { abortEarly: true, strict: true })
.then(() => {
SessionInfo.setLoginState("started");
loginAndVerificate(email, password, verificationCode)
.then((userSession: ISession) => {
createSession(
userSession,
"Registro compleatado. Bienvenido a turnosXpress."
);
})
.catch((error) => {
clearSession(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
})
.catch((error) => {
const e = error as Yup.ValidationError;
clearSession("Ha ocurrido un error. Por favor intentelo nuevamente. " + e.message);
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
const sendRecoveryMail = () => {
const schema = Yup.object().shape({
email: Yup.string()
.email("Debe ingresar un correo electrónico válido.")
.required("El campo de correo electrónico es obligatorio."),
});
eventHandler.setEventType(EVENT_TYPES.LOADING);
schema
.validate({ email }, { abortEarly: true, strict: true })
.then(() => {
SessionInfo.setLoginState("started");
sendRecoveryCode(email)
.then(() => {
alert.showSuccess(
"Se ha enviado un correo de recuperación a la cuenta indicada."
);
setTimeout(() => {
router.push("/landing/recover-account/verify");
}, 1000);
})
.catch((error) => {
clearSession(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
})
.catch((error) => {
const e = error as Yup.ValidationError;
clearSession(e.message);
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
const recoveryAccount = () => {
const schema = Yup.object().shape({
email: Yup.string()
.email("Debe ingresar un correo electrónico válido.")
.required("El campo de correo electrónico es obligatorio."),
verificationCode: Yup.string()
.length(6, "El código de verificación debe tener 6 digitos")
.required("El código de verificacion es obligatorio."),
password: Yup.string()
.min(8, "La contraseña debe tener al menos 8 caracteres.")
.required("El campo de contraseña es obligatorio."),
});
eventHandler.setEventType(EVENT_TYPES.LOADING);
schema
.validate({ email, verificationCode, password }, { abortEarly: true, strict: true })
.then(() => {
recoveryAccountWithCode(email, password, verificationCode)
.then(() => {
alert.showSuccess("Se ha cambiado la contraseña de la cuenta indicada.");
setTimeout(() => {
goTo("/landing/login");
}, 1000);
})
.catch((error) => {
clearSession(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
})
.catch((error) => {
const e = error as Yup.ValidationError;
clearSession(e.message);
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
const iniciarSesion = () => {
const schema = Yup.object().shape({
email: Yup.string()
.email("Debe ingresar un correo electrónico válido.")
.required("El campo de correo electrónico es obligatorio."),
password: Yup.string()
.min(8, "La contraseña debe tener al menos 8 caracteres.")
.required("El campo de contraseña es obligatorio."),
});
eventHandler.setEventType(EVENT_TYPES.LOADING);
schema
.validate({ email, password }, { abortEarly: false })
.then(() => {
SessionInfo.setLoginState("started");
login(email, password)
.then((userSession: ISession) => {
createSession(userSession, "Has iniciado sesión correctamente!");
})
.catch((error: ApiError) => {
clearSession(error.format());
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
})
.catch((error) => {
let errorDesc = "";
if (error instanceof Yup.ValidationError) {
const e: Yup.ValidationError = error as Yup.ValidationError;
errorDesc = e.errors.reduce((prev, curr) => prev + " " + curr, "");
} else {
errorDesc = "Ha ocurrido un error. Por favor intentelo nuevamente.";
}
clearSession(errorDesc);
})
.finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
useEffect(() => {
if (SessionInfo.loged) {
manageLoginActions();
}
}, [SessionInfo.loged]);
return (
<AnimatedContainer
color="#aeaeae"
minSize={150}
maxSize={500}
items={10}
style={{
minHeight: "100vh",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
background:
"linear-gradient(180deg, var(--wine-darkest) 0%, var(--wine-dark) 100%)",
}}
>
<ScrollToTop />
<div className="homeCentered">
<HeaderConfProvider />
<GoogleOAuthProvider clientId={clientId}>
<div
style={{
paddingLeft: "20px",
paddingRight: "20px",
translate: "0px -30px",
}}
>
<div className="card">
<div
style={{
textAlign: "center",
paddingBottom: "30px",
paddingTop: "20px",
position: "relative",
}}
>
{verification && (
<>
<h1 className="homeTitleHeader">Finalizar registro</h1>
<p>
Hemos enviado un correo electronico a tu cuenta con el
código de verificación para completar el registro.{" "}
<strong>Por favor revisa tu bandeja de entrada.</strong>
</p>
</>
)}
{recovery && (
<>
<h1 className="homeTitleHeader">Reestablecer clave</h1>
<p>
Te enviaremos un correo electrónico a la dirección
registrada con tu cuenta. Asegúrate de proporcionarnos
el mismo correo con el que te registraste.{" "}
<strong>
Revisa tu bandeja de entrada y, si no lo encuentras,
también la carpeta de spam. Luego, sigue las
instrucciones.
</strong>
</p>
</>
)}
{recoveryCode && (
<>
<h1 className="homeTitleHeader">Recuperar el acceso</h1>
<p>
Hemos enviado un correo electrónico a tu cuenta con el
código de verificación para completar el proceso de
recuperación.{" "}
<strong>
Ingresa tu email, la nueva clave y el código de
verificación que te enviamos.
</strong>
</p>
</>
)}
{!verification && !recovery && !recoveryCode && (
<h1 className="homeTitleHeader">Ingresar</h1>
)}
<Textbox
name="name"
placeholder="Email"
type="text"
value={email}
width="100%"
onChange={(e) => {
setEmail(e.target.value);
}}
onKeyUp={(e) => {
if (!verification && !recovery && !recoveryCode) {
if (e.key === "Enter") {
document.getElementById("password")?.focus();
}
}
}}
/>
{!recovery && (
<Textbox
name="password"
placeholder="Clave"
type="password"
value={password}
width="100%"
onChange={(e) => {
setPassword(e.target.value);
}}
onKeyUp={(e) => {
if (!verification && !recovery && !recoveryCode) {
if (e.key === "Enter") {
iniciarSesion();
}
}
}}
/>
)}
{(verification || recoveryCode) && (
<Textbox
placeholder="Código de verificaion"
type="text"
value={verificationCode}
width="100%"
onChange={(e) => {
setVerificationCode(e.target.value);
}}
/>
)}
{verification && (
<Button
name="btnLogin"
text="Verificar"
width="100%"
onClick={verificateLogin}
style={{ marginTop: "20px" }}
type="submit"
/>
)}
{recovery && (
<Button
name="btnLogin"
text="Enviar email"
width="100%"
onClick={sendRecoveryMail}
style={{ marginTop: "20px" }}
type="submit"
/>
)}
{recoveryCode && (
<Button
name="btnLogin"
text="Cambiar clave"
width="100%"
onClick={recoveryAccount}
style={{ marginTop: "20px" }}
type="submit"
/>
)}
{!verification && !recovery && !recoveryCode && (
<Button
name="btnLogin"
text="Ingresar"
width="100%"
onClick={iniciarSesion}
style={{ marginTop: "20px" }}
type="submit"
/>
)}
{!verification && !recovery && !recoveryCode && (
<div>
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "flex-start",
justifyContent: "flex-start",
}}
>
<Checkbox
checked={checkReadTerms}
onClick={() => setCheckReadTerms(!checkReadTerms)}
/>
<div style={{ marginTop: "8px" }}>
Declaro que acepto los siguientes&nbsp;
<Link href="/landing/terms">
Términos y condiciones
</Link>{" "}
y{" "}
<Link href="/landing/privacy">
Políticas de privacidad
</Link>
</div>
</div>
<ButtonGoogle termsReaded={checkReadTerms} />
</div>
)}
{!recoveryCode && (
<p style={{ marginTop: "20px" }}>
No tienes una cuenta?&nbsp;
<Link href="/landing/signup">Registrate!</Link>
</p>
)}
{!recovery && !recoveryCode && (
<Link
href="/landing/recover-account"
style={{ display: "block", marginTop: "10px" }}
>
Olvide mi clave!
</Link>
)}
{recovery && !recoveryCode && (
<Link
href="/landing/recover-account/verify"
style={{ display: "block", marginTop: "10px" }}
>
Ya tengo el código de verificación!
</Link>
)}
</div>
</div>
</div>
</GoogleOAuthProvider>
</div>
<EvangelizeBanner variant="popup" delay={4000} />
</AnimatedContainer>
);
}