347 lines
10 KiB
TypeScript
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;
|