mirror of
https://github.com/Alvin-Zilverstand/challenge-11.git
synced 2026-03-06 11:06:21 +01:00
Update customer management functionality by adding modification support, enhancing the customer model to include modifications, and improving the UI for customer and modification forms. Refactor API routes for better error handling and streamline customer data management.
This commit is contained in:
14
client/public/favicon.svg
Normal file
14
client/public/favicon.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Car body -->
|
||||||
|
<path d="M6 20C6 18.8954 6.89543 18 8 18H24C25.1046 18 26 18.8954 26 20V24C26 25.1046 25.1046 26 24 26H8C6.89543 26 6 25.1046 6 24V20Z" fill="#ff3d00"/>
|
||||||
|
<!-- Car top -->
|
||||||
|
<path d="M10 14C10 12.8954 10.8954 12 12 12H20C21.1046 12 22 12.8954 22 14V18H10V14Z" fill="#ff3d00"/>
|
||||||
|
<!-- Wheels -->
|
||||||
|
<circle cx="10" cy="22" r="3" fill="#212121"/>
|
||||||
|
<circle cx="22" cy="22" r="3" fill="#212121"/>
|
||||||
|
<!-- Speed lines -->
|
||||||
|
<path d="M4 16L8 16" stroke="#ff3d00" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M4 18L8 18" stroke="#ff3d00" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M4 20L8 20" stroke="#ff3d00" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 826 B |
@@ -2,14 +2,14 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" type="image/svg+xml" href="%PUBLIC_URL%/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="Car Tuning & Modification Management System"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>AutoTune Pro | Car Tuning Management</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|||||||
@@ -22,40 +22,47 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
FormControl,
|
FormControl,
|
||||||
InputLabel,
|
InputLabel,
|
||||||
|
Grid,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Divider
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import { Edit as EditIcon, Delete as DeleteIcon, Add as AddIcon } from '@mui/icons-material';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const carModels = [
|
const carModels = [
|
||||||
{ value: 'bmw_m3', label: 'BMW M3' },
|
'BMW M3',
|
||||||
{ value: 'bmw_m4', label: 'BMW M4' },
|
'BMW M4',
|
||||||
{ value: 'audi_rs3', label: 'Audi RS3' },
|
'Audi RS3',
|
||||||
{ value: 'audi_rs4', label: 'Audi RS4' },
|
'Audi RS4',
|
||||||
{ value: 'mercedes_c63', label: 'Mercedes-AMG C63' },
|
'Mercedes-AMG C63',
|
||||||
{ value: 'mercedes_e63', label: 'Mercedes-AMG E63' },
|
'Mercedes-AMG E63',
|
||||||
{ value: 'volkswagen_golf_r', label: 'Volkswagen Golf R' },
|
'Volkswagen Golf R',
|
||||||
{ value: 'volkswagen_arteon_r', label: 'Volkswagen Arteon R' },
|
'Volkswagen Arteon R',
|
||||||
{ value: 'toyota_supra', label: 'Toyota Supra' },
|
'Toyota Supra',
|
||||||
{ value: 'nissan_gtr', label: 'Nissan GT-R' },
|
'Nissan GT-R',
|
||||||
{ value: 'porsche_911', label: 'Porsche 911' },
|
'Porsche 911',
|
||||||
{ value: 'porsche_cayman', label: 'Porsche Cayman' },
|
'Porsche Cayman',
|
||||||
{ value: 'honda_civic_type_r', label: 'Honda Civic Type R' },
|
'Honda Civic Type R',
|
||||||
{ value: 'subaru_wrx_sti', label: 'Subaru WRX STI' },
|
'Subaru WRX STI',
|
||||||
{ value: 'mitsubishi_evo', label: 'Mitsubishi Lancer Evolution' },
|
'Mitsubishi Lancer Evolution',
|
||||||
{ value: 'other', label: 'Other' },
|
'Other'
|
||||||
|
];
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
'Engine',
|
||||||
|
'Exhaust',
|
||||||
|
'Suspension',
|
||||||
|
'Brakes',
|
||||||
|
'Wheels'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Create axios instance with default config
|
// Create axios instance with default config
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: 'http://localhost:5000/api',
|
baseURL: 'http://localhost:5000/api'
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add request interceptor to add token to all requests
|
// Add request interceptor to include token
|
||||||
api.interceptors.request.use(
|
api.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
@@ -72,17 +79,24 @@ api.interceptors.request.use(
|
|||||||
const CustomerManagement = () => {
|
const CustomerManagement = () => {
|
||||||
const [customers, setCustomers] = useState([]);
|
const [customers, setCustomers] = useState([]);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const [openModDialog, setOpenModDialog] = useState(false);
|
||||||
const [selectedCustomer, setSelectedCustomer] = useState(null);
|
const [selectedCustomer, setSelectedCustomer] = useState(null);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const [success, setSuccess] = useState('');
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
address: '',
|
address: '',
|
||||||
carModel: '',
|
carModel: '',
|
||||||
carYear: '',
|
carYear: ''
|
||||||
|
});
|
||||||
|
const [modificationData, setModificationData] = useState({
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
price: '',
|
||||||
|
category: ''
|
||||||
});
|
});
|
||||||
const [error, setError] = useState('');
|
|
||||||
const [success, setSuccess] = useState('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchCustomers();
|
fetchCustomers();
|
||||||
@@ -99,32 +113,56 @@ const CustomerManagement = () => {
|
|||||||
|
|
||||||
const handleOpen = (customer = null) => {
|
const handleOpen = (customer = null) => {
|
||||||
if (customer) {
|
if (customer) {
|
||||||
setSelectedCustomer(customer);
|
|
||||||
setFormData(customer);
|
setFormData(customer);
|
||||||
|
setSelectedCustomer(customer);
|
||||||
} else {
|
} else {
|
||||||
setSelectedCustomer(null);
|
|
||||||
setFormData({
|
setFormData({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
address: '',
|
address: '',
|
||||||
carModel: '',
|
carModel: '',
|
||||||
carYear: '',
|
carYear: ''
|
||||||
});
|
});
|
||||||
|
setSelectedCustomer(null);
|
||||||
}
|
}
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOpenModDialog = (customer) => {
|
||||||
|
setSelectedCustomer(customer);
|
||||||
|
setModificationData({
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
price: '',
|
||||||
|
category: ''
|
||||||
|
});
|
||||||
|
setOpenModDialog(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setError('');
|
setError('');
|
||||||
setSuccess('');
|
setSuccess('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleCloseModDialog = () => {
|
||||||
|
setOpenModDialog(false);
|
||||||
|
setError('');
|
||||||
|
setSuccess('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e) => {
|
||||||
setFormData({
|
setFormData({
|
||||||
...formData,
|
...formData,
|
||||||
[e.target.name]: e.target.value,
|
[e.target.name]: e.target.value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleModInputChange = (e) => {
|
||||||
|
setModificationData({
|
||||||
|
...modificationData,
|
||||||
|
[e.target.name]: e.target.value
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -145,6 +183,18 @@ const CustomerManagement = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAddModification = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
await api.put(`/customers/${selectedCustomer._id}/modifications`, modificationData);
|
||||||
|
setSuccess('Modification added successfully');
|
||||||
|
fetchCustomers();
|
||||||
|
handleCloseModDialog();
|
||||||
|
} catch (err) {
|
||||||
|
setError(err.response?.data?.message || 'An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = async (id) => {
|
const handleDelete = async (id) => {
|
||||||
if (window.confirm('Are you sure you want to delete this customer?')) {
|
if (window.confirm('Are you sure you want to delete this customer?')) {
|
||||||
try {
|
try {
|
||||||
@@ -159,8 +209,8 @@ const CustomerManagement = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
|
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||||
<Typography variant="h4" component="h1" gutterBottom sx={{ fontWeight: 'bold' }}>
|
<Typography variant="h4" component="h1" gutterBottom>
|
||||||
Customer Management
|
Customer Management
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button
|
<Button
|
||||||
@@ -173,17 +223,8 @@ const CustomerManagement = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{error && (
|
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
|
||||||
<Alert severity="error" sx={{ mb: 2 }}>
|
{success && <Alert severity="success" sx={{ mb: 2 }}>{success}</Alert>}
|
||||||
{error}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{success && (
|
|
||||||
<Alert severity="success" sx={{ mb: 2 }}>
|
|
||||||
{success}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TableContainer component={Paper}>
|
<TableContainer component={Paper}>
|
||||||
<Table>
|
<Table>
|
||||||
@@ -194,6 +235,7 @@ const CustomerManagement = () => {
|
|||||||
<TableCell>Phone</TableCell>
|
<TableCell>Phone</TableCell>
|
||||||
<TableCell>Car Model</TableCell>
|
<TableCell>Car Model</TableCell>
|
||||||
<TableCell>Car Year</TableCell>
|
<TableCell>Car Year</TableCell>
|
||||||
|
<TableCell>Modifications</TableCell>
|
||||||
<TableCell>Actions</TableCell>
|
<TableCell>Actions</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
@@ -205,6 +247,24 @@ const CustomerManagement = () => {
|
|||||||
<TableCell>{customer.phone}</TableCell>
|
<TableCell>{customer.phone}</TableCell>
|
||||||
<TableCell>{customer.carModel}</TableCell>
|
<TableCell>{customer.carModel}</TableCell>
|
||||||
<TableCell>{customer.carYear}</TableCell>
|
<TableCell>{customer.carYear}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
onClick={() => handleOpenModDialog(customer)}
|
||||||
|
>
|
||||||
|
Add Modification
|
||||||
|
</Button>
|
||||||
|
{customer.modifications && customer.modifications.length > 0 && (
|
||||||
|
<Box sx={{ mt: 1 }}>
|
||||||
|
{customer.modifications.map((mod, index) => (
|
||||||
|
<Typography key={index} variant="body2">
|
||||||
|
{mod.name} - {mod.category}
|
||||||
|
</Typography>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<IconButton onClick={() => handleOpen(customer)} color="primary">
|
<IconButton onClick={() => handleOpen(customer)} color="primary">
|
||||||
<EditIcon />
|
<EditIcon />
|
||||||
@@ -219,82 +279,157 @@ const CustomerManagement = () => {
|
|||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
|
||||||
|
{/* Customer Form Dialog */}
|
||||||
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
|
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
|
||||||
<DialogTitle>
|
<DialogTitle>{selectedCustomer ? 'Edit Customer' : 'Add Customer'}</DialogTitle>
|
||||||
{selectedCustomer ? 'Edit Customer' : 'Add New Customer'}
|
<DialogContent>
|
||||||
</DialogTitle>
|
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 2 }}>
|
||||||
<form onSubmit={handleSubmit}>
|
<Grid container spacing={2}>
|
||||||
<DialogContent>
|
<Grid item xs={12}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
label="Name"
|
label="Full Name"
|
||||||
name="name"
|
name="name"
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={handleChange}
|
onChange={handleInputChange}
|
||||||
margin="normal"
|
required
|
||||||
required
|
/>
|
||||||
/>
|
</Grid>
|
||||||
<TextField
|
<Grid item xs={12}>
|
||||||
fullWidth
|
<TextField
|
||||||
label="Email"
|
fullWidth
|
||||||
name="email"
|
label="Email Address"
|
||||||
type="email"
|
name="email"
|
||||||
value={formData.email}
|
type="email"
|
||||||
onChange={handleChange}
|
value={formData.email}
|
||||||
margin="normal"
|
onChange={handleInputChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<TextField
|
</Grid>
|
||||||
fullWidth
|
<Grid item xs={12}>
|
||||||
label="Phone"
|
<TextField
|
||||||
name="phone"
|
fullWidth
|
||||||
value={formData.phone}
|
label="Phone Number"
|
||||||
onChange={handleChange}
|
name="phone"
|
||||||
margin="normal"
|
value={formData.phone}
|
||||||
required
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
<TextField
|
/>
|
||||||
fullWidth
|
</Grid>
|
||||||
label="Address"
|
<Grid item xs={12}>
|
||||||
name="address"
|
<TextField
|
||||||
value={formData.address}
|
fullWidth
|
||||||
onChange={handleChange}
|
label="Address"
|
||||||
margin="normal"
|
name="address"
|
||||||
multiline
|
value={formData.address}
|
||||||
rows={2}
|
onChange={handleInputChange}
|
||||||
/>
|
required
|
||||||
<FormControl fullWidth margin="normal" required>
|
/>
|
||||||
<InputLabel>Car Model</InputLabel>
|
</Grid>
|
||||||
<Select
|
<Grid item xs={12}>
|
||||||
name="carModel"
|
<FormControl fullWidth required>
|
||||||
value={formData.carModel}
|
<InputLabel>Car Model</InputLabel>
|
||||||
onChange={handleChange}
|
<Select
|
||||||
label="Car Model"
|
name="carModel"
|
||||||
>
|
value={formData.carModel}
|
||||||
{carModels.map((model) => (
|
onChange={handleInputChange}
|
||||||
<MenuItem key={model.value} value={model.value}>
|
label="Car Model"
|
||||||
{model.label}
|
>
|
||||||
</MenuItem>
|
{carModels.map((model) => (
|
||||||
))}
|
<MenuItem key={model} value={model}>
|
||||||
</Select>
|
{model}
|
||||||
</FormControl>
|
</MenuItem>
|
||||||
<TextField
|
))}
|
||||||
fullWidth
|
</Select>
|
||||||
label="Car Year"
|
</FormControl>
|
||||||
name="carYear"
|
</Grid>
|
||||||
value={formData.carYear}
|
<Grid item xs={12}>
|
||||||
onChange={handleChange}
|
<TextField
|
||||||
margin="normal"
|
fullWidth
|
||||||
required
|
label="Car Year"
|
||||||
/>
|
name="carYear"
|
||||||
</DialogContent>
|
type="number"
|
||||||
<DialogActions>
|
value={formData.carYear}
|
||||||
<Button onClick={handleClose}>Cancel</Button>
|
onChange={handleInputChange}
|
||||||
<Button type="submit" variant="contained" color="primary">
|
required
|
||||||
{selectedCustomer ? 'Update' : 'Add'}
|
/>
|
||||||
</Button>
|
</Grid>
|
||||||
</DialogActions>
|
</Grid>
|
||||||
</form>
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleClose}>Cancel</Button>
|
||||||
|
<Button onClick={handleSubmit} variant="contained" color="primary">
|
||||||
|
{selectedCustomer ? 'Update' : 'Add'}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Modification Form Dialog */}
|
||||||
|
<Dialog open={openModDialog} onClose={handleCloseModDialog} maxWidth="sm" fullWidth>
|
||||||
|
<DialogTitle>Add Modification</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box component="form" onSubmit={handleAddModification} sx={{ mt: 2 }}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Modification Name"
|
||||||
|
name="name"
|
||||||
|
value={modificationData.name}
|
||||||
|
onChange={handleModInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Description"
|
||||||
|
name="description"
|
||||||
|
multiline
|
||||||
|
rows={3}
|
||||||
|
value={modificationData.description}
|
||||||
|
onChange={handleModInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Price"
|
||||||
|
name="price"
|
||||||
|
type="number"
|
||||||
|
value={modificationData.price}
|
||||||
|
onChange={handleModInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<FormControl fullWidth required>
|
||||||
|
<InputLabel>Category</InputLabel>
|
||||||
|
<Select
|
||||||
|
name="category"
|
||||||
|
value={modificationData.category}
|
||||||
|
onChange={handleModInputChange}
|
||||||
|
label="Category"
|
||||||
|
>
|
||||||
|
{categories.map((category) => (
|
||||||
|
<MenuItem key={category} value={category}>
|
||||||
|
{category}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleCloseModDialog}>Cancel</Button>
|
||||||
|
<Button onClick={handleAddModification} variant="contained" color="primary">
|
||||||
|
Add Modification
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const customerSchema = new mongoose.Schema({
|
|||||||
},
|
},
|
||||||
address: {
|
address: {
|
||||||
type: String,
|
type: String,
|
||||||
|
required: true,
|
||||||
trim: true
|
trim: true
|
||||||
},
|
},
|
||||||
carModel: {
|
carModel: {
|
||||||
@@ -28,10 +29,31 @@ const customerSchema = new mongoose.Schema({
|
|||||||
trim: true
|
trim: true
|
||||||
},
|
},
|
||||||
carYear: {
|
carYear: {
|
||||||
type: String,
|
type: Number,
|
||||||
required: true,
|
required: true
|
||||||
trim: true
|
|
||||||
},
|
},
|
||||||
|
modifications: [{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
dateAdded: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now
|
||||||
|
}
|
||||||
|
}],
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: Date.now
|
default: Date.now
|
||||||
@@ -48,4 +70,6 @@ customerSchema.pre('save', function(next) {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = mongoose.model('Customer', customerSchema);
|
const Customer = mongoose.model('Customer', customerSchema);
|
||||||
|
|
||||||
|
module.exports = Customer;
|
||||||
@@ -9,7 +9,7 @@ router.get('/', auth, async (req, res) => {
|
|||||||
const customers = await Customer.find().sort({ name: 1 });
|
const customers = await Customer.find().sort({ name: 1 });
|
||||||
res.json(customers);
|
res.json(customers);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ message: err.message });
|
res.status(500).send('Server Error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,24 +22,16 @@ router.get('/:id', auth, async (req, res) => {
|
|||||||
}
|
}
|
||||||
res.json(customer);
|
res.json(customer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ message: err.message });
|
res.status(500).send('Server Error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create customer
|
// Create customer
|
||||||
router.post('/', auth, async (req, res) => {
|
router.post('/', auth, async (req, res) => {
|
||||||
const customer = new Customer({
|
|
||||||
name: req.body.name,
|
|
||||||
email: req.body.email,
|
|
||||||
phone: req.body.phone,
|
|
||||||
address: req.body.address,
|
|
||||||
carModel: req.body.carModel,
|
|
||||||
carYear: req.body.carYear,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newCustomer = await customer.save();
|
const customer = new Customer(req.body);
|
||||||
res.status(201).json(newCustomer);
|
await customer.save();
|
||||||
|
res.status(201).json(customer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(400).json({ message: err.message });
|
res.status(400).json({ message: err.message });
|
||||||
}
|
}
|
||||||
@@ -53,9 +45,28 @@ router.put('/:id', auth, async (req, res) => {
|
|||||||
return res.status(404).json({ message: 'Customer not found' });
|
return res.status(404).json({ message: 'Customer not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(customer, req.body);
|
Object.keys(req.body).forEach(key => {
|
||||||
const updatedCustomer = await customer.save();
|
customer[key] = req.body[key];
|
||||||
res.json(updatedCustomer);
|
});
|
||||||
|
|
||||||
|
await customer.save();
|
||||||
|
res.json(customer);
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).json({ message: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add modification to customer
|
||||||
|
router.put('/:id/modifications', auth, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const customer = await Customer.findById(req.params.id);
|
||||||
|
if (!customer) {
|
||||||
|
return res.status(404).json({ message: 'Customer not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
customer.modifications.push(req.body);
|
||||||
|
await customer.save();
|
||||||
|
res.json(customer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(400).json({ message: err.message });
|
res.status(400).json({ message: err.message });
|
||||||
}
|
}
|
||||||
@@ -72,7 +83,7 @@ router.delete('/:id', auth, async (req, res) => {
|
|||||||
await customer.remove();
|
await customer.remove();
|
||||||
res.json({ message: 'Customer deleted' });
|
res.json({ message: 'Customer deleted' });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ message: err.message });
|
res.status(500).send('Server Error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user