28295e346c
- Created a global TypeScript declaration for the txadmin interface on the Window object. - Implemented date formatting utilities using date-fns with Spanish locale support. - Added TypeScript configuration files for app, Electron, and Node environments. - Set up Vite configuration for React application.
128 lines
5.8 KiB
TypeScript
128 lines
5.8 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import { X } from 'lucide-react';
|
|
import { updateUserProfile, setVerifiedStatus } from '../../api/sysadmin';
|
|
|
|
export const EditUserModal = ({ user, onClose, onSaved }: { user: any, onClose: () => void, onSaved: () => void }) => {
|
|
const [formData, setFormData] = useState({
|
|
firstName: user.firstName || '',
|
|
lastName: user.lastName || '',
|
|
street: user.street || '',
|
|
streetNumber: user.streetNumber || '',
|
|
city: user.city || '',
|
|
state: user.state || '',
|
|
country: user.country || '',
|
|
phoneCountryCode: user.phoneCountryCode || '',
|
|
phoneAreaCode: user.phoneAreaCode || '',
|
|
phoneNumber: user.phoneNumber || '',
|
|
verificated: user.verificated || false,
|
|
});
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setLoading(true);
|
|
try {
|
|
const promises: Promise<any>[] = [
|
|
updateUserProfile({ userId: user._id, ...formData })
|
|
];
|
|
if (formData.verificated !== user.verificated) {
|
|
promises.push(setVerifiedStatus(user._id, formData.verificated));
|
|
}
|
|
await Promise.all(promises);
|
|
onSaved();
|
|
onClose();
|
|
} catch (err) {
|
|
alert('Error guardando perfil');
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
return (
|
|
<div style={{ position: 'fixed', inset: 0, zIndex: 50, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.5)', backdropFilter: 'blur(4px)' }}>
|
|
<motion.div
|
|
initial={{ scale: 0.9, opacity: 0 }}
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
className="glass-panel"
|
|
style={{ width: '90%', maxWidth: '600px', maxHeight: '90vh', overflowY: 'auto', padding: '2rem', position: 'relative' }}
|
|
>
|
|
<button onClick={onClose} style={{ position: 'absolute', top: '1.5rem', right: '1.5rem', background: 'transparent', color: 'var(--text-muted)' }}>
|
|
<X size={24} />
|
|
</button>
|
|
|
|
<h2 style={{ fontSize: '1.5rem', marginBottom: '1.5rem' }}>Editar Perfil: {user.email}</h2>
|
|
|
|
<form onSubmit={handleSubmit} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
|
|
<div>
|
|
<label className="modal-label">Nombre</label>
|
|
<input className="input-glass" value={formData.firstName} onChange={e => setFormData({...formData, firstName: e.target.value})} />
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Apellido</label>
|
|
<input className="input-glass" value={formData.lastName} onChange={e => setFormData({...formData, lastName: e.target.value})} />
|
|
</div>
|
|
|
|
<div style={{ gridColumn: '1 / -1', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
<h3 style={{ margin: '1rem 0 0.5rem', color: 'var(--primary)', fontSize: '1.1rem' }}>Contacto</h3>
|
|
<button
|
|
type="button"
|
|
onClick={() => setFormData({...formData, verificated: !formData.verificated})}
|
|
className="btn-secondary"
|
|
style={{ display: 'flex', alignItems: 'center', gap: '8px', color: formData.verificated ? 'var(--success)' : 'var(--warning)', padding: '4px 12px' }}
|
|
>
|
|
{formData.verificated ? 'Usuario Verificado' : 'Usuario No Verificado'}
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Cód. País</label>
|
|
<input className="input-glass" value={formData.phoneCountryCode} onChange={e => setFormData({...formData, phoneCountryCode: e.target.value})} />
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Cód. Área</label>
|
|
<input className="input-glass" value={formData.phoneAreaCode} onChange={e => setFormData({...formData, phoneAreaCode: e.target.value})} />
|
|
</div>
|
|
<div style={{ gridColumn: '1 / -1' }}>
|
|
<label className="modal-label">Teléfono</label>
|
|
<input className="input-glass" value={formData.phoneNumber} onChange={e => setFormData({...formData, phoneNumber: e.target.value})} />
|
|
</div>
|
|
|
|
<div style={{ gridColumn: '1 / -1' }}>
|
|
<h3 style={{ margin: '1rem 0 0.5rem', color: 'var(--primary)', fontSize: '1.1rem' }}>Dirección</h3>
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Calle</label>
|
|
<input className="input-glass" value={formData.street} onChange={e => setFormData({...formData, street: e.target.value})} />
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Número</label>
|
|
<input className="input-glass" value={formData.streetNumber} onChange={e => setFormData({...formData, streetNumber: e.target.value})} />
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">Ciudad</label>
|
|
<input className="input-glass" value={formData.city} onChange={e => setFormData({...formData, city: e.target.value})} />
|
|
</div>
|
|
<div>
|
|
<label className="modal-label">País</label>
|
|
<input className="input-glass" value={formData.country} onChange={e => setFormData({...formData, country: e.target.value})} />
|
|
</div>
|
|
|
|
<div style={{ gridColumn: '1 / -1', marginTop: '1.5rem', display: 'flex', justifyContent: 'flex-end', gap: '1rem' }}>
|
|
<button type="button" className="btn-secondary" onClick={onClose}>Cancelar</button>
|
|
<button type="submit" className="btn-primary" disabled={loading}>{loading ? 'Guardando...' : 'Guardar Cambios'}</button>
|
|
</div>
|
|
</form>
|
|
|
|
<style dangerouslySetInnerHTML={{__html: `
|
|
.modal-label {
|
|
display: block;
|
|
font-size: 0.85rem;
|
|
color: var(--text-muted);
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
`}} />
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
};
|