diff --git a/cosiap_api/static/images/LogosGobierno.svg b/cosiap_api/static/images/LogosGobierno.svg new file mode 100644 index 0000000000000000000000000000000000000000..493bf5f663bc78bcfd25f467251e44a8bd5b28d2 --- /dev/null +++ b/cosiap_api/static/images/LogosGobierno.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cosiap_frontend/src/App.jsx b/cosiap_frontend/src/App.jsx index f812c9360be2551044f5cb82be65dbc2629ffbcd..5590358c2306683ecd690a7ff706f3ce4ef8005d 100644 --- a/cosiap_frontend/src/App.jsx +++ b/cosiap_frontend/src/App.jsx @@ -5,22 +5,24 @@ import {Autenticador} from "@/components/common/utility/Autenticador"; import {LoginRequiredRoutes} from "@/components/common/utility/LoginRequiredRoutes" import "./App.css"; -import {LoginPage} from "./components/users/LoginPage/LoginPage"; +import { AuthPage } from "./components/users/AuthPage"; import {InicioTest} from './components/users/InicioTest'; + function App() { return ( Sistema de apoyos COZCyT + {/* Rutas publicas */} - } /> - } /> + } /> + } /> {/* Rutas protegidas */} }> diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index 1330ca3f38cc38abd7e364a0a78d5a1cbeac7780..f324376fb8a68ce887f310b95cfce3cfc2cb9ceb 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -45,11 +45,11 @@ const api = { axios: ax, //Enpoints del modulo Usuario usuarios: { - get: () => ax.get('/usuarios'), - post: (data) => ax.post('/usuarios', data), - getById: (id) => ax.get(`/usuarios/${id}`), - update: (id, data) => ax.put(`/usuarios/${id}`, data), - delete: (id) => ax.delete(`/usuarios/${id}`), + get: () => ax.get('api/usuarios'), + post: (data) => ax.post('api/usuarios/', data), + getById: (id) => ax.get(`api/usuarios/${id}`), + update: (id, data) => ax.put(`api/usuarios/${id}`, data), + delete: (id) => ax.delete(`api/usuarios/${id}`), token: { login: (data) => ax.post('api/usuarios/token/',data), refresh: () => ax.post('api/usuarios/token/refresh/'), diff --git a/cosiap_frontend/src/assets/iconsImg/Eye.svg b/cosiap_frontend/src/assets/iconsImg/Eye.svg new file mode 100644 index 0000000000000000000000000000000000000000..e4bde4b4058263b7ecded94ba4d9cb566ea85506 --- /dev/null +++ b/cosiap_frontend/src/assets/iconsImg/Eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/cosiap_frontend/src/assets/iconsImg/EyeOff.svg b/cosiap_frontend/src/assets/iconsImg/EyeOff.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f2c12aacbe37a92fd83274fdc49074b24512d12 --- /dev/null +++ b/cosiap_frontend/src/assets/iconsImg/EyeOff.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cosiap_frontend/src/assets/iconsImg/password.svg b/cosiap_frontend/src/assets/iconsImg/password.svg new file mode 100644 index 0000000000000000000000000000000000000000..40ad639a875d3efe67bd7fdfdbea12b69f6d47d7 --- /dev/null +++ b/cosiap_frontend/src/assets/iconsImg/password.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cosiap_frontend/src/assets/iconsImg/user.svg b/cosiap_frontend/src/assets/iconsImg/user.svg new file mode 100644 index 0000000000000000000000000000000000000000..f280c166c5b1142da3f970469b072ce6c0ab6582 --- /dev/null +++ b/cosiap_frontend/src/assets/iconsImg/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/cosiap_frontend/src/assets/img/LoginBackground.png b/cosiap_frontend/src/assets/img/LoginBackground.png deleted file mode 100644 index 75fcd72f716057a1c198401dc742370924879ad6..0000000000000000000000000000000000000000 Binary files a/cosiap_frontend/src/assets/img/LoginBackground.png and /dev/null differ diff --git a/cosiap_frontend/src/assets/img/LogosGobierno.png b/cosiap_frontend/src/assets/img/LogosGobierno.png deleted file mode 100644 index 8acbe4105836731b5dd4ffc6ec3406451a6b14aa..0000000000000000000000000000000000000000 Binary files a/cosiap_frontend/src/assets/img/LogosGobierno.png and /dev/null differ diff --git a/cosiap_frontend/src/components/common/ui/FormInput.jsx b/cosiap_frontend/src/components/common/base/FormInput.jsx similarity index 86% rename from cosiap_frontend/src/components/common/ui/FormInput.jsx rename to cosiap_frontend/src/components/common/base/FormInput.jsx index 3ac82c14b9fbfc2c4cd73a52d3387ec9f7c0d601..00adf8963f26d85ff47f065fdcdf3eedbe5e8c90 100644 --- a/cosiap_frontend/src/components/common/ui/FormInput.jsx +++ b/cosiap_frontend/src/components/common/base/FormInput.jsx @@ -1,9 +1,9 @@ import PropTypes from 'prop-types'; import {ErrorDisplay} from '@/components/common/ui/ErrorDisplay' -export function FormInput({ id, name, type, placeholder, className, register, errors }) { +export function FormInput({ id, name, type, placeholder, className, register, errors, onChange }) { return ( -
+ <> -
+ ); } @@ -23,6 +24,7 @@ FormInput.propTypes = { type: PropTypes.string.isRequired, placeholder: PropTypes.string, className: PropTypes.string, + onChange: PropTypes.string, register: PropTypes.func.isRequired, errors: PropTypes.oneOfType([ PropTypes.object, diff --git a/cosiap_frontend/src/components/common/base/FormInputPassword.jsx b/cosiap_frontend/src/components/common/base/FormInputPassword.jsx new file mode 100644 index 0000000000000000000000000000000000000000..cd684e4f4a6b11cd305775ce5a01e317aa63832e --- /dev/null +++ b/cosiap_frontend/src/components/common/base/FormInputPassword.jsx @@ -0,0 +1,51 @@ +import {FormInput} from '@/components/common/base/FormInput.jsx'; +import PropTypes from 'prop-types'; +import { useState } from 'react'; + +export const FormInputPassword = ({ name, placeholder, className, register, errors }) => { + const [showPassword, setShowPassword] = useState(false); + const [inputValue, setInputValue] = useState(''); + + const switchShowPassword = () => { + setShowPassword(!showPassword); + }; + + const handleInputChange = (e) => { + setInputValue(e.target.value); + }; + + return ( + <> + + {inputValue && ( + + )} + + + ); +}; + +FormInputPassword.propTypes = { + name: PropTypes.string.isRequired, + placeholder: PropTypes.string, + className: PropTypes.string, + register: PropTypes.func.isRequired, + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) +}; \ No newline at end of file diff --git a/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx b/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx new file mode 100644 index 0000000000000000000000000000000000000000..53e85fc28a7ea414c09770b1833881d091ab1f3f --- /dev/null +++ b/cosiap_frontend/src/components/common/layouts/LayoutBaseAuthenticator.jsx @@ -0,0 +1,44 @@ + +export default function LayoutBaseAuthenticator({title, children}) { + return ( +
+
+
+ +
+
+ +
+
+
+ +
+
+ {/* Contenido de authentication */} +
+
+
+ company +

+ {title} +

+
+ + {children} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx b/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx index ebcada877ddd525791e2a761db42e2090d3e0a50..1c3f76cc474a5ca69803294bb3f7c373d90a2626 100644 --- a/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx +++ b/cosiap_frontend/src/components/common/ui/ErrorDisplay.jsx @@ -5,7 +5,7 @@ export const ErrorDisplay = ({ errors }) => { if (!errors) return null; return ( -
+
{renderErrors(errors)}
); diff --git a/cosiap_frontend/src/components/users/AuthPage.jsx b/cosiap_frontend/src/components/users/AuthPage.jsx new file mode 100644 index 0000000000000000000000000000000000000000..75bbf61aa25dfada2ef84590ebb79121f36c5a0f --- /dev/null +++ b/cosiap_frontend/src/components/users/AuthPage.jsx @@ -0,0 +1,29 @@ +import LayoutBaseAuthenticator from '@/components/common/layouts/LayoutBaseAuthenticator'; +import { Login } from "./Login/Login"; +import Register from './Register/Register'; +import { useState } from 'react'; + +export function AuthPage() { + const [component, setComponent] = useState('Login') + + const renderPage = () => { + switch (component) { + case 'Login': + return ; + case 'Register': + return ; + // case 'resetPassword': + // return ; + default: + return ; + } + } + + return ( + + {renderPage()} + + ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Login/Login.jsx b/cosiap_frontend/src/components/users/Login/Login.jsx new file mode 100644 index 0000000000000000000000000000000000000000..da4d585bbec15e8edf1227bbc9ad34ebd8373e6f --- /dev/null +++ b/cosiap_frontend/src/components/users/Login/Login.jsx @@ -0,0 +1,19 @@ + +import { LoginForm } from './LoginForm'; + +export function Login( {setComponent} ) { + return ( + <> + +

+ ¿Haz olvidado tu contraseña? +

+

+ ¿Aun no tienes cuenta? +

+

setComponent('Register')}> + Registrate +

+ + ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx b/cosiap_frontend/src/components/users/Login/LoginForm.jsx similarity index 61% rename from cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx rename to cosiap_frontend/src/components/users/Login/LoginForm.jsx index a9ab1fe01e8e38b124af8a36164d9eb157d7cad5..c6d1a0b645810e597029cba4b05a3eaa29fcb435 100644 --- a/cosiap_frontend/src/components/users/LoginPage/LoginForm.jsx +++ b/cosiap_frontend/src/components/users/Login/LoginForm.jsx @@ -2,7 +2,8 @@ import { useForm } from "react-hook-form"; 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 {LoginInputCURP} from '@/components/users/Login/LoginInputCURP' +import { LoginInputPassword } from "@/components/users/Login/LoginInputPassword"; import { useState } from "react"; import {ErrorDisplay} from '@/components/common/ui/ErrorDisplay' @@ -10,8 +11,8 @@ const CURP_REGEX = /^[A-Z]{1}[AEIOU]{1}[A-Z]{2}[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|1[ const validationSchema = Yup.object({ curp: Yup.string() - .matches(CURP_REGEX, "CURP inválido") - .required("Requerido"), + .required("Requerido") + .matches(CURP_REGEX, "CURP inválido"), password: Yup.string().required("Requerido"), }); @@ -38,41 +39,40 @@ export function LoginForm() { return (
+
- - - + +
+ + +
+
+ +
-

- ¿Haz olvidado tu contraseña? -

-

- ¿Aun no tienes cuenta? -

-

- Registrate -

+
); } diff --git a/cosiap_frontend/src/components/users/Login/LoginInputCURP.jsx b/cosiap_frontend/src/components/users/Login/LoginInputCURP.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c5ffafa97ce5fbf4f0611213c4dd346b05f8aeff --- /dev/null +++ b/cosiap_frontend/src/components/users/Login/LoginInputCURP.jsx @@ -0,0 +1,33 @@ +import {FormInput} from '@/components/common/base/FormInput.jsx'; +import PropTypes from 'prop-types'; + +export const LoginInputCURP = ({ name, type, placeholder, className, register, errors }) => { + return ( + <> + + Icono Correo + + + ); +}; + +LoginInputCURP.propTypes = { + name: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + placeholder: PropTypes.string, + className: PropTypes.string, + register: PropTypes.func.isRequired, + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) +}; \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Login/LoginInputPassword.jsx b/cosiap_frontend/src/components/users/Login/LoginInputPassword.jsx new file mode 100644 index 0000000000000000000000000000000000000000..1daaa4a099d22b100b2bd1023f7d818cb95d739a --- /dev/null +++ b/cosiap_frontend/src/components/users/Login/LoginInputPassword.jsx @@ -0,0 +1,31 @@ +import {FormInputPassword} from '@/components/common/base/FormInputPassword.jsx'; +import PropTypes from 'prop-types'; + +export const LoginInputPassword = ({ name, placeholder, className, register, errors }) => { + + return ( + <> + + + + ); +}; + +LoginInputPassword.propTypes = { + name: PropTypes.string.isRequired, + placeholder: PropTypes.string, + className: PropTypes.string, + register: PropTypes.func.isRequired, + 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 deleted file mode 100644 index c15abd263ed6150a265c98787371ec089265cc7d..0000000000000000000000000000000000000000 --- a/cosiap_frontend/src/components/users/LoginPage/LoginContainer.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { LoginForm } from './LoginForm'; - -export function LoginContainer() { - return ( -
-
-
= 640 ? "absolute" : "relative", - left: window.innerWidth >= 640 ? "25%" : "0", - top: window.innerWidth >= 640 ? "50%" : "auto", - transform: window.innerWidth >= 640 ? "translateY(-50%)" : "none", - }} - > -
- company -

- INICIAR SESIÓN -

-
- -
-
-
- ); -} diff --git a/cosiap_frontend/src/components/users/LoginPage/LoginPage.jsx b/cosiap_frontend/src/components/users/LoginPage/LoginPage.jsx deleted file mode 100644 index fa918d383ec92a10046873942ec62c2fa1fada5e..0000000000000000000000000000000000000000 --- a/cosiap_frontend/src/components/users/LoginPage/LoginPage.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import { LoginContainer } from './LoginContainer'; - -export function LoginPage() { - return ( - - ); -} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/LoginPage/loginInput.jsx b/cosiap_frontend/src/components/users/LoginPage/loginInput.jsx deleted file mode 100644 index 642062f1333e97783e834db1a730ed907b6ee145..0000000000000000000000000000000000000000 --- a/cosiap_frontend/src/components/users/LoginPage/loginInput.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import {FormInput} from '@/components/common/ui/FormInput'; -import PropTypes from 'prop-types'; - -export const LoginInput = ({ name, type, placeholder, className, register, errors }) => { - return ( - - ); -}; - -LoginInput.propTypes = { - name: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, - placeholder: PropTypes.string, - className: PropTypes.string, - register: PropTypes.func.isRequired, - errors: PropTypes.oneOfType([ - PropTypes.object, - PropTypes.array, - PropTypes.string - ]) -}; \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Register/Register.jsx b/cosiap_frontend/src/components/users/Register/Register.jsx new file mode 100644 index 0000000000000000000000000000000000000000..9b6b4cb44f6b3f681be4a2232cd20a621f9386c7 --- /dev/null +++ b/cosiap_frontend/src/components/users/Register/Register.jsx @@ -0,0 +1,36 @@ +import { useState } from "react"; +import RegisterForm from "./RegisterForm"; + +export default function Register( {setComponent} ) { + const [sentEmail, setSentEmail] = useState(false); + return ( + <> + { + !sentEmail ? ( + <> + +

setComponent('Login')}> + Iniciar sesión +

+ + ) : ( + <> +
+
+

¡Correo de confirmación
enviado!

+
+
+

Se ha enviado un correo
electrónico para confirmar la
creación de tu cuenta.

+
+
+
+ +
+ + ) + } + + ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Register/RegisterForm.jsx b/cosiap_frontend/src/components/users/Register/RegisterForm.jsx new file mode 100644 index 0000000000000000000000000000000000000000..7cd781fb85022ae9766427b19eea7c15f1d0a926 --- /dev/null +++ b/cosiap_frontend/src/components/users/Register/RegisterForm.jsx @@ -0,0 +1,110 @@ +import { RegisterInput } from "./RegisterInput"; +import { RegisterInputPassword } from "./RegisterInputPassword"; +import { useState } from "react"; +import { ErrorDisplay } from '@/components/common/ui/ErrorDisplay'; +import { useForm } from "react-hook-form"; +import * as Yup from "yup"; +import { yupResolver } from "@hookform/resolvers/yup"; +import api from "@/api"; // Asegúrate de importar tu instancia de API + +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({ + nombre: Yup.string() + .required('Campo requerido'), + curp: Yup.string() + .required("Campo requerido") + .matches(CURP_REGEX, "Campo requerido"), + email: Yup.string() + .email("El email no es válido") + .required("Campo requerido"), + password: Yup.string() + .required("Campo requerido"), + confirmar_password: Yup.string() + .required("Campo requerido") + .oneOf([Yup.ref('password'), null], 'Las contraseñas no coinciden') +}); + +export default function RegisterForm( {setSentEmail} ) { + const [registerErrorMessage, setRegisterErrorMessage] = useState(''); + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + resolver: yupResolver(validationSchema), + }); + + const handleFormSubmission = async (data) => { + try { + const response = await api.usuarios.post(data); + console.log("Registration successful:", response.data); + setSentEmail(true); + } catch (error) { + console.error("Registration failed:", error); + console.log(error.response.data.detail); + setRegisterErrorMessage(error.response.data); + } + }; + + return ( +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Register/RegisterInput.jsx b/cosiap_frontend/src/components/users/Register/RegisterInput.jsx new file mode 100644 index 0000000000000000000000000000000000000000..49957513ef571cac975bed3548ce867a90b535b9 --- /dev/null +++ b/cosiap_frontend/src/components/users/Register/RegisterInput.jsx @@ -0,0 +1,32 @@ +import {FormInput} from '@/components/common/base/FormInput.jsx'; +import PropTypes from 'prop-types'; + +export const RegisterInput = ({ name, type, placeholder, className, register, errors }) => { + return ( + <> + + + + ); +}; + +RegisterInput.propTypes = { + name: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + placeholder: PropTypes.string, + className: PropTypes.string, + register: PropTypes.func.isRequired, + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) +}; \ No newline at end of file diff --git a/cosiap_frontend/src/components/users/Register/RegisterInputPassword.jsx b/cosiap_frontend/src/components/users/Register/RegisterInputPassword.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e43b7485e5c848b940f2042042cb900b32e23b2e --- /dev/null +++ b/cosiap_frontend/src/components/users/Register/RegisterInputPassword.jsx @@ -0,0 +1,30 @@ +import {FormInputPassword} from '@/components/common/base/FormInputPassword.jsx'; +import PropTypes from 'prop-types'; + +export const RegisterInputPassword = ({ name, placeholder, className, register, errors }) => { + + return ( + <> + + + ); +}; + +RegisterInputPassword.propTypes = { + name: PropTypes.string.isRequired, + placeholder: PropTypes.string, + className: PropTypes.string, + register: PropTypes.func.isRequired, + errors: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.array, + PropTypes.string + ]) +}; \ No newline at end of file