From 53f307a0d452689b8ace4852ff7e4f6d3869628a Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:15:07 +0100 Subject: [PATCH 1/9] =?UTF-8?q?Correcciones=20en=20los=20estilos=20para=20?= =?UTF-8?q?reenviar=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ConfirmRegister/ConfirmRegister.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ConfirmRegister/ConfirmRegister.css b/src/components/ConfirmRegister/ConfirmRegister.css index 0393083..03330a7 100644 --- a/src/components/ConfirmRegister/ConfirmRegister.css +++ b/src/components/ConfirmRegister/ConfirmRegister.css @@ -42,6 +42,10 @@ padding: 0; /* Sin relleno */ } + .resend-button:hover { + @apply bg-transparent text-tertiary; + } + .resend-button:disabled { cursor: not-allowed; color: #d1d5db; /* Gris claro cuando está deshabilitado */ From 2395d0c89d6eb43eb619dc3d85d6cbcc700df4e4 Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:16:01 +0100 Subject: [PATCH 2/9] =?UTF-8?q?Estandarizaci=C3=B3n=20de=20los=20mensajes?= =?UTF-8?q?=20de=20notificaci=C3=B3n=20(error/=C3=A9xito)=20en=20formulari?= =?UTF-8?q?os?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.css | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/index.css b/src/index.css index 1ce6e42..15a892d 100644 --- a/src/index.css +++ b/src/index.css @@ -9,10 +9,10 @@ src: url("./assets//fonts/Montserrat-VariableFont_wght.ttf") format("truetype"); } -body { +/* body { */ /* Reglas para ajustar siempre la versión mobile a un tamaño máximo y al centro */ /* @apply max-w-[375px] w-full mx-auto */ -} +/* } */ .container-shadow { box-shadow: 0 -1px 15px rgba(0, 0, 0, 0.2); @@ -40,8 +40,25 @@ button { background-color: #F2EBF7 !important; border-radius: 50%; opacity: 1; - } - .swiper-pagination-bullet-active { +} + +.swiper-pagination-bullet-active { background-color: #FF9D14 !important; transform: scale(1.2); - } \ No newline at end of file +} + +.form__error-validation { + @apply text-red-500 text-xs +} + +.form__notification { + @apply w-fit mt-2 mx-auto px-3 py-1 rounded-md +} + +.form__notification--success { + @apply bg-green-200 text-green-500 +} + +.form__notification--error { + @apply bg-red-200 text-red-500 +} \ No newline at end of file From dee1b3d045431ad8337fe9f2360228d414dccad0 Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:24:02 +0100 Subject: [PATCH 3/9] =?UTF-8?q?Correci=C3=B3n=20de=20issue#52=20y=20correc?= =?UTF-8?q?i=C3=B3n=20al=20mostrar=20las=20notificaciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LoginForm/LoginForm.tsx | 59 +++++++++++++------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/components/LoginForm/LoginForm.tsx b/src/components/LoginForm/LoginForm.tsx index d0d75e0..6da7922 100644 --- a/src/components/LoginForm/LoginForm.tsx +++ b/src/components/LoginForm/LoginForm.tsx @@ -3,12 +3,12 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { LoginSchema, loginSchema } from "../../schemas/login.schema"; import { useContext, useState } from "react"; import { AxiosError } from "axios"; -import { useNavigate } from "react-router-dom"; // Para redirección -import AuthLayout from "../../layout/AuthLayout.tsx"; // Asegúrate de importar el AuthLayout -import "./LoginForm.css"; +import { useNavigate } from "react-router-dom"; +import AuthLayout from "../../layout/AuthLayout.tsx"; import authServices from "../../services/auth.services.ts"; import { AuthContext } from "../../contexts/auth.context.tsx"; import { User } from "../../types/user.ts"; +// import "./LoginForm.css"; const Login: React.FC = () => { const { @@ -24,6 +24,7 @@ const Login: React.FC = () => { // Manejo de notificaciones const [reqError, setReqError] = useState<string | null>(null); const [successNotification, setSuccessNotification] = useState<string | null>(null); + const { setUser } = useContext(AuthContext); const navigate = useNavigate(); @@ -34,25 +35,28 @@ const Login: React.FC = () => { // Si la respuesta es exitosa if (response.status === 200) { - reset(); // Limpiar el formulario setSuccessNotification("Inicio de sesión exitoso"); - console.log(response.data); - // Guardar el token en localStorage o en un estado global (ejemplo) - localStorage.setItem("authToken", response.data.token); + // console.log(response.data); const user: User = { ...response.data.user, _id: response.data.userId, }; - console.log(user); + localStorage.setItem("authToken", response.data.token); localStorage.setItem("user", JSON.stringify(user)); - setUser(user); - + // console.log(user); + // Redirigir después de un tiempo - setTimeout(() => navigate("/"), 2000); + setTimeout(() => { + reset(); // Limpiar el formulario + setUser(user) + navigate("/") + }, 2000); } + + } catch (error) { // Manejo de errores if (error instanceof AxiosError && error.response?.data) { @@ -62,7 +66,8 @@ const Login: React.FC = () => { setReqError(error.response.data.message); } } else { - setReqError("Error desconocido. Por favor intente de nuevo."); + console.log(error) + setReqError("Error en la comunicación con el servidor"); } setTimeout(() => setReqError(null), 5000); } @@ -70,13 +75,6 @@ const Login: React.FC = () => { return ( <AuthLayout> - {/* Mostrar errores globales en la parte superior */} - {reqError && ( - <div className="form__global-error-container"> - <span className="form__error-message">{reqError}</span> - </div> - )} - {/* Formulario de inicio de sesión */} <form onSubmit={handleSubmit(onSubmit)} @@ -90,6 +88,9 @@ const Login: React.FC = () => { id="email" placeholder="john@doe.com" /> + {errors.email && ( + <span className="form__error-validation">{errors.email.message}</span> + )} </div> <div> <label htmlFor="password">Contraseña</label> @@ -99,6 +100,9 @@ const Login: React.FC = () => { id="password" placeholder="••••••••" /> + {errors.password && ( + <span className="form__error-validation">{errors.password.message}</span> + )} </div> <div className="text-right"> <a @@ -124,22 +128,17 @@ const Login: React.FC = () => { </p> </form> - {/* Mostrar errores específicos de cada campo debajo del formulario */} - {errors.email && ( - <div className="form__error-container"> - <span className="form__error-message">{errors.email.message}</span> - </div> - )} - {errors.password && ( - <div className="form__error-container"> - <span className="form__error-message">{errors.password.message}</span> + {/* Mostrar errores globales en la parte superior */} + {reqError && ( + <div className="form__notification form__notification--error"> + <p>{reqError}</p> </div> )} {/* Notificación de éxito */} {successNotification && ( - <div className="form__success-container"> - <span className="form__success-message">{successNotification}</span> + <div className="form__notification form__notification--success"> + <p>{successNotification}</p> </div> )} </AuthLayout> From 3591cd3eb999a90047316ab25b15d28523f6fdf4 Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:27:32 +0100 Subject: [PATCH 4/9] =?UTF-8?q?Adaptaci=C3=B3n=20de=20la=20data=20recibida?= =?UTF-8?q?=20al=20contenido=20y=20correcci=C3=B3n=20del=20tama=C3=B1o=20d?= =?UTF-8?q?el=20logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConfirmationView/ConfirmationView.css | 2 +- .../ConfirmationView/ConfirmationView.tsx | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/ConfirmationView/ConfirmationView.css b/src/components/ConfirmationView/ConfirmationView.css index 49b4577..2567d9f 100644 --- a/src/components/ConfirmationView/ConfirmationView.css +++ b/src/components/ConfirmationView/ConfirmationView.css @@ -1,5 +1,5 @@ .logoClassName { - transform: scale(2.2); /* Escala la imagen al 220% */ + transform: scale(1.5); /* Escala la imagen al 220% */ transition: transform 0.3s ease; /* Suaviza la animación de escala */ object-fit: contain; /* Asegura que la imagen no se recorte ni pierda proporción */ width: 100%; /* Ajusta el tamaño al 100% del contenedor */ diff --git a/src/components/ConfirmationView/ConfirmationView.tsx b/src/components/ConfirmationView/ConfirmationView.tsx index 381b4f7..53f9696 100644 --- a/src/components/ConfirmationView/ConfirmationView.tsx +++ b/src/components/ConfirmationView/ConfirmationView.tsx @@ -3,18 +3,22 @@ import AuthLayout from "../../layout/AuthLayout"; // Importamos AuthLayout import vacationImage from "../../assets/img/vacationImage.png"; // Asegúrate de tener la imagen en esta ruta import { Link } from "react-router-dom"; import './ConfirmationView.css'; +import { useContext } from "react"; +import { ReservationContext } from "../../contexts/reservation.context"; const ConfirmationView = () => { + const { experience, reservation } = useContext(ReservationContext) + return ( - <AuthLayout showText={false} logoClassName="logoClassName" showBackButton={false}> {/* Solo aquí se pasa la clase personalizada */} - <div className="w-full max-w-md"> {/* Ajustamos la altura para que no haya un exceso de margen blanco */} + <AuthLayout showText={false} logoClassName="logoClassName" showTextImage={false} showBackButton={false}> {/* Solo aquí se pasa la clase personalizada */} + <div className="w-full max-w-md p-2"> {/* Ajustamos la altura para que no haya un exceso de margen blanco */} {/* Contenido principal */} <div className="text-center mt-[100px] mb-0"> {/* Ajuste en el margin-top para centrar más el contenido, y eliminamos el margen inferior */} <h2 className="text-lg font-bold text-gray-800 mb-6 text-left">¡Experiencia confirmada!</h2> {/* Información de la reserva */} - <div className="flex items-center justify-start gap-4 mb-4"> + <div className="flex justify-start gap-4 mb-4"> <div className="relative"> <img src={vacationImage} // Aquí se usa la nueva imagen @@ -23,8 +27,8 @@ const ConfirmationView = () => { /> </div> <div> - <p className="text-lg font-semibold text-gray-800">Cocktail en la playa</p> - <p className="text-sm text-gray-600">Order number #837nx38</p> + <p className="text-lg font-semibold text-gray-800">{ experience?.title }</p> + <p className="text-sm text-gray-600"></p> </div> </div> @@ -32,15 +36,15 @@ const ConfirmationView = () => { <div className="text-left mb-12 mt-6 ml-1"> {/* Ajuste de márgenes */} <p className="flex items-center text-dark mb-2"> <FaCalendarAlt className="text-brandYellow mr-2" /> - <span>13 al 15 de noviembre</span> + <span>{ reservation?.bookingDate?.toLocaleDateString() }</span> </p> <p className="flex items-center text-dark mb-2"> <FaClock className="text-brandYellow mr-2" /> - <span>18:00 hs</span> + <span>{ reservation?.bookingDate?.toLocaleTimeString() }</span> </p> <p className="flex items-center text-dark"> <FaMapMarkerAlt className="text-brandYellow mr-2" /> - <span>Malibu Beach, California</span> + <span>{ experience?.location[1] }, { experience?.location[0] }</span> </p> </div> From 0513dfb64c11d5adca76082354105c8ec0138fec Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:36:56 +0100 Subject: [PATCH 5/9] Arreglo estilos --- src/components/ConfirmRegister/ConfirmRegister.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ConfirmRegister/ConfirmRegister.css b/src/components/ConfirmRegister/ConfirmRegister.css index 03330a7..09854ce 100644 --- a/src/components/ConfirmRegister/ConfirmRegister.css +++ b/src/components/ConfirmRegister/ConfirmRegister.css @@ -47,6 +47,7 @@ } .resend-button:disabled { + background-color: transparent; cursor: not-allowed; color: #d1d5db; /* Gris claro cuando está deshabilitado */ } From 04b1c487fcf29d61b600e70ff20e17ec0cc7b265 Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:38:45 +0100 Subject: [PATCH 6/9] =?UTF-8?q?Correcci=C3=B3n=20de=20la=20l=C3=B3gica=20d?= =?UTF-8?q?el=20contexto=20de=20autenticaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/contexts/auth.context.tsx | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/contexts/auth.context.tsx b/src/contexts/auth.context.tsx index fa25e70..269c267 100644 --- a/src/contexts/auth.context.tsx +++ b/src/contexts/auth.context.tsx @@ -20,7 +20,6 @@ type AuthProviderProps = { } const AuthProviderWrapper = ({ children }: AuthProviderProps) => { - const [user, setUser] = useState<User | null>(null) const [isLoading, setIsLoading] = useState(true) @@ -38,6 +37,7 @@ const AuthProviderWrapper = ({ children }: AuthProviderProps) => { const logout = async () => { const token = localStorage.getItem('authToken') + if (token) { try { await authServices.logout(token) @@ -45,34 +45,52 @@ const AuthProviderWrapper = ({ children }: AuthProviderProps) => { console.error("Error during logout:", error) } } + setIsLoading(false) setUser(null) removeToken() + localStorage.clear() + + window.location.href = "/" } const authenticateUser = async (onSuccess = () => { }) => { const token = localStorage.getItem("authToken") - + if (token) { + // Si hay token, intenta verificarlo, por si está caducado o no es correcto try { const { data }: { data: User } = await authServices.verify(token) const storedUser = localStorage.getItem("user") - if(storedUser && JSON.parse(storedUser).email === data.sub) { + // Doble verificación, para saber que el token pertenece al usuario logeado + if (storedUser && JSON.parse(storedUser).email === data.sub) { setUser(JSON.parse(storedUser)) } else { // console.log("Los datos inicio de sesión no coinciden") - logout() + // Este logout no funciona, porque el token no sería válido, tampoco para ejecutar la operación + // logout() + localStorage.clear() } setIsLoading(false) onSuccess() } catch (err) { console.error("Authentication error:", err) - logout() + + localStorage.clear() + // Este logout no funciona, porque el token no sería válido, tampoco para ejecutar la operación + // logout() } } else { - logout() + console.log("NO HAY TOKEN BRO") + + setIsLoading(false) + // Si no hay token, no se puede realizar esta petición, porque necesita de un token + // logout() + localStorage.clear() + + // Simplemente se redirige al Home } } From b73409a93dc29cf5b333e4f1009ccaeccab12c9a Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:40:09 +0100 Subject: [PATCH 7/9] =?UTF-8?q?Correcci=C3=B3n=20mensajes=20de=20notificac?= =?UTF-8?q?i=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Register/Register.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/Register/Register.tsx b/src/components/Register/Register.tsx index d5662cd..3751fef 100644 --- a/src/components/Register/Register.tsx +++ b/src/components/Register/Register.tsx @@ -5,9 +5,9 @@ import { Controller, useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { SignUpSchema, signUpSchema } from "../../schemas/signUp.schema" import AuthLayout from "../../layout/AuthLayout"; -import "./Register.css" import authServices from "../../services/auth.services"; import { countriesPhoneList } from "../../mocks/countriesPhoneList.mock"; +// import "./Register.css" const Register: React.FC = () => { const { @@ -62,15 +62,17 @@ const Register: React.FC = () => { }, 5000) } catch (error) { + if (error instanceof AxiosError) { if (error.response?.data) { - + if (error.response.data.errors) { setReqError(error.response.data.errors) } else { - setReqError([error.response.data.details.message]) + setReqError([error.response.data.message]) } } else { + setReqError([error.message]) } } else { @@ -223,10 +225,11 @@ const Register: React.FC = () => { { reqError.map((e, i) => <p key={`${Date.now()}-${i}`}>{e}</p>) } - </div> - } + </div>} {successNotification && - <p className="form__notification form__notification--success">{successNotification}</p>} + <div className="form__notification form__notification--success"> + <p>{successNotification}</p> + </div>} </AuthLayout > ) } From 290f4024d8804b10755cabd1df5a909b4cea870d Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 08:50:47 +0100 Subject: [PATCH 8/9] Asteriscos en campos obligatorios --- src/components/Register/Register.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Register/Register.tsx b/src/components/Register/Register.tsx index 3751fef..f81b52b 100644 --- a/src/components/Register/Register.tsx +++ b/src/components/Register/Register.tsx @@ -90,7 +90,7 @@ const Register: React.FC = () => { className="w-full flex flex-col gap-3 [&>div]:flex [&>div]:flex-col [&>div]:gap-2 [&_label]:text-sm [&_input]:px-4 [&_input]:py-3 [&_input]:text-sm" > <div> - <label htmlFor="name">Nombre</label> + <label htmlFor="name">Nombre *</label> <input {...register("name")} type="text" @@ -101,7 +101,7 @@ const Register: React.FC = () => { <span className="form__error-validation"> {errors.name.message} </span>} </div> <div> - <label htmlFor="email">Correo electrónico</label> + <label htmlFor="email">Correo electrónico *</label> <input {...register("email")} type="email" @@ -112,7 +112,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.email.message}</span>} </div> <div> - <label htmlFor="password">Contraseña</label> + <label htmlFor="password">Contraseña *</label> <input {...register("password")} type="password" @@ -122,7 +122,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.password.message}</span>} </div> <div> - <label htmlFor="confirmPassword">Repite tu contraseña</label> + <label htmlFor="confirmPassword">Repite tu contraseña *</label> <input {...register("confirmPassword")} type="password" @@ -132,7 +132,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.confirmPassword.message}</span>} </div> <div> - <label htmlFor="location">País</label> + <label htmlFor="location">País *</label> <input {...register("location")} type="text" @@ -142,7 +142,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.location.message}</span>} </div> <div> - <label htmlFor="phone">Teléfono</label> + <label htmlFor="phone">Teléfono *</label> <div className="flex gap-2"> <Controller name="phone.prefix" @@ -175,7 +175,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.phone.number.message}</span>} </div> <div className="relative"> - <label htmlFor="role">Quiero registrarme como...</label> + <label htmlFor="role">Quiero registrarme como... *</label> <select {...register("role")} id="role" @@ -190,7 +190,7 @@ const Register: React.FC = () => { <span className="form__error-validation">{errors.role.message}</span>} </div> <div className="mt-2"> - <label className="!text-xs">Para registrarte en la plataforma debes ser mayor de edad. Al marcar la siguiente casilla confirmas tener al menos 18 años.</label> + <label className="!text-xs">Para registrarte en la plataforma debes ser mayor de edad. Al marcar la siguiente casilla confirmas tener al menos 18 años. *</label> <div className="flex items-center gap-2"> <input {...register("age")} From 52e55e5b2ef548b38d6084bd52db4464b8da520d Mon Sep 17 00:00:00 2001 From: javierhidalgodev <javierhidalgodev@gmail.com> Date: Fri, 6 Dec 2024 12:11:04 +0100 Subject: [PATCH 9/9] =?UTF-8?q?Limitaci=C3=B3n=20de=20caracteres=20en=20no?= =?UTF-8?q?mbre/email=20a=2050?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/schemas/signUp.schema.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/schemas/signUp.schema.ts b/src/schemas/signUp.schema.ts index 4b716fb..979f51d 100644 --- a/src/schemas/signUp.schema.ts +++ b/src/schemas/signUp.schema.ts @@ -5,12 +5,14 @@ export const signUpSchema = z name: z .string() .min(2, "El nombre debe tener al menos 2 caracteres") + .max(50, "El nombre no puede superar los 50 caracteres") .regex(/^[A-Za-záéíóúÁÉÍÓÚñÑ\s]+$/, "Por favor, usa solo letras") .trim() .transform((val) => val.replace(/\s+/g, ' ').trim()), email: z .string() .min(1, "El correo es obligatorio") + .max(50, "El correo electrónico no puede superar los 50 caracteres") .email({ message: "Formato incorrecto: example@demo.com" })