Files
Hotel-Booking/Frontend/src/App.tsx
Iliyan Angelov 1a103a769f updates
2025-12-01 01:08:39 +02:00

710 lines
23 KiB
TypeScript

import { useEffect, lazy, Suspense } from 'react';
import { useLocation } from 'react-router-dom';
import {
BrowserRouter,
Routes,
Route,
Navigate
} from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { LoadingProvider, useNavigationLoading, useLoading } from './shared/contexts/LoadingContext';
import { CookieConsentProvider } from './shared/contexts/CookieConsentContext';
import { CurrencyProvider } from './features/payments/contexts/CurrencyContext';
import { CompanySettingsProvider } from './shared/contexts/CompanySettingsContext';
import { AuthModalProvider } from './features/auth/contexts/AuthModalContext';
import { AntibotProvider } from './features/auth/contexts/AntibotContext';
import OfflineIndicator from './shared/components/OfflineIndicator';
import CookieConsentBanner from './shared/components/CookieConsentBanner';
import CookiePreferencesModal from './shared/components/CookiePreferencesModal';
import AnalyticsLoader from './shared/components/AnalyticsLoader';
import Loading from './shared/components/Loading';
import Preloader from './shared/components/Preloader';
import ScrollToTop from './shared/components/ScrollToTop';
import AuthModalManager from './features/auth/components/AuthModalManager';
import ResetPasswordRouteHandler from './features/auth/components/ResetPasswordRouteHandler';
import ErrorBoundaryRoute from './shared/components/ErrorBoundaryRoute';
import useAuthStore from './store/useAuthStore';
import useFavoritesStore from './store/useFavoritesStore';
import LayoutMain from './shared/components/LayoutMain';
import AdminLayout from './pages/AdminLayout';
import {
ProtectedRoute,
AdminRoute,
StaffRoute,
AccountantRoute,
CustomerRoute
} from './features/auth/components';
const HomePage = lazy(() => import('./features/content/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 BookingSuccessPage = lazy(() => import('./pages/customer/BookingSuccessPage') as Promise<{ default: React.ComponentType<any> }>);
const BookingDetailPage = lazy(() => import('./pages/customer/BookingDetailPage'));
const FullPaymentPage = lazy(() => import('./pages/customer/FullPaymentPage'));
const PaymentConfirmationPage = lazy(() => import('./pages/customer/PaymentConfirmationPage'));
const PaymentResultPage = lazy(() => import('./pages/customer/PaymentResultPage'));
const PayPalReturnPage = lazy(() => import('./pages/customer/PayPalReturnPage'));
const PayPalCancelPage = lazy(() => import('./pages/customer/PayPalCancelPage'));
const BoricaReturnPage = lazy(() => import('./pages/customer/BoricaReturnPage'));
const InvoicePage = lazy(() => import('./pages/customer/InvoicePage'));
const InvoiceEditPage = lazy(() => import('./pages/admin/InvoiceEditPage'));
const ProfilePage = lazy(() => import('./pages/customer/ProfilePage'));
const LoyaltyPage = lazy(() => import('./pages/customer/LoyaltyPage'));
const GroupBookingPage = lazy(() => import('./pages/customer/GroupBookingPage'));
const ComplaintPage = lazy(() => import('./pages/customer/ComplaintPage'));
const GDPRPage = lazy(() => import('./pages/customer/GDPRPage'));
const AboutPage = lazy(() => import('./features/content/pages/AboutPage'));
const ContactPage = lazy(() => import('./features/content/pages/ContactPage'));
const PrivacyPolicyPage = lazy(() => import('./features/content/pages/PrivacyPolicyPage'));
const TermsPage = lazy(() => import('./features/content/pages/TermsPage'));
const RefundsPolicyPage = lazy(() => import('./features/content/pages/RefundsPolicyPage'));
const CancellationPolicyPage = lazy(() => import('./features/content/pages/CancellationPolicyPage'));
const AccessibilityPage = lazy(() => import('./features/content/pages/AccessibilityPage'));
const FAQPage = lazy(() => import('./features/content/pages/FAQPage'));
const BlogPage = lazy(() => import('./features/content/pages/BlogPage'));
const BlogDetailPage = lazy(() => import('./features/content/pages/BlogDetailPage'));
const AdminDashboardPage = lazy(() => import('./pages/admin/DashboardPage'));
const InvoiceManagementPage = lazy(() => import('./pages/admin/InvoiceManagementPage'));
const PaymentManagementPage = lazy(() => import('./pages/admin/PaymentManagementPage'));
const UserManagementPage = lazy(() => import('./pages/admin/UserManagementPage'));
const GuestProfilePage = lazy(() => import('./pages/admin/GuestProfilePage'));
const GroupBookingManagementPage = lazy(() => import('./pages/admin/GroupBookingManagementPage'));
const AdminBookingManagementPage = lazy(() => import('./pages/admin/BookingManagementPage'));
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 TaskManagementPage = lazy(() => import('./pages/admin/TaskManagementPage'));
const WorkflowManagementPage = lazy(() => import('./pages/admin/WorkflowManagementPage'));
const NotificationManagementPage = lazy(() => import('./pages/admin/NotificationManagementPage'));
const ReceptionDashboardPage = lazy(() => import('./pages/admin/ReceptionDashboardPage'));
const LoyaltyManagementPage = lazy(() => import('./pages/admin/LoyaltyManagementPage'));
const AdvancedRoomManagementPage = lazy(() => import('./pages/admin/AdvancedRoomManagementPage'));
const RatePlanManagementPage = lazy(() => import('./pages/admin/RatePlanManagementPage'));
const PackageManagementPage = lazy(() => import('./pages/admin/PackageManagementPage'));
const SecurityManagementPage = lazy(() => import('./pages/admin/SecurityManagementPage'));
const EmailCampaignManagementPage = lazy(() => import('./pages/admin/EmailCampaignManagementPage'));
const ReviewManagementPage = lazy(() => import('./pages/admin/ReviewManagementPage'));
const BlogManagementPage = lazy(() => import('./pages/admin/BlogManagementPage'));
const ComplaintManagementPage = lazy(() => import('./pages/admin/ComplaintManagementPage'));
const FinancialAuditTrailPage = lazy(() => import('./pages/admin/FinancialAuditTrailPage'));
const ComplianceReportingPage = lazy(() => import('./pages/admin/ComplianceReportingPage'));
const ApprovalManagementPage = lazy(() => import('./pages/admin/ApprovalManagementPage'));
const GDPRManagementPage = lazy(() => import('./pages/admin/GDPRManagementPage'));
const WebhookManagementPage = lazy(() => import('./pages/admin/WebhookManagementPage'));
const APIKeyManagementPage = lazy(() => import('./pages/admin/APIKeyManagementPage'));
const BackupManagementPage = lazy(() => import('./pages/admin/BackupManagementPage'));
const StaffDashboardPage = lazy(() => import('./pages/staff/DashboardPage'));
const StaffBookingManagementPage = lazy(() => import('./pages/staff/BookingManagementPage'));
const StaffReceptionDashboardPage = lazy(() => import('./pages/staff/ReceptionDashboardPage'));
const StaffPaymentManagementPage = lazy(() => import('./pages/staff/PaymentManagementPage'));
const StaffAnalyticsDashboardPage = lazy(() => import('./pages/staff/AnalyticsDashboardPage'));
const StaffLoyaltyManagementPage = lazy(() => import('./pages/staff/LoyaltyManagementPage'));
const StaffGuestProfilePage = lazy(() => import('./pages/staff/GuestProfilePage'));
const StaffAdvancedRoomManagementPage = lazy(() => import('./pages/staff/AdvancedRoomManagementPage'));
const ChatManagementPage = lazy(() => import('./pages/staff/ChatManagementPage'));
const StaffLayout = lazy(() => import('./pages/StaffLayout'));
const AccountantDashboardPage = lazy(() => import('./pages/accountant/DashboardPage'));
const AccountantPaymentManagementPage = lazy(() => import('./pages/accountant/PaymentManagementPage'));
const AccountantInvoiceManagementPage = lazy(() => import('./pages/accountant/InvoiceManagementPage'));
const AccountantAnalyticsDashboardPage = lazy(() => import('./pages/accountant/AnalyticsDashboardPage'));
const AccountantLayout = lazy(() => import('./pages/AccountantLayout'));
const NotFoundPage = lazy(() => import('./shared/pages/NotFoundPage'));
// Component to track navigation changes - must be inside Router
const NavigationTracker: React.FC = () => {
const { pathname } = useLocation();
const { setNavigationLoading } = useLoading();
useEffect(() => {
// Show navigation loading when route changes
setNavigationLoading(true);
// Hide navigation loading after a short delay
const timer = setTimeout(() => {
setNavigationLoading(false);
}, 300);
return () => clearTimeout(timer);
}, [pathname, setNavigationLoading]);
return null;
};
// Wrapper component to use navigation loading hook inside CompanySettingsProvider
const PreloaderWrapper: React.FC = () => {
const { isLoading } = useNavigationLoading();
return <Preloader isLoading={isLoading} />;
};
function App() {
const {
isAuthenticated,
userInfo,
logout,
initializeAuth
} = useAuthStore();
const {
fetchFavorites,
syncGuestFavorites,
loadGuestFavorites,
} = useFavoritesStore();
useEffect(() => {
// Initialize auth asynchronously to validate cookies
initializeAuth().catch((error) => {
// Silently handle auth initialization errors
// User will be prompted to login if needed
console.debug('Auth initialization failed:', error);
});
}, [initializeAuth]);
useEffect(() => {
if (isAuthenticated) {
syncGuestFavorites().then(() => {
fetchFavorites();
});
} else {
loadGuestFavorites();
}
}, [
isAuthenticated,
fetchFavorites,
syncGuestFavorites,
loadGuestFavorites,
]);
const handleLogout = async () => {
await logout();
};
return (
<LoadingProvider>
<CookieConsentProvider>
<CurrencyProvider>
<CompanySettingsProvider>
<AntibotProvider>
<AuthModalProvider>
<BrowserRouter
future={{
v7_startTransition: true,
v7_relativeSplatPath: true,
}}
>
<PreloaderWrapper />
<ScrollToTop />
<NavigationTracker />
<Suspense fallback={<Loading fullScreen text="Loading page..." />}>
<Routes>
{}
<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={
<CustomerRoute>
<FavoritesPage />
</CustomerRoute>
}
/>
<Route
path="payment-result"
element={
<ErrorBoundaryRoute>
<PaymentResultPage />
</ErrorBoundaryRoute>
}
/>
<Route
path="payment/paypal/return"
element={
<ErrorBoundaryRoute>
<PayPalReturnPage />
</ErrorBoundaryRoute>
}
/>
<Route
path="payment/paypal/cancel"
element={
<ErrorBoundaryRoute>
<PayPalCancelPage />
</ErrorBoundaryRoute>
}
/>
<Route
path="payment/borica/return"
element={
<ErrorBoundaryRoute>
<BoricaReturnPage />
</ErrorBoundaryRoute>
}
/>
<Route
path="invoices/:id"
element={
<ProtectedRoute>
<InvoicePage />
</ProtectedRoute>
}
/>
<Route
path="about"
element={<AboutPage />}
/>
<Route
path="contact"
element={<ContactPage />}
/>
<Route
path="privacy"
element={<PrivacyPolicyPage />}
/>
<Route
path="terms"
element={<TermsPage />}
/>
<Route
path="refunds"
element={<RefundsPolicyPage />}
/>
<Route
path="cancellation"
element={<CancellationPolicyPage />}
/>
<Route
path="accessibility"
element={<AccessibilityPage />}
/>
<Route
path="faq"
element={<FAQPage />}
/>
<Route
path="blog"
element={<BlogPage />}
/>
<Route
path="blog/:slug"
element={<BlogDetailPage />}
/>
{}
<Route
path="dashboard"
element={
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
}
/>
<Route
path="booking-success/:id"
element={
<ErrorBoundaryRoute>
<CustomerRoute>
<BookingSuccessPage />
</CustomerRoute>
</ErrorBoundaryRoute>
}
/>
<Route
path="bookings"
element={
<ErrorBoundaryRoute>
<CustomerRoute>
<MyBookingsPage />
</CustomerRoute>
</ErrorBoundaryRoute>
}
/>
<Route
path="bookings/:id"
element={
<ErrorBoundaryRoute>
<CustomerRoute>
<BookingDetailPage />
</CustomerRoute>
</ErrorBoundaryRoute>
}
/>
<Route
path="payment/:bookingId"
element={
<ErrorBoundaryRoute>
<CustomerRoute>
<FullPaymentPage />
</CustomerRoute>
</ErrorBoundaryRoute>
}
/>
<Route
path="payment-confirmation/:id"
element={
<ErrorBoundaryRoute>
<CustomerRoute>
<PaymentConfirmationPage />
</CustomerRoute>
</ErrorBoundaryRoute>
}
/>
<Route
path="profile"
element={
<ProtectedRoute>
<ProfilePage />
</ProtectedRoute>
}
/>
<Route
path="loyalty"
element={
<CustomerRoute>
<LoyaltyPage />
</CustomerRoute>
}
/>
<Route
path="group-bookings"
element={
<CustomerRoute>
<GroupBookingPage />
</CustomerRoute>
}
/>
<Route
path="complaints"
element={
<CustomerRoute>
<ComplaintPage />
</CustomerRoute>
}
/>
<Route
path="gdpr"
element={
<ProtectedRoute>
<GDPRPage />
</ProtectedRoute>
}
/>
</Route>
{}
<Route
path="/reset-password/:token"
element={<ResetPasswordRouteHandler />}
/>
{}
<Route
path="/admin"
element={
<ErrorBoundaryRoute>
<AdminRoute>
<AdminLayout />
</AdminRoute>
</ErrorBoundaryRoute>
}
>
<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="advanced-rooms"
element={<AdvancedRoomManagementPage />}
/>
<Route
path="page-content"
element={<PageContentDashboardPage />}
/>
<Route
path="analytics"
element={<AnalyticsDashboardPage />}
/>
<Route
path="tasks"
element={<TaskManagementPage />}
/>
<Route
path="workflows"
element={<WorkflowManagementPage />}
/>
<Route
path="notifications"
element={<NotificationManagementPage />}
/>
<Route
path="settings"
element={<SettingsPage />}
/>
<Route
path="invoices"
element={<InvoiceManagementPage />}
/>
<Route
path="invoices/:id/edit"
element={<InvoiceEditPage />}
/>
<Route
path="invoices/:id"
element={<InvoicePage />}
/>
<Route
path="payments"
element={<PaymentManagementPage />}
/>
<Route
path="loyalty"
element={<LoyaltyManagementPage />}
/>
<Route
path="guest-profiles"
element={<GuestProfilePage />}
/>
<Route
path="group-bookings"
element={<GroupBookingManagementPage />}
/>
<Route
path="bookings"
element={<AdminBookingManagementPage />}
/>
<Route
path="rate-plans"
element={<RatePlanManagementPage />}
/>
<Route
path="packages"
element={<PackageManagementPage />}
/>
<Route
path="security"
element={<SecurityManagementPage />}
/>
<Route
path="email-campaigns"
element={<EmailCampaignManagementPage />}
/>
<Route
path="reviews"
element={<ReviewManagementPage />}
/>
<Route
path="blog"
element={<BlogManagementPage />}
/>
<Route
path="complaints"
element={<ComplaintManagementPage />}
/>
<Route
path="financial-audit"
element={<FinancialAuditTrailPage />}
/>
<Route
path="compliance"
element={<ComplianceReportingPage />}
/>
<Route
path="approvals"
element={<ApprovalManagementPage />}
/>
<Route
path="gdpr"
element={<GDPRManagementPage />}
/>
<Route
path="webhooks"
element={<WebhookManagementPage />}
/>
<Route
path="api-keys"
element={<APIKeyManagementPage />}
/>
<Route
path="backups"
element={<BackupManagementPage />}
/>
</Route>
{}
<Route
path="/staff"
element={
<ErrorBoundaryRoute>
<StaffRoute>
<StaffLayout />
</StaffRoute>
</ErrorBoundaryRoute>
}
>
<Route
index
element={<Navigate to="dashboard" replace />}
/>
<Route path="dashboard" element={<StaffDashboardPage />} />
<Route
path="bookings"
element={<StaffBookingManagementPage />}
/>
<Route
path="reception"
element={<StaffReceptionDashboardPage />}
/>
<Route
path="payments"
element={<StaffPaymentManagementPage />}
/>
<Route
path="reports"
element={<StaffAnalyticsDashboardPage />}
/>
<Route
path="chats"
element={<ChatManagementPage />}
/>
<Route
path="loyalty"
element={<StaffLoyaltyManagementPage />}
/>
<Route
path="guest-profiles"
element={<StaffGuestProfilePage />}
/>
<Route
path="advanced-rooms"
element={<StaffAdvancedRoomManagementPage />}
/>
</Route>
{/* Accountant Routes */}
<Route
path="/accountant"
element={
<ErrorBoundaryRoute>
<AccountantRoute>
<AccountantLayout />
</AccountantRoute>
</ErrorBoundaryRoute>
}
>
<Route
index
element={<Navigate to="dashboard" replace />}
/>
<Route path="dashboard" element={<AccountantDashboardPage />} />
<Route
path="payments"
element={<AccountantPaymentManagementPage />}
/>
<Route
path="invoices"
element={<AccountantInvoiceManagementPage />}
/>
<Route
path="invoices/:id/edit"
element={<InvoiceEditPage />}
/>
<Route
path="invoices/:id"
element={<InvoicePage />}
/>
<Route
path="reports"
element={<AccountantAnalyticsDashboardPage />}
/>
</Route>
{}
<Route
path="*"
element={<NotFoundPage />}
/>
</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 />
<CookiePreferencesModal />
<AnalyticsLoader />
<AuthModalManager />
</Suspense>
</BrowserRouter>
</AuthModalProvider>
</AntibotProvider>
</CompanySettingsProvider>
</CurrencyProvider>
</CookieConsentProvider>
</LoadingProvider>
);
}
export default App;