diff --git a/app/bulkCreate/page.js b/app/bulkCreate/page.js
new file mode 100644
index 0000000..b352752
--- /dev/null
+++ b/app/bulkCreate/page.js
@@ -0,0 +1,115 @@
+"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([{ id: 0, formData: {}, errors: {} }]);
+ 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, { id: forms.length, formData: {}, errors: {} }]);
+ };
+
+ const removeForm = (id) => {
+ setForms(forms.filter(form => form.id !== id));
+ };
+
+ const updateFormData = (id, data) => {
+ setForms(forms.map(form => form.id === id ? { ...form, formData: data } : form));
+ };
+
+ 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 newForms = forms.map((form) => {
+ const newErrors = {};
+ if (!form.formData.name) newErrors.name = "Este campo es obligatorio.";
+ if (!form.formData.email) newErrors.email = "Este campo es obligatorio.";
+ if (!form.formData.password) newErrors.password = "Este campo es obligatorio.";
+ if (form.formData.password !== form.formData.password_second) newErrors.password_second = "Las contraseñas no coinciden.";
+ if (!form.formData.cellphone) newErrors.cellphone = "Este campo es obligatorio.";
+ if (form.formData.email && !validateEmail(form.formData.email)) newErrors.email = "El formato del email no es válido.";
+ return { ...form, errors: newErrors };
+ });
+
+ setForms(newForms);
+
+ const hasErrors = newForms.some(form => Object.keys(form.errors).length > 0);
+ if (hasErrors) {
+ setMessage("Por favor, corrige los errores en los formularios.");
+ setOpenSnack(true);
+ return;
+ }
+
+ let users = newForms.map(form => ({
+ name: form.formData.name,
+ email: form.formData.email,
+ password: form.formData.password,
+ password_second: form.formData.password_second,
+ cellphone: form.formData.cellphone
+ }));
+
+ let objetos = { users };
+
+ console.log('Users to be sent:', objetos); // Asegúrate de que los datos son correctos
+
+ try {
+ const response = await AuthService.bulkCreateUsers(objetos); // Enviar como objeto con clave 'users'
+ if (response && response.message) {
+ setMessage(`Usuarios creados: ${response.message.successful}, fallidos: ${response.message.failed}`);
+ } else {
+ setMessage('Error inesperado al crear usuarios');
+ }
+ } catch (error) {
+ setMessage('Error al conectar con el servidor');
+ }
+ setOpenSnack(true);
+ };
+
+ return (
+
+
+ Registrar Múltiples Usuarios
+ setOpenSnack(!openSnack)} />
+ {forms.map((form, 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/app/login/page.js b/app/login/page.js
index 9ebaef4..07cf8b9 100644
--- a/app/login/page.js
+++ b/app/login/page.js
@@ -1,27 +1,39 @@
"use client"
-import React, {useState} from 'react';
-import {Card, CardContent, Container} from "@mui/material";
+import React, { useState } from 'react';
+import { Card, CardContent, Container } from "@mui/material";
import TextField from '@mui/material/TextField';
-import Button from "@mui/material/Button";
+import Button from '@mui/material/Button';
import SimpleSnackbar from '../../components/SimpleSnackbar';
import { useRouter } from 'next/navigation';
+import FormHelperText from '@mui/material/FormHelperText';
import AuthService from '../../services/AuthService';
import './page.css';
-export default function Login(){
+export default function Login() {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [state, setState] = useState(true);
+ const [emailError, setEmailError] = useState("");
+ const [generalError, setGeneralError] = useState("");
const handleLogin = async () => {
- const login = await AuthService.handleLogin(email, password);
- setState(login);
- if(login){
+ const response = await AuthService.handleLogin(email, password);
+ if (response.success) {
+ setState(true);
router.push('/users');
+ } else {
+ if (response.message === "Correo electrónico no encontrado en la base de datos") {
+ setEmailError("El email no existe, regístrate.");
+ setGeneralError("");
+ } else {
+ setEmailError("");
+ setGeneralError(response.message || "Usuario o contraseña incorrectos");
+ }
+ setState(false);
}
}
@@ -36,25 +48,36 @@ export default function Login(){
Inicia Sesión
- setState(true)}/>
+ setState(true)} />
setEmail(e.target.value)}
+ value={email}
+ onChange={(e) => {
+ setEmail(e.target.value);
+ setEmailError("");
+ }}
+ error={emailError !== ""}
+ helperText={emailError}
/>
-
+
+
+ {emailError}
+
+
setPassword(e.target.value)}
/>
@@ -68,4 +91,4 @@ export default function Login(){
);
-}
\ No newline at end of file
+}
diff --git a/app/register/page.js b/app/register/page.js
index e5d96cb..76d7a37 100644
--- a/app/register/page.js
+++ b/app/register/page.js
@@ -1,104 +1,83 @@
"use client"
import React from "react";
-import {Card, CardContent, Container} from "@mui/material";
-import TextField from "@mui/material/TextField";
-import Button from "@mui/material/Button";
+import { Container, Button } from "@mui/material";
import SimpleSnackbar from "@/components/SimpleSnackbar";
import AuthService from "@/services/AuthService";
+import RegisterForm from "@/components/registerForm";
+import { useRouter } from 'next/navigation';
import './page.css';
const Register = () => {
- // Register from user -> name, email, password, cellphone
- const [name, setName] = React.useState("");
- const [email, setEmail] = React.useState("");
- const [password, setPassword] = React.useState("");
- const [password_second, setPasswordSecond] = React.useState("");
- const [cellphone, setCellphone] = React.useState("");
-
+ const [forms, setForms] = React.useState([{ id: 0, formData: {}, errors: {} }]);
const [message, setMessage] = React.useState("");
const [openSnack, setOpenSnack] = React.useState(false);
- const handleRegister = async () => {
- if(password !== password_second){
- setMessage("Las contraseñas no coinciden");
+ const router = useRouter();
+
+ const updateFormData = (id, data) => {
+ setForms(forms.map(form => form.id === id ? { ...form, formData: data } : form));
+ };
+
+ const handleRegisterAll = async () => {
+ const newForms = forms.map((form) => {
+ const newErrors = {};
+ if (!form.formData.name) newErrors.name = "Este campo es obligatorio.";
+ if (!form.formData.email) newErrors.email = "Este campo es obligatorio.";
+ if (!form.formData.password) newErrors.password = "Este campo es obligatorio.";
+ if (form.formData.password !== form.formData.password_second) newErrors.password_second = "Las contraseñas no coinciden.";
+ if (!form.formData.cellphone) newErrors.cellphone = "Este campo es obligatorio.";
+ return { ...form, errors: newErrors };
+ });
+
+ setForms(newForms);
+
+ const hasErrors = newForms.some(form => Object.keys(form.errors).length > 0);
+ if (hasErrors) {
+ setMessage("Todos los campos deben ser completados correctamente.");
setOpenSnack(true);
return;
}
- const response = await AuthService.registerUser(name, email, password, password_second, cellphone);
- if(!response){
- setMessage("Error al registrar usuario");
- setOpenSnack(true);
- } else {
- setMessage("Usuario Registrado Exitosamente!");
- setOpenSnack(true);
+
+ for (const form of forms) {
+ const { name, email, password, password_second, cellphone } = form.formData;
+ const response = await AuthService.registerUser(name, email, password, password_second, cellphone);
+ if (!response) {
+ setMessage(`Error al registrar usuario ${form.id + 1}`);
+ setOpenSnack(true);
+ return;
+ }
}
- }
+
+ setMessage("Todos los usuarios registrados exitosamente!");
+ setOpenSnack(true);
+ };
+
+ const handleBack = () => {
+ router.push('/login');
+ };
return (
- {setOpenSnack(!openSnack)}}/>
-
-
- Register User
-
- setName(e.target.value)}
- />
-
-
- setEmail(e.target.value)}
- />
-
-
- setPassword(e.target.value)}
- />
-
-
- setPasswordSecond(e.target.value)}
- />
-
-
- setCellphone(e.target.value)}
- />
-
-
-
-
-
-
+ { setOpenSnack(!openSnack); }}
+ />
+ {forms.map((form, index) => (
+
+
+
+ ))}
+
+
- )
-}
-export default Register;
\ No newline at end of file
+ );
+};
+
+export default Register;
diff --git a/components/Navbar.js b/components/Navbar.js
index c281d22..d34ebed 100644
--- a/components/Navbar.js
+++ b/components/Navbar.js
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from 'react';
+import React, { useEffect, useState } from 'react';
import './Navbar.css';
import Button from '@mui/material/Button';
import AuthService from '@/services/AuthService';
@@ -6,32 +6,33 @@ import { useRouter } from 'next/navigation';
const Navbar = () => {
const router = useRouter();
- const [user, setUser] = useState({name:""});
+ const [user, setUser] = useState({ name: "" });
- useEffect(() => {
- setUser(JSON.parse(localStorage.getItem('user')));
- }, []);
+ useEffect(() => {
+ setUser(JSON.parse(localStorage.getItem('user')));
+ }, []);
- const handleLogout = async () => {
+ const handleLogout = async () =>
+ {
const token = localStorage.getItem('token');
const result = await AuthService.logOut(token);
- if(result){
- router.push('/login');
- }
+ if (result) {
+ router.push('/login');
}
+ }
- return (
-
-
- {user?.name}
-
-
-
-
-
- )
+ return (
+
+
+ {user?.name}
+
+
+
+
+
+
+
+ )
}
export default Navbar;
\ No newline at end of file
diff --git a/components/SimpleSnackbar.js b/components/SimpleSnackbar.js
index 7898c54..1c84c3a 100644
--- a/components/SimpleSnackbar.js
+++ b/components/SimpleSnackbar.js
@@ -1,14 +1,21 @@
"use client"
import * as React from 'react';
import Snackbar from '@mui/material/Snackbar';
+import MuiAlert from '@mui/material/Alert';
import IconButton from '@mui/material/IconButton';
import CloseIcon from '@mui/icons-material/Close';
-const SimpleSnackbar = (props) => {
+const Alert = React.forwardRef(function Alert(props, ref) {
+ return ;
+});
+
+const SimpleSnackbar = (props) => {
const { message, openSnack, closeSnack } = props;
const handleClose = (event, reason) => {
- event.preventDefault();
+ if (event) {
+ event.preventDefault();
+ }
if (reason === 'clickaway') {
return;
}
@@ -35,11 +42,14 @@ const SimpleSnackbar = (props) => {
open={openSnack}
autoHideDuration={6000}
onClose={handleClose}
- message={message}
- //action={action}
- />
+ action={action}
+ >
+
+ {message}
+
+
);
}
-export default SimpleSnackbar;
\ No newline at end of file
+export default SimpleSnackbar;
diff --git a/components/registerForm.js b/components/registerForm.js
new file mode 100644
index 0000000..3d5efb8
--- /dev/null
+++ b/components/registerForm.js
@@ -0,0 +1,86 @@
+// components/RegisterForm.js
+import React from 'react';
+import { Card, CardContent, TextField } from "@mui/material";
+
+const RegisterForm = ({ index, formData, errors, updateFormData }) => {
+ const handleChange = (field, value) => {
+ updateFormData(index, { ...formData, [field]: value });
+ };
+
+ return (
+
+
+ Register User {index + 1}
+
+ handleChange('name', e.target.value)}
+ error={!!errors.name}
+ helperText={errors.name}
+ />
+
+
+ handleChange('email', e.target.value)}
+ error={!!errors.email}
+ helperText={errors.email}
+ />
+
+
+ handleChange('password', e.target.value)}
+ error={!!errors.password}
+ helperText={errors.password}
+ />
+
+
+ handleChange('password_second', e.target.value)}
+ error={!!errors.password_second}
+ helperText={errors.password_second}
+ />
+
+
+ handleChange('cellphone', e.target.value)}
+ error={!!errors.cellphone}
+ helperText={errors.cellphone}
+ />
+
+
+
+ );
+};
+
+export default RegisterForm;
diff --git a/services/AuthService.js b/services/AuthService.js
index 3b7920a..fecb33f 100644
--- a/services/AuthService.js
+++ b/services/AuthService.js
@@ -1,49 +1,26 @@
import axios from 'axios';
const handleLogin = async (user, pass) => {
- try{
+ 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
+ // response.data contains a token in BASE64 format
const decoded = atob(response.data);
localStorage.setItem('token', response.data);
localStorage.setItem('user', decoded);
- return true;
+ return { success: true };
} catch (e) {
console.error(e);
- return false;
+ return { success: false, message: 'Usuario o contraseña incorrectos' };
}
}
const getUsers = async () => {
try {
- //const response = await axios.get('fakeapi');
- const response = {
- data: [
- {
- id: 1,
- name: 'muhammad fake',
- email: 'a@b.cl',
- status: true
- },
-
- {
- id: 2,
- name: 'muhammed fake',
- email: 'b@b.cl',
- status: true
- },
- {
- id: 3,
- name: 'muhammid fake',
- email: 'c@b.cl',
- status: true
- },
- ]
- }
+ const response = await axios.get('http://localhost:3001/api/v1/users');
return response.data;
} catch (e) {
console.error(e);
@@ -53,13 +30,13 @@ const getUsers = async () => {
const getUserById = async (id, token) => {
try {
- const response = await axios.get('http://localhost:3001/api/v1/users/' + id, {
+ const response = await axios.get(`http://localhost:3001/api/v1/users/${id}`, {
headers: {
token,
}
});
return response.data;
- } catch(e){
+ } catch (e) {
console.error(e);
return null;
}
@@ -72,7 +49,7 @@ const logOut = async (token) => {
'token': token,
}
});
- if(response.status !== 200){
+ if (response.status !== 200) {
return false;
}
localStorage.removeItem('token');
@@ -85,7 +62,7 @@ const logOut = async (token) => {
}
const registerUser = async (name, email, password, password_second, cellphone) => {
- try{
+ try {
const response = await axios.post('http://localhost:3001/api/v1/auth/register', {
name,
email,
@@ -94,7 +71,7 @@ const registerUser = async (name, email, password, password_second, cellphone) =
cellphone,
});
return (response.status === 200);
- }catch (e) {
+ } catch (e) {
console.error(e);
return false;
}
@@ -102,7 +79,7 @@ const registerUser = async (name, email, password, password_second, cellphone) =
const updateUser = async (id, user, token) => {
try {
- const response = await axios.put('http://localhost:3001/api/v1/users/' + id, user, {
+ const response = await axios.put(`http://localhost:3001/api/v1/users/${id}`, user, {
headers: {
token,
}
@@ -113,6 +90,33 @@ const updateUser = async (id, user, token) => {
return false;
}
}
+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 [];
+ }
+};
+
+// Nueva función para la creación de usuarios en masa
+const bulkCreateUsers = async (objetos) => {
+ console.log("Users received:", objetos); // Verifica los datos aquí
+ try {
+ const response = await axios.post('http://localhost:3001/api/v1/users/bulkCreate', objetos);
+ return response.data; // Asegúrate de que la respuesta contiene 'data'
+ } catch (error) {
+ console.error("Error:", error); // Más detalle del error
+ return { message: 'Error al crear usuarios' }; // Asegúrate de que siempre devuelve un objeto con 'message'
+ }
+ };
export default {
handleLogin,
@@ -121,4 +125,6 @@ export default {
logOut,
registerUser,
updateUser,
-};
\ No newline at end of file
+ bulkCreateUsers, // Asegúrate de exportar la nueva función
+ findUsers,
+};