From 40a783d6165c7ef66fbbbef5955ab5bb827fea12 Mon Sep 17 00:00:00 2001 From: RafaUC Date: Thu, 4 Jul 2024 10:03:54 -0600 Subject: [PATCH] implementados el componente Error Display --- cosiap_api/cosiap_api/settings.py | 4 +-- cosiap_api/users/views.py | 6 ++-- .../src/components/common/ui/ErrorDisplay.css | 0 .../src/components/common/ui/ErrorDisplay.jsx | 36 +++++++++++++++++++ .../common/ui/ErrorDisplay.utils.js | 14 ++++++++ .../src/components/common/ui/FormInput.jsx | 13 ++++--- .../users/LoginPage/LoginContainer.jsx | 2 +- .../components/users/LoginPage/LoginForm.jsx | 16 +++++---- .../components/users/LoginPage/loginInput.jsx | 15 ++++---- 9 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 cosiap_frontend/src/components/common/ui/ErrorDisplay.css create mode 100644 cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx create mode 100644 cosiap_frontend/src/components/common/ui/ErrorDisplay.utils.js diff --git a/cosiap_api/cosiap_api/settings.py b/cosiap_api/cosiap_api/settings.py index 8b3015d..68e6856 100644 --- a/cosiap_api/cosiap_api/settings.py +++ b/cosiap_api/cosiap_api/settings.py @@ -184,8 +184,8 @@ SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), - 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=0.5), + 'REFRESH_TOKEN_LIFETIME': timedelta(minutes=1), 'ROTATE_REFRESH_TOKENS': False, 'BLACKLIST_AFTER_ROTATION': False, 'ALGORITHM': 'HS256', diff --git a/cosiap_api/users/views.py b/cosiap_api/users/views.py index 8e869c8..4252bbe 100644 --- a/cosiap_api/users/views.py +++ b/cosiap_api/users/views.py @@ -45,10 +45,8 @@ class CustomTokenObtainPairView(TokenObtainPairView): # Eliminar el refresh token de la respuesta JSON del response.data['refresh'] # Agregar mensaje de éxito - response.data['message'] = {'succes':'Login successful'} - else: - response.data['errors'] = response.data # Mover errores a la clave 'errors' - response.data['message'] = {'error':'Login failed'} + response.data['message'] = {'succes':'Login exitoso'} + return response class CustomTokenRefreshView(TokenRefreshView): diff --git a/cosiap_frontend/src/components/common/ui/ErrorDisplay.css b/cosiap_frontend/src/components/common/ui/ErrorDisplay.css new file mode 100644 index 0000000..e69de29 diff --git a/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx b/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx new file mode 100644 index 0000000..ebcada8 --- /dev/null +++ b/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx @@ -0,0 +1,36 @@ +import PropTypes from 'prop-types'; + + +export const ErrorDisplay = ({ errors }) => { + if (!errors) return null; + + return ( +
+ {renderErrors(errors)} +
+ ); +}; + +const renderErrors = (errors) => { + if (typeof errors === 'string') { + return

{errors}

; + } else if (Array.isArray(errors)) { + return errors.map((error, index) =>

{error}

); + } else if (typeof errors === 'object' && !Array.isArray(errors)) { + return Object.values(errors).map((errorList, index) => ( +
+ {errorList.map((error, idx) =>

{error}

)} +
+ )); + } +}; + +ErrorDisplay.propTypes = { + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) +}; + +export default ErrorDisplay; \ No newline at end of file diff --git a/cosiap_frontend/src/components/common/ui/ErrorDisplay.utils.js b/cosiap_frontend/src/components/common/ui/ErrorDisplay.utils.js new file mode 100644 index 0000000..2b9ed51 --- /dev/null +++ b/cosiap_frontend/src/components/common/ui/ErrorDisplay.utils.js @@ -0,0 +1,14 @@ +export function mergeErrors(errorList) { + // Filtrar y eliminar elementos undefined del array + const filteredErrors = errorList.filter(error => error !== undefined); + + return filteredErrors.reduce((acc, error) => { + Object.keys(error).forEach(key => { + if (!acc[key]) { + acc[key] = []; + } + acc[key] = acc[key].concat(error[key]); + }); + return acc; + }, {}); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/common/ui/FormInput.jsx b/cosiap_frontend/src/components/common/ui/FormInput.jsx index 7d397a5..3ac82c1 100644 --- a/cosiap_frontend/src/components/common/ui/FormInput.jsx +++ b/cosiap_frontend/src/components/common/ui/FormInput.jsx @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; +import {ErrorDisplay} from '@/components/common/ui/ErrorDisplay' -export function FormInput({ id, name, type, placeholder, className, register, error }) { +export function FormInput({ id, name, type, placeholder, className, register, errors }) { return (
- {error &&
{error.message}
} +
); } @@ -20,8 +21,12 @@ FormInput.propTypes = { id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, type: PropTypes.string.isRequired, - placeholder: PropTypes.string.isRequired, + placeholder: PropTypes.string, className: PropTypes.string, register: PropTypes.func.isRequired, - error: PropTypes.object, + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) }; \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/LoginPage/LoginContainer.jsx b/cosiap_frontend/src/components/users/LoginPage/LoginContainer.jsx index 039145b..c15abd2 100644 --- a/cosiap_frontend/src/components/users/LoginPage/LoginContainer.jsx +++ b/cosiap_frontend/src/components/users/LoginPage/LoginContainer.jsx @@ -5,7 +5,7 @@ export function LoginContainer() {
= 640 ? "absolute" : "relative", diff --git a/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx b/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx index 93ec644..a9ab1fe 100644 --- a/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx +++ b/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx @@ -3,17 +3,20 @@ import * as Yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; import api from "@/api"; // Asegúrate de importar tu instancia de API import {LoginInput} from '@/components/users/LoginPage/loginInput' +import { useState } from "react"; +import {ErrorDisplay} from '@/components/common/ui/ErrorDisplay' const CURP_REGEX = /^[A-Z]{1}[AEIOU]{1}[A-Z]{2}[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[HM]{1}(AS|BC|BS|CC|CH|CL|CM|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS|NE)[B-DF-HJ-NP-TV-Z]{3}[0-9A-Z]{1}[0-9]{1}$/; const validationSchema = Yup.object({ curp: Yup.string() - .matches(CURP_REGEX, "CURP inválida") + .matches(CURP_REGEX, "CURP inválido") .required("Requerido"), password: Yup.string().required("Requerido"), }); export function LoginForm() { + const [loginError, setLoginError] = useState('') const { register, handleSubmit, @@ -21,7 +24,7 @@ export function LoginForm() { } = useForm({ resolver: yupResolver(validationSchema), }); - + const onSubmit = async (data) => { try { const response = await api.usuarios.token.login(data); @@ -29,26 +32,27 @@ export function LoginForm() { // Manejar la respuesta exitosa aquí } catch (error) { console.error("Login failed:", error); - // Manejar el error aquí + setLoginError(error.response.data.detail) } }; return (
-
+ +