Files
Hotel-Booking/Frontend/src/App.tsx
Iliyan Angelov ab832f851b updates
2025-11-18 18:35:46 +02:00

347 lines
10 KiB
TypeScript

import React, { useEffect, lazy, Suspense } from 'react';
import {
BrowserRouter,
Routes,
Route,
Navigate
} from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { GlobalLoadingProvider } from './contexts/GlobalLoadingContext';
import { CookieConsentProvider } from './contexts/CookieConsentContext';
import { CurrencyProvider } from './contexts/CurrencyContext';
import OfflineIndicator from './components/common/OfflineIndicator';
import CookieConsentBanner from './components/common/CookieConsentBanner';
import AnalyticsLoader from './components/common/AnalyticsLoader';
import Loading from './components/common/Loading';
// Store
import useAuthStore from './store/useAuthStore';
import useFavoritesStore from './store/useFavoritesStore';
// Layout Components
import { LayoutMain } from './components/layout';
import AdminLayout from './pages/AdminLayout';
// Auth Components
import {
ProtectedRoute,
AdminRoute
} from './components/auth';
// Lazy load pages for code splitting
const HomePage = lazy(() => import('./pages/HomePage'));
const DashboardPage = lazy(() => import('./pages/customer/DashboardPage'));
const RoomListPage = lazy(() => import('./pages/customer/RoomListPage'));
const RoomDetailPage = lazy(() => import('./pages/customer/RoomDetailPage'));
const SearchResultsPage = lazy(() => import('./pages/customer/SearchResultsPage'));
const FavoritesPage = lazy(() => import('./pages/customer/FavoritesPage'));
const MyBookingsPage = lazy(() => import('./pages/customer/MyBookingsPage'));
const BookingPage = lazy(() => import('./pages/customer/BookingPage'));
const BookingSuccessPage = lazy(() => import('./pages/customer/BookingSuccessPage'));
const BookingDetailPage = lazy(() => import('./pages/customer/BookingDetailPage'));
const DepositPaymentPage = lazy(() => import('./pages/customer/DepositPaymentPage'));
const FullPaymentPage = lazy(() => import('./pages/customer/FullPaymentPage'));
const PaymentConfirmationPage = lazy(() => import('./pages/customer/PaymentConfirmationPage'));
const PaymentResultPage = lazy(() => import('./pages/customer/PaymentResultPage'));
const InvoicePage = lazy(() => import('./pages/customer/InvoicePage'));
const ProfilePage = lazy(() => import('./pages/customer/ProfilePage'));
const AboutPage = lazy(() => import('./pages/AboutPage'));
const ContactPage = lazy(() => import('./pages/ContactPage'));
const LoginPage = lazy(() => import('./pages/auth/LoginPage'));
const RegisterPage = lazy(() => import('./pages/auth/RegisterPage'));
const ForgotPasswordPage = lazy(() => import('./pages/auth/ForgotPasswordPage'));
const ResetPasswordPage = lazy(() => import('./pages/auth/ResetPasswordPage'));
// Lazy load admin pages
const AdminDashboardPage = lazy(() => import('./pages/admin/DashboardPage'));
const UserManagementPage = lazy(() => import('./pages/admin/UserManagementPage'));
const PageContentDashboardPage = lazy(() => import('./pages/admin/PageContentDashboard'));
const AnalyticsDashboardPage = lazy(() => import('./pages/admin/AnalyticsDashboardPage'));
const BusinessDashboardPage = lazy(() => import('./pages/admin/BusinessDashboardPage'));
const SettingsPage = lazy(() => import('./pages/admin/SettingsPage'));
const ReceptionDashboardPage = lazy(() => import('./pages/admin/ReceptionDashboardPage'));
// Demo component for pages not yet created
const DemoPage: React.FC<{ title: string }> = ({ title }) => (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold text-gray-800">
{title}
</h1>
<p className="text-gray-600 mt-4">
This page is under development...
</p>
</div>
);
function App() {
// Use Zustand store
const {
isAuthenticated,
userInfo,
logout,
initializeAuth
} = useAuthStore();
const {
fetchFavorites,
syncGuestFavorites,
loadGuestFavorites,
} = useFavoritesStore();
// Initialize auth state when app loads
useEffect(() => {
initializeAuth();
}, [initializeAuth]);
// Load favorites when authenticated or load guest favorites
useEffect(() => {
if (isAuthenticated) {
// Sync guest favorites first, then fetch
syncGuestFavorites().then(() => {
fetchFavorites();
});
} else {
// Load guest favorites from localStorage
loadGuestFavorites();
}
}, [
isAuthenticated,
fetchFavorites,
syncGuestFavorites,
loadGuestFavorites,
]);
// Handle logout
const handleLogout = async () => {
await logout();
};
return (
<GlobalLoadingProvider>
<CookieConsentProvider>
<CurrencyProvider>
<BrowserRouter
future={{
v7_startTransition: true,
v7_relativeSplatPath: true,
}}
>
<Suspense fallback={<Loading fullScreen text="Loading page..." />}>
<Routes>
{/* Public Routes with Main Layout */}
<Route
path="/"
element={
<LayoutMain
isAuthenticated={isAuthenticated}
userInfo={userInfo}
onLogout={handleLogout}
/>
}
>
<Route index element={<HomePage />} />
<Route
path="rooms"
element={<RoomListPage />}
/>
<Route
path="rooms/search"
element={<SearchResultsPage />}
/>
<Route
path="rooms/:room_number"
element={<RoomDetailPage />}
/>
<Route
path="favorites"
element={<FavoritesPage />}
/>
<Route
path="payment-result"
element={<PaymentResultPage />}
/>
<Route
path="invoices/:id"
element={
<ProtectedRoute>
<InvoicePage />
</ProtectedRoute>
}
/>
<Route
path="about"
element={<AboutPage />}
/>
<Route
path="contact"
element={<ContactPage />}
/>
{/* Protected Routes - Requires login */}
<Route
path="dashboard"
element={
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
}
/>
<Route
path="booking/:id"
element={
<ProtectedRoute>
<BookingPage />
</ProtectedRoute>
}
/>
<Route
path="booking-success/:id"
element={
<ProtectedRoute>
<BookingSuccessPage />
</ProtectedRoute>
}
/>
<Route
path="deposit-payment/:bookingId"
element={
<ProtectedRoute>
<DepositPaymentPage />
</ProtectedRoute>
}
/>
<Route
path="bookings"
element={
<ProtectedRoute>
<MyBookingsPage />
</ProtectedRoute>
}
/>
<Route
path="bookings/:id"
element={
<ProtectedRoute>
<BookingDetailPage />
</ProtectedRoute>
}
/>
<Route
path="payment/:bookingId"
element={
<ProtectedRoute>
<FullPaymentPage />
</ProtectedRoute>
}
/>
<Route
path="payment-confirmation/:id"
element={
<ProtectedRoute>
<PaymentConfirmationPage />
</ProtectedRoute>
}
/>
<Route
path="profile"
element={
<ProtectedRoute>
<ProfilePage />
</ProtectedRoute>
}
/>
</Route>
{/* Auth Routes (no layout) */}
<Route
path="/login"
element={<LoginPage />}
/>
<Route
path="/register"
element={<RegisterPage />}
/>
<Route
path="/forgot-password"
element={<ForgotPasswordPage />}
/>
<Route
path="/reset-password/:token"
element={<ResetPasswordPage />}
/>
{/* Admin Routes - Only admin can access */}
<Route
path="/admin"
element={
<AdminRoute>
<AdminLayout />
</AdminRoute>
}
>
<Route
index
element={<Navigate to="dashboard" replace />}
/>
<Route path="dashboard" element={<AdminDashboardPage />} />
<Route
path="users"
element={<UserManagementPage />}
/>
<Route
path="business"
element={<BusinessDashboardPage />}
/>
<Route
path="reception"
element={<ReceptionDashboardPage />}
/>
<Route
path="page-content"
element={<PageContentDashboardPage />}
/>
<Route
path="analytics"
element={<AnalyticsDashboardPage />}
/>
<Route
path="settings"
element={<SettingsPage />}
/>
</Route>
{/* 404 Route */}
<Route
path="*"
element={<DemoPage title="404 - Page not found" />}
/>
</Routes>
<ToastContainer
position="top-right"
autoClose={3000}
hideProgressBar={false}
newestOnTop
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light"
toastClassName="rounded-lg shadow-lg"
bodyClassName="text-sm font-medium"
/>
<OfflineIndicator />
<CookieConsentBanner />
<AnalyticsLoader />
</Suspense>
</BrowserRouter>
</CurrencyProvider>
</CookieConsentProvider>
</GlobalLoadingProvider>
);
}
export default App;