@licklist/design 0.78.5-dev.107 → 0.78.5-dev.108

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.
Files changed (414) hide show
  1. package/bitbucket-pipelines.yml +4 -13
  2. package/dist/Maintenance/Maintenance.scss.js +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/product-set/form/ProductsControl.d.ts +1 -2
  5. package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
  6. package/dist/product-set/form/ProductsControl.js +24 -0
  7. package/dist/v2/components/ActionMenu/ActionMenu.scss.js +1 -1
  8. package/dist/v2/components/Badge/Badge.scss.js +1 -1
  9. package/dist/v2/components/Button/Button.scss.js +1 -1
  10. package/dist/v2/components/Button/GhostButton.scss.js +1 -1
  11. package/dist/v2/components/Checkbox/Checkbox.scss.js +1 -1
  12. package/dist/v2/components/DataTable/DataTable.d.ts.map +1 -1
  13. package/dist/v2/components/DataTable/DataTable.js +2 -86
  14. package/dist/v2/components/IconButton/IconButton.scss.js +1 -1
  15. package/dist/v2/components/Modal/DeleteModal.d.ts.map +1 -1
  16. package/dist/v2/components/Modal/DeleteModal.js +11 -13
  17. package/dist/v2/components/Modal/DeleteModal.scss.js +1 -1
  18. package/dist/v2/components/NPSScore/NPSScore.scss.js +1 -1
  19. package/dist/v2/components/NewTabs/NewTabs.scss.js +1 -1
  20. package/dist/v2/components/PeriodCard/PeriodCard.d.ts +66 -0
  21. package/dist/v2/components/PeriodCard/PeriodCard.d.ts.map +1 -0
  22. package/dist/v2/components/PeriodCard/PeriodCard.js +351 -0
  23. package/dist/v2/components/PeriodCard/PeriodCard.scss.js +6 -0
  24. package/dist/v2/components/PeriodCard/index.d.ts +3 -0
  25. package/dist/v2/components/PeriodCard/index.d.ts.map +1 -0
  26. package/dist/v2/components/ReorderRow/ReorderRow.d.ts +24 -0
  27. package/dist/v2/components/ReorderRow/ReorderRow.d.ts.map +1 -0
  28. package/dist/v2/components/ReorderRow/ReorderRow.js +109 -0
  29. package/dist/v2/components/ReorderRow/ReorderRow.scss.js +6 -0
  30. package/dist/v2/components/ReorderRow/index.d.ts +3 -0
  31. package/dist/v2/components/ReorderRow/index.d.ts.map +1 -0
  32. package/dist/v2/components/Select/Select.scss.js +1 -1
  33. package/dist/v2/components/StatusBadge/StatusBadge.scss.js +1 -1
  34. package/dist/v2/components/StepIndicator/StepIndicator.scss.js +1 -1
  35. package/dist/v2/components/Tabs/Tabs.scss.js +1 -1
  36. package/dist/v2/components/Toggle/Toggle.d.ts.map +1 -1
  37. package/dist/v2/components/Toggle/Toggle.js +5 -8
  38. package/dist/v2/components/Tooltip/Tooltip.scss.js +1 -1
  39. package/dist/v2/components/UserAvatar/UserAvatar.scss.js +1 -1
  40. package/dist/v2/components/UserPanel/UserPanel.scss.js +1 -1
  41. package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss.js +1 -1
  42. package/dist/v2/components/ZoneCard/ZoneCard.scss.js +1 -1
  43. package/dist/v2/components/index.d.ts +4 -0
  44. package/dist/v2/components/index.d.ts.map +1 -1
  45. package/dist/v2/dashboard-analytics/chart/Chart.scss.js +1 -1
  46. package/dist/v2/dashboard-analytics/metric-card/MetricCard.scss.js +1 -1
  47. package/dist/v2/dashboard-analytics/venue-card/VenueCard.scss.js +1 -1
  48. package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.scss.js +1 -1
  49. package/dist/v2/icons/index.js +16 -1
  50. package/dist/v2/index.d.ts +8 -0
  51. package/dist/v2/index.d.ts.map +1 -1
  52. package/dist/v2/navigation/DashboardLayout/AdminSidebar.scss.js +1 -1
  53. package/dist/v2/navigation/DashboardLayout/DashboardLayout.scss.js +1 -1
  54. package/dist/v2/navigation/DashboardLayout/ProviderSidebar.scss.js +1 -1
  55. package/dist/v2/navigation/DashboardLayout/TopNavigation.scss.js +1 -1
  56. package/dist/v2/pages/Settings/SettingsTabs.scss.js +1 -1
  57. package/dist/v2/pages/Settings/components/SidebarCustomisation.js +5 -0
  58. package/dist/v2/pages/Settings/components/SidebarCustomisation.scss.js +1 -1
  59. package/dist/v2/pages/Settings/components/SidebarNavItem.js +5 -0
  60. package/dist/v2/pages/auth/AuthLayout/AuthLayout.scss.js +1 -1
  61. package/dist/v2/shadcn/components/ui/accordion.d.ts +8 -0
  62. package/dist/v2/shadcn/components/ui/accordion.d.ts.map +1 -0
  63. package/dist/v2/shadcn/components/ui/alert-dialog.d.ts +21 -0
  64. package/dist/v2/shadcn/components/ui/alert-dialog.d.ts.map +1 -0
  65. package/dist/v2/shadcn/components/ui/alert.d.ts +9 -0
  66. package/dist/v2/shadcn/components/ui/alert.d.ts.map +1 -0
  67. package/dist/v2/shadcn/components/ui/aspect-ratio.d.ts +4 -0
  68. package/dist/v2/shadcn/components/ui/aspect-ratio.d.ts.map +1 -0
  69. package/dist/v2/shadcn/components/ui/avatar.d.ts +7 -0
  70. package/dist/v2/shadcn/components/ui/avatar.d.ts.map +1 -0
  71. package/dist/v2/shadcn/components/ui/badge.d.ts +10 -0
  72. package/dist/v2/shadcn/components/ui/badge.d.ts.map +1 -0
  73. package/dist/v2/shadcn/components/ui/breadcrumb.d.ts +20 -0
  74. package/dist/v2/shadcn/components/ui/breadcrumb.d.ts.map +1 -0
  75. package/dist/v2/shadcn/components/ui/button.d.ts +14 -0
  76. package/dist/v2/shadcn/components/ui/button.d.ts.map +1 -0
  77. package/dist/v2/shadcn/components/ui/calendar.d.ts +9 -0
  78. package/dist/v2/shadcn/components/ui/calendar.d.ts.map +1 -0
  79. package/dist/v2/shadcn/components/ui/card.d.ts +9 -0
  80. package/dist/v2/shadcn/components/ui/card.d.ts.map +1 -0
  81. package/dist/v2/shadcn/components/ui/carousel.d.ts +19 -0
  82. package/dist/v2/shadcn/components/ui/carousel.d.ts.map +1 -0
  83. package/dist/v2/shadcn/components/ui/checkbox.d.ts +6 -0
  84. package/dist/v2/shadcn/components/ui/checkbox.d.ts.map +1 -0
  85. package/dist/v2/shadcn/components/ui/checkbox.js +115 -0
  86. package/dist/v2/shadcn/components/ui/checkbox.scss.js +6 -0
  87. package/dist/v2/shadcn/components/ui/collapsible.d.ts +6 -0
  88. package/dist/v2/shadcn/components/ui/collapsible.d.ts.map +1 -0
  89. package/dist/v2/shadcn/components/ui/command.d.ts +83 -0
  90. package/dist/v2/shadcn/components/ui/command.d.ts.map +1 -0
  91. package/dist/v2/shadcn/components/ui/context-menu.d.ts +28 -0
  92. package/dist/v2/shadcn/components/ui/context-menu.d.ts.map +1 -0
  93. package/dist/v2/shadcn/components/ui/dialog.d.ts +20 -0
  94. package/dist/v2/shadcn/components/ui/dialog.d.ts.map +1 -0
  95. package/dist/v2/shadcn/components/ui/dialog.js +169 -0
  96. package/dist/v2/shadcn/components/ui/drawer.d.ts +23 -0
  97. package/dist/v2/shadcn/components/ui/drawer.d.ts.map +1 -0
  98. package/dist/v2/shadcn/components/ui/dropdown-menu.d.ts +28 -0
  99. package/dist/v2/shadcn/components/ui/dropdown-menu.d.ts.map +1 -0
  100. package/dist/v2/shadcn/components/ui/form.d.ts +24 -0
  101. package/dist/v2/shadcn/components/ui/form.d.ts.map +1 -0
  102. package/dist/v2/shadcn/components/ui/hover-card.d.ts +7 -0
  103. package/dist/v2/shadcn/components/ui/hover-card.d.ts.map +1 -0
  104. package/dist/v2/shadcn/components/ui/input-otp.d.ts +35 -0
  105. package/dist/v2/shadcn/components/ui/input-otp.d.ts.map +1 -0
  106. package/dist/v2/shadcn/components/ui/input.d.ts +6 -0
  107. package/dist/v2/shadcn/components/ui/input.d.ts.map +1 -0
  108. package/dist/v2/shadcn/components/ui/label.d.ts +6 -0
  109. package/dist/v2/shadcn/components/ui/label.d.ts.map +1 -0
  110. package/dist/v2/shadcn/components/ui/menubar.d.ts +34 -0
  111. package/dist/v2/shadcn/components/ui/menubar.d.ts.map +1 -0
  112. package/dist/v2/shadcn/components/ui/navigation-menu.d.ts +13 -0
  113. package/dist/v2/shadcn/components/ui/navigation-menu.d.ts.map +1 -0
  114. package/dist/v2/shadcn/components/ui/pagination.d.ts +29 -0
  115. package/dist/v2/shadcn/components/ui/pagination.d.ts.map +1 -0
  116. package/dist/v2/shadcn/components/ui/popover.d.ts +7 -0
  117. package/dist/v2/shadcn/components/ui/popover.d.ts.map +1 -0
  118. package/dist/v2/shadcn/components/ui/progress.d.ts +5 -0
  119. package/dist/v2/shadcn/components/ui/progress.d.ts.map +1 -0
  120. package/dist/v2/shadcn/components/ui/radio-card.d.ts +12 -0
  121. package/dist/v2/shadcn/components/ui/radio-card.d.ts.map +1 -0
  122. package/dist/v2/shadcn/components/ui/radio-group.d.ts +6 -0
  123. package/dist/v2/shadcn/components/ui/radio-group.d.ts.map +1 -0
  124. package/dist/v2/shadcn/components/ui/scroll-area.d.ts +6 -0
  125. package/dist/v2/shadcn/components/ui/scroll-area.d.ts.map +1 -0
  126. package/dist/v2/shadcn/components/ui/select.d.ts +14 -0
  127. package/dist/v2/shadcn/components/ui/select.d.ts.map +1 -0
  128. package/dist/v2/shadcn/components/ui/separator.d.ts +5 -0
  129. package/dist/v2/shadcn/components/ui/separator.d.ts.map +1 -0
  130. package/dist/v2/shadcn/components/ui/sheet.d.ts +26 -0
  131. package/dist/v2/shadcn/components/ui/sheet.d.ts.map +1 -0
  132. package/dist/v2/shadcn/components/ui/sidebar.d.ts +67 -0
  133. package/dist/v2/shadcn/components/ui/sidebar.d.ts.map +1 -0
  134. package/dist/v2/shadcn/components/ui/skeleton.d.ts +3 -0
  135. package/dist/v2/shadcn/components/ui/skeleton.d.ts.map +1 -0
  136. package/dist/v2/shadcn/components/ui/slider.d.ts +5 -0
  137. package/dist/v2/shadcn/components/ui/slider.d.ts.map +1 -0
  138. package/dist/v2/shadcn/components/ui/switch.d.ts +6 -0
  139. package/dist/v2/shadcn/components/ui/switch.d.ts.map +1 -0
  140. package/dist/v2/shadcn/components/ui/switch.js +115 -0
  141. package/dist/v2/shadcn/components/ui/switch.scss.js +6 -0
  142. package/dist/v2/shadcn/components/ui/table-pagination.d.ts +11 -0
  143. package/dist/v2/shadcn/components/ui/table-pagination.d.ts.map +1 -0
  144. package/dist/v2/shadcn/components/ui/table.d.ts +11 -0
  145. package/dist/v2/shadcn/components/ui/table.d.ts.map +1 -0
  146. package/dist/v2/shadcn/components/ui/tabs.d.ts +8 -0
  147. package/dist/v2/shadcn/components/ui/tabs.d.ts.map +1 -0
  148. package/dist/v2/shadcn/components/ui/textarea.d.ts +6 -0
  149. package/dist/v2/shadcn/components/ui/textarea.d.ts.map +1 -0
  150. package/dist/v2/shadcn/components/ui/toast.d.ts +16 -0
  151. package/dist/v2/shadcn/components/ui/toast.d.ts.map +1 -0
  152. package/dist/v2/shadcn/components/ui/toaster.d.ts +2 -0
  153. package/dist/v2/shadcn/components/ui/toaster.d.ts.map +1 -0
  154. package/dist/v2/shadcn/components/ui/toggle-group.d.ts +13 -0
  155. package/dist/v2/shadcn/components/ui/toggle-group.d.ts.map +1 -0
  156. package/dist/v2/shadcn/components/ui/toggle.d.ts +13 -0
  157. package/dist/v2/shadcn/components/ui/toggle.d.ts.map +1 -0
  158. package/dist/v2/shadcn/components/ui/tooltip.d.ts +8 -0
  159. package/dist/v2/shadcn/components/ui/tooltip.d.ts.map +1 -0
  160. package/dist/v2/shadcn/components/ui/use-toast.d.ts +3 -0
  161. package/dist/v2/shadcn/components/ui/use-toast.d.ts.map +1 -0
  162. package/dist/v2/shadcn/hooks/use-mobile.d.ts +2 -0
  163. package/dist/v2/shadcn/hooks/use-mobile.d.ts.map +1 -0
  164. package/dist/v2/shadcn/hooks/use-toast.d.ts +45 -0
  165. package/dist/v2/shadcn/hooks/use-toast.d.ts.map +1 -0
  166. package/dist/v2/shadcn/index.d.ts +20 -0
  167. package/dist/v2/shadcn/index.d.ts.map +1 -0
  168. package/dist/v2/shadcn/lib/utils.d.ts +3 -0
  169. package/dist/v2/shadcn/lib/utils.d.ts.map +1 -0
  170. package/dist/v2/shadcn/lib/utils.js +11 -0
  171. package/dist/v2/shadcn/styles/globals.css +112 -0
  172. package/dist/v2/styles/form/NewInput.scss.js +1 -1
  173. package/package.json +6 -6
  174. package/rollup.config.js +2 -16
  175. package/src/iframe/payment/payment-status-page/PaymentStatusPage.tsx +1 -1
  176. package/src/product-set/form/ProductsControl.tsx +1 -2
  177. package/src/v2/components/DataTable/DataTable.tsx +1 -23
  178. package/src/v2/components/Modal/DeleteModal.tsx +20 -12
  179. package/src/v2/components/PeriodCard/PeriodCard.scss +157 -0
  180. package/src/v2/components/PeriodCard/PeriodCard.stories.tsx +245 -0
  181. package/src/v2/components/PeriodCard/PeriodCard.tsx +350 -0
  182. package/src/v2/components/PeriodCard/index.ts +8 -0
  183. package/src/v2/components/ReorderRow/ReorderRow.scss +68 -0
  184. package/src/v2/components/ReorderRow/ReorderRow.stories.tsx +124 -0
  185. package/src/v2/components/ReorderRow/ReorderRow.tsx +88 -0
  186. package/src/v2/components/ReorderRow/index.ts +2 -0
  187. package/src/v2/components/Toggle/Toggle.tsx +5 -6
  188. package/src/v2/components/index.ts +6 -0
  189. package/src/v2/index.ts +82 -0
  190. package/src/v2/shadcn/_reference/AccountManagerCard.tsx +45 -0
  191. package/src/v2/shadcn/_reference/AffiliatesTable.tsx +178 -0
  192. package/src/v2/shadcn/_reference/AuditArchive.tsx +165 -0
  193. package/src/v2/shadcn/_reference/AuditContent.tsx +270 -0
  194. package/src/v2/shadcn/_reference/AutomationsGeneralSettings.tsx +251 -0
  195. package/src/v2/shadcn/_reference/AvatarUpload.tsx +150 -0
  196. package/src/v2/shadcn/_reference/BookingsSummaryCard.tsx +268 -0
  197. package/src/v2/shadcn/_reference/CodeCleanUpAudit.tsx +274 -0
  198. package/src/v2/shadcn/_reference/CompaniesTable.tsx +387 -0
  199. package/src/v2/shadcn/_reference/ComponentAudit.tsx +239 -0
  200. package/src/v2/shadcn/_reference/ConfigureSettingsCard.tsx +95 -0
  201. package/src/v2/shadcn/_reference/CustomerCard.tsx +155 -0
  202. package/src/v2/shadcn/_reference/DashboardCards.tsx +50 -0
  203. package/src/v2/shadcn/_reference/DashboardFooter.tsx +18 -0
  204. package/src/v2/shadcn/_reference/DiarySettings.tsx +187 -0
  205. package/src/v2/shadcn/_reference/DiaryView.tsx +998 -0
  206. package/src/v2/shadcn/_reference/EmptyState.tsx +76 -0
  207. package/src/v2/shadcn/_reference/EntityInfoCard.tsx +48 -0
  208. package/src/v2/shadcn/_reference/ExistingUserAssignments.tsx +131 -0
  209. package/src/v2/shadcn/_reference/FeatureToggle.tsx +72 -0
  210. package/src/v2/shadcn/_reference/FlowCard.tsx +170 -0
  211. package/src/v2/shadcn/_reference/FlowsContent.tsx +688 -0
  212. package/src/v2/shadcn/_reference/FlowsGeneralSettings.tsx +27 -0
  213. package/src/v2/shadcn/_reference/GeneralSettings.tsx +33 -0
  214. package/src/v2/shadcn/_reference/InventoryGeneralSettings.tsx +82 -0
  215. package/src/v2/shadcn/_reference/LanguageSelector.tsx +97 -0
  216. package/src/v2/shadcn/_reference/LoadingScreen.tsx +25 -0
  217. package/src/v2/shadcn/_reference/LoadingSpinner.tsx +41 -0
  218. package/src/v2/shadcn/_reference/ManagedClientsList.tsx +121 -0
  219. package/src/v2/shadcn/_reference/NPSScore.tsx +379 -0
  220. package/src/v2/shadcn/_reference/NPSSummaryCard.tsx +181 -0
  221. package/src/v2/shadcn/_reference/NotificationBanner.tsx +129 -0
  222. package/src/v2/shadcn/_reference/NotificationPanel.tsx +208 -0
  223. package/src/v2/shadcn/_reference/OnlineUsersCard.tsx +73 -0
  224. package/src/v2/shadcn/_reference/ProtectedRoute.tsx +39 -0
  225. package/src/v2/shadcn/_reference/ProvidersTable.tsx +353 -0
  226. package/src/v2/shadcn/_reference/QuickAddPanel.tsx +1057 -0
  227. package/src/v2/shadcn/_reference/QuickFilters.tsx +112 -0
  228. package/src/v2/shadcn/_reference/ScheduleView.tsx +410 -0
  229. package/src/v2/shadcn/_reference/ScrollToTop.tsx +14 -0
  230. package/src/v2/shadcn/_reference/SecondaryNav.tsx +50 -0
  231. package/src/v2/shadcn/_reference/SecuritySettings.tsx +258 -0
  232. package/src/v2/shadcn/_reference/SessionDetailView.tsx +294 -0
  233. package/src/v2/shadcn/_reference/Sidebar.tsx +14 -0
  234. package/src/v2/shadcn/_reference/SidebarAwareLayout.tsx +30 -0
  235. package/src/v2/shadcn/_reference/SidebarLabelCustomization.tsx +285 -0
  236. package/src/v2/shadcn/_reference/SimulationBanner.tsx +57 -0
  237. package/src/v2/shadcn/_reference/SortControls.tsx +65 -0
  238. package/src/v2/shadcn/_reference/StatusBadge.tsx +49 -0
  239. package/src/v2/shadcn/_reference/StyleGuideContent.tsx +331 -0
  240. package/src/v2/shadcn/_reference/TableActionMenu.tsx +126 -0
  241. package/src/v2/shadcn/_reference/ThemeProvider.tsx +119 -0
  242. package/src/v2/shadcn/_reference/ThemeSettings.tsx +73 -0
  243. package/src/v2/shadcn/_reference/TopNavigation.tsx +332 -0
  244. package/src/v2/shadcn/_reference/UserActivityHistory.tsx +209 -0
  245. package/src/v2/shadcn/_reference/UserLanguageSettings.tsx +94 -0
  246. package/src/v2/shadcn/_reference/UserPanel.tsx +472 -0
  247. package/src/v2/shadcn/_reference/UsersTable.tsx +1023 -0
  248. package/src/v2/shadcn/_reference/WaiverForm.tsx +301 -0
  249. package/src/v2/shadcn/_reference/WaiversGeneralSettings.tsx +46 -0
  250. package/src/v2/shadcn/_reference/WaiversTable.tsx +290 -0
  251. package/src/v2/shadcn/_reference/WaiversTemplatesSettings.tsx +416 -0
  252. package/src/v2/shadcn/_reference/ai/AIChatPanel.tsx +313 -0
  253. package/src/v2/shadcn/_reference/ai/AIChatSearchBar.tsx +36 -0
  254. package/src/v2/shadcn/_reference/ai/ChatInteractiveBlock.tsx +298 -0
  255. package/src/v2/shadcn/_reference/ai/ChatMessageContent.tsx +40 -0
  256. package/src/v2/shadcn/_reference/ai/parseInteractiveBlocks.ts +142 -0
  257. package/src/v2/shadcn/_reference/auth/AuthLayout.tsx +55 -0
  258. package/src/v2/shadcn/_reference/auth/CreatePasswordForm.tsx +285 -0
  259. package/src/v2/shadcn/_reference/auth/CreatePasswordPanel.tsx +20 -0
  260. package/src/v2/shadcn/_reference/auth/LoginFooter.tsx +14 -0
  261. package/src/v2/shadcn/_reference/auth/LoginForm.tsx +205 -0
  262. package/src/v2/shadcn/_reference/auth/LoginPanel.tsx +41 -0
  263. package/src/v2/shadcn/_reference/auth/ResetPasswordForm.tsx +102 -0
  264. package/src/v2/shadcn/_reference/auth/ResetPasswordPanel.tsx +20 -0
  265. package/src/v2/shadcn/_reference/auth/VerifyEmailForm.tsx +95 -0
  266. package/src/v2/shadcn/_reference/auth/VerifyEmailPanel.tsx +20 -0
  267. package/src/v2/shadcn/_reference/email/EmailAttachment.tsx +119 -0
  268. package/src/v2/shadcn/_reference/email/EmailAutomation.tsx +92 -0
  269. package/src/v2/shadcn/_reference/email/EmailPlaceholders.tsx +64 -0
  270. package/src/v2/shadcn/_reference/email/UnlayerEmailEditor.tsx +41 -0
  271. package/src/v2/shadcn/_reference/email/emailTemplateData.ts +53 -0
  272. package/src/v2/shadcn/_reference/emptyStateIcons.tsx +103 -0
  273. package/src/v2/shadcn/_reference/games/MazeGame.tsx +394 -0
  274. package/src/v2/shadcn/_reference/games/RunnerGame.tsx +497 -0
  275. package/src/v2/shadcn/_reference/logos/BookedLogoFull.tsx +36 -0
  276. package/src/v2/shadcn/_reference/logos/BookedLogoMark.tsx +31 -0
  277. package/src/v2/shadcn/_reference/logos/BookedLogoNew.tsx +36 -0
  278. package/src/v2/shadcn/_reference/pricing/DynamicPricingRulesEditor.tsx +401 -0
  279. package/src/v2/shadcn/_reference/pricing/DynamicPricingTierCard.tsx +77 -0
  280. package/src/v2/shadcn/_reference/pricing/DynamicPricingTiersList.tsx +218 -0
  281. package/src/v2/shadcn/_reference/pricing/PricingCalendar.tsx +810 -0
  282. package/src/v2/shadcn/_reference/pricing/PricingPeriodCard.tsx +152 -0
  283. package/src/v2/shadcn/_reference/pricing/PricingPeriodForm.tsx +377 -0
  284. package/src/v2/shadcn/_reference/pricing/PricingPeriodsList.tsx +213 -0
  285. package/src/v2/shadcn/_reference/pricing/getRuleSummary.ts +39 -0
  286. package/src/v2/shadcn/_reference/products/AvailabilityRulesSection.tsx +184 -0
  287. package/src/v2/shadcn/_reference/products/AvailabilitySection.tsx +677 -0
  288. package/src/v2/shadcn/_reference/products/BookingTypeConfigOptions.tsx +40 -0
  289. package/src/v2/shadcn/_reference/products/CapacityPeriodsSection.tsx +238 -0
  290. package/src/v2/shadcn/_reference/products/DynamicPricingTiersSection.tsx +131 -0
  291. package/src/v2/shadcn/_reference/products/GiftCardOrdersTab.tsx +192 -0
  292. package/src/v2/shadcn/_reference/products/GiftCardSettings.tsx +342 -0
  293. package/src/v2/shadcn/_reference/products/PackageProductsSection.tsx +322 -0
  294. package/src/v2/shadcn/_reference/products/PricingSection.tsx +173 -0
  295. package/src/v2/shadcn/_reference/products/ProductTypeFields.tsx +353 -0
  296. package/src/v2/shadcn/_reference/products/ProductTypeIcon.tsx +95 -0
  297. package/src/v2/shadcn/_reference/products/VariablePricingSection.tsx +140 -0
  298. package/src/v2/shadcn/_reference/products/productTypeConfig.ts +182 -0
  299. package/src/v2/shadcn/_reference/shared/BackButton.tsx +50 -0
  300. package/src/v2/shadcn/_reference/shared/CancelConfirmationDialog.tsx +18 -0
  301. package/src/v2/shadcn/_reference/shared/ConfirmationDialog.tsx +136 -0
  302. package/src/v2/shadcn/_reference/shared/DeleteConfirmationDialog.tsx +18 -0
  303. package/src/v2/shadcn/_reference/shared/DeleteEntityPage.tsx +221 -0
  304. package/src/v2/shadcn/_reference/shared/SidebarIcons.tsx +108 -0
  305. package/src/v2/shadcn/_reference/shared/UnifiedSidebar.tsx +722 -0
  306. package/src/v2/shadcn/_reference/tables/BulkActionsBar.tsx +68 -0
  307. package/src/v2/shadcn/_reference/tables/DataTable.tsx +221 -0
  308. package/src/v2/shadcn/_reference/tables/TableControls.tsx +94 -0
  309. package/src/v2/shadcn/_reference/tables/index.ts +3 -0
  310. package/src/v2/shadcn/_reference/tables/types.ts +79 -0
  311. package/src/v2/shadcn/_reference/zones/LegacyZoneSettings.tsx +299 -0
  312. package/src/v2/shadcn/components/ui/accordion.stories.tsx +63 -0
  313. package/src/v2/shadcn/components/ui/accordion.tsx +52 -0
  314. package/src/v2/shadcn/components/ui/alert-dialog.stories.tsx +44 -0
  315. package/src/v2/shadcn/components/ui/alert-dialog.tsx +104 -0
  316. package/src/v2/shadcn/components/ui/alert.stories.tsx +44 -0
  317. package/src/v2/shadcn/components/ui/alert.tsx +43 -0
  318. package/src/v2/shadcn/components/ui/aspect-ratio.stories.tsx +46 -0
  319. package/src/v2/shadcn/components/ui/aspect-ratio.tsx +5 -0
  320. package/src/v2/shadcn/components/ui/avatar.stories.tsx +39 -0
  321. package/src/v2/shadcn/components/ui/avatar.tsx +38 -0
  322. package/src/v2/shadcn/components/ui/badge.stories.tsx +17 -0
  323. package/src/v2/shadcn/components/ui/badge.tsx +30 -0
  324. package/src/v2/shadcn/components/ui/breadcrumb.stories.tsx +91 -0
  325. package/src/v2/shadcn/components/ui/breadcrumb.tsx +90 -0
  326. package/src/v2/shadcn/components/ui/button.stories.tsx +20 -0
  327. package/src/v2/shadcn/components/ui/button.tsx +60 -0
  328. package/src/v2/shadcn/components/ui/calendar.stories.tsx +61 -0
  329. package/src/v2/shadcn/components/ui/calendar.tsx +54 -0
  330. package/src/v2/shadcn/components/ui/card.stories.tsx +37 -0
  331. package/src/v2/shadcn/components/ui/card.tsx +43 -0
  332. package/src/v2/shadcn/components/ui/carousel.stories.tsx +92 -0
  333. package/src/v2/shadcn/components/ui/carousel.tsx +224 -0
  334. package/src/v2/shadcn/components/ui/checkbox.scss +38 -0
  335. package/src/v2/shadcn/components/ui/checkbox.stories.tsx +23 -0
  336. package/src/v2/shadcn/components/ui/checkbox.tsx +24 -0
  337. package/src/v2/shadcn/components/ui/collapsible.stories.tsx +59 -0
  338. package/src/v2/shadcn/components/ui/collapsible.tsx +9 -0
  339. package/src/v2/shadcn/components/ui/command.stories.tsx +70 -0
  340. package/src/v2/shadcn/components/ui/command.tsx +132 -0
  341. package/src/v2/shadcn/components/ui/context-menu.stories.tsx +72 -0
  342. package/src/v2/shadcn/components/ui/context-menu.tsx +178 -0
  343. package/src/v2/shadcn/components/ui/dialog.stories.tsx +67 -0
  344. package/src/v2/shadcn/components/ui/dialog.tsx +95 -0
  345. package/src/v2/shadcn/components/ui/drawer.stories.tsx +50 -0
  346. package/src/v2/shadcn/components/ui/drawer.tsx +87 -0
  347. package/src/v2/shadcn/components/ui/dropdown-menu.stories.tsx +73 -0
  348. package/src/v2/shadcn/components/ui/dropdown-menu.tsx +179 -0
  349. package/src/v2/shadcn/components/ui/form.stories.tsx +105 -0
  350. package/src/v2/shadcn/components/ui/form.tsx +129 -0
  351. package/src/v2/shadcn/components/ui/hover-card.stories.tsx +35 -0
  352. package/src/v2/shadcn/components/ui/hover-card.tsx +27 -0
  353. package/src/v2/shadcn/components/ui/input-otp.stories.tsx +72 -0
  354. package/src/v2/shadcn/components/ui/input-otp.tsx +61 -0
  355. package/src/v2/shadcn/components/ui/input.stories.tsx +16 -0
  356. package/src/v2/shadcn/components/ui/input.tsx +25 -0
  357. package/src/v2/shadcn/components/ui/label.stories.tsx +13 -0
  358. package/src/v2/shadcn/components/ui/label.tsx +17 -0
  359. package/src/v2/shadcn/components/ui/menubar.stories.tsx +86 -0
  360. package/src/v2/shadcn/components/ui/menubar.tsx +207 -0
  361. package/src/v2/shadcn/components/ui/navigation-menu.stories.tsx +68 -0
  362. package/src/v2/shadcn/components/ui/navigation-menu.tsx +120 -0
  363. package/src/v2/shadcn/components/ui/pagination.stories.tsx +78 -0
  364. package/src/v2/shadcn/components/ui/pagination.tsx +81 -0
  365. package/src/v2/shadcn/components/ui/popover.stories.tsx +44 -0
  366. package/src/v2/shadcn/components/ui/popover.tsx +29 -0
  367. package/src/v2/shadcn/components/ui/progress.stories.tsx +17 -0
  368. package/src/v2/shadcn/components/ui/progress.tsx +23 -0
  369. package/src/v2/shadcn/components/ui/radio-card.stories.tsx +68 -0
  370. package/src/v2/shadcn/components/ui/radio-card.tsx +52 -0
  371. package/src/v2/shadcn/components/ui/radio-group.stories.tsx +77 -0
  372. package/src/v2/shadcn/components/ui/radio-group.tsx +35 -0
  373. package/src/v2/shadcn/components/ui/scroll-area.stories.tsx +56 -0
  374. package/src/v2/shadcn/components/ui/scroll-area.tsx +38 -0
  375. package/src/v2/shadcn/components/ui/select.stories.tsx +60 -0
  376. package/src/v2/shadcn/components/ui/select.tsx +148 -0
  377. package/src/v2/shadcn/components/ui/separator.stories.tsx +30 -0
  378. package/src/v2/shadcn/components/ui/separator.tsx +20 -0
  379. package/src/v2/shadcn/components/ui/sheet.stories.tsx +115 -0
  380. package/src/v2/shadcn/components/ui/sheet.tsx +107 -0
  381. package/src/v2/shadcn/components/ui/sidebar.stories.tsx +167 -0
  382. package/src/v2/shadcn/components/ui/sidebar.tsx +637 -0
  383. package/src/v2/shadcn/components/ui/skeleton.stories.tsx +36 -0
  384. package/src/v2/shadcn/components/ui/skeleton.tsx +7 -0
  385. package/src/v2/shadcn/components/ui/slider.stories.tsx +16 -0
  386. package/src/v2/shadcn/components/ui/slider.tsx +23 -0
  387. package/src/v2/shadcn/components/ui/switch.scss +63 -0
  388. package/src/v2/shadcn/components/ui/switch.stories.tsx +23 -0
  389. package/src/v2/shadcn/components/ui/switch.tsx +24 -0
  390. package/src/v2/shadcn/components/ui/table-pagination.stories.tsx +81 -0
  391. package/src/v2/shadcn/components/ui/table-pagination.tsx +61 -0
  392. package/src/v2/shadcn/components/ui/table.stories.tsx +40 -0
  393. package/src/v2/shadcn/components/ui/table.tsx +72 -0
  394. package/src/v2/shadcn/components/ui/tabs.stories.tsx +85 -0
  395. package/src/v2/shadcn/components/ui/tabs.tsx +53 -0
  396. package/src/v2/shadcn/components/ui/textarea.stories.tsx +15 -0
  397. package/src/v2/shadcn/components/ui/textarea.tsx +21 -0
  398. package/src/v2/shadcn/components/ui/toast.stories.tsx +77 -0
  399. package/src/v2/shadcn/components/ui/toast.tsx +111 -0
  400. package/src/v2/shadcn/components/ui/toaster.stories.tsx +46 -0
  401. package/src/v2/shadcn/components/ui/toaster.tsx +24 -0
  402. package/src/v2/shadcn/components/ui/toggle-group.stories.tsx +95 -0
  403. package/src/v2/shadcn/components/ui/toggle-group.tsx +49 -0
  404. package/src/v2/shadcn/components/ui/toggle.stories.tsx +18 -0
  405. package/src/v2/shadcn/components/ui/toggle.tsx +37 -0
  406. package/src/v2/shadcn/components/ui/tooltip.stories.tsx +57 -0
  407. package/src/v2/shadcn/components/ui/tooltip.tsx +28 -0
  408. package/src/v2/shadcn/components/ui/use-toast.ts +3 -0
  409. package/src/v2/shadcn/hooks/use-mobile.tsx +19 -0
  410. package/src/v2/shadcn/hooks/use-toast.ts +184 -0
  411. package/src/v2/shadcn/index.ts +76 -0
  412. package/src/v2/shadcn/lib/utils.ts +6 -0
  413. package/src/v2/shadcn/styles/globals.css +112 -0
  414. package/.vscode/settings.json +0 -3
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { Checkbox } from '../ui/checkbox';
3
+ import { Label } from '../ui/label';
4
+
5
+ interface ConfigOption {
6
+ id: string;
7
+ label: string;
8
+ checked: boolean;
9
+ onChange: (checked: boolean) => void;
10
+ }
11
+
12
+ interface BookingTypeConfigOptionsProps {
13
+ options: ConfigOption[];
14
+ }
15
+
16
+ /**
17
+ * Configuration checkbox options for Booking Type products
18
+ * Extracted to keep the main form component manageable
19
+ */
20
+ const BookingTypeConfigOptions: React.FC<BookingTypeConfigOptionsProps> = ({ options }) => {
21
+ return (
22
+ <div className="flex flex-col gap-3">
23
+ {options.map((option) => (
24
+ <div key={option.id} className="flex items-start gap-2">
25
+ <Checkbox
26
+ id={option.id}
27
+ checked={option.checked}
28
+ onCheckedChange={(checked) => option.onChange(checked === true)}
29
+ className="mt-0.5"
30
+ />
31
+ <Label htmlFor={option.id} className="font-normal cursor-pointer leading-tight">
32
+ {option.label}
33
+ </Label>
34
+ </div>
35
+ ))}
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default BookingTypeConfigOptions;
@@ -0,0 +1,238 @@
1
+ import React from 'react';
2
+ import { Button } from '../ui/button';
3
+ import { Input } from '../ui/input';
4
+ import { Label } from '../ui/label';
5
+ import { Checkbox } from '../ui/checkbox';
6
+ import { Switch } from '../ui/switch';
7
+ import { IconPlus, IconDelete, IconTime } from '../../../icons';
8
+
9
+ export interface CapacityPeriod {
10
+ days: string[];
11
+ is_24_hours: boolean;
12
+ start_time?: string;
13
+ end_time?: string;
14
+ max_capacity: number;
15
+ min_capacity: number | null;
16
+ }
17
+
18
+ const DAY_OPTIONS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
19
+
20
+ /** Returns an error message if any capacity periods have overlapping day+time combinations, or null if valid. */
21
+ export function validateCapacityPeriods(periods: CapacityPeriod[]): string | null {
22
+ if (periods.length < 2) return null;
23
+
24
+ const timeToMinutes = (t: string): number => {
25
+ const [h, m] = t.split(':').map(Number);
26
+ return h * 60 + m;
27
+ };
28
+
29
+ const timesOverlap = (a: CapacityPeriod, b: CapacityPeriod): boolean => {
30
+ // If either covers all hours, they overlap on any shared day
31
+ if (a.is_24_hours || b.is_24_hours) return true;
32
+ const aStart = timeToMinutes(a.start_time || '00:00');
33
+ const aEnd = timeToMinutes(a.end_time || '23:59');
34
+ const bStart = timeToMinutes(b.start_time || '00:00');
35
+ const bEnd = timeToMinutes(b.end_time || '23:59');
36
+ return aStart < bEnd && bStart < aEnd;
37
+ };
38
+
39
+ for (let i = 0; i < periods.length; i++) {
40
+ for (let j = i + 1; j < periods.length; j++) {
41
+ const a = periods[i];
42
+ const b = periods[j];
43
+ const sharedDays = (a.days || []).filter(d => (b.days || []).includes(d));
44
+ if (sharedDays.length > 0 && timesOverlap(a, b)) {
45
+ return `Capacity periods ${i + 1} and ${j + 1} overlap on ${sharedDays.join(', ')}. Please adjust the days or times so they don't conflict.`;
46
+ }
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+
52
+ interface CapacityPeriodsSectionProps {
53
+ periods: CapacityPeriod[];
54
+ onChange: (periods: CapacityPeriod[]) => void;
55
+ }
56
+
57
+ const CapacityPeriodsSection: React.FC<CapacityPeriodsSectionProps> = ({ periods, onChange }) => {
58
+ const sameCapacityEveryDay = periods.length === 0;
59
+
60
+ const handleToggleSameCapacity = (checked: boolean) => {
61
+ if (checked) {
62
+ // "Same capacity every day" = clear all periods
63
+ onChange([]);
64
+ } else {
65
+ // Add a default period
66
+ onChange([{ days: [], is_24_hours: true, max_capacity: 1, min_capacity: null }]);
67
+ }
68
+ };
69
+
70
+ const addPeriod = () => {
71
+ onChange([...periods, { days: [], is_24_hours: true, max_capacity: 1, min_capacity: null }]);
72
+ };
73
+
74
+ const updatePeriod = (index: number, updates: Partial<CapacityPeriod>) => {
75
+ onChange(periods.map((p, i) => i === index ? { ...p, ...updates } : p));
76
+ };
77
+
78
+ const removePeriod = (index: number) => {
79
+ onChange(periods.filter((_, i) => i !== index));
80
+ };
81
+
82
+ const toggleDay = (periodIndex: number, day: string) => {
83
+ const period = periods[periodIndex];
84
+ const days = period.days || [];
85
+ const updated = days.includes(day) ? days.filter(d => d !== day) : [...days, day];
86
+ updatePeriod(periodIndex, { days: updated });
87
+ };
88
+
89
+ const toggle24Hours = (index: number, checked: boolean) => {
90
+ if (checked) {
91
+ updatePeriod(index, { is_24_hours: true, start_time: undefined, end_time: undefined });
92
+ } else {
93
+ updatePeriod(index, { is_24_hours: false, start_time: '09:00', end_time: '17:00' });
94
+ }
95
+ };
96
+
97
+ return (
98
+ <div className="flex flex-col gap-4">
99
+ <div className="flex flex-col gap-1">
100
+ <h2 className="text-label-primary text-base font-semibold">Capacity Overrides</h2>
101
+ <p className="text-label-secondary text-xs">
102
+ Override capacity on specific days and times. Base values apply when no period matches.
103
+ </p>
104
+ <p className="text-label-secondary text-xs">
105
+ Default capacities apply when no overrides set.
106
+ </p>
107
+ </div>
108
+
109
+ {/* Same capacity toggle */}
110
+ <div className="flex items-center gap-2">
111
+ <Switch
112
+ checked={sameCapacityEveryDay}
113
+ onCheckedChange={handleToggleSameCapacity}
114
+ />
115
+ <Label className="cursor-pointer text-sm">Same capacity every day</Label>
116
+ </div>
117
+
118
+ {/* Period cards - only when toggle is off */}
119
+ {!sameCapacityEveryDay && (
120
+ <div className="flex flex-col gap-4">
121
+ {periods.map((period, index) => (
122
+ <div key={index} className="flex flex-col gap-4 p-4 rounded-lg bg-surface-secondary">
123
+ <div className="flex items-center justify-between">
124
+ <div className="flex items-center gap-2">
125
+ <IconTime className="w-5 h-5 fill-fill-secondary" />
126
+ <span className="text-label-secondary text-xs border border-border-primary rounded-full px-2.5 py-0.5">
127
+ Capacity Period
128
+ </span>
129
+ </div>
130
+ <Button variant="ghost" size="icon" onClick={() => removePeriod(index)} className="h-8 w-8 bg-surface-danger-soft border-transparent hover:!bg-surface-danger-soft-hover [&_path]:fill-fill-danger">
131
+ <IconDelete className="w-4 h-4" />
132
+ </Button>
133
+ </div>
134
+
135
+ {/* Capacity Override */}
136
+ <div className="flex flex-col gap-3">
137
+ <Label className="text-sm font-semibold">Capacity Override</Label>
138
+ <div className="grid grid-cols-2 gap-4">
139
+ <div className="flex flex-col gap-2">
140
+ <div className="flex items-center justify-between">
141
+ <Label>Min Capacity</Label>
142
+ <span className="text-label-secondary text-xs">(optional)</span>
143
+ </div>
144
+ <Input
145
+ type="number"
146
+ min={0}
147
+ value={period.min_capacity === null ? '' : period.min_capacity === 0 ? '' : period.min_capacity}
148
+ onChange={(e) => updatePeriod(index, { min_capacity: e.target.value === '' ? null : (parseInt(e.target.value) || 0) })}
149
+ />
150
+ </div>
151
+ <div className="flex flex-col gap-2">
152
+ <Label>Max Capacity</Label>
153
+ <Input
154
+ type="number"
155
+ min={1}
156
+ value={period.max_capacity === 0 ? '' : period.max_capacity}
157
+ onChange={(e) => updatePeriod(index, { max_capacity: e.target.value === '' ? 0 : (parseInt(e.target.value) || 0) })}
158
+ />
159
+ </div>
160
+ </div>
161
+ </div>
162
+
163
+ {/* Day selection */}
164
+ <div className="flex flex-col gap-2">
165
+ <Label className="text-sm font-semibold">Days</Label>
166
+ <div className="grid grid-cols-2 gap-2">
167
+ <div className="flex flex-col gap-2">
168
+ {DAY_OPTIONS.slice(0, 4).map(day => (
169
+ <label key={day} className="flex items-center gap-1.5">
170
+ <Checkbox
171
+ checked={period.days?.includes(day) || false}
172
+ onCheckedChange={() => toggleDay(index, day)}
173
+ />
174
+ <span className="text-label-primary text-sm">{day}</span>
175
+ </label>
176
+ ))}
177
+ </div>
178
+ <div className="flex flex-col gap-2">
179
+ {DAY_OPTIONS.slice(4).map(day => (
180
+ <label key={day} className="flex items-center gap-1.5">
181
+ <Checkbox
182
+ checked={period.days?.includes(day) || false}
183
+ onCheckedChange={() => toggleDay(index, day)}
184
+ />
185
+ <span className="text-label-primary text-sm">{day}</span>
186
+ </label>
187
+ ))}
188
+ </div>
189
+ </div>
190
+ </div>
191
+
192
+ {/* Time section */}
193
+ <div className="flex flex-col gap-3">
194
+ <Label className="text-sm font-semibold">Time</Label>
195
+ <div className="flex items-center gap-2">
196
+ <Switch
197
+ checked={period.is_24_hours ?? true}
198
+ onCheckedChange={(checked) => toggle24Hours(index, checked)}
199
+ />
200
+ <Label className="cursor-pointer">Align with Opening Hours</Label>
201
+ </div>
202
+
203
+ {!period.is_24_hours && (
204
+ <div className="grid grid-cols-2 gap-4">
205
+ <div className="flex flex-col gap-2">
206
+ <Label>Start Time</Label>
207
+ <Input
208
+ type="time"
209
+ value={period.start_time || '09:00'}
210
+ onChange={(e) => updatePeriod(index, { start_time: e.target.value })}
211
+ />
212
+ </div>
213
+ <div className="flex flex-col gap-2">
214
+ <Label>End Time</Label>
215
+ <Input
216
+ type="time"
217
+ value={period.end_time || '17:00'}
218
+ onChange={(e) => updatePeriod(index, { end_time: e.target.value })}
219
+ />
220
+ </div>
221
+ </div>
222
+ )}
223
+ </div>
224
+ </div>
225
+ ))}
226
+
227
+ {/* Add Period button below cards */}
228
+ <Button variant="ghost" onClick={addPeriod} withIcon className="w-fit">
229
+ <IconPlus className="w-4 h-4 fill-fill-primary" />
230
+ Add Period
231
+ </Button>
232
+ </div>
233
+ )}
234
+ </div>
235
+ );
236
+ };
237
+
238
+ export default CapacityPeriodsSection;
@@ -0,0 +1,131 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Input } from '../ui/input';
3
+ import { Label } from '../ui/label';
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from '../ui/select';
11
+ import { supabase } from '@/integrations/supabase/client';
12
+ import getRuleSummary from '../pricing/getRuleSummary';
13
+ import type { DynamicPricingRule } from '../pricing/DynamicPricingRulesEditor';
14
+
15
+ export interface DynamicTierEntry {
16
+ tier_id: string;
17
+ name: string;
18
+ adjustment: number;
19
+ direction: 'increase' | 'decrease';
20
+ rules: DynamicPricingRule[];
21
+ }
22
+
23
+ interface DynamicPricingTiersSectionProps {
24
+ providerId?: string;
25
+ tiers: DynamicTierEntry[];
26
+ onTiersChange: (tiers: DynamicTierEntry[]) => void;
27
+ }
28
+
29
+ const DynamicPricingTiersSection: React.FC<DynamicPricingTiersSectionProps> = ({
30
+ providerId,
31
+ tiers,
32
+ onTiersChange,
33
+ }) => {
34
+ // Fetch dynamic tiers from DB on mount
35
+ useEffect(() => {
36
+ if (!providerId || tiers.length > 0) return;
37
+
38
+ const fetchTiers = async () => {
39
+ const { data } = await supabase
40
+ .from('dynamic_pricing_tiers' as any)
41
+ .select('id, name, rules')
42
+ .eq('provider_id', providerId)
43
+ .eq('status', 'active')
44
+ .eq('is_active', true)
45
+ .order('display_order', { ascending: true });
46
+
47
+ if (data && data.length > 0) {
48
+ const entries: DynamicTierEntry[] = (data as any[]).map(t => ({
49
+ tier_id: t.id,
50
+ name: t.name,
51
+ adjustment: 0,
52
+ direction: 'increase' as const,
53
+ rules: Array.isArray(t.rules) ? t.rules : [],
54
+ }));
55
+ onTiersChange(entries);
56
+ }
57
+ };
58
+
59
+ fetchTiers();
60
+ }, [providerId]);
61
+
62
+ if (tiers.length === 0) {
63
+ return null;
64
+ }
65
+
66
+ return (
67
+ <div className="flex flex-col gap-4 pt-4 border-t border-border-primary">
68
+ <div className="flex flex-col gap-1">
69
+ <h2 className="text-label-primary text-xl font-semibold">Dynamic Pricing Tiers</h2>
70
+ <p className="text-label-secondary text-sm">Adjust the base price by a +/- amount for each tier.</p>
71
+ </div>
72
+
73
+ <div className="flex flex-col gap-3">
74
+ {tiers.map((tier, index) => (
75
+ <div key={tier.tier_id} className="flex items-start gap-4 p-4 border border-border-primary rounded-lg">
76
+ <div className="flex flex-col gap-1 flex-1 min-w-0">
77
+ <p className="text-label-primary text-sm font-medium">{tier.name}</p>
78
+ {tier.rules && tier.rules.length > 0 && (
79
+ <div className="flex flex-wrap gap-1">
80
+ {tier.rules.map((rule: DynamicPricingRule, i: number) => (
81
+ <span
82
+ key={i}
83
+ className="inline-flex items-center px-2 py-0.5 rounded-md bg-surface-secondary text-label-secondary text-xs"
84
+ >
85
+ {getRuleSummary(rule)}
86
+ </span>
87
+ ))}
88
+ </div>
89
+ )}
90
+ </div>
91
+ <div className="flex items-center gap-1 flex-shrink-0">
92
+ <span className="text-label-secondary text-sm">£</span>
93
+ <Input
94
+ type="text"
95
+ inputMode="decimal"
96
+ defaultValue={tier.adjustment === 0 ? '' : tier.adjustment.toFixed(2)}
97
+ key={`${tier.tier_id}-${tier.adjustment}`}
98
+ onBlur={(e) => {
99
+ const raw = e.target.value.trim();
100
+ const absVal = raw === '' ? 0 : parseFloat(parseFloat(raw).toFixed(2));
101
+ const newVal = isNaN(absVal) ? 0 : absVal;
102
+ onTiersChange(tiers.map((t, i) => i === index ? { ...t, adjustment: newVal } : t));
103
+ if (raw !== '') {
104
+ e.target.value = newVal.toFixed(2);
105
+ }
106
+ }}
107
+ className="w-24"
108
+ />
109
+ <Select
110
+ value={tier.direction}
111
+ onValueChange={(val: string) => {
112
+ onTiersChange(tiers.map((t, i) => i === index ? { ...t, direction: val as 'increase' | 'decrease' } : t));
113
+ }}
114
+ >
115
+ <SelectTrigger className="w-[120px]">
116
+ <SelectValue />
117
+ </SelectTrigger>
118
+ <SelectContent>
119
+ <SelectItem value="increase">Increase</SelectItem>
120
+ <SelectItem value="decrease">Decrease</SelectItem>
121
+ </SelectContent>
122
+ </Select>
123
+ </div>
124
+ </div>
125
+ ))}
126
+ </div>
127
+ </div>
128
+ );
129
+ };
130
+
131
+ export default DynamicPricingTiersSection;
@@ -0,0 +1,192 @@
1
+ import React from 'react';
2
+ import { useQuery } from '@tanstack/react-query';
3
+ import { supabase } from '@/integrations/supabase/client';
4
+ import { DataTable } from '../tables/DataTable';
5
+ import { ColumnConfig, RowAction } from '../tables/types';
6
+ import { TableControls } from '../tables/TableControls';
7
+ import { SearchConfig, FilterConfig } from '../tables/types';
8
+ import StatusBadge from '../StatusBadge';
9
+ import EmptyState from '../EmptyState';
10
+ import LoadingSpinner from '../LoadingSpinner';
11
+ import { format } from 'date-fns';
12
+ import { useNotify } from '../../hooks/useNotify';
13
+
14
+ interface GiftCardSale {
15
+ id: string;
16
+ code: string;
17
+ denomination: number;
18
+ balance: number;
19
+ status: string;
20
+ currency: string;
21
+ purchaser_name: string | null;
22
+ purchaser_email: string | null;
23
+ recipient_name: string | null;
24
+ recipient_email: string | null;
25
+ is_gift: boolean;
26
+ purchased_at: string;
27
+ expires_at: string | null;
28
+ denomination_image_url: string | null;
29
+ }
30
+
31
+ interface GiftCardOrdersTabProps {
32
+ productId: string;
33
+ }
34
+
35
+ const GiftCardOrdersTab: React.FC<GiftCardOrdersTabProps> = ({ productId }) => {
36
+ const [searchQuery, setSearchQuery] = React.useState('');
37
+ const [activeFilter, setActiveFilter] = React.useState<string>('all');
38
+ const { showSuccess } = useNotify();
39
+
40
+ const { data: sales = [], isLoading } = useQuery({
41
+ queryKey: ['gift-card-sales', productId],
42
+ queryFn: async () => {
43
+ const { data, error } = await supabase
44
+ .from('gift_card_sales')
45
+ .select('*')
46
+ .eq('product_id', productId)
47
+ .order('purchased_at', { ascending: false });
48
+ if (error) throw error;
49
+ return (data || []) as GiftCardSale[];
50
+ },
51
+ enabled: !!productId,
52
+ });
53
+
54
+ const filteredSales = sales.filter(sale => {
55
+ if (!sale || !sale.code) return false;
56
+ const query = searchQuery.toLowerCase();
57
+ const matchesSearch =
58
+ sale.code.toLowerCase().includes(query) ||
59
+ (sale.purchaser_name && sale.purchaser_name.toLowerCase().includes(query)) ||
60
+ (sale.purchaser_email && sale.purchaser_email.toLowerCase().includes(query)) ||
61
+ (sale.recipient_name && sale.recipient_name.toLowerCase().includes(query));
62
+ const matchesFilter = activeFilter === 'all' || sale.status === activeFilter;
63
+ return matchesSearch && matchesFilter;
64
+ });
65
+
66
+ const searchConfig: SearchConfig = {
67
+ placeholder: 'Search by code, name or email',
68
+ value: searchQuery,
69
+ onChange: setSearchQuery,
70
+ label: 'Search Orders',
71
+ };
72
+
73
+ const statusCounts = sales.reduce((acc, s) => {
74
+ if (!s) return acc;
75
+ acc[s.status] = (acc[s.status] || 0) + 1;
76
+ return acc;
77
+ }, {} as Record<string, number>);
78
+
79
+ const filters: FilterConfig[] = Object.keys(statusCounts).map(status => ({
80
+ label: `${status.charAt(0).toUpperCase() + status.slice(1)} (${statusCounts[status]})`,
81
+ value: status,
82
+ isActive: activeFilter === status,
83
+ onClick: () => setActiveFilter(activeFilter === status ? 'all' : status),
84
+ }));
85
+
86
+ const rowActions = (sale: GiftCardSale): RowAction<GiftCardSale>[] => [
87
+ {
88
+ label: 'Copy Code',
89
+ onClick: (sale) => {
90
+ navigator.clipboard.writeText(sale.code);
91
+ showSuccess(`Code ${sale.code} copied to clipboard`);
92
+ },
93
+ },
94
+ {
95
+ label: 'View Details',
96
+ onClick: () => { /* TODO */ },
97
+ },
98
+ {
99
+ label: 'Disable Card',
100
+ onClick: () => { /* TODO */ },
101
+ variant: 'danger',
102
+ },
103
+ ];
104
+
105
+ const columns: ColumnConfig<GiftCardSale>[] = [
106
+ {
107
+ label: 'Customer',
108
+ render: (sale) => (
109
+ <div className="flex flex-col justify-center items-start gap-0.5 min-w-0">
110
+ <span className="text-label-primary text-[13px] font-normal truncate w-full">
111
+ {sale.is_gift ? sale.recipient_name || 'Gift' : sale.purchaser_name || '—'}
112
+ </span>
113
+ <span className="text-label-secondary text-xs font-normal truncate w-full">
114
+ {sale.is_gift ? sale.recipient_email || sale.purchaser_email || '' : sale.purchaser_email || ''}
115
+ </span>
116
+ </div>
117
+ ),
118
+ },
119
+ {
120
+ label: 'Value / Balance',
121
+ render: (sale) => (
122
+ <div className="flex flex-col justify-center items-start gap-0.5">
123
+ <span className="text-label-primary text-[13px] font-normal">£{Number(sale.denomination).toFixed(2)}</span>
124
+ <span className="text-label-secondary text-xs font-normal">Bal: £{Number(sale.balance).toFixed(2)}</span>
125
+ </div>
126
+ ),
127
+ width: 'w-[130px]',
128
+ labelClassName: 'hidden sm:flex',
129
+ className: 'hidden sm:flex',
130
+ },
131
+ {
132
+ label: 'Purchased / Expires',
133
+ render: (sale) => (
134
+ <div className="flex flex-col justify-center items-start gap-0.5">
135
+ <span className="text-label-primary text-[13px] font-normal">
136
+ {format(new Date(sale.purchased_at), 'd MMM yyyy')}
137
+ </span>
138
+ <span className="text-label-secondary text-xs font-normal">
139
+ {sale.expires_at ? format(new Date(sale.expires_at), 'd MMM yyyy') : 'No expiry'}
140
+ </span>
141
+ </div>
142
+ ),
143
+ width: 'w-[150px]',
144
+ labelClassName: 'hidden md:flex',
145
+ className: 'hidden md:flex',
146
+ },
147
+ {
148
+ label: 'Status',
149
+ render: (sale) => (
150
+ <StatusBadge status={sale.status as 'active' | 'disabled'} />
151
+ ),
152
+ width: 'w-[100px]',
153
+ },
154
+ ];
155
+
156
+ if (isLoading) {
157
+ return (
158
+ <div className="flex items-center justify-center py-12">
159
+ <LoadingSpinner size="sm" />
160
+ </div>
161
+ );
162
+ }
163
+
164
+ if (sales.length === 0) {
165
+ return (
166
+ <EmptyState
167
+ icon="Inventory"
168
+ title="No Orders Yet"
169
+ description="Gift card purchases will appear here."
170
+ />
171
+ );
172
+ }
173
+
174
+ return (
175
+ <div className="flex flex-col gap-4">
176
+ <TableControls searchConfig={searchConfig} filters={filters} />
177
+ <DataTable
178
+ data={filteredSales}
179
+ columns={columns}
180
+ keyExtractor={(sale) => sale.id}
181
+ rowActions={rowActions}
182
+ emptyState={
183
+ <div className="px-4 py-8 text-center">
184
+ <p className="text-label-secondary">No orders match your search.</p>
185
+ </div>
186
+ }
187
+ />
188
+ </div>
189
+ );
190
+ };
191
+
192
+ export default GiftCardOrdersTab;