From ec07b89dab044a24f6921301941f21bf6cd9d890 Mon Sep 17 00:00:00 2001 From: Alvin <524715@vistacollege.nl> Date: Tue, 10 Jun 2025 10:24:25 +0200 Subject: [PATCH] Enhance App component by adding Register and BackToHome routes, and update CustomerList to CustomerManagement for improved customer management functionality. Refactor CustomerManagement to utilize a centralized axios instance for API calls and implement a dropdown for car model selection. --- client/src/App.js | 7 +- client/src/components/BackToHome.js | 39 +++++ client/src/components/CustomerManagement.js | 77 +++++++-- client/src/components/Dashboard.js | 47 +++--- client/src/components/Register.js | 164 ++++++++++++++++++++ 5 files changed, 294 insertions(+), 40 deletions(-) create mode 100644 client/src/components/BackToHome.js create mode 100644 client/src/components/Register.js diff --git a/client/src/App.js b/client/src/App.js index 377a0cf..f979769 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -3,13 +3,16 @@ import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-d import { ThemeProvider, createTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import Login from './components/Login'; +import Register from './components/Register'; import Dashboard from './components/Dashboard'; import CustomerList from './components/CustomerList'; import CustomerDetail from './components/CustomerDetail'; import CarModifications from './components/CarModifications'; import ContactHistory from './components/ContactHistory'; +import CustomerManagement from './components/CustomerManagement'; import PrivateRoute from './components/PrivateRoute'; import UserManagement from './components/UserManagement'; +import BackToHome from './components/BackToHome'; // Create a theme that matches the "stoer en snel" (tough and fast) requirement const theme = createTheme({ @@ -55,6 +58,7 @@ function App() { } /> + } /> - + } /> @@ -105,6 +109,7 @@ function App() { /> } /> + ); diff --git a/client/src/components/BackToHome.js b/client/src/components/BackToHome.js new file mode 100644 index 0000000..5867acb --- /dev/null +++ b/client/src/components/BackToHome.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Button, Box } from '@mui/material'; +import HomeIcon from '@mui/icons-material/Home'; + +const BackToHome = () => { + const navigate = useNavigate(); + + return ( + + + + ); +}; + +export default BackToHome; \ No newline at end of file diff --git a/client/src/components/CustomerManagement.js b/client/src/components/CustomerManagement.js index f0bf083..ffdc1f1 100644 --- a/client/src/components/CustomerManagement.js +++ b/client/src/components/CustomerManagement.js @@ -18,12 +18,57 @@ import { Paper, IconButton, Alert, + MenuItem, + Select, + FormControl, + InputLabel, } 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 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' }, +]; + +// Create axios instance with default config +const api = axios.create({ + baseURL: 'http://localhost:5000/api', + headers: { + 'Content-Type': 'application/json', + }, +}); + +// Add request interceptor to add token to all requests +api.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); + const CustomerManagement = () => { const [customers, setCustomers] = useState([]); const [open, setOpen] = useState(false); @@ -45,7 +90,7 @@ const CustomerManagement = () => { const fetchCustomers = async () => { try { - const response = await axios.get('http://localhost:5000/api/customers'); + const response = await api.get('/customers'); setCustomers(response.data); } catch (err) { setError('Failed to fetch customers'); @@ -87,10 +132,10 @@ const CustomerManagement = () => { e.preventDefault(); try { if (selectedCustomer) { - await axios.put(`http://localhost:5000/api/customers/${selectedCustomer._id}`, formData); + await api.put(`/customers/${selectedCustomer._id}`, formData); setSuccess('Customer updated successfully'); } else { - await axios.post('http://localhost:5000/api/customers', formData); + await api.post('/customers', formData); setSuccess('Customer added successfully'); } fetchCustomers(); @@ -103,7 +148,7 @@ const CustomerManagement = () => { 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}`); + await api.delete(`/customers/${id}`); setSuccess('Customer deleted successfully'); fetchCustomers(); } catch (err) { @@ -218,15 +263,21 @@ const CustomerManagement = () => { multiline rows={2} /> - + + Car Model + + { useEffect(() => { const checkAdminStatus = async () => { try { - const response = await axios.get('http://localhost:5000/api/users/me', { - headers: { - Authorization: `Bearer ${localStorage.getItem('token')}`, - }, - }); + const response = await axios.get('http://localhost:5000/api/users/me'); setIsAdmin(response.data.role === 'admin'); - } catch (error) { - console.error('Error checking admin status:', error); + } catch (err) { + console.error('Error checking admin status:', err); } }; - checkAdminStatus(); }, []); const menuItems = [ { title: 'Customers', + description: 'Manage customer information and car details', icon: , - description: 'View and manage customer information', path: '/customers', }, { title: 'Car Modifications', - icon: , - description: 'Browse available car modifications', + description: 'Browse available car modifications and upgrades', + icon: , path: '/modifications', }, { title: 'Contact History', - icon: , - description: 'View customer interaction history', + description: 'View and manage customer interactions', + icon: , path: '/contacts', }, ...(isAdmin ? [{ title: 'User Management', - icon: , description: 'Manage system users and permissions', + icon: , path: '/users', }] : []), ]; @@ -68,7 +63,7 @@ const Dashboard = () => { {menuItems.map((item) => ( - + { {item.icon} - - {item.title} - - - {item.description} - + + {item.title} + + + {item.description} + ))} diff --git a/client/src/components/Register.js b/client/src/components/Register.js new file mode 100644 index 0000000..d041e56 --- /dev/null +++ b/client/src/components/Register.js @@ -0,0 +1,164 @@ +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { + Container, + Paper, + Typography, + TextField, + Button, + Box, + Alert, +} from '@mui/material'; +import axios from 'axios'; + +const Register = () => { + const navigate = useNavigate(); + const [formData, setFormData] = useState({ + name: '', + email: '', + password: '', + confirmPassword: '', + }); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(''); + + const handleChange = (e) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setError(''); + setSuccess(''); + + if (formData.password !== formData.confirmPassword) { + setError('Passwords do not match'); + return; + } + + try { + const response = await axios.post('http://localhost:5000/api/users/register', { + name: formData.name, + email: formData.email, + password: formData.password, + }); + + setSuccess('Registration successful! Redirecting to login...'); + setTimeout(() => { + navigate('/login'); + }, 2000); + } catch (err) { + setError(err.response?.data?.message || 'Registration failed'); + } + }; + + return ( + + + + + Register + + + {error && ( + + {error} + + )} + + {success && ( + + {success} + + )} + + + + + + + + + + + + + ); +}; + +export default Register; \ No newline at end of file