Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tarea Frontend - Andrés Jara #23

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
101 changes: 101 additions & 0 deletions app/bulkCreate/page.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container>
<Navbar />
<h1>Registrar Múltiples Usuarios</h1>
<SimpleSnackbar message={message} openSnack={openSnack} closeSnack={() => setOpenSnack(!openSnack)} />
{forms.map((_, index) => (
<div key={index}>
<RegisterForm index={index} />
<Button onClick={() => removeForm(index)}>Quitar</Button>
</div>
))}
<Button onClick={addForm}>Agregar Usuario</Button>
<Button variant="contained" color="primary" onClick={handleSubmit}>Registrar Todos</Button>
</Container>
);
};

export default BulkCreate;
124 changes: 124 additions & 0 deletions app/filters/page.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container>
<Navbar />
<h1>Filtros</h1>
<FormControl fullWidth style={{ marginBottom: '20px' }}>
<InputLabel id="statusFilterLabel">Filtrar por estado</InputLabel>
<Select
labelId="statusFilterLabel"
id="statusFilter"
name="status"
value={status}
onChange={handleInputChange}
>
<MenuItem value="">Todos</MenuItem>
<MenuItem value="true">Activos</MenuItem>
<MenuItem value="false">Inactivos</MenuItem>
</Select>
</FormControl>
<TextField
fullWidth
label="Filtrar por nombre"
variant="outlined"
name="name"
value={name}
onChange={handleInputChange}
style={{ marginBottom: '20px' }}
/>
<TextField
fullWidth
label="Filtrar por fecha de inicio de sesión después de"
variant="outlined"
type="date"
name="logAfter"
value={logAfter}
onChange={handleInputChange}
InputLabelProps={{
shrink: true,
}}
style={{ marginBottom: '20px' }}
/>
<TextField
fullWidth
label="Filtrar por fecha de inicio de sesión antes de"
variant="outlined"
type="date"
name="logBefore"
value={logBefore}
onChange={handleInputChange}
InputLabelProps={{
shrink: true,
}}
style={{ marginBottom: '20px' }}
/>
<Table>
<TableHead>
<TableRow>
<TableCell>Nombre</TableCell>
<TableCell>Email</TableCell>
<TableCell>Estado</TableCell>
</TableRow>
</TableHead>
<TableBody>
{users.map(user => (
<TableRow key={user.id}>
<TableCell>{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.status ? 'Activo' : 'Inactivo'}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Container>
);
};

export default Filters;
51 changes: 26 additions & 25 deletions components/Navbar.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="navbar">
<div className="navbar-item">
{user?.name}
</div>
<div className="navbar-item">
<Button onClick={handleLogout}>
Logout
</Button>
</div>
</div>
)
return (
<div className="navbar">
<div className="navbar-item">
{user?.name}
</div>
<div className="navbar-item">
<Button onClick={() => router.push('/filters')}>Filtros</Button>
<Button onClick={() => router.push('/bulkCreate')}>Registrar Múltiples Usuarios</Button>
<Button onClick={handleLogout}>Logout</Button>
</div>
</div>
)
}

export default Navbar;
export default Navbar;
62 changes: 62 additions & 0 deletions components/RegisterForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// components/RegisterForm.js
import React from 'react';
import { Card, CardContent, TextField } from "@mui/material";

const RegisterForm = ({ index }) => {
return (
<Card className="form">
<CardContent>
<h1>Register User {index + 1}</h1>
<div className="input-form">
<TextField
id={`name-${index}`}
label="Nombre"
variant="outlined"
required
placeholder="Oleh Oleig"
/>
</div>
<div className="input-form">
<TextField
id={`email-${index}`}
label="Email"
variant="outlined"
required
placeholder="[email protected]"
/>
</div>
<div className="input-form">
<TextField
id={`password-${index}`}
label="Contraseña"
variant="outlined"
required
type="password"
placeholder="****"
/>
</div>
<div className="input-form">
<TextField
id={`passwordSecond-${index}`}
label="Confirmar Contraseña"
variant="outlined"
type="password"
required
placeholder="****"
/>
</div>
<div className="input-form">
<TextField
id={`cellphone-${index}`}
label="Teléfono"
variant="outlined"
required
placeholder="+56987654321"
/>
</div>
</CardContent>
</Card>
);
};

export default RegisterForm;
Loading