Files
doormile_crm/src/pages/team/UserFormDialog.jsx
2026-07-14 12:15:40 +05:30

100 lines
4.0 KiB
JavaScript

import { useState, useEffect } from 'react';
import {
Dialog, DialogTitle, DialogContent, DialogActions, Button, Grid, TextField,
MenuItem, Alert, CircularProgress, IconButton, useMediaQuery
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import CloseIcon from '@mui/icons-material/Close';
import { createUser, updateUser } from '@/utils/apiClient';
const ROLES = ['admin', 'rep', 'manager'];
const EMPTY = { name: '', email: '', phone: '', role: 'rep', pin: '', password: '' };
const withValue = (opts, v) => (v && !opts.includes(v) ? [v, ...opts] : opts);
export default function UserFormDialog({ open, mode, initial, onClose, onSaved }) {
const isEdit = mode === 'edit';
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
const [form, setForm] = useState(EMPTY);
const [saving, setSaving] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
if (open) {
setForm({ ...EMPTY, ...(initial || {}) });
setError(null);
}
}, [open, initial]);
const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));
const handleSave = async () => {
if (!form.name.trim()) { setError('Name is required.'); return; }
if (!form.email.trim()) { setError('Email is required.'); return; }
if (!isEdit && !form.password.trim()) { setError('Password is required.'); return; }
setSaving(true);
setError(null);
const payload = {
first_name: form.name.trim(),
email: form.email.trim(),
phone: form.phone,
role: form.role,
...(form.password ? { password: form.password } : {}),
...(form.pin ? { pin: String(form.pin) } : {}),
};
try {
if (isEdit) {
await updateUser(initial.id, payload);
} else {
await createUser(payload);
}
onSaved();
} catch (e) {
setError(e.message || 'Failed to save user');
} finally {
setSaving(false);
}
};
return (
<Dialog open={open} onClose={saving ? undefined : onClose} maxWidth="sm" fullWidth fullScreen={fullScreen}>
<DialogTitle sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
{isEdit ? 'Edit Team User' : 'Add Team User'}
<IconButton onClick={onClose} size="small" disabled={saving}><CloseIcon /></IconButton>
</DialogTitle>
<DialogContent dividers>
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
<Grid container spacing={2} sx={{ mt: 0 }}>
<Grid item xs={12} sm={6}><TextField fullWidth size="small" label="Name *" value={form.name} onChange={set('name')} /></Grid>
<Grid item xs={12} sm={6}><TextField fullWidth size="small" label="Email *" value={form.email} onChange={set('email')} /></Grid>
<Grid item xs={12} sm={6}><TextField fullWidth size="small" label="Phone" value={form.phone} onChange={set('phone')} /></Grid>
<Grid item xs={12} sm={6}>
<TextField select fullWidth size="small" label="Role" value={form.role} onChange={set('role')}>
{withValue(ROLES, form.role).map((o) => <MenuItem key={o} value={o}>{o}</MenuItem>)}
</TextField>
</Grid>
<Grid item xs={12} sm={6}><TextField fullWidth size="small" label="PIN" value={form.pin} onChange={set('pin')} /></Grid>
<Grid item xs={12} sm={6}>
<TextField
fullWidth size="small" type="password"
label={isEdit ? 'New Password (optional)' : 'Password *'}
value={form.password}
onChange={set('password')}
/>
</Grid>
</Grid>
</DialogContent>
<DialogActions sx={{ px: 3, py: 2 }}>
<Button onClick={onClose} disabled={saving}>Cancel</Button>
<Button variant="contained" onClick={handleSave} disabled={saving} startIcon={saving ? <CircularProgress size={16} color="inherit" /> : null}>
{isEdit ? 'Save Changes' : 'Create User'}
</Button>
</DialogActions>
</Dialog>
);
}