214 lines
7.5 KiB
JavaScript
214 lines
7.5 KiB
JavaScript
import { useState } from 'react';
|
|
|
|
// material-ui
|
|
import {
|
|
Avatar,
|
|
Button,
|
|
FormControlLabel,
|
|
Grid,
|
|
InputLabel,
|
|
MenuItem,
|
|
Paper,
|
|
Select,
|
|
Stack,
|
|
Switch,
|
|
TextField,
|
|
Typography,
|
|
useMediaQuery,
|
|
useTheme
|
|
} from '@mui/material';
|
|
import { MdPersonAddAlt1 } from 'react-icons/md';
|
|
import { useMutation } from '@tanstack/react-query';
|
|
|
|
// project import
|
|
import MainCard from 'components/MainCard';
|
|
import { createAdminTenant } from 'pages/api/doormileApi';
|
|
import Loader from 'components/Loader';
|
|
import { enqueueSnackbar } from 'notistack';
|
|
import { useNavigate } from 'react-router';
|
|
import { DT, tint } from 'themes/dt/tokens';
|
|
|
|
const Createclient = () => {
|
|
const theme = useTheme();
|
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
const navigate = useNavigate();
|
|
|
|
const [tenantname, setTenantname] = useState('');
|
|
const [primaryemail, setPrimaryemail] = useState('');
|
|
const [primarycontact, setPrimarycontact] = useState('');
|
|
// Confirmed live: POST /admin/tenants doesn't reject lowercase status, but
|
|
// stores it exactly as sent — every real tenant uses "Active" (title
|
|
// case), so a lowercase one would be inconsistent with the rest of the
|
|
// data even though the request itself succeeds.
|
|
const [status, setStatus] = useState('Active');
|
|
const [requiredeliveryotp, setRequiredeliveryotp] = useState(false);
|
|
|
|
const opentoast = (message) => {
|
|
enqueueSnackbar(message, {
|
|
variant: 'error',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 2000
|
|
});
|
|
};
|
|
|
|
const createTenantMutation = useMutation({
|
|
mutationFn: (payload) => createAdminTenant(payload),
|
|
onSuccess: (res) => {
|
|
if (res.success) {
|
|
enqueueSnackbar('Client created successfully', {
|
|
variant: 'success',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 2000
|
|
});
|
|
navigate('/doormile/tenants');
|
|
} else {
|
|
opentoast(res.message || 'Client already exists');
|
|
}
|
|
},
|
|
onError: (err) => {
|
|
opentoast(err.response?.data?.message || err.message || 'Failed to create client');
|
|
}
|
|
});
|
|
|
|
const createprofile = () => {
|
|
if (!tenantname) {
|
|
opentoast('Fill Client / Business Name');
|
|
} else if (!primarycontact || primarycontact.length !== 10) {
|
|
opentoast('Fill a valid 10-digit Contact Number');
|
|
} else if (!primaryemail) {
|
|
opentoast('Fill Primary Email');
|
|
} else {
|
|
// POST /admin/tenants — requiredeliveryotp is a pointer server-side;
|
|
// it's opt-in and off by default, so we only send it when the operator
|
|
// explicitly turns it on rather than always sending false.
|
|
const obj = {
|
|
tenantname,
|
|
primaryemail,
|
|
primarycontact,
|
|
status,
|
|
...(requiredeliveryotp ? { requiredeliveryotp: true } : {})
|
|
};
|
|
|
|
createTenantMutation.mutate(obj);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{createTenantMutation.isPending && <Loader />}
|
|
|
|
<Grid item xs={12} sx={{ mb: 2 }}>
|
|
<Paper
|
|
sx={{
|
|
p: 2.5,
|
|
borderRadius: DT.radiusCard + 'px',
|
|
boxShadow: DT.shadowSoft,
|
|
border: '1px solid',
|
|
borderColor: DT.borderSubtle,
|
|
background: `linear-gradient(135deg, ${tint('#C01227')} 0%, ${tint('#D25463')} 100%)`
|
|
}}
|
|
>
|
|
<Stack direction="row" spacing={1.5} alignItems="center">
|
|
<Avatar sx={{ width: 48, height: 48, bgcolor: DT.brand }}>
|
|
<MdPersonAddAlt1 size={22} />
|
|
</Avatar>
|
|
<Typography variant="h3">Create Client</Typography>
|
|
</Stack>
|
|
</Paper>
|
|
</Grid>
|
|
<MainCard
|
|
contentSX={{ p: { xs: 1.5, md: 3 } }}
|
|
sx={{ borderRadius: DT.radiusCard + 'px', boxShadow: DT.shadowSoft, borderColor: DT.borderSubtle }}
|
|
>
|
|
<Grid container spacing={isMobile ? 2 : 3}>
|
|
<Grid item xs={12}>
|
|
<MainCard sx={{ height: '100%' }} contentSX={{ p: { xs: 1.5, md: 2.5 } }}>
|
|
<Grid container spacing={isMobile ? 2 : 3}>
|
|
<Grid item xs={12} sm={6}>
|
|
<Stack spacing={1.25}>
|
|
<InputLabel htmlFor="tenant-name">Client / Business Name</InputLabel>
|
|
<TextField
|
|
fullWidth
|
|
id="tenant-name"
|
|
placeholder="e.g. DailyGrubs"
|
|
onChange={(e) => setTenantname(e.target.value)}
|
|
value={tenantname}
|
|
autoComplete="off"
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<Stack spacing={1.25}>
|
|
<InputLabel htmlFor="tenant-status">Status</InputLabel>
|
|
<Select id="tenant-status" fullWidth value={status} onChange={(e) => setStatus(e.target.value)}>
|
|
<MenuItem value="Active">Active</MenuItem>
|
|
<MenuItem value="Inactive">Inactive</MenuItem>
|
|
</Select>
|
|
</Stack>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<Stack spacing={1.25}>
|
|
<InputLabel htmlFor="tenant-contact">Primary Contact Number</InputLabel>
|
|
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
|
|
<Select defaultValue="+1" disabled sx={{ cursor: 'not-allowed' }}>
|
|
<MenuItem value="+1">+91</MenuItem>
|
|
</Select>
|
|
<TextField
|
|
type="number"
|
|
id="tenant-contact"
|
|
fullWidth
|
|
placeholder="Contact Number"
|
|
onChange={(e) => {
|
|
if (e.target.value.toString().length <= 10) {
|
|
setPrimarycontact(e.target.value);
|
|
}
|
|
}}
|
|
value={primarycontact}
|
|
autoComplete="off"
|
|
/>
|
|
</Stack>
|
|
</Stack>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<Stack spacing={1.25}>
|
|
<InputLabel htmlFor="tenant-email">Primary Email</InputLabel>
|
|
<TextField
|
|
type="email"
|
|
fullWidth
|
|
id="tenant-email"
|
|
placeholder="Primary Email Address"
|
|
onChange={(e) => setPrimaryemail(e.target.value)}
|
|
value={primaryemail}
|
|
autoComplete="off"
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<FormControlLabel
|
|
control={<Switch checked={requiredeliveryotp} onChange={(e) => setRequiredeliveryotp(e.target.checked)} />}
|
|
label="Require delivery OTP for this client (off by default)"
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</MainCard>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Stack
|
|
direction={{ xs: 'column', sm: 'row' }}
|
|
justifyContent="flex-end"
|
|
alignItems={{ xs: 'stretch', sm: 'center' }}
|
|
spacing={2}
|
|
>
|
|
<Button variant="contained" onClick={createprofile} fullWidth={isMobile}>
|
|
Create
|
|
</Button>
|
|
</Stack>
|
|
</Grid>
|
|
</Grid>
|
|
</MainCard>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Createclient;
|