- POST /api/hotels/:slug/users: password now optional - with password → create active user (email_confirmed=true) - without password → create inactive user, send invite email with 7-day token - POST /api/auth/accept-invite: validates token, sets password, activates account, returns JWT for auto-login - Migration 083: invite_token + invite_expires columns on users - email.ts: sendInviteEmail() with branded HTML template - AcceptInvitePage at /invite/:token — set password form, auto-login on success - AuthContext: loginWithToken() for programmatic session set - UserModal: password field optional for new users, hint about invite email Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
154 lines
9.8 KiB
TypeScript
154 lines
9.8 KiB
TypeScript
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
|
|
import { ThemeProvider } from './contexts/ThemeContext'
|
|
import { AuthProvider } from './contexts/AuthContext'
|
|
import { ModulesProvider } from './contexts/ModulesContext'
|
|
import { AmenitiesProvider } from './contexts/AmenitiesContext'
|
|
import { BedTypesProvider } from './contexts/BedTypesContext'
|
|
import { NotificationsProvider } from './contexts/NotificationsContext'
|
|
import { AppLayout } from './layouts/AppLayout'
|
|
import { LoginPage } from './pages/LoginPage'
|
|
import { CalendarPage } from './pages/CalendarPage'
|
|
import { BookingsPage } from './pages/BookingsPage'
|
|
import { RoomsPage } from './pages/RoomsPage'
|
|
import { HousekeepingPage } from './pages/HousekeepingPage'
|
|
import { ChannelsPage } from './pages/ChannelsPage'
|
|
import { ApiDocsPage } from './pages/ApiDocsPage'
|
|
import { SettingsPage } from './pages/SettingsPage'
|
|
import { ModulesPage } from './pages/ModulesPage'
|
|
import { ReportsPage } from './pages/ReportsPage'
|
|
import { WebsitePage } from './pages/WebsitePage'
|
|
import { BookingWidgetPage } from './pages/BookingWidgetPage'
|
|
import { AvailabilityPage } from './pages/AvailabilityPage'
|
|
import { FloorMapPage } from './pages/FloorMapPage'
|
|
import { MigrationPage } from './pages/MigrationPage'
|
|
import { PosPage } from './pages/PosPage'
|
|
import { ReviewsPage } from './pages/ReviewsPage'
|
|
import { RoomServicePage } from './pages/RoomServicePage'
|
|
import { RentalPage } from './pages/RentalPage'
|
|
import { RoomCategoriesPage } from './pages/RoomCategoriesPage'
|
|
import { DocumentsPage } from './pages/DocumentsPage'
|
|
import { UsersPage } from './pages/UsersPage'
|
|
import { GuestsPage } from './pages/GuestsPage'
|
|
import { TariffsPage } from './pages/TariffsPage'
|
|
import { DynamicPricingPage } from './pages/DynamicPricingPage'
|
|
import { LoyaltyPage } from './pages/LoyaltyPage'
|
|
import { MaintenancePage } from './pages/MaintenancePage'
|
|
import { DiscountsPage } from './pages/DiscountsPage'
|
|
import { GuestReviewPage } from './pages/GuestReviewPage'
|
|
import { GuestRoomServicePage } from './pages/GuestRoomServicePage'
|
|
import { ResetPasswordPage } from './pages/ResetPasswordPage'
|
|
import { AcceptInvitePage } from './pages/AcceptInvitePage'
|
|
import { TvWelcomePage } from './pages/TvWelcomePage'
|
|
import { TechnicalPage } from './pages/TechnicalPage'
|
|
import { SchedulePage } from './pages/SchedulePage'
|
|
import { BillingPage } from './pages/BillingPage'
|
|
import { EquipmentPage } from './pages/EquipmentPage'
|
|
import { WiFiPage } from './pages/WiFiPage'
|
|
import { TTLockPage } from './pages/TTLockPage'
|
|
import { ChecklistSettingsPage } from './pages/ChecklistSettingsPage'
|
|
import { MinibarSettingsPage } from './pages/MinibarSettingsPage'
|
|
import { MinibarStockPage } from './pages/MinibarStockPage'
|
|
import { PaymentSettingsPage } from './pages/PaymentSettingsPage'
|
|
import { DepositSettingsPage } from './pages/DepositSettingsPage'
|
|
import { DepositHistoryPage } from './pages/DepositHistoryPage'
|
|
import { PayDepositPage } from './pages/PayDepositPage'
|
|
import { BookingWidgetStandalonePage } from './pages/BookingWidgetStandalonePage'
|
|
import { BookingConfirmPage } from './pages/BookingConfirmPage'
|
|
import { ModuleGuard } from './components/ModuleGuard'
|
|
import { PermissionGuard } from './components/PermissionGuard'
|
|
import { RolePermissionsProvider, useRolePermissions } from './contexts/RolePermissionsContext'
|
|
import { useAuth } from './contexts/AuthContext'
|
|
|
|
// Redirects to the user's role home page after login
|
|
function HomeRedirect() {
|
|
const { user } = useAuth()
|
|
const { userHomePage, loading } = useRolePermissions()
|
|
if (!user) return <Navigate to="/login" replace />
|
|
if (loading) return null
|
|
return <Navigate to={userHomePage} replace />
|
|
}
|
|
|
|
// Shorthand: wrap element with PermissionGuard
|
|
function P({ perm, children }: { perm: string; children: React.ReactNode }) {
|
|
return <PermissionGuard permission={perm}>{children}</PermissionGuard>
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<ThemeProvider>
|
|
<AuthProvider>
|
|
<ModulesProvider>
|
|
<RolePermissionsProvider>
|
|
<NotificationsProvider>
|
|
<AmenitiesProvider>
|
|
<BedTypesProvider>
|
|
<BrowserRouter>
|
|
<Routes>
|
|
{/* Public */}
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="/reset-password" element={<ResetPasswordPage />} />
|
|
<Route path="/invite/:token" element={<AcceptInvitePage />} />
|
|
<Route path="/review/:slug" element={<GuestReviewPage />} />
|
|
<Route path="/room-service/:slug" element={<GuestRoomServicePage />} />
|
|
<Route path="/:slug/pay" element={<PayDepositPage />} />
|
|
<Route path="/:slug/book" element={<BookingWidgetStandalonePage />} />
|
|
<Route path="/booking-confirm/:id" element={<BookingConfirmPage />} />
|
|
|
|
{/* PMS routes */}
|
|
<Route element={<AppLayout />}>
|
|
<Route path="/calendar" element={<P perm="calendar"> <CalendarPage /> </P>} />
|
|
<Route path="/bookings" element={<P perm="bookings"> <BookingsPage /> </P>} />
|
|
<Route path="/guests" element={<P perm="guests"> <GuestsPage /> </P>} />
|
|
<Route path="/rooms" element={<P perm="rooms"> <RoomsPage /> </P>} />
|
|
<Route path="/room-categories" element={<P perm="rooms"> <RoomCategoriesPage /></P>} />
|
|
<Route path="/availability" element={<P perm="availability"><AvailabilityPage /></P>} />
|
|
<Route path="/floor-map" element={<P perm="floor_map"> <FloorMapPage /> </P>} />
|
|
<Route path="/housekeeping" element={<P perm="housekeeping"><ModuleGuard moduleId="housekeeping"><HousekeepingPage /></ModuleGuard></P>} />
|
|
<Route path="/technical" element={<P perm="maintenance"> <TechnicalPage /> </P>} />
|
|
<Route path="/maintenance" element={<P perm="maintenance"> <MaintenancePage /> </P>} />
|
|
<Route path="/pos" element={<P perm="pos"> <ModuleGuard moduleId="pos"><PosPage /></ModuleGuard> </P>} />
|
|
<Route path="/room-service" element={<P perm="room_service"><ModuleGuard moduleId="room-service"><RoomServicePage /></ModuleGuard></P>} />
|
|
<Route path="/reviews" element={<P perm="reviews"> <ModuleGuard moduleId="reviews"><ReviewsPage /></ModuleGuard> </P>} />
|
|
<Route path="/tariffs" element={<P perm="tariffs"> <TariffsPage /> </P>} />
|
|
<Route path="/dynamic-pricing" element={<P perm="pricing"> <DynamicPricingPage /></P>} />
|
|
<Route path="/discounts" element={<P perm="discounts"> <DiscountsPage /> </P>} />
|
|
<Route path="/rental" element={<P perm="rental"> <ModuleGuard moduleId="rental"><RentalPage /></ModuleGuard> </P>} />
|
|
<Route path="/channels" element={<P perm="channels"> <ModuleGuard moduleId="channel-manager"><ChannelsPage /></ModuleGuard></P>} />
|
|
<Route path="/website" element={<P perm="website"> <WebsitePage /> </P>} />
|
|
<Route path="/booking-widget" element={<P perm="website"> <BookingWidgetPage /></P>} />
|
|
<Route path="/reports" element={<P perm="reports"> <ReportsPage /> </P>} />
|
|
<Route path="/loyalty" element={<P perm="loyalty"> <LoyaltyPage /> </P>} />
|
|
<Route path="/users" element={<P perm="users"> <UsersPage /> </P>} />
|
|
<Route path="/schedule" element={<P perm="users"> <SchedulePage /> </P>} />
|
|
<Route path="/documents" element={<P perm="documents"> <DocumentsPage /> </P>} />
|
|
<Route path="/settings" element={<P perm="settings"> <SettingsPage /> </P>} />
|
|
<Route path="/modules" element={<P perm="settings"> <ModulesPage /> </P>} />
|
|
<Route path="/billing" element={<P perm="settings"> <BillingPage /> </P>} />
|
|
<Route path="/equipment" element={<P perm="equipment"> <EquipmentPage /> </P>} />
|
|
<Route path="/wifi" element={<P perm="wifi"> <WiFiPage /> </P>} />
|
|
<Route path="/ttlock" element={<P perm="ttlock"> <TTLockPage /> </P>} />
|
|
<Route path="/settings/checklists" element={<P perm="settings"><ChecklistSettingsPage /></P>} />
|
|
<Route path="/settings/payments" element={<P perm="settings"><PaymentSettingsPage /> </P>} />
|
|
<Route path="/settings/minibar" element={<P perm="settings"><MinibarSettingsPage /> </P>} />
|
|
<Route path="/settings/minibar/stock" element={<P perm="settings"><MinibarStockPage /> </P>} />
|
|
<Route path="/settings/deposit" element={<P perm="settings"><DepositSettingsPage /> </P>} />
|
|
<Route path="/settings/deposit/history" element={<P perm="settings"><DepositHistoryPage /> </P>} />
|
|
<Route path="/migration" element={<P perm="settings"> <MigrationPage /> </P>} />
|
|
<Route path="/api-docs" element={<P perm="settings"> <ApiDocsPage /> </P>} />
|
|
<Route path="/tv-welcome" element={<TvWelcomePage />} />
|
|
</Route>
|
|
|
|
<Route path="/" element={<HomeRedirect />} />
|
|
<Route path="*" element={<Navigate to="/login" replace />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
</BedTypesProvider>
|
|
</AmenitiesProvider>
|
|
</NotificationsProvider>
|
|
</RolePermissionsProvider>
|
|
</ModulesProvider>
|
|
</AuthProvider>
|
|
</ThemeProvider>
|
|
)
|
|
}
|