trip-planner/frontend/src/components/Dashboard.jsx
2025-10-04 14:59:20 +02:00

166 lines
No EOL
4.6 KiB
JavaScript

import { useState, useEffect, useRef } from 'react';
import { useAuth } from '../contexts/AuthContext';
import api from '../utils/api';
import TripList from './TripList';
import TripModal from './TripModal';
import ConfirmDialog from './ConfirmDialog';
const Dashboard = () => {
const { user, logout } = useAuth();
const [trips, setTrips] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [showTripModal, setShowTripModal] = useState(false);
const [selectedTrip, setSelectedTrip] = useState(null);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [tripToDelete, setTripToDelete] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const [showUserDropdown, setShowUserDropdown] = useState(false);
const userDropdownRef = useRef(null);
useEffect(() => {
fetchTrips();
}, []);
useEffect(() => {
const handleClickOutside = (event) => {
if (userDropdownRef.current && !userDropdownRef.current.contains(event.target)) {
setShowUserDropdown(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, []);
const fetchTrips = async () => {
try {
setIsLoading(true);
const response = await api.get('/trips');
setTrips(response.data.data);
} catch (error) {
console.error('Error fetching trips:', error);
} finally {
setIsLoading(false);
}
};
const handleLogout = async () => {
await logout();
};
const handleCreateTrip = () => {
setSelectedTrip(null);
setShowTripModal(true);
};
const handleEditTrip = (trip) => {
setSelectedTrip(trip);
setShowTripModal(true);
};
const handleDeleteTrip = (trip) => {
setTripToDelete(trip);
setShowDeleteConfirm(true);
};
const handleTripSubmit = async (tripData) => {
setIsSubmitting(true);
try {
if (selectedTrip) {
const response = await api.put(`/trips/${selectedTrip.id}`, tripData);
setTrips(trips.map(trip =>
trip.id === selectedTrip.id ? response.data.data : trip
));
} else {
const response = await api.post('/trips', tripData);
setTrips([response.data.data, ...trips]);
}
setShowTripModal(false);
setSelectedTrip(null);
} catch (error) {
console.error('Error saving trip:', error);
throw error;
} finally {
setIsSubmitting(false);
}
};
const confirmDeleteTrip = async () => {
try {
await api.delete(`/trips/${tripToDelete.id}`);
setTrips(trips.filter(trip => trip.id !== tripToDelete.id));
setShowDeleteConfirm(false);
setTripToDelete(null);
} catch (error) {
console.error('Error deleting trip:', error);
throw error;
}
};
return (
<div className="dashboard">
<header className="dashboard-header">
<div className="dashboard-title">
<h1>TripPlanner</h1>
</div>
<div className="user-info">
<span>Welcome back!</span>
<div className="user-dropdown" ref={userDropdownRef}>
<button
className="user-menu-trigger"
onClick={() => setShowUserDropdown(!showUserDropdown)}
>
{user?.name}
<span className="dropdown-arrow"></span>
</button>
{showUserDropdown && (
<div className="user-dropdown-menu">
<button onClick={handleLogout} className="dropdown-item">
🚪 Logout
</button>
</div>
)}
</div>
</div>
</header>
<main className="dashboard-content">
<TripList
trips={trips}
isLoading={isLoading}
onEdit={handleEditTrip}
onDelete={handleDeleteTrip}
onCreateTrip={handleCreateTrip}
/>
</main>
<TripModal
isOpen={showTripModal}
onClose={() => {
setShowTripModal(false);
setSelectedTrip(null);
}}
onSubmit={handleTripSubmit}
trip={selectedTrip}
isLoading={isSubmitting}
/>
<ConfirmDialog
isOpen={showDeleteConfirm}
onClose={() => {
setShowDeleteConfirm(false);
setTripToDelete(null);
}}
onConfirm={confirmDeleteTrip}
title="Delete Trip"
message={`Are you sure you want to delete "${tripToDelete?.name}"? This action cannot be undone.`}
confirmText="Delete"
variant="danger"
/>
</div>
);
};
export default Dashboard;