Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from 'react'; | |
| import { db } from '../../firebase/config'; | |
| import { ref, onValue, set, update } from 'firebase/database'; | |
| import { Users, Shield, UserPlus, Trash2, CheckCircle, Activity, ShieldCheck, UserCog } from 'lucide-react'; | |
| export default function UserManager() { | |
| const [employees, setEmployees] = useState([]); | |
| const [newEmployee, setNewEmployee] = useState({ email: '', role: 'mesero', name: '' }); | |
| useEffect(() => { | |
| onValue(ref(db, 'users'), (snapshot) => { | |
| const data = snapshot.val(); | |
| if (data) { | |
| setEmployees(Object.keys(data).map(uid => ({ uid, ...data[uid] }))); | |
| } | |
| }); | |
| }, []); | |
| const handleUpdateRole = async (uid, newRole) => { | |
| await update(ref(db, `users/${uid}`), { role: newRole }); | |
| }; | |
| const roleColors = { | |
| admin: 'var(--primary)', | |
| mesero: 'var(--success)', | |
| cocina: 'var(--warning)', | |
| cajero: '#50ADE6' | |
| }; | |
| return ( | |
| <div className="animate-fade-in" style={{ padding: '0 1rem' }}> | |
| <header style={{ marginBottom: '2.5rem' }}> | |
| <h2 className="text-gradient" style={{ fontSize: '2rem', fontWeight: '800', display: 'flex', alignItems: 'center', gap: '0.75rem' }}> | |
| <UserCog size={28} /> Equipo y Roles | |
| </h2> | |
| <p style={{ color: 'var(--text-muted)' }}>Control de acceso y permisos para empleados</p> | |
| </header> | |
| <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '1.5rem' }}> | |
| {employees.map(emp => ( | |
| <div key={emp.uid} className="glass-card" style={{ padding: '1.5rem', borderLeft: `4px solid ${roleColors[emp.role] || '#fff'}` }}> | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', marginBottom: '1rem' }}> | |
| <div> | |
| <h3 style={{ fontSize: '1.1rem', fontWeight: '700' }}>{emp.name || 'Sin Nombre'}</h3> | |
| <p style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>{emp.email}</p> | |
| </div> | |
| <div style={{ background: 'rgba(255,255,255,0.05)', padding: '0.5rem', borderRadius: '50%' }}> | |
| <Shield size={20} style={{ color: roleColors[emp.role] }} /> | |
| </div> | |
| </div> | |
| <div style={{ marginBottom: '1.5rem' }}> | |
| <label style={labelStyle}>Rol Asignado</label> | |
| <select | |
| value={emp.role} | |
| onChange={(e) => handleUpdateRole(emp.uid, e.target.value)} | |
| style={{...inputStyle, background: 'rgba(0,0,0,0.2)', border: '1px solid var(--border-subtle)'}} | |
| > | |
| <option value="admin">Administrador (Total)</option> | |
| <option value="mesero">Mesero (POS)</option> | |
| <option value="cocina">Cocina (KDS)</option> | |
| <option value="cajero">Cajero (Caja/POS)</option> | |
| </select> | |
| </div> | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> | |
| <div style={{ display: 'flex', alignItems: 'center', gap: '0.4rem', fontSize: '0.7rem', color: 'var(--success)' }}> | |
| <Activity size={12} /> Activo | |
| </div> | |
| <button style={{ background: 'none', border: 'none', color: 'var(--primary)', cursor: 'pointer' }} title="Revocar Acceso"> | |
| <Trash2 size={16} /> | |
| </button> | |
| </div> | |
| </div> | |
| ))} | |
| <div className="glass-card" style={{ border: '2px dashed var(--border-subtle)', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', textAlign: 'center', padding: '2rem', gap: '1rem' }}> | |
| <div style={{ background: 'rgba(255,255,255,0.05)', padding: '1rem', borderRadius: '50%', color: 'var(--text-muted)' }}> | |
| <UserPlus size={32} /> | |
| </div> | |
| <h3 style={{ fontSize: '1rem', fontWeight: '700' }}>Registrar Nuevo Empleado</h3> | |
| <p style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>El empleado debe registrarse primero en la app para aparecer aquí.</p> | |
| </div> | |
| </div> | |
| <div className="glass-panel" style={{ marginTop: '3rem', padding: '2rem' }}> | |
| <h3 style={{ fontSize: '1.1rem', marginBottom: '1.5rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}> | |
| <ShieldCheck size={18} /> Permisos por Rol | |
| </h3> | |
| <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1.5rem' }}> | |
| {[ | |
| { role: 'Admin', rights: 'Control total de inventario, finanzas y menú.' }, | |
| { role: 'Mesero', rights: 'Toma de pedidos, cierre de cuentas y mapa de mesas.' }, | |
| { role: 'Cocina', rights: 'Visualización de tickets y cambio de estado de preparación.' }, | |
| { role: 'Cajero', rights: 'Gestión de arqueo de caja y cobros de POS.' } | |
| ].map(r => ( | |
| <div key={r.role}> | |
| <h4 style={{ fontSize: '0.9rem', fontWeight: '800', marginBottom: '0.5rem' }}>{r.role}</h4> | |
| <p style={{ fontSize: '0.8rem', color: 'var(--text-muted)', lineHeight: '1.4' }}>{r.rights}</p> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| const inputStyle = { width: '100%', padding: '0.8rem', borderRadius: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid var(--border-subtle)', color: '#fff', outline: 'none' }; | |
| const labelStyle = { display: 'block', fontSize: '0.8rem', color: 'var(--text-muted)', marginBottom: '0.5rem' }; | |