@@ -1,28 +1,26 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button } from '@astryxdesign/core/Button';
|
||||
import { Dialog, DialogHeader } from '@astryxdesign/core/Dialog';
|
||||
import { Layout, LayoutContent, LayoutFooter } from '@astryxdesign/core/Layout';
|
||||
import { FormLayout } from '@astryxdesign/core/FormLayout';
|
||||
import { TextInput } from '@astryxdesign/core/TextInput';
|
||||
import { Selector } from '@astryxdesign/core/Selector';
|
||||
import { Banner } from '@astryxdesign/core/Banner';
|
||||
|
||||
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);
|
||||
const selectorOptions = (opts, v) => withValue(opts, v).map((o) => ({ value: o, label: o.charAt(0).toUpperCase() + o.slice(1) }));
|
||||
|
||||
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);
|
||||
|
||||
const set = (k) => (val) => setForm((f) => ({ ...f, [k]: val }));
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setForm({ ...EMPTY, ...(initial || {}) });
|
||||
@@ -30,6 +28,8 @@ export default function UserFormDialog({ open, mode, initial, onClose, onSaved }
|
||||
}
|
||||
}, [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; }
|
||||
@@ -61,50 +61,39 @@ export default function UserFormDialog({ open, mode, initial, onClose, onSaved }
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog isOpen={open} onOpenChange={(o) => { if (!o) onClose(); }} width={600} purpose="form">
|
||||
<Layout
|
||||
header={<DialogHeader title={isEdit ? 'Edit Team User' : 'Add Team User'} onOpenChange={(o) => { if (!o) onClose(); }} />}
|
||||
content={
|
||||
<LayoutContent>
|
||||
<FormLayout>
|
||||
{error && <Banner status="error" title={error} />}
|
||||
|
||||
<FormLayout direction="horizontal">
|
||||
<TextInput label="Name" isRequired value={form.name} onChange={set('name')} />
|
||||
<TextInput label="Email" type="email" isRequired value={form.email} onChange={set('email')} />
|
||||
</FormLayout>
|
||||
<FormLayout direction="horizontal">
|
||||
<TextInput label="Phone" value={form.phone} onChange={set('phone')} />
|
||||
<Selector label="Role" options={selectorOptions(ROLES, form.role)} value={form.role} onChange={set('role')} />
|
||||
</FormLayout>
|
||||
<FormLayout direction="horizontal">
|
||||
<TextInput label="PIN" value={form.pin} onChange={set('pin')} />
|
||||
<TextInput
|
||||
label={isEdit ? 'New Password (optional)' : 'Password'}
|
||||
isRequired={!isEdit}
|
||||
type="password"
|
||||
value={form.password}
|
||||
onChange={set('password')}
|
||||
/>
|
||||
</FormLayout>
|
||||
</FormLayout>
|
||||
</LayoutContent>
|
||||
}
|
||||
footer={
|
||||
<LayoutFooter hasDivider>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '12px' }}>
|
||||
<Button label="Cancel" variant="ghost" onClick={onClose} isDisabled={saving} />
|
||||
<Button
|
||||
label={isEdit ? 'Save Changes' : 'Create User'}
|
||||
variant="primary"
|
||||
onClick={handleSave}
|
||||
isDisabled={saving}
|
||||
isLoading={saving}
|
||||
/>
|
||||
</div>
|
||||
</LayoutFooter>
|
||||
}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user