Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
345 changes: 345 additions & 0 deletions src/crm/components/CreateCustomerDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,345 @@
import * as React from "react";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import CircularProgress from "@mui/material/CircularProgress";
import Alert from "@mui/material/Alert";
import type { CreateCustomerRequest } from "../types/customer";

interface CreateCustomerDialogProps {
open: boolean;
onClose: () => void;
onCreate: (data: CreateCustomerRequest) => Promise<void>;
}

const initialFormData: CreateCustomerRequest = {
email: "",
login: {
username: "",
password: "",
},
name: {
first: "",
last: "",
title: "Mr",
},
gender: "male",
location: {
street: {
number: 0,
name: "",
},
city: "",
state: "",
country: "",
postcode: "",
},
phone: "",
cell: "",
};

export default function CreateCustomerDialog({
open,
onClose,
onCreate,
}: CreateCustomerDialogProps) {
const [formData, setFormData] =
React.useState<CreateCustomerRequest>(initialFormData);
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);

React.useEffect(() => {
if (open) {
setFormData(initialFormData);
setError(null);
}
}, [open]);

const handleInputChange = (field: string, value: any) => {
setFormData((prev) => {
const keys = field.split(".");
const updated = { ...prev };
let current: any = updated;

for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]]) {
current[keys[i]] = {};
}
current = current[keys[i]];
}

current[keys[keys.length - 1]] = value;
return updated;
});
};

const validateForm = (): boolean => {
if (
!formData.email ||
!formData.login.username ||
!formData.name.first ||
!formData.name.last
) {
setError(
"Please fill in all required fields (Email, Username, First Name, Last Name)",
);
return false;
}

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
setError("Please enter a valid email address");
return false;
}

return true;
};

const handleCreate = async () => {
if (!validateForm()) return;

try {
setLoading(true);
setError(null);
await onCreate(formData);
onClose();
} catch (err) {
setError(
err instanceof Error ? err.message : "Failed to create customer",
);
} finally {
setLoading(false);
}
};

const handleClose = () => {
if (!loading) {
onClose();
}
};

return (
<Dialog open={open} onClose={handleClose} maxWidth="md" fullWidth>
<DialogTitle>
<Typography variant="h6">Create New Customer</Typography>
</DialogTitle>

<DialogContent>
{error && (
<Alert severity="error" sx={{ mb: 2 }}>
{error}
</Alert>
)}

<Grid container spacing={3} sx={{ mt: 1 }}>
<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Email *"
type="email"
value={formData.email}
onChange={(e) => handleInputChange("email", e.target.value)}
required
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Username *"
value={formData.login.username}
onChange={(e) =>
handleInputChange("login.username", e.target.value)
}
required
/>
</Grid>

<Grid item xs={12} sm={4}>
<FormControl fullWidth>
<InputLabel>Title</InputLabel>
<Select
value={formData.name.title || "Mr"}
onChange={(e) =>
handleInputChange("name.title", e.target.value)
}
label="Title"
>
<MenuItem value="Mr">Mr</MenuItem>
<MenuItem value="Mrs">Mrs</MenuItem>
<MenuItem value="Ms">Ms</MenuItem>
<MenuItem value="Miss">Miss</MenuItem>
<MenuItem value="Dr">Dr</MenuItem>
</Select>
</FormControl>
</Grid>

<Grid item xs={12} sm={4}>
<TextField
fullWidth
label="First Name *"
value={formData.name.first}
onChange={(e) => handleInputChange("name.first", e.target.value)}
required
/>
</Grid>

<Grid item xs={12} sm={4}>
<TextField
fullWidth
label="Last Name *"
value={formData.name.last}
onChange={(e) => handleInputChange("name.last", e.target.value)}
required
/>
</Grid>

<Grid item xs={12} sm={6}>
<FormControl fullWidth>
<InputLabel>Gender</InputLabel>
<Select
value={formData.gender || "male"}
onChange={(e) => handleInputChange("gender", e.target.value)}
label="Gender"
>
<MenuItem value="male">Male</MenuItem>
<MenuItem value="female">Female</MenuItem>
<MenuItem value="other">Other</MenuItem>
</Select>
</FormControl>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Password"
type="password"
value={formData.login.password || ""}
onChange={(e) =>
handleInputChange("login.password", e.target.value)
}
helperText="Leave empty for auto-generated password"
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Phone"
value={formData.phone || ""}
onChange={(e) => handleInputChange("phone", e.target.value)}
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Cell Phone"
value={formData.cell || ""}
onChange={(e) => handleInputChange("cell", e.target.value)}
/>
</Grid>

<Grid item xs={12}>
<Typography variant="h6" sx={{ mt: 2, mb: 1 }}>
Address (Optional)
</Typography>
</Grid>

<Grid item xs={12} sm={3}>
<TextField
fullWidth
label="Street Number"
type="number"
value={formData.location?.street?.number || ""}
onChange={(e) =>
handleInputChange(
"location.street.number",
parseInt(e.target.value) || 0,
)
}
/>
</Grid>

<Grid item xs={12} sm={9}>
<TextField
fullWidth
label="Street Name"
value={formData.location?.street?.name || ""}
onChange={(e) =>
handleInputChange("location.street.name", e.target.value)
}
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="City"
value={formData.location?.city || ""}
onChange={(e) =>
handleInputChange("location.city", e.target.value)
}
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="State"
value={formData.location?.state || ""}
onChange={(e) =>
handleInputChange("location.state", e.target.value)
}
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Country"
value={formData.location?.country || ""}
onChange={(e) =>
handleInputChange("location.country", e.target.value)
}
/>
</Grid>

<Grid item xs={12} sm={6}>
<TextField
fullWidth
label="Postal Code"
value={formData.location?.postcode || ""}
onChange={(e) =>
handleInputChange("location.postcode", e.target.value)
}
/>
</Grid>
</Grid>
</DialogContent>

<DialogActions>
<Button onClick={handleClose} disabled={loading}>
Cancel
</Button>
<Button
onClick={handleCreate}
variant="contained"
disabled={loading}
startIcon={loading ? <CircularProgress size={16} /> : null}
>
Create Customer
</Button>
</DialogActions>
</Dialog>
);
}
Loading