From 9f5aeaae6a21cb36c41c99e707c13ded3731cc5b Mon Sep 17 00:00:00 2001 From: seervik <202200836@vupune.ac.in> Date: Wed, 20 Aug 2025 19:48:09 +0530 Subject: [PATCH] Fix cab/route deletion issues and implement real-time UI updates --- server/index.js | 149 +++++++++++++++++-- src/pages/CabOperatorPage.jsx | 265 +++++++++++++++++++++++++++------- 2 files changed, 347 insertions(+), 67 deletions(-) diff --git a/server/index.js b/server/index.js index 7e297381..aca5eebd 100644 --- a/server/index.js +++ b/server/index.js @@ -71,30 +71,155 @@ app.post('/api/cabs', async (req, res) => { // Delete a cab app.delete('/api/cabs/:id', async (req, res) => { - const { id } = req.params; - await pool.query('DELETE FROM cabs WHERE id = $1', [id]); - res.json({ success: true }); + const client = await pool.connect(); + + try { + const { id } = req.params; + console.log('Attempting to delete cab with ID:', id); + + // Start transaction + await client.query('BEGIN'); + + // Check if the cab exists first + const checkResult = await client.query('SELECT * FROM cabs WHERE id = $1', [id]); + if (checkResult.rows.length === 0) { + await client.query('ROLLBACK'); + return res.status(404).json({ error: 'Cab not found' }); + } + + // Delete related schedules first + const deletedSchedules = await client.query('DELETE FROM schedules WHERE cab_id = $1 RETURNING *', [id]); + console.log('Deleted schedules:', deletedSchedules.rows); + + // Delete related routes where this cab is referenced (if any) + const deletedRoutes = await client.query('DELETE FROM routes WHERE cab_operator_id = $1 RETURNING *', [id]); + console.log('Deleted routes:', deletedRoutes.rows); + + // Delete any other related data (bookings, etc.) if they exist + // Add more cascade deletes here as needed for other tables + + // Finally, delete the cab + const result = await client.query('DELETE FROM cabs WHERE id = $1 RETURNING *', [id]); + console.log('Deleted cab:', result.rows[0]); + + // Commit transaction + await client.query('COMMIT'); + + res.json({ + success: true, + deletedCab: result.rows[0], + deletedSchedules: deletedSchedules.rows, + deletedRoutes: deletedRoutes.rows + }); + + } catch (error) { + // Rollback transaction on error + await client.query('ROLLBACK'); + console.error('Error deleting cab:', error); + res.status(500).json({ error: 'Failed to delete cab: ' + error.message }); + } finally { + client.release(); + } }); // Add a route app.post('/api/routes', async (req, res) => { - const { origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id } = req.body; - const result = await pool.query('INSERT INTO routes (origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *', [origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id]); - res.json(result.rows[0]); + try { + console.log('Received route data:', req.body); // Debug log + + const { origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id } = req.body; + + // Validate required fields + if (!origin || !destination || !distance_km) { + return res.status(400).json({ error: 'Missing required fields: origin, destination, distance_km' }); + } + + const result = await pool.query( + 'INSERT INTO routes (origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *', + [origin, destination, distance_km, eta_min, base_fare, active, cab_operator_id] + ); + + console.log('Route created:', result.rows[0]); // Debug log + + // Format the response to match what the frontend expects + const createdRoute = result.rows[0]; + const formattedRoute = { + id: createdRoute.id, + from: createdRoute.origin, + to: createdRoute.destination, + distance: `${createdRoute.distance_km} km` + }; + + res.json(formattedRoute); + + } catch (error) { + console.error('Error creating route:', error); + res.status(500).json({ error: 'Failed to create route: ' + error.message }); + } }); // Delete a route app.delete('/api/routes/:id', async (req, res) => { - const { id } = req.params; - await pool.query('DELETE FROM routes WHERE id = $1', [id]); - res.json({ success: true }); + const client = await pool.connect(); + + try { + const { id } = req.params; + console.log('Attempting to delete route with ID:', id); + + // Start transaction + await client.query('BEGIN'); + + // Delete related schedules first + const deletedSchedules = await client.query('DELETE FROM schedules WHERE route_id = $1 RETURNING *', [id]); + console.log('Deleted schedules:', deletedSchedules.rows); + + // Delete the route + const result = await client.query('DELETE FROM routes WHERE id = $1 RETURNING *', [id]); + console.log('Deleted route:', result.rows[0]); + + // Commit transaction + await client.query('COMMIT'); + + res.json({ + success: true, + deletedRoute: result.rows[0], + deletedSchedules: deletedSchedules.rows + }); + + } catch (error) { + // Rollback transaction on error + await client.query('ROLLBACK'); + console.error('Error deleting route:', error); + res.status(500).json({ error: 'Failed to delete route: ' + error.message }); + } finally { + client.release(); + } }); // Add a schedule app.post('/api/schedules', async (req, res) => { - const { cab_id, route_id, frequency, time, price } = req.body; - const result = await pool.query('INSERT INTO schedules (cab_id, route_id, frequency, time, price) VALUES ($1, $2, $3, $4, $5) RETURNING *', [cab_id, route_id, frequency, time, price]); - res.json(result.rows[0]); + try { + console.log('Received schedule data:', req.body); // Debug log + + const { cab_id, route_id, frequency, time, price } = req.body; + + // Validate required fields + if (!cab_id || !route_id || !frequency || !time || !price) { + return res.status(400).json({ error: 'Missing required fields' }); + } + + const result = await pool.query( + 'INSERT INTO schedules (cab_id, route_id, frequency, time, price) VALUES ($1, $2, $3, $4, $5) RETURNING *', + [cab_id, route_id, frequency, time, price] + ); + + console.log('Schedule created:', result.rows[0]); // Debug log + res.json(result.rows[0]); + + } catch (error) { + console.error('Error creating schedule:', error); + res.status(500).json({ error: 'Failed to create schedule: ' + error.message }); + } }); // Delete a schedule diff --git a/src/pages/CabOperatorPage.jsx b/src/pages/CabOperatorPage.jsx index b7d07935..1eeac14b 100644 --- a/src/pages/CabOperatorPage.jsx +++ b/src/pages/CabOperatorPage.jsx @@ -16,74 +16,220 @@ const CabRouteManagement = () => { const [isCabModalOpen, setIsCabModalOpen] = useState(false); const [isRouteModalOpen, setIsRouteModalOpen] = useState(false); const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false); - const [form] = Form.useForm(); + const [cabForm] = Form.useForm(); + const [routeForm] = Form.useForm(); + const [scheduleForm] = Form.useForm(); + + // Utility function to refresh all data + const refreshAllData = async () => { + try { + const [cabsRes, routesRes, schedulesRes] = await Promise.all([ + fetch('http://localhost:5000/api/cabs'), + fetch('http://localhost:5000/api/routes'), + fetch('http://localhost:5000/api/schedules') + ]); + + const [cabsData, routesData, schedulesData] = await Promise.all([ + cabsRes.json(), + routesRes.json(), + schedulesRes.json() + ]); + + setCabs(cabsData); + setRoutes(routesData); + setSchedule(schedulesData); + } catch (error) { + console.error('Error refreshing data:', error); + } + }; // --- Effects --- useEffect(() => { - fetch('http://localhost:5000/api/cabs') - .then(res => res.json()) - .then(setCabs); - fetch('http://localhost:5000/api/routes') - .then(res => res.json()) - .then(setRoutes); - fetch('http://localhost:5000/api/schedules') - .then(res => res.json()) - .then(setSchedule); + refreshAllData(); }, []); // --- Handlers --- const handleAddCab = async (values) => { - const res = await fetch('http://localhost:5000/api/cabs', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(values) - }); - const newCab = await res.json(); - setCabs([...cabs, newCab]); - message.success('Cab added successfully'); - setIsCabModalOpen(false); + try { + const res = await fetch('http://localhost:5000/api/cabs', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(values) + }); + + if (res.ok) { + const newCab = await res.json(); + console.log('New cab added:', newCab); + + // Refresh all data to ensure consistency + await refreshAllData(); + + message.success('Cab added successfully'); + setIsCabModalOpen(false); + cabForm.resetFields(); + } else { + const error = await res.json(); + message.error('Failed to add cab: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error adding cab:', error); + message.error('Error adding cab: ' + error.message); + } }; const handleDeleteCab = async (id) => { - await fetch(`http://localhost:5000/api/cabs/${id}`, { method: 'DELETE' }); - setCabs(cabs.filter(cab => cab.id !== id)); - message.success('Cab deleted successfully'); + try { + console.log('Deleting cab with ID:', id); // Debug log + const res = await fetch(`http://localhost:5000/api/cabs/${id}`, { + method: 'DELETE' + }); + + if (res.ok) { + const result = await res.json(); + console.log('Delete result:', result); + + // Refresh all data to reflect cascade deletions + await refreshAllData(); + + message.success(`Cab deleted successfully along with ${result.deletedSchedules?.length || 0} related schedules and ${result.deletedRoutes?.length || 0} related routes`); + } else { + const error = await res.json(); + message.error('Failed to delete cab: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error deleting cab:', error); + message.error('Error deleting cab'); + } }; const handleAddRoute = async (values) => { - const res = await fetch('http://localhost:5000/api/routes', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(values) - }); - const newRoute = await res.json(); - setRoutes([...routes, newRoute]); - message.success('Route added successfully'); - setIsRouteModalOpen(false); + try { + console.log('Adding route with values:', values); // Debug log + + // Map frontend fields to backend fields + const routeData = { + origin: values.from, + destination: values.to, + distance_km: parseFloat(values.distance), + eta_min: 30, // default value + base_fare: 10, // default value + active: true, + cab_operator_id: 1 // default value, should be dynamic in real app + }; + + console.log('Route data to send:', routeData); // Debug log + + const res = await fetch('http://localhost:5000/api/routes', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(routeData) + }); + + if (res.ok) { + const newRoute = await res.json(); + console.log('New route received:', newRoute); // Debug log + + // Refresh all data to ensure consistency + await refreshAllData(); + + message.success('Route added successfully'); + setIsRouteModalOpen(false); + routeForm.resetFields(); + } else { + const error = await res.json(); + console.error('Error adding route:', error); + message.error('Failed to add route: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error adding route:', error); + message.error('Error adding route: ' + error.message); + } }; const handleDeleteRoute = async (id) => { - await fetch(`http://localhost:5000/api/routes/${id}`, { method: 'DELETE' }); - setRoutes(routes.filter(route => route.id !== id)); - message.success('Route deleted successfully'); + try { + const res = await fetch(`http://localhost:5000/api/routes/${id}`, { method: 'DELETE' }); + + if (res.ok) { + const result = await res.json(); + console.log('Route delete result:', result); + + // Refresh all data to reflect cascade deletions + await refreshAllData(); + + message.success(`Route deleted successfully along with ${result.deletedSchedules?.length || 0} related schedules`); + } else { + const error = await res.json(); + message.error('Failed to delete route: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error deleting route:', error); + message.error('Error deleting route'); + } }; const handleAddSchedule = async (values) => { - const res = await fetch('http://localhost:5000/api/schedules', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(values) - }); - const newSchedule = await res.json(); - setSchedule([...schedule, newSchedule]); - message.success('Schedule added successfully'); - setIsScheduleModalOpen(false); + try { + // Find the cab and route IDs based on the selected names + const selectedCab = cabs.find(cab => cab.name === values.cab); + const selectedRouteText = values.route; // "Origin - Destination" + const selectedRoute = routes.find(route => `${route.from} - ${route.to}` === selectedRouteText); + + if (!selectedCab || !selectedRoute) { + message.error('Please select valid cab and route'); + return; + } + + const scheduleData = { + cab_id: selectedCab.id, + route_id: selectedRoute.id, + frequency: values.frequency, + time: values.time.format('HH:mm:ss'), + price: parseFloat(values.price) + }; + + const res = await fetch('http://localhost:5000/api/schedules', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(scheduleData) + }); + + if (res.ok) { + const newSchedule = await res.json(); + console.log('New schedule added:', newSchedule); + + // Refresh all data to ensure consistency + await refreshAllData(); + + message.success('Schedule added successfully'); + setIsScheduleModalOpen(false); + scheduleForm.resetFields(); + } else { + const error = await res.json(); + message.error('Failed to add schedule: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error adding schedule:', error); + message.error('Error adding schedule: ' + error.message); + } }; const handleDeleteSchedule = async (id) => { - await fetch(`http://localhost:5000/api/schedules/${id}`, { method: 'DELETE' }); - setSchedule(schedule.filter(sch => sch.id !== id)); - message.success('Schedule deleted successfully'); + try { + const res = await fetch(`http://localhost:5000/api/schedules/${id}`, { method: 'DELETE' }); + + if (res.ok) { + // Refresh all data to ensure consistency + await refreshAllData(); + message.success('Schedule deleted successfully'); + } else { + const error = await res.json(); + message.error('Failed to delete schedule: ' + (error.error || 'Unknown error')); + } + } catch (error) { + console.error('Error deleting schedule:', error); + message.error('Error deleting schedule'); + } }; // --- Table Columns --- @@ -161,11 +307,14 @@ const CabRouteManagement = () => { setIsCabModalOpen(false)} - onOk={() => form.submit()} + onCancel={() => { + setIsCabModalOpen(false); + cabForm.resetFields(); + }} + onOk={() => cabForm.submit()} okText="Save" > -
+ @@ -185,11 +334,14 @@ const CabRouteManagement = () => { setIsRouteModalOpen(false)} - onOk={() => form.submit()} + onCancel={() => { + setIsRouteModalOpen(false); + routeForm.resetFields(); + }} + onOk={() => routeForm.submit()} okText="Save" > - + @@ -205,11 +357,14 @@ const CabRouteManagement = () => { setIsScheduleModalOpen(false)} - onOk={() => form.submit()} + onCancel={() => { + setIsScheduleModalOpen(false); + scheduleForm.resetFields(); + }} + onOk={() => scheduleForm.submit()} okText="Save" > - +