Add new API in the frontend
This commit is contained in:
@@ -2,131 +2,31 @@ import React, { useState } from 'react';
|
||||
import { Users, Plus, Search, Mail, Phone, Shield, Edit, Trash2, UserCheck, UserX } from 'lucide-react';
|
||||
import { Button, Card, Badge, Input } from '../../../../components/ui';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
import { useTeamMembers } from '../../../../api/hooks/tenant';
|
||||
import { useAllUsers, useUpdateUser } from '../../../../api/hooks/user';
|
||||
import { useAuthUser } from '../../../../stores/auth.store';
|
||||
import { useToast } from '../../../../hooks/ui/useToast';
|
||||
|
||||
const TeamPage: React.FC = () => {
|
||||
const { addToast } = useToast();
|
||||
const user = useAuthUser();
|
||||
const tenantId = user?.tenant_id || '';
|
||||
|
||||
const { data: teamMembers = [], isLoading, error } = useTeamMembers(tenantId, true, { enabled: !!tenantId });
|
||||
const { data: allUsers = [] } = useAllUsers();
|
||||
const updateUserMutation = useUpdateUser();
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [selectedRole, setSelectedRole] = useState('all');
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
|
||||
const teamMembers = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'María González',
|
||||
email: 'maria.gonzalez@panaderia.com',
|
||||
phone: '+34 600 123 456',
|
||||
role: 'manager',
|
||||
department: 'Administración',
|
||||
status: 'active',
|
||||
joinDate: '2022-03-15',
|
||||
lastLogin: '2024-01-26 09:30:00',
|
||||
permissions: ['inventory', 'sales', 'reports', 'team'],
|
||||
avatar: '/avatars/maria.jpg',
|
||||
schedule: {
|
||||
monday: '07:00-15:00',
|
||||
tuesday: '07:00-15:00',
|
||||
wednesday: '07:00-15:00',
|
||||
thursday: '07:00-15:00',
|
||||
friday: '07:00-15:00',
|
||||
saturday: 'Libre',
|
||||
sunday: 'Libre'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Carlos Rodríguez',
|
||||
email: 'carlos.rodriguez@panaderia.com',
|
||||
phone: '+34 600 234 567',
|
||||
role: 'baker',
|
||||
department: 'Producción',
|
||||
status: 'active',
|
||||
joinDate: '2021-09-20',
|
||||
lastLogin: '2024-01-26 08:45:00',
|
||||
permissions: ['production', 'inventory'],
|
||||
avatar: '/avatars/carlos.jpg',
|
||||
schedule: {
|
||||
monday: '05:00-13:00',
|
||||
tuesday: '05:00-13:00',
|
||||
wednesday: '05:00-13:00',
|
||||
thursday: '05:00-13:00',
|
||||
friday: '05:00-13:00',
|
||||
saturday: '05:00-11:00',
|
||||
sunday: 'Libre'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Ana Martínez',
|
||||
email: 'ana.martinez@panaderia.com',
|
||||
phone: '+34 600 345 678',
|
||||
role: 'cashier',
|
||||
department: 'Ventas',
|
||||
status: 'active',
|
||||
joinDate: '2023-01-10',
|
||||
lastLogin: '2024-01-26 10:15:00',
|
||||
permissions: ['sales', 'pos'],
|
||||
avatar: '/avatars/ana.jpg',
|
||||
schedule: {
|
||||
monday: '08:00-16:00',
|
||||
tuesday: '08:00-16:00',
|
||||
wednesday: 'Libre',
|
||||
thursday: '08:00-16:00',
|
||||
friday: '08:00-16:00',
|
||||
saturday: '09:00-14:00',
|
||||
sunday: '09:00-14:00'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Luis Fernández',
|
||||
email: 'luis.fernandez@panaderia.com',
|
||||
phone: '+34 600 456 789',
|
||||
role: 'baker',
|
||||
department: 'Producción',
|
||||
status: 'inactive',
|
||||
joinDate: '2020-11-05',
|
||||
lastLogin: '2024-01-20 16:30:00',
|
||||
permissions: ['production'],
|
||||
avatar: '/avatars/luis.jpg',
|
||||
schedule: {
|
||||
monday: '13:00-21:00',
|
||||
tuesday: '13:00-21:00',
|
||||
wednesday: '13:00-21:00',
|
||||
thursday: 'Libre',
|
||||
friday: '13:00-21:00',
|
||||
saturday: 'Libre',
|
||||
sunday: '13:00-21:00'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Isabel Torres',
|
||||
email: 'isabel.torres@panaderia.com',
|
||||
phone: '+34 600 567 890',
|
||||
role: 'assistant',
|
||||
department: 'Ventas',
|
||||
status: 'active',
|
||||
joinDate: '2023-06-01',
|
||||
lastLogin: '2024-01-25 18:20:00',
|
||||
permissions: ['sales'],
|
||||
avatar: '/avatars/isabel.jpg',
|
||||
schedule: {
|
||||
monday: 'Libre',
|
||||
tuesday: '16:00-20:00',
|
||||
wednesday: '16:00-20:00',
|
||||
thursday: '16:00-20:00',
|
||||
friday: '16:00-20:00',
|
||||
saturday: '14:00-20:00',
|
||||
sunday: '14:00-20:00'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const roles = [
|
||||
{ value: 'all', label: 'Todos los Roles', count: teamMembers.length },
|
||||
{ value: 'owner', label: 'Propietario', count: teamMembers.filter(m => m.role === 'owner').length },
|
||||
{ value: 'admin', label: 'Administrador', count: teamMembers.filter(m => m.role === 'admin').length },
|
||||
{ value: 'manager', label: 'Gerente', count: teamMembers.filter(m => m.role === 'manager').length },
|
||||
{ value: 'baker', label: 'Panadero', count: teamMembers.filter(m => m.role === 'baker').length },
|
||||
{ value: 'cashier', label: 'Cajero', count: teamMembers.filter(m => m.role === 'cashier').length },
|
||||
{ value: 'assistant', label: 'Asistente', count: teamMembers.filter(m => m.role === 'assistant').length }
|
||||
{ value: 'employee', label: 'Empleado', count: teamMembers.filter(m => m.role === 'employee').length }
|
||||
];
|
||||
|
||||
const teamStats = {
|
||||
@@ -165,10 +65,28 @@ const TeamPage: React.FC = () => {
|
||||
|
||||
const filteredMembers = teamMembers.filter(member => {
|
||||
const matchesRole = selectedRole === 'all' || member.role === selectedRole;
|
||||
const matchesSearch = member.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
member.email.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesSearch = member.user.first_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
member.user.last_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
member.user.email.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
return matchesRole && matchesSearch;
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
<PageHeader
|
||||
title="Gestión de Equipo"
|
||||
description="Administra los miembros del equipo, roles y permisos"
|
||||
/>
|
||||
<div className="flex items-center justify-center min-h-[400px]">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p>Cargando miembros del equipo...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const formatLastLogin = (timestamp: string) => {
|
||||
const date = new Date(timestamp);
|
||||
@@ -293,7 +211,7 @@ const TeamPage: React.FC = () => {
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center space-x-3 mb-2">
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{member.name}</h3>
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{member.user.first_name} {member.user.last_name}</h3>
|
||||
<Badge variant={getStatusColor(member.status)}>
|
||||
{member.status === 'active' ? 'Activo' : 'Inactivo'}
|
||||
</Badge>
|
||||
@@ -302,11 +220,11 @@ const TeamPage: React.FC = () => {
|
||||
<div className="space-y-1 mb-3">
|
||||
<div className="flex items-center text-sm text-[var(--text-secondary)]">
|
||||
<Mail className="w-4 h-4 mr-2" />
|
||||
{member.email}
|
||||
{member.user.email}
|
||||
</div>
|
||||
<div className="flex items-center text-sm text-[var(--text-secondary)]">
|
||||
<Phone className="w-4 h-4 mr-2" />
|
||||
{member.phone}
|
||||
{member.user.phone || 'No disponible'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -320,35 +238,24 @@ const TeamPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-[var(--text-tertiary)] mb-3">
|
||||
<p>Se unió: {new Date(member.joinDate).toLocaleDateString('es-ES')}</p>
|
||||
<p>Última conexión: {formatLastLogin(member.lastLogin)}</p>
|
||||
<p>Se unió: {new Date(member.joined_at).toLocaleDateString('es-ES')}</p>
|
||||
<p>Estado: {member.is_active ? 'Activo' : 'Inactivo'}</p>
|
||||
</div>
|
||||
|
||||
{/* Permissions */}
|
||||
<div className="mb-3">
|
||||
<p className="text-xs font-medium text-[var(--text-secondary)] mb-2">Permisos:</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{member.permissions.map((permission, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="px-2 py-1 bg-[var(--color-info)]/10 text-[var(--color-info)] text-xs rounded-full"
|
||||
>
|
||||
{permission}
|
||||
</span>
|
||||
))}
|
||||
<span className="px-2 py-1 bg-[var(--color-info)]/10 text-[var(--color-info)] text-xs rounded-full">
|
||||
{getRoleLabel(member.role)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Schedule Preview */}
|
||||
{/* Member Info */}
|
||||
<div className="text-xs text-[var(--text-tertiary)]">
|
||||
<p className="font-medium mb-1">Horario esta semana:</p>
|
||||
<div className="grid grid-cols-2 gap-1">
|
||||
{Object.entries(member.schedule).slice(0, 4).map(([day, hours]) => (
|
||||
<span key={day}>
|
||||
{day.charAt(0).toUpperCase()}: {hours}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<p className="font-medium mb-1">Información adicional:</p>
|
||||
<p>ID: {member.id}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user