diff --git a/README.md b/README.md index 0dc9ea2..5e0ac9f 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,7 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +hay que logearse para acceder a la vista de filtro de usuarios, y el registro multiple + +registro multiple devuelve la respuesta del backend cuando se registran los usuarios, si es que los form cumplen con los requisitos diff --git a/app/bulkCreate/page.js b/app/bulkCreate/page.js new file mode 100644 index 0000000..e18d90a --- /dev/null +++ b/app/bulkCreate/page.js @@ -0,0 +1,101 @@ +// app/bulkCreate/page.js +"use client" +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { Container, Button } from "@mui/material"; +import Navbar from '@/components/Navbar'; +import RegisterForm from '@/components/RegisterForm'; +import AuthService from '@/services/AuthService'; +import SimpleSnackbar from '@/components/SimpleSnackbar'; + +const BulkCreate = () => { + const [forms, setForms] = useState([{}]); + const [message, setMessage] = useState(""); + const [openSnack, setOpenSnack] = useState(false); + const router = useRouter(); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (!token) { + router.push('/login'); + } + }, [router]); + + const addForm = () => { + setForms([...forms, {}]); + }; + + const removeForm = (index) => { + setForms(forms.filter((_, i) => i !== index)); + }; + + const validateEmail = (email) => { + const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return re.test(String(email).toLowerCase()); + }; + + const handleSubmit = async () => { + const token = localStorage.getItem('token'); + if (!token) { + setMessage('Por favor, inicia sesión primero'); + setOpenSnack(true); + return; + } + + const users = forms.map((_, index) => ({ + name: document.getElementById(`name-${index}`).value, + email: document.getElementById(`email-${index}`).value, + password: document.getElementById(`password-${index}`).value, + password_second: document.getElementById(`passwordSecond-${index}`).value, + cellphone: document.getElementById(`cellphone-${index}`).value, + })); + + // Validación de campos vacíos + const incompleteForms = users.filter(user => + !user.name || !user.email || !user.password || !user.password_second || !user.cellphone + ); + if (incompleteForms.length > 0) { + setMessage("Por favor, rellena todos los campos de los formularios."); + setOpenSnack(true); + return; + } + + // Validación de formato de email + const invalidEmails = users.filter(user => !validateEmail(user.email)); + if (invalidEmails.length > 0) { + setMessage("Algunos correos electrónicos no tienen un formato válido."); + setOpenSnack(true); + return; + } + + // Validación de contraseñas + const invalidPasswords = users.filter(user => user.password !== user.password_second); + if (invalidPasswords.length > 0) { + setMessage("Algunas contraseñas no coinciden."); + setOpenSnack(true); + return; + } + + const response = await AuthService.bulkCreateUsers(users); + setMessage(response); + setOpenSnack(true); + }; + + return ( + + +

Registrar Múltiples Usuarios

+ setOpenSnack(!openSnack)} /> + {forms.map((_, index) => ( +
+ + +
+ ))} + + +
+ ); +}; + +export default BulkCreate; diff --git a/app/filters/page.js b/app/filters/page.js new file mode 100644 index 0000000..64d441c --- /dev/null +++ b/app/filters/page.js @@ -0,0 +1,124 @@ +// app/filters/page.js +"use client" +import React, { useEffect, useState } from 'react'; +import { Container, Select, MenuItem, FormControl, InputLabel, TextField, Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material'; +import { useRouter, useSearchParams } from 'next/navigation'; +import AuthService from '@/services/AuthService'; +import Navbar from '@/components/Navbar'; + +const Filters = () => { + const [users, setUsers] = useState([]); + const router = useRouter(); + const searchParams = useSearchParams(); + const status = searchParams.get('status') || ''; + const name = searchParams.get('name') || ''; + const logAfter = searchParams.get('logAfter') || ''; + const logBefore = searchParams.get('logBefore') || ''; + + useEffect(() => { + const token = localStorage.getItem('token'); + if (!token) { + router.push('/login'); + return; + } + + const fetchFilteredUsers = async () => { + const filters = { + status, + name, + logAfter, + logBefore, + }; + const data = await AuthService.findUsers(filters); + setUsers(data); + }; + fetchFilteredUsers(); + }, [status, name, logAfter, logBefore, router]); + + const handleInputChange = (e) => { + const { name, value } = e.target; + const params = new URLSearchParams(window.location.search); + if (value) { + params.set(name, value); + } else { + params.delete(name); + } + router.push(`/filters?${params.toString()}`); + }; + + return ( + + +

Filtros

+ + Filtrar por estado + + + + + + + + + Nombre + Email + Estado + + + + {users.map(user => ( + + {user.name} + {user.email} + {user.status ? 'Activo' : 'Inactivo'} + + ))} + +
+
+ ); +}; + +export default Filters; diff --git a/components/Navbar.js b/components/Navbar.js index c281d22..1bebda8 100644 --- a/components/Navbar.js +++ b/components/Navbar.js @@ -1,37 +1,38 @@ -import React, {useEffect, useState} from 'react'; +// Navbar.js +import React, { useEffect, useState } from 'react'; import './Navbar.css'; import Button from '@mui/material/Button'; import AuthService from '@/services/AuthService'; import { useRouter } from 'next/navigation'; const Navbar = () => { - const router = useRouter(); - const [user, setUser] = useState({name:""}); + const router = useRouter(); + const [user, setUser] = useState({ name: "" }); - useEffect(() => { - setUser(JSON.parse(localStorage.getItem('user'))); - }, []); + useEffect(() => { + setUser(JSON.parse(localStorage.getItem('user'))); + }, []); - const handleLogout = async () => { - const token = localStorage.getItem('token'); - const result = await AuthService.logOut(token); - if(result){ - router.push('/login'); - } + const handleLogout = async () => { + const token = localStorage.getItem('token'); + const result = await AuthService.logOut(token); + if (result) { + router.push('/login'); } + } - return ( -
-
- {user?.name} -
-
- -
-
- ) + return ( +
+
+ {user?.name} +
+
+ + + +
+
+ ) } -export default Navbar; \ No newline at end of file +export default Navbar; diff --git a/components/RegisterForm.js b/components/RegisterForm.js new file mode 100644 index 0000000..54ce05a --- /dev/null +++ b/components/RegisterForm.js @@ -0,0 +1,62 @@ +// components/RegisterForm.js +import React from 'react'; +import { Card, CardContent, TextField } from "@mui/material"; + +const RegisterForm = ({ index }) => { + return ( + + +

Register User {index + 1}

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ ); +}; + +export default RegisterForm; diff --git a/services/AuthService.js b/services/AuthService.js index 3b7920a..7e92d73 100644 --- a/services/AuthService.js +++ b/services/AuthService.js @@ -1,124 +1,133 @@ +// AuthService.js import axios from 'axios'; const handleLogin = async (user, pass) => { - try{ - const response = await axios.post('http://localhost:3001/api/v1/auth/login', { - email: user, - password: pass, - }); - //response.data contains a token in BASE64 format - - const decoded = atob(response.data); - localStorage.setItem('token', response.data); - localStorage.setItem('user', decoded); - return true; - } catch (e) { - console.error(e); - return false; - } -} + try { + const response = await axios.post('http://localhost:3001/api/v1/auth/login', { + email: user, + password: pass, + }); + const decoded = atob(response.data); + localStorage.setItem('token', response.data); + localStorage.setItem('user', decoded); + return true; + } catch (e) { + console.error(e); + return false; + } +}; const getUsers = async () => { - try { - //const response = await axios.get('fakeapi'); - const response = { - data: [ - { - id: 1, - name: 'muhammad fake', - email: 'a@b.cl', - status: true - }, + try { + const response = await axios.get('http://localhost:3001/api/v1/users'); + return response.data; + } catch (e) { + console.error(e); + return []; + } +}; - { - id: 2, - name: 'muhammed fake', - email: 'b@b.cl', - status: true - }, - { - id: 3, - name: 'muhammid fake', - email: 'c@b.cl', - status: true - }, - ] - } - return response.data; - } catch (e) { - console.error(e); - return []; - } -} +const findUsers = async (filters) => { + try { + const token = localStorage.getItem('token'); + const response = await axios.get('http://localhost:3001/api/v1/users/findUsers', { + headers: { + token, + }, + params: filters + }); + return response.data; + } catch (e) { + console.error(e); + return []; + } +}; const getUserById = async (id, token) => { - try { - const response = await axios.get('http://localhost:3001/api/v1/users/' + id, { - headers: { - token, - } - }); - return response.data; - } catch(e){ - console.error(e); - return null; - } -} + try { + const response = await axios.get('http://localhost:3001/api/v1/users/' + id, { + headers: { + token, + } + }); + return response.data; + } catch (e) { + console.error(e); + return null; + } +}; const logOut = async (token) => { - try { - const response = await axios.post('http://localhost:3001/api/v1/auth/logout', {}, { - headers: { - 'token': token, - } - }); - if(response.status !== 200){ - return false; - } - localStorage.removeItem('token'); - localStorage.removeItem('user'); - return true; - } catch (e) { - console.error(e); - return false; + try { + const response = await axios.post('http://localhost:3001/api/v1/auth/logout', {}, { + headers: { + 'token': token, + } + }); + if (response.status !== 200) { + return false; } -} + localStorage.removeItem('token'); + localStorage.removeItem('user'); + return true; + } catch (e) { + console.error(e); + return false; + } +}; const registerUser = async (name, email, password, password_second, cellphone) => { - try{ - const response = await axios.post('http://localhost:3001/api/v1/auth/register', { - name, - email, - password, - password_second, - cellphone, - }); - return (response.status === 200); - }catch (e) { - console.error(e); - return false; - } -} + try { + const response = await axios.post('http://localhost:3001/api/v1/auth/register', { + name, + email, + password, + password_second, + cellphone, + }); + return (response.status === 200); + } catch (e) { + console.error(e); + return false; + } +}; + +const bulkCreateUsers = async (users) => { + try { + const token = localStorage.getItem('token'); + const response = await axios.post('http://localhost:3001/api/v1/users/bulkCreate', users, { + headers: { + token, + } + }); + return response.data; + } catch (e) { + console.error(e); + return { code: 500, message: "Error al registrar usuarios" }; + } +}; const updateUser = async (id, user, token) => { - try { - const response = await axios.put('http://localhost:3001/api/v1/users/' + id, user, { - headers: { - token, - } - }); - return (response.status === 200); - } catch (e) { - console.error(e); - return false; - } -} + try { + const response = await axios.put('http://localhost:3001/api/v1/users/' + id, user, { + headers: { + token, + } + }); + return (response.status === 200); + } catch (e) { + console.error(e); + return false; + } +}; export default { - handleLogin, - getUsers, - getUserById, - logOut, - registerUser, - updateUser, -}; \ No newline at end of file + handleLogin, + getUsers, + findUsers, + getUserById, + logOut, + registerUser, + bulkCreateUsers, + updateUser, +};