diff --git a/client/public/favicon.svg b/client/public/favicon.svg
new file mode 100644
index 0000000..740de80
--- /dev/null
+++ b/client/public/favicon.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/client/public/index.html b/client/public/index.html
index aa069f2..10b4f00 100644
--- a/client/public/index.html
+++ b/client/public/index.html
@@ -2,14 +2,14 @@
-
+
-
+
- React App
+ AutoTune Pro | Car Tuning Management
diff --git a/client/src/components/CustomerManagement.js b/client/src/components/CustomerManagement.js
index ffdc1f1..78bb3b0 100644
--- a/client/src/components/CustomerManagement.js
+++ b/client/src/components/CustomerManagement.js
@@ -22,40 +22,47 @@ import {
Select,
FormControl,
InputLabel,
+ Grid,
+ Card,
+ CardContent,
+ Divider
} 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 { Edit as EditIcon, Delete as DeleteIcon, Add as AddIcon } from '@mui/icons-material';
import axios from 'axios';
const carModels = [
- { value: 'bmw_m3', label: 'BMW M3' },
- { value: 'bmw_m4', label: 'BMW M4' },
- { value: 'audi_rs3', label: 'Audi RS3' },
- { value: 'audi_rs4', label: 'Audi RS4' },
- { value: 'mercedes_c63', label: 'Mercedes-AMG C63' },
- { value: 'mercedes_e63', label: 'Mercedes-AMG E63' },
- { value: 'volkswagen_golf_r', label: 'Volkswagen Golf R' },
- { value: 'volkswagen_arteon_r', label: 'Volkswagen Arteon R' },
- { value: 'toyota_supra', label: 'Toyota Supra' },
- { value: 'nissan_gtr', label: 'Nissan GT-R' },
- { value: 'porsche_911', label: 'Porsche 911' },
- { value: 'porsche_cayman', label: 'Porsche Cayman' },
- { value: 'honda_civic_type_r', label: 'Honda Civic Type R' },
- { value: 'subaru_wrx_sti', label: 'Subaru WRX STI' },
- { value: 'mitsubishi_evo', label: 'Mitsubishi Lancer Evolution' },
- { value: 'other', label: 'Other' },
+ 'BMW M3',
+ 'BMW M4',
+ 'Audi RS3',
+ 'Audi RS4',
+ 'Mercedes-AMG C63',
+ 'Mercedes-AMG E63',
+ 'Volkswagen Golf R',
+ 'Volkswagen Arteon R',
+ 'Toyota Supra',
+ 'Nissan GT-R',
+ 'Porsche 911',
+ 'Porsche Cayman',
+ 'Honda Civic Type R',
+ 'Subaru WRX STI',
+ 'Mitsubishi Lancer Evolution',
+ 'Other'
+];
+
+const categories = [
+ 'Engine',
+ 'Exhaust',
+ 'Suspension',
+ 'Brakes',
+ 'Wheels'
];
// Create axios instance with default config
const api = axios.create({
- baseURL: 'http://localhost:5000/api',
- headers: {
- 'Content-Type': 'application/json',
- },
+ baseURL: 'http://localhost:5000/api'
});
-// Add request interceptor to add token to all requests
+// Add request interceptor to include token
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
@@ -72,17 +79,24 @@ api.interceptors.request.use(
const CustomerManagement = () => {
const [customers, setCustomers] = useState([]);
const [open, setOpen] = useState(false);
+ const [openModDialog, setOpenModDialog] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
+ const [error, setError] = useState('');
+ const [success, setSuccess] = useState('');
const [formData, setFormData] = useState({
name: '',
email: '',
phone: '',
address: '',
carModel: '',
- carYear: '',
+ carYear: ''
+ });
+ const [modificationData, setModificationData] = useState({
+ name: '',
+ description: '',
+ price: '',
+ category: ''
});
- const [error, setError] = useState('');
- const [success, setSuccess] = useState('');
useEffect(() => {
fetchCustomers();
@@ -99,32 +113,56 @@ const CustomerManagement = () => {
const handleOpen = (customer = null) => {
if (customer) {
- setSelectedCustomer(customer);
setFormData(customer);
+ setSelectedCustomer(customer);
} else {
- setSelectedCustomer(null);
setFormData({
name: '',
email: '',
phone: '',
address: '',
carModel: '',
- carYear: '',
+ carYear: ''
});
+ setSelectedCustomer(null);
}
setOpen(true);
};
+ const handleOpenModDialog = (customer) => {
+ setSelectedCustomer(customer);
+ setModificationData({
+ name: '',
+ description: '',
+ price: '',
+ category: ''
+ });
+ setOpenModDialog(true);
+ };
+
const handleClose = () => {
setOpen(false);
setError('');
setSuccess('');
};
- const handleChange = (e) => {
+ const handleCloseModDialog = () => {
+ setOpenModDialog(false);
+ setError('');
+ setSuccess('');
+ };
+
+ const handleInputChange = (e) => {
setFormData({
...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) => {
if (window.confirm('Are you sure you want to delete this customer?')) {
try {
@@ -159,8 +209,8 @@ const CustomerManagement = () => {
return (
-
-
+
+
Customer Management
- {error && (
-
- {error}
-
- )}
-
- {success && (
-
- {success}
-
- )}
+ {error && {error}}
+ {success && {success}}
@@ -194,6 +235,7 @@ const CustomerManagement = () => {
Phone
Car Model
Car Year
+ Modifications
Actions
@@ -205,6 +247,24 @@ const CustomerManagement = () => {
{customer.phone}
{customer.carModel}
{customer.carYear}
+
+
+ {customer.modifications && customer.modifications.length > 0 && (
+
+ {customer.modifications.map((mod, index) => (
+
+ {mod.name} - {mod.category}
+
+ ))}
+
+ )}
+
handleOpen(customer)} color="primary">
@@ -219,82 +279,157 @@ const CustomerManagement = () => {
+ {/* Customer Form Dialog */}
+
+ {/* Modification Form Dialog */}
+
);
diff --git a/models/Customer.js b/models/Customer.js
index c027459..9ea3dbe 100644
--- a/models/Customer.js
+++ b/models/Customer.js
@@ -20,6 +20,7 @@ const customerSchema = new mongoose.Schema({
},
address: {
type: String,
+ required: true,
trim: true
},
carModel: {
@@ -28,10 +29,31 @@ const customerSchema = new mongoose.Schema({
trim: true
},
carYear: {
- type: String,
- required: true,
- trim: true
+ type: Number,
+ required: 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: {
type: Date,
default: Date.now
@@ -48,4 +70,6 @@ customerSchema.pre('save', function(next) {
next();
});
-module.exports = mongoose.model('Customer', customerSchema);
\ No newline at end of file
+const Customer = mongoose.model('Customer', customerSchema);
+
+module.exports = Customer;
\ No newline at end of file
diff --git a/routes/customers.js b/routes/customers.js
index ca15ee8..39b6f53 100644
--- a/routes/customers.js
+++ b/routes/customers.js
@@ -9,7 +9,7 @@ router.get('/', auth, async (req, res) => {
const customers = await Customer.find().sort({ name: 1 });
res.json(customers);
} 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);
} catch (err) {
- res.status(500).json({ message: err.message });
+ res.status(500).send('Server Error');
}
});
// Create customer
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 {
- const newCustomer = await customer.save();
- res.status(201).json(newCustomer);
+ const customer = new Customer(req.body);
+ await customer.save();
+ res.status(201).json(customer);
} catch (err) {
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' });
}
- Object.assign(customer, req.body);
- const updatedCustomer = await customer.save();
- res.json(updatedCustomer);
+ Object.keys(req.body).forEach(key => {
+ customer[key] = req.body[key];
+ });
+
+ 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) {
res.status(400).json({ message: err.message });
}
@@ -72,7 +83,7 @@ router.delete('/:id', auth, async (req, res) => {
await customer.remove();
res.json({ message: 'Customer deleted' });
} catch (err) {
- res.status(500).json({ message: err.message });
+ res.status(500).send('Server Error');
}
});