@licklist/design 0.78.5-dev.107 → 0.78.5-dev.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bitbucket-pipelines.yml +4 -13
- package/dist/Maintenance/Maintenance.scss.js +1 -1
- package/dist/index.js +2 -0
- package/dist/product-set/form/ProductsControl.d.ts +1 -2
- package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
- package/dist/product-set/form/ProductsControl.js +24 -0
- package/dist/v2/components/ActionMenu/ActionMenu.scss.js +1 -1
- package/dist/v2/components/Badge/Badge.scss.js +1 -1
- package/dist/v2/components/Button/Button.scss.js +1 -1
- package/dist/v2/components/Button/GhostButton.scss.js +1 -1
- package/dist/v2/components/Checkbox/Checkbox.scss.js +1 -1
- package/dist/v2/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/v2/components/DataTable/DataTable.js +2 -86
- package/dist/v2/components/IconButton/IconButton.scss.js +1 -1
- package/dist/v2/components/Modal/DeleteModal.d.ts.map +1 -1
- package/dist/v2/components/Modal/DeleteModal.js +11 -13
- package/dist/v2/components/Modal/DeleteModal.scss.js +1 -1
- package/dist/v2/components/NPSScore/NPSScore.scss.js +1 -1
- package/dist/v2/components/NewTabs/NewTabs.scss.js +1 -1
- package/dist/v2/components/PeriodCard/PeriodCard.d.ts +66 -0
- package/dist/v2/components/PeriodCard/PeriodCard.d.ts.map +1 -0
- package/dist/v2/components/PeriodCard/PeriodCard.js +351 -0
- package/dist/v2/components/PeriodCard/PeriodCard.scss.js +6 -0
- package/dist/v2/components/PeriodCard/index.d.ts +3 -0
- package/dist/v2/components/PeriodCard/index.d.ts.map +1 -0
- package/dist/v2/components/ReorderRow/ReorderRow.d.ts +24 -0
- package/dist/v2/components/ReorderRow/ReorderRow.d.ts.map +1 -0
- package/dist/v2/components/ReorderRow/ReorderRow.js +109 -0
- package/dist/v2/components/ReorderRow/ReorderRow.scss.js +6 -0
- package/dist/v2/components/ReorderRow/index.d.ts +3 -0
- package/dist/v2/components/ReorderRow/index.d.ts.map +1 -0
- package/dist/v2/components/Select/Select.scss.js +1 -1
- package/dist/v2/components/StatusBadge/StatusBadge.scss.js +1 -1
- package/dist/v2/components/StepIndicator/StepIndicator.scss.js +1 -1
- package/dist/v2/components/Tabs/Tabs.scss.js +1 -1
- package/dist/v2/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/v2/components/Toggle/Toggle.js +5 -8
- package/dist/v2/components/Tooltip/Tooltip.scss.js +1 -1
- package/dist/v2/components/UserAvatar/UserAvatar.scss.js +1 -1
- package/dist/v2/components/UserPanel/UserPanel.scss.js +1 -1
- package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss.js +1 -1
- package/dist/v2/components/ZoneCard/ZoneCard.scss.js +1 -1
- package/dist/v2/components/index.d.ts +4 -0
- package/dist/v2/components/index.d.ts.map +1 -1
- package/dist/v2/dashboard-analytics/chart/Chart.scss.js +1 -1
- package/dist/v2/dashboard-analytics/metric-card/MetricCard.scss.js +1 -1
- package/dist/v2/dashboard-analytics/venue-card/VenueCard.scss.js +1 -1
- package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.scss.js +1 -1
- package/dist/v2/icons/index.js +16 -1
- package/dist/v2/index.d.ts +8 -0
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/navigation/DashboardLayout/AdminSidebar.scss.js +1 -1
- package/dist/v2/navigation/DashboardLayout/DashboardLayout.scss.js +1 -1
- package/dist/v2/navigation/DashboardLayout/ProviderSidebar.scss.js +1 -1
- package/dist/v2/navigation/DashboardLayout/TopNavigation.scss.js +1 -1
- package/dist/v2/pages/Settings/SettingsTabs.scss.js +1 -1
- package/dist/v2/pages/Settings/components/SidebarCustomisation.js +5 -0
- package/dist/v2/pages/Settings/components/SidebarCustomisation.scss.js +1 -1
- package/dist/v2/pages/Settings/components/SidebarNavItem.js +5 -0
- package/dist/v2/pages/auth/AuthLayout/AuthLayout.scss.js +1 -1
- package/dist/v2/shadcn/components/ui/accordion.d.ts +8 -0
- package/dist/v2/shadcn/components/ui/accordion.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/alert-dialog.d.ts +21 -0
- package/dist/v2/shadcn/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/alert.d.ts +9 -0
- package/dist/v2/shadcn/components/ui/alert.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/aspect-ratio.d.ts +4 -0
- package/dist/v2/shadcn/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/avatar.d.ts +7 -0
- package/dist/v2/shadcn/components/ui/avatar.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/badge.d.ts +10 -0
- package/dist/v2/shadcn/components/ui/badge.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/breadcrumb.d.ts +20 -0
- package/dist/v2/shadcn/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/button.d.ts +14 -0
- package/dist/v2/shadcn/components/ui/button.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/calendar.d.ts +9 -0
- package/dist/v2/shadcn/components/ui/calendar.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/card.d.ts +9 -0
- package/dist/v2/shadcn/components/ui/card.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/carousel.d.ts +19 -0
- package/dist/v2/shadcn/components/ui/carousel.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/checkbox.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/checkbox.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/checkbox.js +115 -0
- package/dist/v2/shadcn/components/ui/checkbox.scss.js +6 -0
- package/dist/v2/shadcn/components/ui/collapsible.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/collapsible.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/command.d.ts +83 -0
- package/dist/v2/shadcn/components/ui/command.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/context-menu.d.ts +28 -0
- package/dist/v2/shadcn/components/ui/context-menu.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/dialog.d.ts +20 -0
- package/dist/v2/shadcn/components/ui/dialog.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/dialog.js +169 -0
- package/dist/v2/shadcn/components/ui/drawer.d.ts +23 -0
- package/dist/v2/shadcn/components/ui/drawer.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/dropdown-menu.d.ts +28 -0
- package/dist/v2/shadcn/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/form.d.ts +24 -0
- package/dist/v2/shadcn/components/ui/form.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/hover-card.d.ts +7 -0
- package/dist/v2/shadcn/components/ui/hover-card.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/input-otp.d.ts +35 -0
- package/dist/v2/shadcn/components/ui/input-otp.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/input.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/input.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/label.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/label.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/menubar.d.ts +34 -0
- package/dist/v2/shadcn/components/ui/menubar.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/navigation-menu.d.ts +13 -0
- package/dist/v2/shadcn/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/pagination.d.ts +29 -0
- package/dist/v2/shadcn/components/ui/pagination.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/popover.d.ts +7 -0
- package/dist/v2/shadcn/components/ui/popover.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/progress.d.ts +5 -0
- package/dist/v2/shadcn/components/ui/progress.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/radio-card.d.ts +12 -0
- package/dist/v2/shadcn/components/ui/radio-card.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/radio-group.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/radio-group.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/scroll-area.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/select.d.ts +14 -0
- package/dist/v2/shadcn/components/ui/select.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/separator.d.ts +5 -0
- package/dist/v2/shadcn/components/ui/separator.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/sheet.d.ts +26 -0
- package/dist/v2/shadcn/components/ui/sheet.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/sidebar.d.ts +67 -0
- package/dist/v2/shadcn/components/ui/sidebar.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/skeleton.d.ts +3 -0
- package/dist/v2/shadcn/components/ui/skeleton.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/slider.d.ts +5 -0
- package/dist/v2/shadcn/components/ui/slider.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/switch.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/switch.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/switch.js +115 -0
- package/dist/v2/shadcn/components/ui/switch.scss.js +6 -0
- package/dist/v2/shadcn/components/ui/table-pagination.d.ts +11 -0
- package/dist/v2/shadcn/components/ui/table-pagination.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/table.d.ts +11 -0
- package/dist/v2/shadcn/components/ui/table.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/tabs.d.ts +8 -0
- package/dist/v2/shadcn/components/ui/tabs.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/textarea.d.ts +6 -0
- package/dist/v2/shadcn/components/ui/textarea.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/toast.d.ts +16 -0
- package/dist/v2/shadcn/components/ui/toast.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/toaster.d.ts +2 -0
- package/dist/v2/shadcn/components/ui/toaster.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/toggle-group.d.ts +13 -0
- package/dist/v2/shadcn/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/toggle.d.ts +13 -0
- package/dist/v2/shadcn/components/ui/toggle.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/tooltip.d.ts +8 -0
- package/dist/v2/shadcn/components/ui/tooltip.d.ts.map +1 -0
- package/dist/v2/shadcn/components/ui/use-toast.d.ts +3 -0
- package/dist/v2/shadcn/components/ui/use-toast.d.ts.map +1 -0
- package/dist/v2/shadcn/hooks/use-mobile.d.ts +2 -0
- package/dist/v2/shadcn/hooks/use-mobile.d.ts.map +1 -0
- package/dist/v2/shadcn/hooks/use-toast.d.ts +45 -0
- package/dist/v2/shadcn/hooks/use-toast.d.ts.map +1 -0
- package/dist/v2/shadcn/index.d.ts +20 -0
- package/dist/v2/shadcn/index.d.ts.map +1 -0
- package/dist/v2/shadcn/lib/utils.d.ts +3 -0
- package/dist/v2/shadcn/lib/utils.d.ts.map +1 -0
- package/dist/v2/shadcn/lib/utils.js +11 -0
- package/dist/v2/shadcn/styles/globals.css +112 -0
- package/dist/v2/styles/form/NewInput.scss.js +1 -1
- package/package.json +6 -6
- package/rollup.config.js +2 -16
- package/src/iframe/payment/payment-status-page/PaymentStatusPage.tsx +1 -1
- package/src/product-set/form/ProductsControl.tsx +1 -2
- package/src/v2/components/DataTable/DataTable.tsx +1 -23
- package/src/v2/components/Modal/DeleteModal.tsx +20 -12
- package/src/v2/components/PeriodCard/PeriodCard.scss +157 -0
- package/src/v2/components/PeriodCard/PeriodCard.stories.tsx +245 -0
- package/src/v2/components/PeriodCard/PeriodCard.tsx +350 -0
- package/src/v2/components/PeriodCard/index.ts +8 -0
- package/src/v2/components/ReorderRow/ReorderRow.scss +68 -0
- package/src/v2/components/ReorderRow/ReorderRow.stories.tsx +124 -0
- package/src/v2/components/ReorderRow/ReorderRow.tsx +88 -0
- package/src/v2/components/ReorderRow/index.ts +2 -0
- package/src/v2/components/Toggle/Toggle.tsx +5 -6
- package/src/v2/components/index.ts +6 -0
- package/src/v2/index.ts +82 -0
- package/src/v2/shadcn/_reference/AccountManagerCard.tsx +45 -0
- package/src/v2/shadcn/_reference/AffiliatesTable.tsx +178 -0
- package/src/v2/shadcn/_reference/AuditArchive.tsx +165 -0
- package/src/v2/shadcn/_reference/AuditContent.tsx +270 -0
- package/src/v2/shadcn/_reference/AutomationsGeneralSettings.tsx +251 -0
- package/src/v2/shadcn/_reference/AvatarUpload.tsx +150 -0
- package/src/v2/shadcn/_reference/BookingsSummaryCard.tsx +268 -0
- package/src/v2/shadcn/_reference/CodeCleanUpAudit.tsx +274 -0
- package/src/v2/shadcn/_reference/CompaniesTable.tsx +387 -0
- package/src/v2/shadcn/_reference/ComponentAudit.tsx +239 -0
- package/src/v2/shadcn/_reference/ConfigureSettingsCard.tsx +95 -0
- package/src/v2/shadcn/_reference/CustomerCard.tsx +155 -0
- package/src/v2/shadcn/_reference/DashboardCards.tsx +50 -0
- package/src/v2/shadcn/_reference/DashboardFooter.tsx +18 -0
- package/src/v2/shadcn/_reference/DiarySettings.tsx +187 -0
- package/src/v2/shadcn/_reference/DiaryView.tsx +998 -0
- package/src/v2/shadcn/_reference/EmptyState.tsx +76 -0
- package/src/v2/shadcn/_reference/EntityInfoCard.tsx +48 -0
- package/src/v2/shadcn/_reference/ExistingUserAssignments.tsx +131 -0
- package/src/v2/shadcn/_reference/FeatureToggle.tsx +72 -0
- package/src/v2/shadcn/_reference/FlowCard.tsx +170 -0
- package/src/v2/shadcn/_reference/FlowsContent.tsx +688 -0
- package/src/v2/shadcn/_reference/FlowsGeneralSettings.tsx +27 -0
- package/src/v2/shadcn/_reference/GeneralSettings.tsx +33 -0
- package/src/v2/shadcn/_reference/InventoryGeneralSettings.tsx +82 -0
- package/src/v2/shadcn/_reference/LanguageSelector.tsx +97 -0
- package/src/v2/shadcn/_reference/LoadingScreen.tsx +25 -0
- package/src/v2/shadcn/_reference/LoadingSpinner.tsx +41 -0
- package/src/v2/shadcn/_reference/ManagedClientsList.tsx +121 -0
- package/src/v2/shadcn/_reference/NPSScore.tsx +379 -0
- package/src/v2/shadcn/_reference/NPSSummaryCard.tsx +181 -0
- package/src/v2/shadcn/_reference/NotificationBanner.tsx +129 -0
- package/src/v2/shadcn/_reference/NotificationPanel.tsx +208 -0
- package/src/v2/shadcn/_reference/OnlineUsersCard.tsx +73 -0
- package/src/v2/shadcn/_reference/ProtectedRoute.tsx +39 -0
- package/src/v2/shadcn/_reference/ProvidersTable.tsx +353 -0
- package/src/v2/shadcn/_reference/QuickAddPanel.tsx +1057 -0
- package/src/v2/shadcn/_reference/QuickFilters.tsx +112 -0
- package/src/v2/shadcn/_reference/ScheduleView.tsx +410 -0
- package/src/v2/shadcn/_reference/ScrollToTop.tsx +14 -0
- package/src/v2/shadcn/_reference/SecondaryNav.tsx +50 -0
- package/src/v2/shadcn/_reference/SecuritySettings.tsx +258 -0
- package/src/v2/shadcn/_reference/SessionDetailView.tsx +294 -0
- package/src/v2/shadcn/_reference/Sidebar.tsx +14 -0
- package/src/v2/shadcn/_reference/SidebarAwareLayout.tsx +30 -0
- package/src/v2/shadcn/_reference/SidebarLabelCustomization.tsx +285 -0
- package/src/v2/shadcn/_reference/SimulationBanner.tsx +57 -0
- package/src/v2/shadcn/_reference/SortControls.tsx +65 -0
- package/src/v2/shadcn/_reference/StatusBadge.tsx +49 -0
- package/src/v2/shadcn/_reference/StyleGuideContent.tsx +331 -0
- package/src/v2/shadcn/_reference/TableActionMenu.tsx +126 -0
- package/src/v2/shadcn/_reference/ThemeProvider.tsx +119 -0
- package/src/v2/shadcn/_reference/ThemeSettings.tsx +73 -0
- package/src/v2/shadcn/_reference/TopNavigation.tsx +332 -0
- package/src/v2/shadcn/_reference/UserActivityHistory.tsx +209 -0
- package/src/v2/shadcn/_reference/UserLanguageSettings.tsx +94 -0
- package/src/v2/shadcn/_reference/UserPanel.tsx +472 -0
- package/src/v2/shadcn/_reference/UsersTable.tsx +1023 -0
- package/src/v2/shadcn/_reference/WaiverForm.tsx +301 -0
- package/src/v2/shadcn/_reference/WaiversGeneralSettings.tsx +46 -0
- package/src/v2/shadcn/_reference/WaiversTable.tsx +290 -0
- package/src/v2/shadcn/_reference/WaiversTemplatesSettings.tsx +416 -0
- package/src/v2/shadcn/_reference/ai/AIChatPanel.tsx +313 -0
- package/src/v2/shadcn/_reference/ai/AIChatSearchBar.tsx +36 -0
- package/src/v2/shadcn/_reference/ai/ChatInteractiveBlock.tsx +298 -0
- package/src/v2/shadcn/_reference/ai/ChatMessageContent.tsx +40 -0
- package/src/v2/shadcn/_reference/ai/parseInteractiveBlocks.ts +142 -0
- package/src/v2/shadcn/_reference/auth/AuthLayout.tsx +55 -0
- package/src/v2/shadcn/_reference/auth/CreatePasswordForm.tsx +285 -0
- package/src/v2/shadcn/_reference/auth/CreatePasswordPanel.tsx +20 -0
- package/src/v2/shadcn/_reference/auth/LoginFooter.tsx +14 -0
- package/src/v2/shadcn/_reference/auth/LoginForm.tsx +205 -0
- package/src/v2/shadcn/_reference/auth/LoginPanel.tsx +41 -0
- package/src/v2/shadcn/_reference/auth/ResetPasswordForm.tsx +102 -0
- package/src/v2/shadcn/_reference/auth/ResetPasswordPanel.tsx +20 -0
- package/src/v2/shadcn/_reference/auth/VerifyEmailForm.tsx +95 -0
- package/src/v2/shadcn/_reference/auth/VerifyEmailPanel.tsx +20 -0
- package/src/v2/shadcn/_reference/email/EmailAttachment.tsx +119 -0
- package/src/v2/shadcn/_reference/email/EmailAutomation.tsx +92 -0
- package/src/v2/shadcn/_reference/email/EmailPlaceholders.tsx +64 -0
- package/src/v2/shadcn/_reference/email/UnlayerEmailEditor.tsx +41 -0
- package/src/v2/shadcn/_reference/email/emailTemplateData.ts +53 -0
- package/src/v2/shadcn/_reference/emptyStateIcons.tsx +103 -0
- package/src/v2/shadcn/_reference/games/MazeGame.tsx +394 -0
- package/src/v2/shadcn/_reference/games/RunnerGame.tsx +497 -0
- package/src/v2/shadcn/_reference/logos/BookedLogoFull.tsx +36 -0
- package/src/v2/shadcn/_reference/logos/BookedLogoMark.tsx +31 -0
- package/src/v2/shadcn/_reference/logos/BookedLogoNew.tsx +36 -0
- package/src/v2/shadcn/_reference/pricing/DynamicPricingRulesEditor.tsx +401 -0
- package/src/v2/shadcn/_reference/pricing/DynamicPricingTierCard.tsx +77 -0
- package/src/v2/shadcn/_reference/pricing/DynamicPricingTiersList.tsx +218 -0
- package/src/v2/shadcn/_reference/pricing/PricingCalendar.tsx +810 -0
- package/src/v2/shadcn/_reference/pricing/PricingPeriodCard.tsx +152 -0
- package/src/v2/shadcn/_reference/pricing/PricingPeriodForm.tsx +377 -0
- package/src/v2/shadcn/_reference/pricing/PricingPeriodsList.tsx +213 -0
- package/src/v2/shadcn/_reference/pricing/getRuleSummary.ts +39 -0
- package/src/v2/shadcn/_reference/products/AvailabilityRulesSection.tsx +184 -0
- package/src/v2/shadcn/_reference/products/AvailabilitySection.tsx +677 -0
- package/src/v2/shadcn/_reference/products/BookingTypeConfigOptions.tsx +40 -0
- package/src/v2/shadcn/_reference/products/CapacityPeriodsSection.tsx +238 -0
- package/src/v2/shadcn/_reference/products/DynamicPricingTiersSection.tsx +131 -0
- package/src/v2/shadcn/_reference/products/GiftCardOrdersTab.tsx +192 -0
- package/src/v2/shadcn/_reference/products/GiftCardSettings.tsx +342 -0
- package/src/v2/shadcn/_reference/products/PackageProductsSection.tsx +322 -0
- package/src/v2/shadcn/_reference/products/PricingSection.tsx +173 -0
- package/src/v2/shadcn/_reference/products/ProductTypeFields.tsx +353 -0
- package/src/v2/shadcn/_reference/products/ProductTypeIcon.tsx +95 -0
- package/src/v2/shadcn/_reference/products/VariablePricingSection.tsx +140 -0
- package/src/v2/shadcn/_reference/products/productTypeConfig.ts +182 -0
- package/src/v2/shadcn/_reference/shared/BackButton.tsx +50 -0
- package/src/v2/shadcn/_reference/shared/CancelConfirmationDialog.tsx +18 -0
- package/src/v2/shadcn/_reference/shared/ConfirmationDialog.tsx +136 -0
- package/src/v2/shadcn/_reference/shared/DeleteConfirmationDialog.tsx +18 -0
- package/src/v2/shadcn/_reference/shared/DeleteEntityPage.tsx +221 -0
- package/src/v2/shadcn/_reference/shared/SidebarIcons.tsx +108 -0
- package/src/v2/shadcn/_reference/shared/UnifiedSidebar.tsx +722 -0
- package/src/v2/shadcn/_reference/tables/BulkActionsBar.tsx +68 -0
- package/src/v2/shadcn/_reference/tables/DataTable.tsx +221 -0
- package/src/v2/shadcn/_reference/tables/TableControls.tsx +94 -0
- package/src/v2/shadcn/_reference/tables/index.ts +3 -0
- package/src/v2/shadcn/_reference/tables/types.ts +79 -0
- package/src/v2/shadcn/_reference/zones/LegacyZoneSettings.tsx +299 -0
- package/src/v2/shadcn/components/ui/accordion.stories.tsx +63 -0
- package/src/v2/shadcn/components/ui/accordion.tsx +52 -0
- package/src/v2/shadcn/components/ui/alert-dialog.stories.tsx +44 -0
- package/src/v2/shadcn/components/ui/alert-dialog.tsx +104 -0
- package/src/v2/shadcn/components/ui/alert.stories.tsx +44 -0
- package/src/v2/shadcn/components/ui/alert.tsx +43 -0
- package/src/v2/shadcn/components/ui/aspect-ratio.stories.tsx +46 -0
- package/src/v2/shadcn/components/ui/aspect-ratio.tsx +5 -0
- package/src/v2/shadcn/components/ui/avatar.stories.tsx +39 -0
- package/src/v2/shadcn/components/ui/avatar.tsx +38 -0
- package/src/v2/shadcn/components/ui/badge.stories.tsx +17 -0
- package/src/v2/shadcn/components/ui/badge.tsx +30 -0
- package/src/v2/shadcn/components/ui/breadcrumb.stories.tsx +91 -0
- package/src/v2/shadcn/components/ui/breadcrumb.tsx +90 -0
- package/src/v2/shadcn/components/ui/button.stories.tsx +20 -0
- package/src/v2/shadcn/components/ui/button.tsx +60 -0
- package/src/v2/shadcn/components/ui/calendar.stories.tsx +61 -0
- package/src/v2/shadcn/components/ui/calendar.tsx +54 -0
- package/src/v2/shadcn/components/ui/card.stories.tsx +37 -0
- package/src/v2/shadcn/components/ui/card.tsx +43 -0
- package/src/v2/shadcn/components/ui/carousel.stories.tsx +92 -0
- package/src/v2/shadcn/components/ui/carousel.tsx +224 -0
- package/src/v2/shadcn/components/ui/checkbox.scss +38 -0
- package/src/v2/shadcn/components/ui/checkbox.stories.tsx +23 -0
- package/src/v2/shadcn/components/ui/checkbox.tsx +24 -0
- package/src/v2/shadcn/components/ui/collapsible.stories.tsx +59 -0
- package/src/v2/shadcn/components/ui/collapsible.tsx +9 -0
- package/src/v2/shadcn/components/ui/command.stories.tsx +70 -0
- package/src/v2/shadcn/components/ui/command.tsx +132 -0
- package/src/v2/shadcn/components/ui/context-menu.stories.tsx +72 -0
- package/src/v2/shadcn/components/ui/context-menu.tsx +178 -0
- package/src/v2/shadcn/components/ui/dialog.stories.tsx +67 -0
- package/src/v2/shadcn/components/ui/dialog.tsx +95 -0
- package/src/v2/shadcn/components/ui/drawer.stories.tsx +50 -0
- package/src/v2/shadcn/components/ui/drawer.tsx +87 -0
- package/src/v2/shadcn/components/ui/dropdown-menu.stories.tsx +73 -0
- package/src/v2/shadcn/components/ui/dropdown-menu.tsx +179 -0
- package/src/v2/shadcn/components/ui/form.stories.tsx +105 -0
- package/src/v2/shadcn/components/ui/form.tsx +129 -0
- package/src/v2/shadcn/components/ui/hover-card.stories.tsx +35 -0
- package/src/v2/shadcn/components/ui/hover-card.tsx +27 -0
- package/src/v2/shadcn/components/ui/input-otp.stories.tsx +72 -0
- package/src/v2/shadcn/components/ui/input-otp.tsx +61 -0
- package/src/v2/shadcn/components/ui/input.stories.tsx +16 -0
- package/src/v2/shadcn/components/ui/input.tsx +25 -0
- package/src/v2/shadcn/components/ui/label.stories.tsx +13 -0
- package/src/v2/shadcn/components/ui/label.tsx +17 -0
- package/src/v2/shadcn/components/ui/menubar.stories.tsx +86 -0
- package/src/v2/shadcn/components/ui/menubar.tsx +207 -0
- package/src/v2/shadcn/components/ui/navigation-menu.stories.tsx +68 -0
- package/src/v2/shadcn/components/ui/navigation-menu.tsx +120 -0
- package/src/v2/shadcn/components/ui/pagination.stories.tsx +78 -0
- package/src/v2/shadcn/components/ui/pagination.tsx +81 -0
- package/src/v2/shadcn/components/ui/popover.stories.tsx +44 -0
- package/src/v2/shadcn/components/ui/popover.tsx +29 -0
- package/src/v2/shadcn/components/ui/progress.stories.tsx +17 -0
- package/src/v2/shadcn/components/ui/progress.tsx +23 -0
- package/src/v2/shadcn/components/ui/radio-card.stories.tsx +68 -0
- package/src/v2/shadcn/components/ui/radio-card.tsx +52 -0
- package/src/v2/shadcn/components/ui/radio-group.stories.tsx +77 -0
- package/src/v2/shadcn/components/ui/radio-group.tsx +35 -0
- package/src/v2/shadcn/components/ui/scroll-area.stories.tsx +56 -0
- package/src/v2/shadcn/components/ui/scroll-area.tsx +38 -0
- package/src/v2/shadcn/components/ui/select.stories.tsx +60 -0
- package/src/v2/shadcn/components/ui/select.tsx +148 -0
- package/src/v2/shadcn/components/ui/separator.stories.tsx +30 -0
- package/src/v2/shadcn/components/ui/separator.tsx +20 -0
- package/src/v2/shadcn/components/ui/sheet.stories.tsx +115 -0
- package/src/v2/shadcn/components/ui/sheet.tsx +107 -0
- package/src/v2/shadcn/components/ui/sidebar.stories.tsx +167 -0
- package/src/v2/shadcn/components/ui/sidebar.tsx +637 -0
- package/src/v2/shadcn/components/ui/skeleton.stories.tsx +36 -0
- package/src/v2/shadcn/components/ui/skeleton.tsx +7 -0
- package/src/v2/shadcn/components/ui/slider.stories.tsx +16 -0
- package/src/v2/shadcn/components/ui/slider.tsx +23 -0
- package/src/v2/shadcn/components/ui/switch.scss +63 -0
- package/src/v2/shadcn/components/ui/switch.stories.tsx +23 -0
- package/src/v2/shadcn/components/ui/switch.tsx +24 -0
- package/src/v2/shadcn/components/ui/table-pagination.stories.tsx +81 -0
- package/src/v2/shadcn/components/ui/table-pagination.tsx +61 -0
- package/src/v2/shadcn/components/ui/table.stories.tsx +40 -0
- package/src/v2/shadcn/components/ui/table.tsx +72 -0
- package/src/v2/shadcn/components/ui/tabs.stories.tsx +85 -0
- package/src/v2/shadcn/components/ui/tabs.tsx +53 -0
- package/src/v2/shadcn/components/ui/textarea.stories.tsx +15 -0
- package/src/v2/shadcn/components/ui/textarea.tsx +21 -0
- package/src/v2/shadcn/components/ui/toast.stories.tsx +77 -0
- package/src/v2/shadcn/components/ui/toast.tsx +111 -0
- package/src/v2/shadcn/components/ui/toaster.stories.tsx +46 -0
- package/src/v2/shadcn/components/ui/toaster.tsx +24 -0
- package/src/v2/shadcn/components/ui/toggle-group.stories.tsx +95 -0
- package/src/v2/shadcn/components/ui/toggle-group.tsx +49 -0
- package/src/v2/shadcn/components/ui/toggle.stories.tsx +18 -0
- package/src/v2/shadcn/components/ui/toggle.tsx +37 -0
- package/src/v2/shadcn/components/ui/tooltip.stories.tsx +57 -0
- package/src/v2/shadcn/components/ui/tooltip.tsx +28 -0
- package/src/v2/shadcn/components/ui/use-toast.ts +3 -0
- package/src/v2/shadcn/hooks/use-mobile.tsx +19 -0
- package/src/v2/shadcn/hooks/use-toast.ts +184 -0
- package/src/v2/shadcn/index.ts +76 -0
- package/src/v2/shadcn/lib/utils.ts +6 -0
- package/src/v2/shadcn/styles/globals.css +112 -0
- package/.vscode/settings.json +0 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from './ui/button';
|
|
3
|
+
import { cn } from '../lib/utils';
|
|
4
|
+
|
|
5
|
+
export interface QuickFilter {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
group?: string; // Optional group for multi-select within same group
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface QuickFiltersBaseProps {
|
|
12
|
+
label?: string;
|
|
13
|
+
filters: QuickFilter[];
|
|
14
|
+
allFilterValue?: string;
|
|
15
|
+
groupDividerAfter?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface QuickFiltersSingleProps extends QuickFiltersBaseProps {
|
|
19
|
+
activeFilter: string;
|
|
20
|
+
onFilterChange: (filter: string) => void;
|
|
21
|
+
activeFilters?: never;
|
|
22
|
+
multiSelect?: false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface QuickFiltersMultiProps extends QuickFiltersBaseProps {
|
|
26
|
+
activeFilters: string[];
|
|
27
|
+
onFilterChange: (filters: string[]) => void;
|
|
28
|
+
activeFilter?: never;
|
|
29
|
+
multiSelect: true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type QuickFiltersProps = QuickFiltersSingleProps | QuickFiltersMultiProps;
|
|
33
|
+
|
|
34
|
+
export const QuickFilters: React.FC<QuickFiltersProps> = (props) => {
|
|
35
|
+
const {
|
|
36
|
+
label = 'Quick Filters:',
|
|
37
|
+
filters,
|
|
38
|
+
allFilterValue = 'all',
|
|
39
|
+
groupDividerAfter,
|
|
40
|
+
} = props;
|
|
41
|
+
|
|
42
|
+
const isMultiSelect = props.multiSelect === true;
|
|
43
|
+
|
|
44
|
+
// Normalize to array for internal logic
|
|
45
|
+
const activeFiltersArray = isMultiSelect
|
|
46
|
+
? props.activeFilters
|
|
47
|
+
: [props.activeFilter];
|
|
48
|
+
|
|
49
|
+
const handleFilterClick = (filterValue: string) => {
|
|
50
|
+
if (isMultiSelect) {
|
|
51
|
+
const filter = filters.find(f => f.value === filterValue);
|
|
52
|
+
const filterGroup = filter?.group;
|
|
53
|
+
|
|
54
|
+
if (activeFiltersArray.includes(filterValue)) {
|
|
55
|
+
// Remove the filter
|
|
56
|
+
const newFilters = activeFiltersArray.filter(f => f !== filterValue);
|
|
57
|
+
props.onFilterChange(newFilters.length === 0 ? [allFilterValue] : newFilters);
|
|
58
|
+
} else {
|
|
59
|
+
// Add the filter - if it has a group, remove others in same group first
|
|
60
|
+
let newFilters = activeFiltersArray.filter(f => f !== allFilterValue);
|
|
61
|
+
|
|
62
|
+
if (filterGroup) {
|
|
63
|
+
// Remove any other filter in the same group
|
|
64
|
+
const sameGroupFilters = filters.filter(f => f.group === filterGroup).map(f => f.value);
|
|
65
|
+
newFilters = newFilters.filter(f => !sameGroupFilters.includes(f));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
newFilters.push(filterValue);
|
|
69
|
+
props.onFilterChange(newFilters);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// Single select - toggle behavior: clicking active filter resets to 'all'
|
|
73
|
+
const newValue = props.activeFilter === filterValue ? allFilterValue : filterValue;
|
|
74
|
+
props.onFilterChange(newValue);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const isAllActive = isMultiSelect
|
|
79
|
+
? activeFiltersArray.length === 0 || (activeFiltersArray.length === 1 && activeFiltersArray[0] === allFilterValue)
|
|
80
|
+
: props.activeFilter === allFilterValue;
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className="flex flex-wrap items-center gap-2 min-w-0">
|
|
84
|
+
<span className="text-label-secondary text-[13px] font-medium whitespace-nowrap">
|
|
85
|
+
{label}
|
|
86
|
+
</span>
|
|
87
|
+
{filters.map((filter) => {
|
|
88
|
+
const isActive = !isAllActive && activeFiltersArray.includes(filter.value);
|
|
89
|
+
return (
|
|
90
|
+
<React.Fragment key={filter.value}>
|
|
91
|
+
<Button
|
|
92
|
+
variant={isActive ? 'default' : 'outline'}
|
|
93
|
+
size="sm"
|
|
94
|
+
onClick={() => handleFilterClick(filter.value)}
|
|
95
|
+
className={cn(
|
|
96
|
+
"text-[11px] font-mono rounded-full px-3 whitespace-nowrap min-w-0 h-8 border",
|
|
97
|
+
isActive
|
|
98
|
+
? "bg-fill-primary hover:bg-fill-primary/90 active:bg-fill-primary/80 border-transparent"
|
|
99
|
+
: "border-border-primary"
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
{filter.label}
|
|
103
|
+
</Button>
|
|
104
|
+
{groupDividerAfter === filter.value && (
|
|
105
|
+
<div className="w-px h-5 bg-border-primary mx-1 flex-shrink-0" />
|
|
106
|
+
)}
|
|
107
|
+
</React.Fragment>
|
|
108
|
+
);
|
|
109
|
+
})}
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import React, { useState, useEffect, useMemo } from 'react';
|
|
2
|
+
import { supabase } from '@/integrations/supabase/client';
|
|
3
|
+
import { useNotify } from '../hooks/useNotify';
|
|
4
|
+
import { format, addDays, getDay } from 'date-fns';
|
|
5
|
+
import { cn } from '../lib/utils';
|
|
6
|
+
import { Button } from './ui/button';
|
|
7
|
+
import { IconArrowLeft, IconArrowRight, IconChevronRight } from '../../icons';
|
|
8
|
+
import { Badge } from './ui/badge';
|
|
9
|
+
import { useProvider } from '@/contexts/ProviderContext';
|
|
10
|
+
import LoadingSpinner from './LoadingSpinner';
|
|
11
|
+
|
|
12
|
+
interface Product {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
type: string;
|
|
16
|
+
duration: number | null;
|
|
17
|
+
capacity: number | null;
|
|
18
|
+
daily_times: string[] | null;
|
|
19
|
+
// JSON type from database
|
|
20
|
+
day_availability: unknown;
|
|
21
|
+
is_daily_availability: boolean | null;
|
|
22
|
+
zone_id: string | null;
|
|
23
|
+
resource_id: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface Resource {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
max_capacity: number;
|
|
30
|
+
instances: number;
|
|
31
|
+
zone_id: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Flow {
|
|
35
|
+
id: string;
|
|
36
|
+
type: 'booking' | 'enquiry';
|
|
37
|
+
reference_number: string;
|
|
38
|
+
customer_name: string;
|
|
39
|
+
activity_name: string;
|
|
40
|
+
booking_date: string;
|
|
41
|
+
booking_time_start: string;
|
|
42
|
+
booking_time_end: string | null;
|
|
43
|
+
status: string;
|
|
44
|
+
total_amount: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface OpeningHour {
|
|
48
|
+
day_of_week: number;
|
|
49
|
+
is_open: boolean;
|
|
50
|
+
open_time: string;
|
|
51
|
+
close_time: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface SessionSlot {
|
|
55
|
+
productId: string;
|
|
56
|
+
productName: string;
|
|
57
|
+
startTime: string;
|
|
58
|
+
endTime: string;
|
|
59
|
+
capacity: number;
|
|
60
|
+
bookedCount: number;
|
|
61
|
+
bookings: Flow[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type SessionStatus = 'upcoming' | 'in_progress' | 'finished';
|
|
65
|
+
|
|
66
|
+
// Get session status based on current time
|
|
67
|
+
const getSessionStatus = (startTime: string, endTime: string, targetDate: Date): SessionStatus => {
|
|
68
|
+
const now = new Date();
|
|
69
|
+
const today = new Date();
|
|
70
|
+
today.setHours(0, 0, 0, 0);
|
|
71
|
+
|
|
72
|
+
const targetDay = new Date(targetDate);
|
|
73
|
+
targetDay.setHours(0, 0, 0, 0);
|
|
74
|
+
|
|
75
|
+
// If target date is in the past, session is finished
|
|
76
|
+
if (targetDay < today) {
|
|
77
|
+
return 'finished';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// If target date is in the future, session is upcoming
|
|
81
|
+
if (targetDay > today) {
|
|
82
|
+
return 'upcoming';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Target date is today - check times
|
|
86
|
+
const currentMinutes = now.getHours() * 60 + now.getMinutes();
|
|
87
|
+
const startMinutes = parseTimeToMinutes(startTime);
|
|
88
|
+
const endMinutes = parseTimeToMinutes(endTime);
|
|
89
|
+
|
|
90
|
+
if (currentMinutes >= endMinutes) {
|
|
91
|
+
return 'finished';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (currentMinutes >= startMinutes) {
|
|
95
|
+
return 'in_progress';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return 'upcoming';
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
interface ScheduleViewProps {
|
|
102
|
+
providerId: string;
|
|
103
|
+
onSessionClick?: (session: SessionSlot, dateDisplay: string, dateFormatted: string) => void;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Parse time string to minutes from midnight
|
|
107
|
+
const parseTimeToMinutes = (timeStr: string): number => {
|
|
108
|
+
const [hour, minute] = timeStr.split(':').map(Number);
|
|
109
|
+
return hour * 60 + minute;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Format minutes to time string
|
|
113
|
+
const formatMinutesToTime = (minutes: number): string => {
|
|
114
|
+
const hour = Math.floor(minutes / 60) % 24;
|
|
115
|
+
const min = minutes % 60;
|
|
116
|
+
return `${hour.toString().padStart(2, '0')}:${min.toString().padStart(2, '0')}`;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const ScheduleView: React.FC<ScheduleViewProps> = ({ providerId, onSessionClick }) => {
|
|
120
|
+
const { provider } = useProvider();
|
|
121
|
+
const { showError } = useNotify();
|
|
122
|
+
const [products, setProducts] = useState<Product[]>([]);
|
|
123
|
+
const [resources, setResources] = useState<Resource[]>([]);
|
|
124
|
+
const [flows, setFlows] = useState<Flow[]>([]);
|
|
125
|
+
const [openingHours, setOpeningHours] = useState<OpeningHour[]>([]);
|
|
126
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
127
|
+
const [dayOffset, setDayOffset] = useState(0);
|
|
128
|
+
|
|
129
|
+
// Calculate target date
|
|
130
|
+
const targetDate = addDays(new Date(), dayOffset);
|
|
131
|
+
const formattedDate = format(targetDate, 'yyyy-MM-dd');
|
|
132
|
+
const displayDate = format(targetDate, 'EEEE, d MMMM yyyy');
|
|
133
|
+
const dayOfWeek = getDay(targetDate);
|
|
134
|
+
|
|
135
|
+
// Get opening hours for this day
|
|
136
|
+
const todaysHours = openingHours.find((h) => h.day_of_week === dayOfWeek);
|
|
137
|
+
const isOpen = todaysHours?.is_open ?? false;
|
|
138
|
+
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
fetchData();
|
|
141
|
+
}, [providerId, formattedDate]);
|
|
142
|
+
|
|
143
|
+
const fetchData = async () => {
|
|
144
|
+
setIsLoading(true);
|
|
145
|
+
try {
|
|
146
|
+
// Fetch opening hours
|
|
147
|
+
const { data: hoursData, error: hoursError } = await supabase
|
|
148
|
+
.from('provider_opening_hours')
|
|
149
|
+
.select('*')
|
|
150
|
+
.eq('provider_id', providerId);
|
|
151
|
+
|
|
152
|
+
if (hoursError) throw hoursError;
|
|
153
|
+
setOpeningHours(hoursData || []);
|
|
154
|
+
|
|
155
|
+
// Fetch products (activities) for this provider with fixed session availability
|
|
156
|
+
const { data: productsData, error: productsError } = await supabase
|
|
157
|
+
.from('products')
|
|
158
|
+
.select('*')
|
|
159
|
+
.eq('provider_id', providerId)
|
|
160
|
+
.eq('status', 'active')
|
|
161
|
+
.eq('type', 'activity');
|
|
162
|
+
|
|
163
|
+
if (productsError) throw productsError;
|
|
164
|
+
setProducts(productsData || []);
|
|
165
|
+
|
|
166
|
+
// Fetch zones for this provider to get resources
|
|
167
|
+
const { data: zonesData, error: zonesError } = await supabase
|
|
168
|
+
.from('zones')
|
|
169
|
+
.select('id')
|
|
170
|
+
.eq('provider_id', providerId)
|
|
171
|
+
.eq('status', 'active');
|
|
172
|
+
|
|
173
|
+
if (zonesError) throw zonesError;
|
|
174
|
+
|
|
175
|
+
// Fetch resources for all zones
|
|
176
|
+
if (zonesData && zonesData.length > 0) {
|
|
177
|
+
const zoneIds = zonesData.map(z => z.id);
|
|
178
|
+
const { data: resourcesData, error: resourcesError } = await supabase
|
|
179
|
+
.from('resources')
|
|
180
|
+
.select('id, name, max_capacity, instances, zone_id')
|
|
181
|
+
.in('zone_id', zoneIds);
|
|
182
|
+
|
|
183
|
+
if (resourcesError) throw resourcesError;
|
|
184
|
+
setResources(resourcesData || []);
|
|
185
|
+
} else {
|
|
186
|
+
setResources([]);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Fetch flows for the selected date
|
|
190
|
+
const { data: flowsData, error: flowsError } = await supabase
|
|
191
|
+
.from('bookings')
|
|
192
|
+
.select('*')
|
|
193
|
+
.eq('provider_id', providerId)
|
|
194
|
+
.eq('booking_date', formattedDate)
|
|
195
|
+
.order('booking_time_start');
|
|
196
|
+
|
|
197
|
+
if (flowsError) throw flowsError;
|
|
198
|
+
setFlows(flowsData || []);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('Error fetching schedule data:', error);
|
|
201
|
+
showError('Failed to load schedule data');
|
|
202
|
+
} finally {
|
|
203
|
+
setIsLoading(false);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Build sessions from products
|
|
208
|
+
const sessions = useMemo(() => {
|
|
209
|
+
const sessionList: SessionSlot[] = [];
|
|
210
|
+
|
|
211
|
+
products.forEach((product) => {
|
|
212
|
+
// Check if product has daily times
|
|
213
|
+
if (!product.daily_times || product.daily_times.length === 0) return;
|
|
214
|
+
|
|
215
|
+
// Check if product is available on this day of week
|
|
216
|
+
if (!product.is_daily_availability && product.day_availability) {
|
|
217
|
+
const dayAvailability = product.day_availability as { day: number; enabled: boolean }[];
|
|
218
|
+
if (Array.isArray(dayAvailability)) {
|
|
219
|
+
const dayConfig = dayAvailability.find((d) => d.day === dayOfWeek);
|
|
220
|
+
if (!dayConfig?.enabled) return;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Get capacity from linked resource (instances × max_capacity), fallback to product capacity
|
|
225
|
+
let sessionCapacity = product.capacity || 0;
|
|
226
|
+
if (product.resource_id) {
|
|
227
|
+
const linkedResource = resources.find(r => r.id === product.resource_id);
|
|
228
|
+
if (linkedResource) {
|
|
229
|
+
// Total capacity = number of instances × capacity per instance
|
|
230
|
+
sessionCapacity = linkedResource.instances * linkedResource.max_capacity;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Create a session for each daily time
|
|
235
|
+
product.daily_times.forEach((startTime) => {
|
|
236
|
+
const startMinutes = parseTimeToMinutes(startTime);
|
|
237
|
+
const durationMinutes = product.duration || 60;
|
|
238
|
+
const endMinutes = startMinutes + durationMinutes;
|
|
239
|
+
const endTime = formatMinutesToTime(endMinutes);
|
|
240
|
+
|
|
241
|
+
// Count bookings for this session
|
|
242
|
+
const sessionBookings = flows.filter((flow) => {
|
|
243
|
+
const flowStart = flow.booking_time_start.slice(0, 5);
|
|
244
|
+
return (
|
|
245
|
+
flow.activity_name === product.name &&
|
|
246
|
+
flowStart === startTime &&
|
|
247
|
+
flow.status === 'active'
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
sessionList.push({
|
|
252
|
+
productId: product.id,
|
|
253
|
+
productName: product.name,
|
|
254
|
+
startTime,
|
|
255
|
+
endTime,
|
|
256
|
+
capacity: sessionCapacity,
|
|
257
|
+
bookedCount: sessionBookings.length,
|
|
258
|
+
bookings: sessionBookings,
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Sort by start time
|
|
264
|
+
sessionList.sort((a, b) => {
|
|
265
|
+
const aMinutes = parseTimeToMinutes(a.startTime);
|
|
266
|
+
const bMinutes = parseTimeToMinutes(b.startTime);
|
|
267
|
+
return aMinutes - bMinutes;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
return sessionList;
|
|
271
|
+
}, [products, flows, resources, dayOfWeek]);
|
|
272
|
+
|
|
273
|
+
// Day pagination handlers
|
|
274
|
+
const handlePrevDay = () => setDayOffset((prev) => prev - 1);
|
|
275
|
+
const handleNextDay = () => setDayOffset((prev) => prev + 1);
|
|
276
|
+
|
|
277
|
+
// Get capacity badge color
|
|
278
|
+
const getCapacityColor = (booked: number, total: number) => {
|
|
279
|
+
if (total === 0) return 'bg-surface-secondary text-label-tertiary border-border-primary';
|
|
280
|
+
const percentage = (booked / total) * 100;
|
|
281
|
+
if (percentage >= 100) return 'bg-surface-status-error text-label-status-error border-border-status-error';
|
|
282
|
+
if (percentage >= 80) return 'bg-surface-status-warning text-label-status-warning border-border-status-warning';
|
|
283
|
+
if (percentage >= 50) return 'bg-surface-status-info text-label-status-info border-border-status-info';
|
|
284
|
+
return 'bg-surface-status-success text-label-status-success border-border-status-success';
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
if (isLoading) {
|
|
288
|
+
return (
|
|
289
|
+
<div className="flex items-center justify-center py-12">
|
|
290
|
+
<LoadingSpinner size="sm" />
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<div className="flex flex-col gap-4 w-full min-w-0">
|
|
297
|
+
{/* Header with Date and Day Pagination */}
|
|
298
|
+
<div className="flex items-center justify-between">
|
|
299
|
+
<div className="flex flex-col gap-1">
|
|
300
|
+
<div className="text-label-primary text-lg font-semibold">{displayDate}</div>
|
|
301
|
+
{!isOpen && (
|
|
302
|
+
<span className="text-label-status-error text-sm">Closed</span>
|
|
303
|
+
)}
|
|
304
|
+
</div>
|
|
305
|
+
{/* Day Pagination Controls */}
|
|
306
|
+
<div className="flex items-center gap-2">
|
|
307
|
+
<Button
|
|
308
|
+
variant="ghost"
|
|
309
|
+
size="icon"
|
|
310
|
+
onClick={handlePrevDay}
|
|
311
|
+
className="h-8 w-8 rounded-full bg-surface-action-soft hover:bg-surface-action-soft-hover text-fill-action"
|
|
312
|
+
>
|
|
313
|
+
<IconArrowLeft className="h-4 w-4" />
|
|
314
|
+
</Button>
|
|
315
|
+
<Button
|
|
316
|
+
variant="ghost"
|
|
317
|
+
size="icon"
|
|
318
|
+
onClick={handleNextDay}
|
|
319
|
+
className="h-8 w-8 rounded-full bg-surface-action-soft hover:bg-surface-action-soft-hover text-fill-action"
|
|
320
|
+
>
|
|
321
|
+
<IconArrowRight className="h-4 w-4" />
|
|
322
|
+
</Button>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
{/* Opening & Closing Times */}
|
|
327
|
+
{isOpen && todaysHours && (
|
|
328
|
+
<div className="flex items-center gap-2 text-sm text-label-tertiary">
|
|
329
|
+
<span>Opens: {todaysHours.open_time.slice(0, 5)}</span>
|
|
330
|
+
<span>•</span>
|
|
331
|
+
<span>Closes: {todaysHours.close_time.slice(0, 5)}</span>
|
|
332
|
+
</div>
|
|
333
|
+
)}
|
|
334
|
+
|
|
335
|
+
{/* Sessions List */}
|
|
336
|
+
<div className="flex flex-col gap-2">
|
|
337
|
+
{sessions.length === 0 ? (
|
|
338
|
+
<div className="text-center py-12 text-label-tertiary">
|
|
339
|
+
<p className="text-lg font-medium mb-2">No sessions scheduled</p>
|
|
340
|
+
<p className="text-sm">
|
|
341
|
+
Add activities with fixed session times to see them here.
|
|
342
|
+
</p>
|
|
343
|
+
</div>
|
|
344
|
+
) : (
|
|
345
|
+
sessions.map((session, index) => {
|
|
346
|
+
const status = getSessionStatus(session.startTime, session.endTime, targetDate);
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<button
|
|
350
|
+
key={`${session.productId}-${session.startTime}-${index}`}
|
|
351
|
+
onClick={() => onSessionClick?.(session, displayDate, formattedDate)}
|
|
352
|
+
className={cn(
|
|
353
|
+
'flex items-center justify-between p-4 rounded-lg border border-border-primary',
|
|
354
|
+
'hover:bg-surface-secondary transition-colors text-left w-full',
|
|
355
|
+
'focus:outline-none focus:ring-2 focus:ring-fill-highlight focus:ring-offset-2',
|
|
356
|
+
status === 'finished' ? 'bg-surface-secondary opacity-60' : 'bg-surface-primary'
|
|
357
|
+
)}
|
|
358
|
+
>
|
|
359
|
+
<div className="flex flex-col gap-1">
|
|
360
|
+
<div className="flex items-center gap-2">
|
|
361
|
+
<span className={cn(
|
|
362
|
+
"text-label-primary font-medium text-base",
|
|
363
|
+
status === 'finished' && "text-label-tertiary"
|
|
364
|
+
)}>
|
|
365
|
+
{session.productName}
|
|
366
|
+
</span>
|
|
367
|
+
{status === 'in_progress' && (
|
|
368
|
+
<Badge className="bg-surface-status-success text-label-status-success border-border-status-success text-xs px-2 py-0.5">
|
|
369
|
+
In Progress
|
|
370
|
+
</Badge>
|
|
371
|
+
)}
|
|
372
|
+
{status === 'finished' && (
|
|
373
|
+
<Badge className="bg-surface-secondary text-label-tertiary border-border-primary text-xs px-2 py-0.5">
|
|
374
|
+
Finished
|
|
375
|
+
</Badge>
|
|
376
|
+
)}
|
|
377
|
+
</div>
|
|
378
|
+
<span className={cn(
|
|
379
|
+
"text-label-tertiary text-sm",
|
|
380
|
+
status === 'finished' && "text-label-quaternary"
|
|
381
|
+
)}>
|
|
382
|
+
{session.startTime} - {session.endTime}
|
|
383
|
+
</span>
|
|
384
|
+
</div>
|
|
385
|
+
<div className="flex items-center gap-3">
|
|
386
|
+
<Badge
|
|
387
|
+
className={cn(
|
|
388
|
+
'text-sm font-medium px-3 py-1',
|
|
389
|
+
status === 'finished'
|
|
390
|
+
? 'bg-surface-secondary text-label-tertiary border-border-primary'
|
|
391
|
+
: getCapacityColor(session.bookedCount, session.capacity)
|
|
392
|
+
)}
|
|
393
|
+
>
|
|
394
|
+
{session.bookedCount}/{session.capacity} spaces
|
|
395
|
+
</Badge>
|
|
396
|
+
<IconChevronRight className={cn(
|
|
397
|
+
"h-5 w-5",
|
|
398
|
+
status === 'finished' ? "text-label-quaternary" : "text-label-tertiary"
|
|
399
|
+
)} />
|
|
400
|
+
</div>
|
|
401
|
+
</button>
|
|
402
|
+
);
|
|
403
|
+
})
|
|
404
|
+
)}
|
|
405
|
+
</div>
|
|
406
|
+
</div>
|
|
407
|
+
);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
export default ScheduleView;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useLocation } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
const ScrollToTop = () => {
|
|
5
|
+
const { pathname } = useLocation();
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
window.scrollTo(0, 0);
|
|
9
|
+
}, [pathname]);
|
|
10
|
+
|
|
11
|
+
return null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default ScrollToTop;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { NavLink } from 'react-router-dom';
|
|
3
|
+
import { cn } from '../lib/utils';
|
|
4
|
+
import { useUser } from '@/contexts/UserContext';
|
|
5
|
+
|
|
6
|
+
export interface SecondaryNavItem {
|
|
7
|
+
label: string;
|
|
8
|
+
to: string;
|
|
9
|
+
roles?: string[]; // Optional: only show to users with these roles
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SecondaryNavProps {
|
|
13
|
+
items: SecondaryNavItem[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SecondaryNav: React.FC<SecondaryNavProps> = ({ items }) => {
|
|
17
|
+
const { primaryRole } = useUser();
|
|
18
|
+
|
|
19
|
+
// Filter items based on user role
|
|
20
|
+
const visibleItems = items.filter(item => {
|
|
21
|
+
if (!item.roles || item.roles.length === 0) {
|
|
22
|
+
return true; // Show items without role restrictions
|
|
23
|
+
}
|
|
24
|
+
// Check if user has any of the required roles
|
|
25
|
+
return primaryRole && item.roles.includes(primaryRole);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<nav className="flex items-start gap-6 self-stretch pt-2 pb-0 pl-2 max-sm:pt-2 max-sm:pb-0">
|
|
30
|
+
{visibleItems.map((item) => (
|
|
31
|
+
<NavLink
|
|
32
|
+
key={item.to}
|
|
33
|
+
to={item.to}
|
|
34
|
+
end
|
|
35
|
+
className={({ isActive }) => cn(
|
|
36
|
+
"flex flex-col items-center gap-4 relative group",
|
|
37
|
+
isActive && "[&>span]:text-label-primary [&>div]:bg-fill-primary [&>div]:w-full"
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
<span className="text-label-secondary text-[15px] font-semibold leading-[18px] group-hover:text-label-action transition-colors">
|
|
41
|
+
{item.label}
|
|
42
|
+
</span>
|
|
43
|
+
<div className="w-px h-0.5 self-center bg-transparent rounded-[3px] group-hover:bg-fill-action group-hover:w-1/2 transition-all" />
|
|
44
|
+
</NavLink>
|
|
45
|
+
))}
|
|
46
|
+
</nav>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default SecondaryNav;
|