Add new car modification options to CarModifications component, including performance upgrades for engine, exhaust, suspension, and brakes. Update Customer model to include address and car year fields, and implement pre-save hook for updatedAt timestamp. Enhance customer routes with authentication middleware and improved error handling.

This commit is contained in:
Alvin
2025-06-10 10:09:38 +02:00
parent 7b394b92d9
commit cefd020db6
4 changed files with 435 additions and 39 deletions

View File

@@ -72,6 +72,126 @@ const CarModifications = () => {
icon: wheelsIcon,
category: 'Wheels',
},
{
id: 7,
name: 'Turbocharger Kit',
description: 'Complete turbo upgrade kit for significant power gains',
price: '€2499',
icon: engineIcon,
category: 'Engine',
},
{
id: 8,
name: 'Cat-Back Exhaust',
description: 'Performance exhaust system with sport sound',
price: '€799',
icon: exhaustIcon,
category: 'Exhaust',
},
{
id: 9,
name: 'Coilover Suspension',
description: 'Fully adjustable suspension system for perfect handling',
price: '€1299',
icon: suspensionIcon,
category: 'Suspension',
},
{
id: 10,
name: 'Big Brake Kit',
description: '6-piston caliper upgrade with larger rotors',
price: '€1499',
icon: brakesIcon,
category: 'Brakes',
},
{
id: 11,
name: 'Forged Wheels',
description: 'Lightweight forged alloy wheels for better performance',
price: '€1999',
icon: wheelsIcon,
category: 'Wheels',
},
{
id: 12,
name: 'Stage 2 Tune',
description: 'Advanced ECU remap for maximum power gains',
price: '€499',
icon: engineIcon,
category: 'Engine',
},
{
id: 13,
name: 'Downpipe',
description: 'High-flow downpipe for improved exhaust flow',
price: '€349',
icon: exhaustIcon,
category: 'Exhaust',
},
{
id: 14,
name: 'Sway Bars',
description: 'Upgraded sway bars for reduced body roll',
price: '€299',
icon: suspensionIcon,
category: 'Suspension',
},
{
id: 15,
name: 'Brake Pads',
description: 'High-performance brake pads for better stopping',
price: '€199',
icon: brakesIcon,
category: 'Brakes',
},
{
id: 16,
name: 'Wheel Bearings',
description: 'Upgraded wheel bearings for smoother rotation',
price: '€249',
icon: wheelsIcon,
category: 'Wheels',
},
{
id: 17,
name: 'Intercooler Upgrade',
description: 'Larger intercooler for better cooling efficiency',
price: '€699',
icon: engineIcon,
category: 'Engine',
},
{
id: 18,
name: 'Exhaust Manifold',
description: 'Equal-length exhaust manifold for better flow',
price: '€449',
icon: exhaustIcon,
category: 'Exhaust',
},
{
id: 19,
name: 'Strut Brace',
description: 'Front strut brace for improved chassis rigidity',
price: '€199',
icon: suspensionIcon,
category: 'Suspension',
},
{
id: 20,
name: 'Brake Lines',
description: 'Stainless steel braided brake lines',
price: '€149',
icon: brakesIcon,
category: 'Brakes',
},
{
id: 21,
name: 'Wheel Locks',
description: 'Security wheel locks to prevent theft',
price: '€89',
icon: wheelsIcon,
category: 'Wheels',
}
];
const filteredModifications = modifications.filter((mod) =>

View File

@@ -0,0 +1,252 @@
import React, { useState, useEffect } from 'react';
import {
Container,
Typography,
Box,
Button,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
IconButton,
Alert,
} from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
import AddIcon from '@mui/icons-material/Add';
import axios from 'axios';
const CustomerManagement = () => {
const [customers, setCustomers] = useState([]);
const [open, setOpen] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
const [formData, setFormData] = useState({
name: '',
email: '',
phone: '',
address: '',
carModel: '',
carYear: '',
});
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
useEffect(() => {
fetchCustomers();
}, []);
const fetchCustomers = async () => {
try {
const response = await axios.get('http://localhost:5000/api/customers');
setCustomers(response.data);
} catch (err) {
setError('Failed to fetch customers');
}
};
const handleOpen = (customer = null) => {
if (customer) {
setSelectedCustomer(customer);
setFormData(customer);
} else {
setSelectedCustomer(null);
setFormData({
name: '',
email: '',
phone: '',
address: '',
carModel: '',
carYear: '',
});
}
setOpen(true);
};
const handleClose = () => {
setOpen(false);
setError('');
setSuccess('');
};
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
if (selectedCustomer) {
await axios.put(`http://localhost:5000/api/customers/${selectedCustomer._id}`, formData);
setSuccess('Customer updated successfully');
} else {
await axios.post('http://localhost:5000/api/customers', formData);
setSuccess('Customer added successfully');
}
fetchCustomers();
handleClose();
} catch (err) {
setError(err.response?.data?.message || 'An error occurred');
}
};
const handleDelete = async (id) => {
if (window.confirm('Are you sure you want to delete this customer?')) {
try {
await axios.delete(`http://localhost:5000/api/customers/${id}`);
setSuccess('Customer deleted successfully');
fetchCustomers();
} catch (err) {
setError('Failed to delete customer');
}
}
};
return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4 }}>
<Typography variant="h4" component="h1" gutterBottom sx={{ fontWeight: 'bold' }}>
Customer Management
</Typography>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => handleOpen()}
>
Add Customer
</Button>
</Box>
{error && (
<Alert severity="error" sx={{ mb: 2 }}>
{error}
</Alert>
)}
{success && (
<Alert severity="success" sx={{ mb: 2 }}>
{success}
</Alert>
)}
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell>Phone</TableCell>
<TableCell>Car Model</TableCell>
<TableCell>Car Year</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{customers.map((customer) => (
<TableRow key={customer._id}>
<TableCell>{customer.name}</TableCell>
<TableCell>{customer.email}</TableCell>
<TableCell>{customer.phone}</TableCell>
<TableCell>{customer.carModel}</TableCell>
<TableCell>{customer.carYear}</TableCell>
<TableCell>
<IconButton onClick={() => handleOpen(customer)} color="primary">
<EditIcon />
</IconButton>
<IconButton onClick={() => handleDelete(customer._id)} color="error">
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
<DialogTitle>
{selectedCustomer ? 'Edit Customer' : 'Add New Customer'}
</DialogTitle>
<form onSubmit={handleSubmit}>
<DialogContent>
<TextField
fullWidth
label="Name"
name="name"
value={formData.name}
onChange={handleChange}
margin="normal"
required
/>
<TextField
fullWidth
label="Email"
name="email"
type="email"
value={formData.email}
onChange={handleChange}
margin="normal"
required
/>
<TextField
fullWidth
label="Phone"
name="phone"
value={formData.phone}
onChange={handleChange}
margin="normal"
required
/>
<TextField
fullWidth
label="Address"
name="address"
value={formData.address}
onChange={handleChange}
margin="normal"
multiline
rows={2}
/>
<TextField
fullWidth
label="Car Model"
name="carModel"
value={formData.carModel}
onChange={handleChange}
margin="normal"
required
/>
<TextField
fullWidth
label="Car Year"
name="carYear"
value={formData.carYear}
onChange={handleChange}
margin="normal"
required
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit" variant="contained" color="primary">
{selectedCustomer ? 'Update' : 'Add'}
</Button>
</DialogActions>
</form>
</Dialog>
</Container>
);
};
export default CustomerManagement;