@withpotter/pages-bookings 0.13.0-next.101

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 (270) hide show
  1. package/dist/dashboard/(bookings)/attendees/page.js +8 -0
  2. package/dist/dashboard/(bookings)/attendees/page.js.map +1 -0
  3. package/dist/dashboard/(bookings)/availability/_components/availability-screen.js +714 -0
  4. package/dist/dashboard/(bookings)/availability/_components/availability-screen.js.map +1 -0
  5. package/dist/dashboard/(bookings)/availability/_components/month-availability.js +130 -0
  6. package/dist/dashboard/(bookings)/availability/_components/month-availability.js.map +1 -0
  7. package/dist/dashboard/(bookings)/availability/page.js +10 -0
  8. package/dist/dashboard/(bookings)/availability/page.js.map +1 -0
  9. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/assign-resource-modal.js +133 -0
  10. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/assign-resource-modal.js.map +1 -0
  11. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-constants.js +26 -0
  12. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-constants.js.map +1 -0
  13. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-desktop-layout.js +194 -0
  14. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-desktop-layout.js.map +1 -0
  15. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-layout-props.js +1 -0
  16. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-layout-props.js.map +1 -0
  17. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-lede.js +189 -0
  18. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-lede.js.map +1 -0
  19. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-meta.js +38 -0
  20. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-meta.js.map +1 -0
  21. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-layout.js +315 -0
  22. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-layout.js.map +1 -0
  23. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-screen.js +94 -0
  24. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-mobile-screen.js.map +1 -0
  25. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-money.js +54 -0
  26. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-money.js.map +1 -0
  27. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-split.js +71 -0
  28. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/booking-split.js.map +1 -0
  29. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancel-booking-modal.js +102 -0
  30. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancel-booking-modal.js.map +1 -0
  31. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancellation-notice.js +33 -0
  32. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/cancellation-notice.js.map +1 -0
  33. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/customer-info-card.js +65 -0
  34. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/customer-info-card.js.map +1 -0
  35. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/index.js +23 -0
  36. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/index.js.map +1 -0
  37. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/intake-answers-card.js +19 -0
  38. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/intake-answers-card.js.map +1 -0
  39. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/refund-booking-modal.js +156 -0
  40. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/refund-booking-modal.js.map +1 -0
  41. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js +120 -0
  42. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/reschedule-booking-modal.js.map +1 -0
  43. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/security-deposit-card.js +63 -0
  44. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/security-deposit-card.js.map +1 -0
  45. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/settle-deposit-modal.js +141 -0
  46. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/settle-deposit-modal.js.map +1 -0
  47. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/ticket-row-actions.js +49 -0
  48. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/ticket-row-actions.js.map +1 -0
  49. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/waiting-queue-notice.js +42 -0
  50. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components/waiting-queue-notice.js.map +1 -0
  51. package/dist/dashboard/(bookings)/bookings/[bookingId]/_components.js +1 -0
  52. package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/index.js +19 -0
  53. package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/index.js.map +1 -0
  54. package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/use-booking-detail-data.js +352 -0
  55. package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks/use-booking-detail-data.js.map +1 -0
  56. package/dist/dashboard/(bookings)/bookings/[bookingId]/_hooks.js +1 -0
  57. package/dist/dashboard/(bookings)/bookings/[bookingId]/layout.js +33 -0
  58. package/dist/dashboard/(bookings)/bookings/[bookingId]/layout.js.map +1 -0
  59. package/dist/dashboard/(bookings)/bookings/[bookingId]/page.js +356 -0
  60. package/dist/dashboard/(bookings)/bookings/[bookingId]/page.js.map +1 -0
  61. package/dist/dashboard/(bookings)/bookings/_components/appointment-calendar-layout.js +34 -0
  62. package/dist/dashboard/(bookings)/bookings/_components/appointment-calendar-layout.js.map +1 -0
  63. package/dist/dashboard/(bookings)/bookings/_components/booking-constants.js +92 -0
  64. package/dist/dashboard/(bookings)/bookings/_components/booking-constants.js.map +1 -0
  65. package/dist/dashboard/(bookings)/bookings/_components/booking-tab-hints.js +32 -0
  66. package/dist/dashboard/(bookings)/bookings/_components/booking-tab-hints.js.map +1 -0
  67. package/dist/dashboard/(bookings)/bookings/_components/bookings-filter-bar.js +131 -0
  68. package/dist/dashboard/(bookings)/bookings/_components/bookings-filter-bar.js.map +1 -0
  69. package/dist/dashboard/(bookings)/bookings/_components/bookings-mobile-controls.js +119 -0
  70. package/dist/dashboard/(bookings)/bookings/_components/bookings-mobile-controls.js.map +1 -0
  71. package/dist/dashboard/(bookings)/bookings/_components/bookings-screen.js +414 -0
  72. package/dist/dashboard/(bookings)/bookings/_components/bookings-screen.js.map +1 -0
  73. package/dist/dashboard/(bookings)/bookings/_components/bookings-table.js +192 -0
  74. package/dist/dashboard/(bookings)/bookings/_components/bookings-table.js.map +1 -0
  75. package/dist/dashboard/(bookings)/bookings/_components/cannot-take-bookings.js +34 -0
  76. package/dist/dashboard/(bookings)/bookings/_components/cannot-take-bookings.js.map +1 -0
  77. package/dist/dashboard/(bookings)/bookings/_components/demo-data.js +176 -0
  78. package/dist/dashboard/(bookings)/bookings/_components/demo-data.js.map +1 -0
  79. package/dist/dashboard/(bookings)/bookings/_components/index.js +9 -0
  80. package/dist/dashboard/(bookings)/bookings/_components/index.js.map +1 -0
  81. package/dist/dashboard/(bookings)/bookings/_components/today/booking-card.js +126 -0
  82. package/dist/dashboard/(bookings)/bookings/_components/today/booking-card.js.map +1 -0
  83. package/dist/dashboard/(bookings)/bookings/_components/today/demo-data.js +142 -0
  84. package/dist/dashboard/(bookings)/bookings/_components/today/demo-data.js.map +1 -0
  85. package/dist/dashboard/(bookings)/bookings/_components/today/handover.js +128 -0
  86. package/dist/dashboard/(bookings)/bookings/_components/today/handover.js.map +1 -0
  87. package/dist/dashboard/(bookings)/bookings/_components/today/index.js +17 -0
  88. package/dist/dashboard/(bookings)/bookings/_components/today/index.js.map +1 -0
  89. package/dist/dashboard/(bookings)/bookings/_components/today/past-band.js +69 -0
  90. package/dist/dashboard/(bookings)/bookings/_components/today/past-band.js.map +1 -0
  91. package/dist/dashboard/(bookings)/bookings/_components/today/resource-board.js +111 -0
  92. package/dist/dashboard/(bookings)/bookings/_components/today/resource-board.js.map +1 -0
  93. package/dist/dashboard/(bookings)/bookings/_components/today/today-band.js +61 -0
  94. package/dist/dashboard/(bookings)/bookings/_components/today/today-band.js.map +1 -0
  95. package/dist/dashboard/(bookings)/bookings/_components/today/upcoming-band.js +113 -0
  96. package/dist/dashboard/(bookings)/bookings/_components/today/upcoming-band.js.map +1 -0
  97. package/dist/dashboard/(bookings)/bookings/_components/today/waiting-queue.js +62 -0
  98. package/dist/dashboard/(bookings)/bookings/_components/today/waiting-queue.js.map +1 -0
  99. package/dist/dashboard/(bookings)/bookings/_components/today-board.js +192 -0
  100. package/dist/dashboard/(bookings)/bookings/_components/today-board.js.map +1 -0
  101. package/dist/dashboard/(bookings)/bookings/_components/today.js +1 -0
  102. package/dist/dashboard/(bookings)/bookings/_components.js +1 -0
  103. package/dist/dashboard/(bookings)/bookings/_hooks/index.js +5 -0
  104. package/dist/dashboard/(bookings)/bookings/_hooks/index.js.map +1 -0
  105. package/dist/dashboard/(bookings)/bookings/_hooks/use-bookings-data.js +331 -0
  106. package/dist/dashboard/(bookings)/bookings/_hooks/use-bookings-data.js.map +1 -0
  107. package/dist/dashboard/(bookings)/bookings/_hooks/use-today-data.js +309 -0
  108. package/dist/dashboard/(bookings)/bookings/_hooks/use-today-data.js.map +1 -0
  109. package/dist/dashboard/(bookings)/bookings/_hooks.js +1 -0
  110. package/dist/dashboard/(bookings)/bookings/_lib/booking-link.js +13 -0
  111. package/dist/dashboard/(bookings)/bookings/_lib/booking-link.js.map +1 -0
  112. package/dist/dashboard/(bookings)/bookings/attendees/_components/attendee-cards.js +60 -0
  113. package/dist/dashboard/(bookings)/bookings/attendees/_components/attendee-cards.js.map +1 -0
  114. package/dist/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal.js +225 -0
  115. package/dist/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal.js.map +1 -0
  116. package/dist/dashboard/(bookings)/bookings/attendees/demo-data.js +195 -0
  117. package/dist/dashboard/(bookings)/bookings/attendees/demo-data.js.map +1 -0
  118. package/dist/dashboard/(bookings)/bookings/attendees/page.js +341 -0
  119. package/dist/dashboard/(bookings)/bookings/attendees/page.js.map +1 -0
  120. package/dist/dashboard/(bookings)/bookings/new/page.js +129 -0
  121. package/dist/dashboard/(bookings)/bookings/new/page.js.map +1 -0
  122. package/dist/dashboard/(bookings)/bookings/page.js +10 -0
  123. package/dist/dashboard/(bookings)/bookings/page.js.map +1 -0
  124. package/dist/dashboard/(bookings)/bookings/sessions/new/_components/save-buttons.js +36 -0
  125. package/dist/dashboard/(bookings)/bookings/sessions/new/_components/save-buttons.js.map +1 -0
  126. package/dist/dashboard/(bookings)/bookings/sessions/new/_components/session-creator.js +386 -0
  127. package/dist/dashboard/(bookings)/bookings/sessions/new/_components/session-creator.js.map +1 -0
  128. package/dist/dashboard/(bookings)/bookings/sessions/new/_lib/session-payload.js +62 -0
  129. package/dist/dashboard/(bookings)/bookings/sessions/new/_lib/session-payload.js.map +1 -0
  130. package/dist/dashboard/(bookings)/bookings/sessions/new/page.js +10 -0
  131. package/dist/dashboard/(bookings)/bookings/sessions/new/page.js.map +1 -0
  132. package/dist/dashboard/(bookings)/calendar/_components/calendar-nav.js +84 -0
  133. package/dist/dashboard/(bookings)/calendar/_components/calendar-nav.js.map +1 -0
  134. package/dist/dashboard/(bookings)/calendar/_components/calendar-range.js +84 -0
  135. package/dist/dashboard/(bookings)/calendar/_components/calendar-range.js.map +1 -0
  136. package/dist/dashboard/(bookings)/calendar/_components/day-board-view.js +279 -0
  137. package/dist/dashboard/(bookings)/calendar/_components/day-board-view.js.map +1 -0
  138. package/dist/dashboard/(bookings)/calendar/_components/event-detail-modal.js +113 -0
  139. package/dist/dashboard/(bookings)/calendar/_components/event-detail-modal.js.map +1 -0
  140. package/dist/dashboard/(bookings)/calendar/_components/format.js +22 -0
  141. package/dist/dashboard/(bookings)/calendar/_components/format.js.map +1 -0
  142. package/dist/dashboard/(bookings)/calendar/_components/month-grid.js +109 -0
  143. package/dist/dashboard/(bookings)/calendar/_components/month-grid.js.map +1 -0
  144. package/dist/dashboard/(bookings)/calendar/_components/resource-day-grid.js +325 -0
  145. package/dist/dashboard/(bookings)/calendar/_components/resource-day-grid.js.map +1 -0
  146. package/dist/dashboard/(bookings)/calendar/_components/slot-action-sheet.js +209 -0
  147. package/dist/dashboard/(bookings)/calendar/_components/slot-action-sheet.js.map +1 -0
  148. package/dist/dashboard/(bookings)/calendar/_components/use-block-drag.js +77 -0
  149. package/dist/dashboard/(bookings)/calendar/_components/use-block-drag.js.map +1 -0
  150. package/dist/dashboard/(bookings)/calendar/_components/use-calendar-nav.js +69 -0
  151. package/dist/dashboard/(bookings)/calendar/_components/use-calendar-nav.js.map +1 -0
  152. package/dist/dashboard/(bookings)/calendar/_components/week-grid.js +202 -0
  153. package/dist/dashboard/(bookings)/calendar/_components/week-grid.js.map +1 -0
  154. package/dist/dashboard/(bookings)/calendar/_components/year-grid.js +111 -0
  155. package/dist/dashboard/(bookings)/calendar/_components/year-grid.js.map +1 -0
  156. package/dist/dashboard/(bookings)/calendar/page.js +8 -0
  157. package/dist/dashboard/(bookings)/calendar/page.js.map +1 -0
  158. package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feed-modal.js +126 -0
  159. package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feed-modal.js.map +1 -0
  160. package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feeds-section.js +99 -0
  161. package/dist/dashboard/(bookings)/calendar-sync/_components/channel-feeds-section.js.map +1 -0
  162. package/dist/dashboard/(bookings)/calendar-sync/demo-data.js +64 -0
  163. package/dist/dashboard/(bookings)/calendar-sync/demo-data.js.map +1 -0
  164. package/dist/dashboard/(bookings)/calendar-sync/page.js +15 -0
  165. package/dist/dashboard/(bookings)/calendar-sync/page.js.map +1 -0
  166. package/dist/dashboard/(bookings)/check-in/page.js +252 -0
  167. package/dist/dashboard/(bookings)/check-in/page.js.map +1 -0
  168. package/dist/dashboard/(bookings)/events/[eventId]/_components/event-attendees.js +108 -0
  169. package/dist/dashboard/(bookings)/events/[eventId]/_components/event-attendees.js.map +1 -0
  170. package/dist/dashboard/(bookings)/events/[eventId]/_components/event-share.js +73 -0
  171. package/dist/dashboard/(bookings)/events/[eventId]/_components/event-share.js.map +1 -0
  172. package/dist/dashboard/(bookings)/events/[eventId]/layout.js +10 -0
  173. package/dist/dashboard/(bookings)/events/[eventId]/layout.js.map +1 -0
  174. package/dist/dashboard/(bookings)/events/[eventId]/page.js +247 -0
  175. package/dist/dashboard/(bookings)/events/[eventId]/page.js.map +1 -0
  176. package/dist/dashboard/(bookings)/events/_components/event-grid.js +44 -0
  177. package/dist/dashboard/(bookings)/events/_components/event-grid.js.map +1 -0
  178. package/dist/dashboard/(bookings)/events/_components/event-poster.js +17 -0
  179. package/dist/dashboard/(bookings)/events/_components/event-poster.js.map +1 -0
  180. package/dist/dashboard/(bookings)/events/_hooks/use-events-data.js +55 -0
  181. package/dist/dashboard/(bookings)/events/_hooks/use-events-data.js.map +1 -0
  182. package/dist/dashboard/(bookings)/events/_lib/event-facts.js +68 -0
  183. package/dist/dashboard/(bookings)/events/_lib/event-facts.js.map +1 -0
  184. package/dist/dashboard/(bookings)/events/new/_components/event-composer.js +295 -0
  185. package/dist/dashboard/(bookings)/events/new/_components/event-composer.js.map +1 -0
  186. package/dist/dashboard/(bookings)/events/new/_components/event-poster.js +65 -0
  187. package/dist/dashboard/(bookings)/events/new/_components/event-poster.js.map +1 -0
  188. package/dist/dashboard/(bookings)/events/new/_components/ticket-tiers.js +75 -0
  189. package/dist/dashboard/(bookings)/events/new/_components/ticket-tiers.js.map +1 -0
  190. package/dist/dashboard/(bookings)/events/new/page.js +10 -0
  191. package/dist/dashboard/(bookings)/events/new/page.js.map +1 -0
  192. package/dist/dashboard/(bookings)/events/page.js +214 -0
  193. package/dist/dashboard/(bookings)/events/page.js.map +1 -0
  194. package/dist/dashboard/(bookings)/resources/[resourceId]/layout.js +36 -0
  195. package/dist/dashboard/(bookings)/resources/[resourceId]/layout.js.map +1 -0
  196. package/dist/dashboard/(bookings)/resources/[resourceId]/page.js +351 -0
  197. package/dist/dashboard/(bookings)/resources/[resourceId]/page.js.map +1 -0
  198. package/dist/dashboard/(bookings)/resources/_components/block-time-modal.js +130 -0
  199. package/dist/dashboard/(bookings)/resources/_components/block-time-modal.js.map +1 -0
  200. package/dist/dashboard/(bookings)/resources/_components/category-card.js +74 -0
  201. package/dist/dashboard/(bookings)/resources/_components/category-card.js.map +1 -0
  202. package/dist/dashboard/(bookings)/resources/_components/category-form-dialog.js +197 -0
  203. package/dist/dashboard/(bookings)/resources/_components/category-form-dialog.js.map +1 -0
  204. package/dist/dashboard/(bookings)/resources/_components/day-editor.js +194 -0
  205. package/dist/dashboard/(bookings)/resources/_components/day-editor.js.map +1 -0
  206. package/dist/dashboard/(bookings)/resources/_components/group-dialog.js +170 -0
  207. package/dist/dashboard/(bookings)/resources/_components/group-dialog.js.map +1 -0
  208. package/dist/dashboard/(bookings)/resources/_components/group-header.js +90 -0
  209. package/dist/dashboard/(bookings)/resources/_components/group-header.js.map +1 -0
  210. package/dist/dashboard/(bookings)/resources/_components/index.js +22 -0
  211. package/dist/dashboard/(bookings)/resources/_components/index.js.map +1 -0
  212. package/dist/dashboard/(bookings)/resources/_components/mobile-category-form-sheet.js +256 -0
  213. package/dist/dashboard/(bookings)/resources/_components/mobile-category-form-sheet.js.map +1 -0
  214. package/dist/dashboard/(bookings)/resources/_components/resource-form.js +420 -0
  215. package/dist/dashboard/(bookings)/resources/_components/resource-form.js.map +1 -0
  216. package/dist/dashboard/(bookings)/resources/_components/resource-picker.js +144 -0
  217. package/dist/dashboard/(bookings)/resources/_components/resource-picker.js.map +1 -0
  218. package/dist/dashboard/(bookings)/resources/_components/resource-type-picker-empty.js +109 -0
  219. package/dist/dashboard/(bookings)/resources/_components/resource-type-picker-empty.js.map +1 -0
  220. package/dist/dashboard/(bookings)/resources/_components/roster-empty.js +103 -0
  221. package/dist/dashboard/(bookings)/resources/_components/roster-empty.js.map +1 -0
  222. package/dist/dashboard/(bookings)/resources/_components/roster-grid.js +160 -0
  223. package/dist/dashboard/(bookings)/resources/_components/roster-grid.js.map +1 -0
  224. package/dist/dashboard/(bookings)/resources/_components/schedule-editor.js +244 -0
  225. package/dist/dashboard/(bookings)/resources/_components/schedule-editor.js.map +1 -0
  226. package/dist/dashboard/(bookings)/resources/_components/schedule-timezone-field.js +25 -0
  227. package/dist/dashboard/(bookings)/resources/_components/schedule-timezone-field.js.map +1 -0
  228. package/dist/dashboard/(bookings)/resources/_components/solo-schedule-view.js +146 -0
  229. package/dist/dashboard/(bookings)/resources/_components/solo-schedule-view.js.map +1 -0
  230. package/dist/dashboard/(bookings)/resources/_components/team-onboarding-dialog.js +161 -0
  231. package/dist/dashboard/(bookings)/resources/_components/team-onboarding-dialog.js.map +1 -0
  232. package/dist/dashboard/(bookings)/resources/_components/week-grid.js +175 -0
  233. package/dist/dashboard/(bookings)/resources/_components/week-grid.js.map +1 -0
  234. package/dist/dashboard/(bookings)/resources/_components.js +1 -0
  235. package/dist/dashboard/(bookings)/resources/_hooks/index.js +8 -0
  236. package/dist/dashboard/(bookings)/resources/_hooks/index.js.map +1 -0
  237. package/dist/dashboard/(bookings)/resources/_hooks/use-resource-categories-data.js +86 -0
  238. package/dist/dashboard/(bookings)/resources/_hooks/use-resource-categories-data.js.map +1 -0
  239. package/dist/dashboard/(bookings)/resources/_hooks/use-roster-page.js +138 -0
  240. package/dist/dashboard/(bookings)/resources/_hooks/use-roster-page.js.map +1 -0
  241. package/dist/dashboard/(bookings)/resources/_hooks/use-roster.js +182 -0
  242. package/dist/dashboard/(bookings)/resources/_hooks/use-roster.js.map +1 -0
  243. package/dist/dashboard/(bookings)/resources/_hooks.js +1 -0
  244. package/dist/dashboard/(bookings)/resources/_lib/presets.js +147 -0
  245. package/dist/dashboard/(bookings)/resources/_lib/presets.js.map +1 -0
  246. package/dist/dashboard/(bookings)/resources/_lib/schedule-timezone.js +17 -0
  247. package/dist/dashboard/(bookings)/resources/_lib/schedule-timezone.js.map +1 -0
  248. package/dist/dashboard/(bookings)/resources/_lib/shapes.js +105 -0
  249. package/dist/dashboard/(bookings)/resources/_lib/shapes.js.map +1 -0
  250. package/dist/dashboard/(bookings)/resources/_lib/week.js +122 -0
  251. package/dist/dashboard/(bookings)/resources/_lib/week.js.map +1 -0
  252. package/dist/dashboard/(bookings)/resources/page.js +391 -0
  253. package/dist/dashboard/(bookings)/resources/page.js.map +1 -0
  254. package/dist/dashboard/(bookings)/schedule/page.js +8 -0
  255. package/dist/dashboard/(bookings)/schedule/page.js.map +1 -0
  256. package/dist/dashboard/(bookings)/today/page.js +14 -0
  257. package/dist/dashboard/(bookings)/today/page.js.map +1 -0
  258. package/dist/dashboard/(bookings)/waitlist/_components/demo-data.js +99 -0
  259. package/dist/dashboard/(bookings)/waitlist/_components/demo-data.js.map +1 -0
  260. package/dist/dashboard/(bookings)/waitlist/_components/offer-spot-modal.js +71 -0
  261. package/dist/dashboard/(bookings)/waitlist/_components/offer-spot-modal.js.map +1 -0
  262. package/dist/dashboard/(bookings)/waitlist/_components/waitlist-entry-editor.js +150 -0
  263. package/dist/dashboard/(bookings)/waitlist/_components/waitlist-entry-editor.js.map +1 -0
  264. package/dist/dashboard/(bookings)/waitlist/new/page.js +59 -0
  265. package/dist/dashboard/(bookings)/waitlist/new/page.js.map +1 -0
  266. package/dist/dashboard/(bookings)/waitlist/page.js +317 -0
  267. package/dist/dashboard/(bookings)/waitlist/page.js.map +1 -0
  268. package/dist/index.js +1 -0
  269. package/dist/index.js.map +1 -0
  270. package/package.json +60 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/team-onboarding-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { X, Users, Loader2, ArrowRight } from 'lucide-react';\nimport { KIND_OPTIONS } from '@withpotter/lib/resource-types';\nimport type { ResourceCategoryKind } from '@withpotter/lib/resource-types';\n\ninterface TeamOnboardingDialogProps {\n open: boolean;\n onClose: () => void;\n onComplete: (data: {\n label: string;\n labelPlural: string;\n kind: ResourceCategoryKind;\n icon: string;\n }) => Promise<void>;\n}\n\nexport function TeamOnboardingDialog({\n open,\n onClose,\n onComplete,\n}: TeamOnboardingDialogProps) {\n const [step, setStep] = useState<'intro' | 'setup'>('intro');\n const [kind, setKind] = useState<ResourceCategoryKind>('person');\n const [label, setLabel] = useState('');\n const [labelPlural, setLabelPlural] = useState('');\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Auto-suggest plural when user types singular\n const handleLabelChange = (value: string) => {\n setLabel(value);\n if (\n !labelPlural ||\n labelPlural === label + 's' ||\n labelPlural === label + 'es'\n ) {\n setLabelPlural(\n value.endsWith('s') || value.endsWith('sh') || value.endsWith('ch')\n ? value + 'es'\n : value + 's',\n );\n }\n };\n\n const handleComplete = async () => {\n if (!label.trim()) return;\n setSaving(true);\n setError(null);\n try {\n const kindOption = KIND_OPTIONS.find((k) => k.value === kind);\n await onComplete({\n label: label.trim(),\n labelPlural: labelPlural.trim() || label.trim() + 's',\n kind,\n icon: kindOption?.emoji || '👤',\n });\n } catch {\n setError('Something went wrong. Please try again.');\n setSaving(false);\n }\n };\n\n const reset = () => {\n setStep('intro');\n setKind('person');\n setLabel('');\n setLabelPlural('');\n setSaving(false);\n setError(null);\n };\n\n const handleClose = () => {\n reset();\n onClose();\n };\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"absolute inset-0 bg-black/40\" onClick={handleClose} />\n <div className=\"relative bg-[var(--bg-base)] rounded-md shadow-xl w-full max-w-lg mx-4\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-[var(--border-default)]\">\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">\n {step === 'intro' ? 'Growing your team?' : 'Set up your team'}\n </h2>\n <button\n aria-label=\"Close\"\n onClick={handleClose}\n className=\"p-1 text-[var(--text-tertiary)] hover:text-[var(--text-primary)] cursor-pointer\"\n >\n <X className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"px-6 py-5\">\n {step === 'intro' ? (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-center w-16 h-16 mx-auto rounded-full bg-[var(--accent-secondary)]\">\n <Users className=\"w-8 h-8 text-brand-500\" />\n </div>\n <div className=\"text-center space-y-2\">\n <p className=\"text-sm text-[var(--text-secondary)] leading-relaxed\">\n Right now, customers book directly with you. Adding team\n members lets you organize providers into groups (e.g.\n &ldquo;Stylists&rdquo;, &ldquo;Therapists&rdquo;) with\n individual schedules.\n </p>\n <p className=\"text-sm text-[var(--text-secondary)] leading-relaxed\">\n Your existing schedule and bookings will be preserved &mdash;\n you&rsquo;ll just be organizing them under a team.\n </p>\n </div>\n </div>\n ) : (\n <div className=\"space-y-5\">\n {/* Kind picker */}\n <div>\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\n What type of team?\n </label>\n <div className=\"grid grid-cols-2 gap-2\">\n {KIND_OPTIONS.map((option) => (\n <button\n key={option.value}\n onClick={() => setKind(option.value)}\n className={`flex items-center gap-3 p-3 rounded-md border text-left cursor-pointer transition-colors ${\n kind === option.value\n ? 'border-brand-500 bg-[var(--accent-secondary)] text-brand-700'\n : 'border-[var(--border-default)] hover:bg-[var(--interactive-hover)] text-[var(--text-secondary)]'\n }`}\n >\n <span className=\"text-xl\">{option.emoji}</span>\n <div>\n <div className=\"text-sm font-medium\">\n {option.label}\n </div>\n <div className=\"text-xs text-[var(--text-tertiary)]\">\n {option.description}\n </div>\n </div>\n </button>\n ))}\n </div>\n </div>\n\n {/* Labels */}\n <div>\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\n What do you call them?\n </label>\n <p className=\"text-xs text-[var(--text-tertiary)] mb-2\">\n e.g. &ldquo;Stylist&rdquo; / &ldquo;Stylists&rdquo;,\n &ldquo;Room&rdquo; / &ldquo;Rooms&rdquo;\n </p>\n <div className=\"grid grid-cols-2 gap-3\">\n <input\n type=\"text\"\n value={label}\n onChange={(e) => handleLabelChange(e.target.value)}\n placeholder=\"Singular (e.g. Stylist)\"\n className=\"w-full px-3 py-2 text-sm border border-[var(--border-default)] rounded-md bg-[var(--bg-base)] text-[var(--text-primary)] placeholder:text-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-brand-500/30 focus:border-brand-500\"\n />\n <input\n type=\"text\"\n value={labelPlural}\n onChange={(e) => setLabelPlural(e.target.value)}\n placeholder=\"Plural (e.g. Stylists)\"\n className=\"w-full px-3 py-2 text-sm border border-[var(--border-default)] rounded-md bg-[var(--bg-base)] text-[var(--text-primary)] placeholder:text-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-brand-500/30 focus:border-brand-500\"\n />\n </div>\n </div>\n\n {error && (\n <div className=\"text-sm text-[var(--error)]\">{error}</div>\n )}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-[var(--border-default)]\">\n <button\n onClick={handleClose}\n className=\"px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)] cursor-pointer\"\n >\n Cancel\n </button>\n {step === 'intro' ? (\n <button\n onClick={() => setStep('setup')}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] bg-brand-500 rounded-md hover:bg-brand-600 cursor-pointer transition-colors\"\n >\n Let&rsquo;s set it up\n <ArrowRight className=\"w-4 h-4\" />\n </button>\n ) : (\n <button\n onClick={handleComplete}\n disabled={!label.trim() || saving}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-[var(--text-inverse)] bg-brand-500 rounded-md hover:bg-brand-600 cursor-pointer transition-colors disabled:opacity-50\"\n >\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : null}\n {saving ? 'Setting up...' : 'Create Team'}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,175 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Fragment } from "react";
4
+ import { ChevronLeft, ChevronRight } from "lucide-react";
5
+ import { Button } from "@withpotter/ui-kit/button";
6
+ import { TableShell, Th, TableRow } from "@withpotter/ui-kit/table-shell";
7
+ import { IdentityCell } from "@withpotter/ui-kit/table-cells";
8
+ import { cn } from "@withpotter/lib/utils";
9
+ import { GroupBand } from "./group-header";
10
+ import { availabilityWords } from "../_lib/shapes";
11
+ import {
12
+ DAY_SHORT,
13
+ WEEK_DAYS,
14
+ addDays,
15
+ blocksOn,
16
+ businessSlots,
17
+ daySlots,
18
+ fmtSlots,
19
+ isoDay,
20
+ startOfWeek,
21
+ weekLabel
22
+ } from "../_lib/week";
23
+ function WeekGrid({
24
+ sections,
25
+ showBands,
26
+ usage,
27
+ hours,
28
+ blocks,
29
+ weekStart,
30
+ showGroup,
31
+ locations,
32
+ onAddTo,
33
+ onRenameGroup,
34
+ onWeekChange,
35
+ onEditDay
36
+ }) {
37
+ const today = isoDay(/* @__PURE__ */ new Date());
38
+ const dates = WEEK_DAYS.map((_, index) => addDays(weekStart, index));
39
+ const thisWeek = isoDay(startOfWeek(/* @__PURE__ */ new Date())) === isoDay(weekStart);
40
+ return /* @__PURE__ */ jsxs("div", { children: [
41
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 border-b border-[var(--border-subtle)] px-3 py-2", children: [
42
+ /* @__PURE__ */ jsx(
43
+ Button,
44
+ {
45
+ size: "icon",
46
+ variant: "ghost",
47
+ "aria-label": "Previous week",
48
+ onClick: () => onWeekChange(addDays(weekStart, -7)),
49
+ children: /* @__PURE__ */ jsx(ChevronLeft, {})
50
+ }
51
+ ),
52
+ /* @__PURE__ */ jsx("span", { className: "min-w-[9rem] text-center text-sm font-medium text-[var(--text-primary)] tabular-nums", children: weekLabel(weekStart) }),
53
+ /* @__PURE__ */ jsx(
54
+ Button,
55
+ {
56
+ size: "icon",
57
+ variant: "ghost",
58
+ "aria-label": "Next week",
59
+ onClick: () => onWeekChange(addDays(weekStart, 7)),
60
+ children: /* @__PURE__ */ jsx(ChevronRight, {})
61
+ }
62
+ ),
63
+ !thisWeek && /* @__PURE__ */ jsx(
64
+ Button,
65
+ {
66
+ size: "md",
67
+ variant: "ghost",
68
+ onClick: () => onWeekChange(startOfWeek(/* @__PURE__ */ new Date())),
69
+ children: "This week"
70
+ }
71
+ )
72
+ ] }),
73
+ /* @__PURE__ */ jsx(
74
+ TableShell,
75
+ {
76
+ bare: true,
77
+ fixed: true,
78
+ minWidth: 860,
79
+ head: /* @__PURE__ */ jsxs("tr", { children: [
80
+ /* @__PURE__ */ jsx(Th, { className: "w-56", children: "Name" }),
81
+ dates.map((date) => /* @__PURE__ */ jsxs(
82
+ Th,
83
+ {
84
+ align: "center",
85
+ className: cn(isoDay(date) === today && "text-brand-600"),
86
+ children: [
87
+ DAY_SHORT[date.getDay()],
88
+ " ",
89
+ date.getDate()
90
+ ]
91
+ },
92
+ date.toISOString()
93
+ ))
94
+ ] }),
95
+ children: sections.map(({ category, rows }) => /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ showBands && /* @__PURE__ */ jsx(
97
+ GroupBand,
98
+ {
99
+ span: 8,
100
+ category,
101
+ count: rows.length,
102
+ usage: usage.find((u) => u.categoryId === category?.id),
103
+ onAdd: onAddTo,
104
+ onRename: onRenameGroup
105
+ }
106
+ ),
107
+ rows.map((row) => /* @__PURE__ */ jsxs(TableRow, { children: [
108
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(
109
+ IdentityCell,
110
+ {
111
+ name: row.name,
112
+ size: "sm",
113
+ image: row.imageUrl ?? void 0,
114
+ avatarSeed: row.name,
115
+ secondary: [
116
+ showGroup ? row.category?.label : null,
117
+ locations.length ? locations.find((l) => l.id === row.locationId)?.name ?? "Main" : null
118
+ ].filter(Boolean).join(" \xB7 ") || void 0
119
+ }
120
+ ) }),
121
+ dates.map((date) => /* @__PURE__ */ jsx(
122
+ DayCell,
123
+ {
124
+ row,
125
+ date,
126
+ hours,
127
+ blocks,
128
+ onClick: () => onEditDay(row, date)
129
+ },
130
+ date.toISOString()
131
+ ))
132
+ ] }, row.id))
133
+ ] }, category?.id ?? "ungrouped"))
134
+ }
135
+ )
136
+ ] });
137
+ }
138
+ function DayCell({
139
+ row,
140
+ date,
141
+ hours,
142
+ blocks,
143
+ onClick
144
+ }) {
145
+ const iso = isoDay(date);
146
+ const dow = date.getDay();
147
+ const own = daySlots(row.schedule, dow);
148
+ const inherited = own === void 0;
149
+ const slots = inherited ? businessSlots(hours, dow) : own;
150
+ const off = blocksOn(blocks, row.id, iso);
151
+ const inactive = row.status !== "active";
152
+ const words = availabilityWords(row.category?.kind);
153
+ const offReason = off.map((b) => b.title?.trim()).filter(Boolean).join(" \xB7 ");
154
+ return /* @__PURE__ */ jsx("td", { className: "p-1 text-center", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
155
+ "button",
156
+ {
157
+ type: "button",
158
+ onClick,
159
+ "aria-label": `${row.name}, ${DAY_SHORT[dow]} ${date.getDate()}${offReason ? `, off: ${offReason}` : ""}`,
160
+ title: offReason || void 0,
161
+ className: cn(
162
+ "w-full rounded-lg px-2 py-2 text-xs tabular-nums transition-colors hover:bg-[var(--interactive-hover)]",
163
+ (words.byTheNight || slots) && !inactive ? inherited ? "bg-[var(--bg-muted)] text-[var(--text-secondary)]" : "bg-[var(--accent-secondary)] text-[var(--accent-secondary-ink)]" : "text-[var(--text-muted)]"
164
+ ),
165
+ children: inactive ? "\u2014" : off.length ? /* @__PURE__ */ jsxs("span", { className: "block", children: [
166
+ /* @__PURE__ */ jsx("span", { className: "line-through decoration-[var(--text-muted)]", children: words.byTheNight ? "off" : slots ? fmtSlots(slots) : "off" }),
167
+ offReason && /* @__PURE__ */ jsx("span", { className: "mt-1 block truncate text-2xs font-normal opacity-80", children: offReason })
168
+ ] }) : words.byTheNight ? words.open : slots ? fmtSlots(slots) : "\u2014"
169
+ }
170
+ ) });
171
+ }
172
+ export {
173
+ WeekGrid
174
+ };
175
+ //# sourceMappingURL=week-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_components/week-grid.tsx"],"sourcesContent":["'use client';\n\nimport { Fragment } from 'react';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { TableShell, Th, TableRow } from '@withpotter/ui-kit/table-shell';\nimport { IdentityCell } from '@withpotter/ui-kit/table-cells';\nimport { cn } from '@withpotter/lib/utils';\nimport type { WeeklyHours } from '@withpotter/hooks/use-hours-data';\nimport type { CalendarEventItem } from '@withpotter/lib/api/types';\nimport type { CategoryUsage, ResourceCategory } from '@withpotter/lib/resource-types';\nimport type { RosterSection } from '../_hooks/use-roster-page';\nimport type { RosterRow } from '../_hooks/use-roster';\nimport { GroupBand } from './group-header';\nimport { availabilityWords } from '../_lib/shapes';\nimport {\n DAY_SHORT,\n WEEK_DAYS,\n addDays,\n blocksOn,\n businessSlots,\n daySlots,\n fmtSlots,\n isoDay,\n startOfWeek,\n weekLabel,\n} from '../_lib/week';\n\n/**\n * The rota: who is on, which day, and what is already off the board.\n *\n * The same set the list draws, turned ninety degrees. \"Why can nobody book\n * Tuesday\" was four screens — the business's hours, the person's own week, the\n * day blocked off, and the record two levels in — and every one of them held a\n * quarter of the answer. Here the four are one picture, and the cell you are\n * looking at is the cell you press to change it.\n */\nexport function WeekGrid({\n sections,\n showBands,\n usage,\n hours,\n blocks,\n weekStart,\n showGroup,\n locations,\n onAddTo,\n onRenameGroup,\n onWeekChange,\n onEditDay,\n}: {\n /** The groups, in order. One navigator and one grid draw them all. */\n sections: RosterSection[];\n showBands: boolean;\n usage: CategoryUsage[];\n hours: WeeklyHours;\n blocks: CalendarEventItem[];\n weekStart: Date;\n /** Only when there is more than one, exactly as the list column is. */\n showGroup: boolean;\n /** Named branches, when there is more than one. */\n locations: Array<{ id: string; name: string }>;\n onAddTo: (category: ResourceCategory) => void;\n onRenameGroup: (category: ResourceCategory) => void;\n onWeekChange: (next: Date) => void;\n onEditDay: (row: RosterRow, date: Date) => void;\n}) {\n const today = isoDay(new Date());\n const dates = WEEK_DAYS.map((_, index) => addDays(weekStart, index));\n const thisWeek = isoDay(startOfWeek(new Date())) === isoDay(weekStart);\n\n return (\n <div>\n <div className=\"flex items-center gap-1 border-b border-[var(--border-subtle)] px-3 py-2\">\n <Button\n size=\"icon\"\n variant=\"ghost\"\n aria-label=\"Previous week\"\n onClick={() => onWeekChange(addDays(weekStart, -7))}\n >\n <ChevronLeft />\n </Button>\n <span className=\"min-w-[9rem] text-center text-sm font-medium text-[var(--text-primary)] tabular-nums\">\n {weekLabel(weekStart)}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n aria-label=\"Next week\"\n onClick={() => onWeekChange(addDays(weekStart, 7))}\n >\n <ChevronRight />\n </Button>\n {!thisWeek && (\n <Button\n size=\"md\"\n variant=\"ghost\"\n onClick={() => onWeekChange(startOfWeek(new Date()))}\n >\n This week\n </Button>\n )}\n </div>\n\n <TableShell\n bare\n fixed\n minWidth={860}\n head={\n <tr>\n <Th className=\"w-56\">Name</Th>\n {dates.map((date) => (\n <Th\n key={date.toISOString()}\n align=\"center\"\n className={cn(isoDay(date) === today && 'text-brand-600')}\n >\n {DAY_SHORT[date.getDay()]} {date.getDate()}\n </Th>\n ))}\n </tr>\n }\n >\n {sections.map(({ category, rows }) => (\n <Fragment key={category?.id ?? 'ungrouped'}>\n {showBands && (\n <GroupBand\n span={8}\n category={category}\n count={rows.length}\n usage={usage.find((u) => u.categoryId === category?.id)}\n onAdd={onAddTo}\n onRename={onRenameGroup}\n />\n )}\n {rows.map((row) => (\n <TableRow key={row.id}>\n <td>\n <IdentityCell\n name={row.name}\n size=\"sm\"\n image={row.imageUrl ?? undefined}\n avatarSeed={row.name}\n secondary={\n [\n showGroup ? row.category?.label : null,\n locations.length\n ? (locations.find((l) => l.id === row.locationId)\n ?.name ?? 'Main')\n : null,\n ]\n .filter(Boolean)\n .join(' · ') || undefined\n }\n />\n </td>\n {dates.map((date) => (\n <DayCell\n key={date.toISOString()}\n row={row}\n date={date}\n hours={hours}\n blocks={blocks}\n onClick={() => onEditDay(row, date)}\n />\n ))}\n </TableRow>\n ))}\n </Fragment>\n ))}\n </TableShell>\n </div>\n );\n}\n\nfunction DayCell({\n row,\n date,\n hours,\n blocks,\n onClick,\n}: {\n row: RosterRow;\n date: Date;\n hours: WeeklyHours;\n blocks: CalendarEventItem[];\n onClick: () => void;\n}) {\n const iso = isoDay(date);\n const dow = date.getDay();\n const own = daySlots(row.schedule, dow);\n const inherited = own === undefined;\n const slots = inherited ? businessSlots(hours, dow) : own;\n const off = blocksOn(blocks, row.id, iso);\n const inactive = row.status !== 'active';\n const words = availabilityWords(row.category?.kind);\n\n /**\n * WHY IT IS OFF, on the cell that says it is off.\n *\n * The reason is typed into a field whose hint reads \"Shown to you, never to\n * a customer\", and it was shown to nobody: it is saved as the block's title,\n * the day editor re-seeds from it when you open that day again, and the\n * grid — the only place the block is visible at all — drew a struck-through\n * time and stopped. A merchant looking at a week of crossings-out could see\n * that something was off and never which of them was the holiday.\n *\n * Titles are joined when a day carries more than one block, because two\n * halves off for two different reasons is a real day and picking one of them\n * to show would be a guess.\n */\n const offReason = off\n .map((b) => b.title?.trim())\n .filter(Boolean)\n .join(' · ');\n\n return (\n <td className=\"p-1 text-center\" onClick={(e) => e.stopPropagation()}>\n {/* A pressable surface, not a button control: the cell IS the shift. */}\n <button\n type=\"button\"\n onClick={onClick}\n // The reason rides on the accessible name too: the line below is\n // clipped to the column, and this is the whole of it.\n aria-label={`${row.name}, ${DAY_SHORT[dow]} ${date.getDate()}${\n offReason ? `, off: ${offReason}` : ''\n }`}\n title={offReason || undefined}\n className={cn(\n 'w-full rounded-lg px-2 py-2 text-xs tabular-nums transition-colors hover:bg-[var(--interactive-hover)]',\n (words.byTheNight || slots) && !inactive\n ? inherited\n ? 'bg-[var(--bg-muted)] text-[var(--text-secondary)]'\n : 'bg-[var(--accent-secondary)] text-[var(--accent-secondary-ink)]'\n : 'text-[var(--text-muted)]',\n )}\n >\n {inactive ? (\n '—'\n ) : off.length ? (\n <span className=\"block\">\n <span className=\"line-through decoration-[var(--text-muted)]\">\n {words.byTheNight ? 'off' : slots ? fmtSlots(slots) : 'off'}\n </span>\n {offReason && (\n <span className=\"mt-1 block truncate text-2xs font-normal opacity-80\">\n {offReason}\n </span>\n )}\n </span>\n ) : words.byTheNight ? (\n words.open\n ) : slots ? (\n fmtSlots(slots)\n ) : (\n '—'\n )}\n </button>\n </td>\n );\n}\n"],"mappings":";AAyEM,SAOI,KAPJ;AAvEN,SAAS,gBAAgB;AACzB,SAAS,aAAa,oBAAoB;AAC1C,SAAS,cAAc;AACvB,SAAS,YAAY,IAAI,gBAAgB;AACzC,SAAS,oBAAoB;AAC7B,SAAS,UAAU;AAMnB,SAAS,iBAAiB;AAC1B,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAgBG;AACD,QAAM,QAAQ,OAAO,oBAAI,KAAK,CAAC;AAC/B,QAAM,QAAQ,UAAU,IAAI,CAAC,GAAG,UAAU,QAAQ,WAAW,KAAK,CAAC;AACnE,QAAM,WAAW,OAAO,YAAY,oBAAI,KAAK,CAAC,CAAC,MAAM,OAAO,SAAS;AAErE,SACE,qBAAC,SACC;AAAA,yBAAC,SAAI,WAAU,4EACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,cAAW;AAAA,UACX,SAAS,MAAM,aAAa,QAAQ,WAAW,EAAE,CAAC;AAAA,UAElD,8BAAC,eAAY;AAAA;AAAA,MACf;AAAA,MACA,oBAAC,UAAK,WAAU,wFACb,oBAAU,SAAS,GACtB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,cAAW;AAAA,UACX,SAAS,MAAM,aAAa,QAAQ,WAAW,CAAC,CAAC;AAAA,UAEjD,8BAAC,gBAAa;AAAA;AAAA,MAChB;AAAA,MACC,CAAC,YACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,aAAa,YAAY,oBAAI,KAAK,CAAC,CAAC;AAAA,UACpD;AAAA;AAAA,MAED;AAAA,OAEJ;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAI;AAAA,QACJ,OAAK;AAAA,QACL,UAAU;AAAA,QACV,MACE,qBAAC,QACC;AAAA,8BAAC,MAAG,WAAU,QAAO,kBAAI;AAAA,UACxB,MAAM,IAAI,CAAC,SACV;AAAA,YAAC;AAAA;AAAA,cAEC,OAAM;AAAA,cACN,WAAW,GAAG,OAAO,IAAI,MAAM,SAAS,gBAAgB;AAAA,cAEvD;AAAA,0BAAU,KAAK,OAAO,CAAC;AAAA,gBAAE;AAAA,gBAAE,KAAK,QAAQ;AAAA;AAAA;AAAA,YAJpC,KAAK,YAAY;AAAA,UAKxB,CACD;AAAA,WACH;AAAA,QAGD,mBAAS,IAAI,CAAC,EAAE,UAAU,KAAK,MAC9B,qBAAC,YACE;AAAA,uBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN;AAAA,cACA,OAAO,KAAK;AAAA,cACZ,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,eAAe,UAAU,EAAE;AAAA,cACtD,OAAO;AAAA,cACP,UAAU;AAAA;AAAA,UACZ;AAAA,UAED,KAAK,IAAI,CAAC,QACT,qBAAC,YACC;AAAA,gCAAC,QACC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,IAAI;AAAA,gBACV,MAAK;AAAA,gBACL,OAAO,IAAI,YAAY;AAAA,gBACvB,YAAY,IAAI;AAAA,gBAChB,WACE;AAAA,kBACE,YAAY,IAAI,UAAU,QAAQ;AAAA,kBAClC,UAAU,SACL,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,UAAU,GAC1C,QAAQ,SACZ;AAAA,gBACN,EACG,OAAO,OAAO,EACd,KAAK,QAAK,KAAK;AAAA;AAAA,YAEtB,GACF;AAAA,YACC,MAAM,IAAI,CAAC,SACV;AAAA,cAAC;AAAA;AAAA,gBAEC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,SAAS,MAAM,UAAU,KAAK,IAAI;AAAA;AAAA,cAL7B,KAAK,YAAY;AAAA,YAMxB,CACD;AAAA,eA7BY,IAAI,EA8BnB,CACD;AAAA,aA3CY,UAAU,MAAM,WA4C/B,CACD;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,SAAS,QAAQ;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,MAAM,OAAO,IAAI;AACvB,QAAM,MAAM,KAAK,OAAO;AACxB,QAAM,MAAM,SAAS,IAAI,UAAU,GAAG;AACtC,QAAM,YAAY,QAAQ;AAC1B,QAAM,QAAQ,YAAY,cAAc,OAAO,GAAG,IAAI;AACtD,QAAM,MAAM,SAAS,QAAQ,IAAI,IAAI,GAAG;AACxC,QAAM,WAAW,IAAI,WAAW;AAChC,QAAM,QAAQ,kBAAkB,IAAI,UAAU,IAAI;AAgBlD,QAAM,YAAY,IACf,IAAI,CAAC,MAAM,EAAE,OAAO,KAAK,CAAC,EAC1B,OAAO,OAAO,EACd,KAAK,QAAK;AAEb,SACE,oBAAC,QAAG,WAAU,mBAAkB,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAEhE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MAGA,cAAY,GAAG,IAAI,IAAI,KAAK,UAAU,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,GAC1D,YAAY,UAAU,SAAS,KAAK,EACtC;AAAA,MACA,OAAO,aAAa;AAAA,MACpB,WAAW;AAAA,QACT;AAAA,SACC,MAAM,cAAc,UAAU,CAAC,WAC5B,YACE,sDACA,oEACF;AAAA,MACN;AAAA,MAEC,qBACC,WACE,IAAI,SACN,qBAAC,UAAK,WAAU,SACd;AAAA,4BAAC,UAAK,WAAU,+CACb,gBAAM,aAAa,QAAQ,QAAQ,SAAS,KAAK,IAAI,OACxD;AAAA,QACC,aACC,oBAAC,UAAK,WAAU,uDACb,qBACH;AAAA,SAEJ,IACE,MAAM,aACR,MAAM,OACJ,QACF,SAAS,KAAK,IAEd;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":[]}
@@ -0,0 +1 @@
1
+ export * from './_components/index.js';
@@ -0,0 +1,8 @@
1
+ import { useRoster, useTimeOff } from "./use-roster";
2
+ import { useRosterPage } from "./use-roster-page";
3
+ export {
4
+ useRoster,
5
+ useRosterPage,
6
+ useTimeOff
7
+ };
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_hooks/index.ts"],"sourcesContent":["export { useRoster, useTimeOff, type RosterRow } from './use-roster';\nexport { useRosterPage, type View } from './use-roster-page';\n"],"mappings":"AAAA,SAAS,WAAW,kBAAkC;AACtD,SAAS,qBAAgC;","names":[]}
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { useState, useCallback } from "react";
3
+ import { useAuth } from "@withpotter/lib/auth-context";
4
+ import { resourceCategoriesApi, resourcesApi } from "@withpotter/lib/api";
5
+ import { useApiQuery } from "@withpotter/hooks/use-api-query";
6
+ function useResourceCategoriesData() {
7
+ const { tenant } = useAuth();
8
+ const [showCreateDialog, setShowCreateDialog] = useState(false);
9
+ const [editingCategory, setEditingCategory] = useState(null);
10
+ const {
11
+ data: categoriesRaw,
12
+ isLoading: loading,
13
+ error: queryError,
14
+ refetch: loadCategories
15
+ } = useApiQuery(
16
+ ["resource-categories"],
17
+ async (slug) => {
18
+ const cats = await resourceCategoriesApi.list(slug);
19
+ const withCounts = await Promise.all(
20
+ cats.map(async (cat) => {
21
+ try {
22
+ const res = await resourcesApi.listFull(slug, {
23
+ categoryId: cat.id
24
+ });
25
+ return {
26
+ ...cat,
27
+ resourceCount: res.total ?? res.data?.length ?? 0
28
+ };
29
+ } catch {
30
+ return { ...cat, resourceCount: 0 };
31
+ }
32
+ })
33
+ );
34
+ return withCounts;
35
+ }
36
+ );
37
+ const categories = categoriesRaw ?? [];
38
+ const error = queryError?.message ?? null;
39
+ const notifySidebar = () => window.dispatchEvent(new Event("resource-categories-changed"));
40
+ const createCategory = useCallback(
41
+ async (data) => {
42
+ if (!tenant?.slug) return;
43
+ await resourceCategoriesApi.create(tenant.slug, data);
44
+ await loadCategories();
45
+ setShowCreateDialog(false);
46
+ notifySidebar();
47
+ },
48
+ [tenant?.slug, loadCategories]
49
+ );
50
+ const updateCategory = useCallback(
51
+ async (id, data) => {
52
+ if (!tenant?.slug) return;
53
+ await resourceCategoriesApi.update(tenant.slug, id, data);
54
+ await loadCategories();
55
+ setEditingCategory(null);
56
+ notifySidebar();
57
+ },
58
+ [tenant?.slug, loadCategories]
59
+ );
60
+ const deleteCategory = useCallback(
61
+ async (id) => {
62
+ if (!tenant?.slug) return;
63
+ await resourceCategoriesApi.delete(tenant.slug, id);
64
+ await loadCategories();
65
+ notifySidebar();
66
+ },
67
+ [tenant?.slug, loadCategories]
68
+ );
69
+ return {
70
+ categories,
71
+ loading,
72
+ error,
73
+ showCreateDialog,
74
+ setShowCreateDialog,
75
+ editingCategory,
76
+ setEditingCategory,
77
+ loadCategories,
78
+ createCategory,
79
+ updateCategory,
80
+ deleteCategory
81
+ };
82
+ }
83
+ export {
84
+ useResourceCategoriesData
85
+ };
86
+ //# sourceMappingURL=use-resource-categories-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_hooks/use-resource-categories-data.ts"],"sourcesContent":["'use client';\n\nimport { useState, useCallback } from 'react';\nimport { useAuth } from '@withpotter/lib/auth-context';\nimport { resourceCategoriesApi, resourcesApi } from '@withpotter/lib/api';\nimport type {\n ResourceCategory,\n CreateResourceCategoryInput,\n UpdateResourceCategoryInput,\n} from '@withpotter/lib/resource-types';\nimport { useApiQuery } from '@withpotter/hooks/use-api-query';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ninterface CategoryWithCount extends ResourceCategory {\n resourceCount: number;\n}\n\n// ─── Hook ────────────────────────────────────────────────────────────────────\n\nexport function useResourceCategoriesData() {\n const { tenant } = useAuth();\n const [showCreateDialog, setShowCreateDialog] = useState(false);\n const [editingCategory, setEditingCategory] =\n useState<ResourceCategory | null>(null);\n\n const {\n data: categoriesRaw,\n isLoading: loading,\n error: queryError,\n refetch: loadCategories,\n } = useApiQuery<CategoryWithCount[]>(\n ['resource-categories'],\n async (slug) => {\n const cats = await resourceCategoriesApi.list(slug);\n const withCounts: CategoryWithCount[] = await Promise.all(\n cats.map(async (cat) => {\n try {\n const res = await resourcesApi.listFull(slug, {\n categoryId: cat.id,\n });\n return {\n ...cat,\n resourceCount: res.total ?? res.data?.length ?? 0,\n };\n } catch {\n return { ...cat, resourceCount: 0 };\n }\n }),\n );\n return withCounts;\n },\n );\n\n const categories = categoriesRaw ?? [];\n const error = queryError?.message ?? null;\n\n const notifySidebar = () =>\n window.dispatchEvent(new Event('resource-categories-changed'));\n\n const createCategory = useCallback(\n async (data: CreateResourceCategoryInput) => {\n if (!tenant?.slug) return;\n await resourceCategoriesApi.create(tenant.slug, data);\n await loadCategories();\n setShowCreateDialog(false);\n notifySidebar();\n },\n [tenant?.slug, loadCategories],\n );\n\n const updateCategory = useCallback(\n async (id: string, data: UpdateResourceCategoryInput) => {\n if (!tenant?.slug) return;\n await resourceCategoriesApi.update(tenant.slug, id, data);\n await loadCategories();\n setEditingCategory(null);\n notifySidebar();\n },\n [tenant?.slug, loadCategories],\n );\n\n const deleteCategory = useCallback(\n async (id: string) => {\n if (!tenant?.slug) return;\n await resourceCategoriesApi.delete(tenant.slug, id);\n await loadCategories();\n notifySidebar();\n },\n [tenant?.slug, loadCategories],\n );\n\n return {\n categories,\n loading,\n error,\n showCreateDialog,\n setShowCreateDialog,\n editingCategory,\n setEditingCategory,\n loadCategories,\n createCategory,\n updateCategory,\n deleteCategory,\n };\n}\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AACtC,SAAS,eAAe;AACxB,SAAS,uBAAuB,oBAAoB;AAMpD,SAAS,mBAAmB;AAUrB,SAAS,4BAA4B;AAC1C,QAAM,EAAE,OAAO,IAAI,QAAQ;AAC3B,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAC9D,QAAM,CAAC,iBAAiB,kBAAkB,IACxC,SAAkC,IAAI;AAExC,QAAM;AAAA,IACJ,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,EACX,IAAI;AAAA,IACF,CAAC,qBAAqB;AAAA,IACtB,OAAO,SAAS;AACd,YAAM,OAAO,MAAM,sBAAsB,KAAK,IAAI;AAClD,YAAM,aAAkC,MAAM,QAAQ;AAAA,QACpD,KAAK,IAAI,OAAO,QAAQ;AACtB,cAAI;AACF,kBAAM,MAAM,MAAM,aAAa,SAAS,MAAM;AAAA,cAC5C,YAAY,IAAI;AAAA,YAClB,CAAC;AACD,mBAAO;AAAA,cACL,GAAG;AAAA,cACH,eAAe,IAAI,SAAS,IAAI,MAAM,UAAU;AAAA,YAClD;AAAA,UACF,QAAQ;AACN,mBAAO,EAAE,GAAG,KAAK,eAAe,EAAE;AAAA,UACpC;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,aAAa,iBAAiB,CAAC;AACrC,QAAM,QAAQ,YAAY,WAAW;AAErC,QAAM,gBAAgB,MACpB,OAAO,cAAc,IAAI,MAAM,6BAA6B,CAAC;AAE/D,QAAM,iBAAiB;AAAA,IACrB,OAAO,SAAsC;AAC3C,UAAI,CAAC,QAAQ,KAAM;AACnB,YAAM,sBAAsB,OAAO,OAAO,MAAM,IAAI;AACpD,YAAM,eAAe;AACrB,0BAAoB,KAAK;AACzB,oBAAc;AAAA,IAChB;AAAA,IACA,CAAC,QAAQ,MAAM,cAAc;AAAA,EAC/B;AAEA,QAAM,iBAAiB;AAAA,IACrB,OAAO,IAAY,SAAsC;AACvD,UAAI,CAAC,QAAQ,KAAM;AACnB,YAAM,sBAAsB,OAAO,OAAO,MAAM,IAAI,IAAI;AACxD,YAAM,eAAe;AACrB,yBAAmB,IAAI;AACvB,oBAAc;AAAA,IAChB;AAAA,IACA,CAAC,QAAQ,MAAM,cAAc;AAAA,EAC/B;AAEA,QAAM,iBAAiB;AAAA,IACrB,OAAO,OAAe;AACpB,UAAI,CAAC,QAAQ,KAAM;AACnB,YAAM,sBAAsB,OAAO,OAAO,MAAM,EAAE;AAClD,YAAM,eAAe;AACrB,oBAAc;AAAA,IAChB;AAAA,IACA,CAAC,QAAQ,MAAM,cAAc;AAAA,EAC/B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,138 @@
1
+ "use client";
2
+ import { useMemo, useState } from "react";
3
+ import { useSearchParams } from "next/navigation";
4
+ import { useConfirm } from "@withpotter/ui-kit/confirm-dialog";
5
+ import { rosterLabel } from "@withpotter/lib/roster-label";
6
+ import { useTimeOff } from "./use-roster";
7
+ import { addDays, isoDay, startOfWeek } from "../_lib/week";
8
+ function useRosterPage(roster, defaultTitle, generic) {
9
+ const searchParams = useSearchParams();
10
+ const confirm = useConfirm();
11
+ const { categories, rows, loading, error, deleteResource, blockTime } = roster;
12
+ const groupId = searchParams.get("group") ?? "";
13
+ const newGroupId = searchParams.get("newGroup") ?? "";
14
+ const group = categories.find((c) => c.id === groupId) ?? null;
15
+ const [groupFilterId, setGroupFilterId] = useState(groupId);
16
+ const pageTitle = group?.labelPlural ?? rosterLabel(categories, defaultTitle, generic);
17
+ const setGroup = (next) => {
18
+ setGroupFilterId(next);
19
+ };
20
+ const [view, setView] = useState("grid");
21
+ const [weekStart, setWeekStart] = useState(() => startOfWeek(/* @__PURE__ */ new Date()));
22
+ const [search, setSearch] = useState("");
23
+ const [status, setStatus] = useState("");
24
+ const [locationId, setLocationId] = useState("");
25
+ const today = isoDay(/* @__PURE__ */ new Date());
26
+ const from = view === "week" ? isoDay(weekStart) : today;
27
+ const to = view === "week" ? isoDay(addDays(weekStart, 6)) : today;
28
+ const { blocks, refetch: refetchBlocks } = useTimeOff(from, to);
29
+ const [addingTo, setAddingTo] = useState(null);
30
+ const [editingGroup, setEditingGroup] = useState(
31
+ null
32
+ );
33
+ const [addingGroup, setAddingGroup] = useState(false);
34
+ const [blockingFor, setBlockingFor] = useState(null);
35
+ const [blockError, setBlockError] = useState(null);
36
+ const [editingDay, setEditingDay] = useState(null);
37
+ const filtered = useMemo(() => {
38
+ const term = search.trim().toLowerCase();
39
+ return rows.filter((row) => {
40
+ if (groupFilterId && row.categoryId !== groupFilterId) return false;
41
+ if (status && row.status !== status) return false;
42
+ if (locationId && row.locationId !== locationId) return false;
43
+ if (!term) return true;
44
+ return row.name.toLowerCase().includes(term) || row.skills?.some((skill) => skill.toLowerCase().includes(term));
45
+ });
46
+ }, [rows, search, groupFilterId, status, locationId]);
47
+ const sections = useMemo(() => {
48
+ const shown = group ? [group] : groupFilterId ? categories.filter((category) => category.id === groupFilterId) : categories.filter(
49
+ (category) => (
50
+ // With no units anywhere, every group is drawn: its heading is
51
+ // where "Add" lives, and a group that vanished until it had a
52
+ // row left nobody a way to add the first one.
53
+ rows.length === 0 || filtered.some((row) => row.categoryId === category.id) || category.id === newGroupId
54
+ )
55
+ );
56
+ const ordered = [...shown].sort(
57
+ (a, b) => Number(b.id === newGroupId) - Number(a.id === newGroupId)
58
+ );
59
+ const list = ordered.map((category) => ({
60
+ category,
61
+ rows: filtered.filter((row) => row.categoryId === category.id)
62
+ }));
63
+ const orphans = group ? [] : filtered.filter(
64
+ (row) => !categories.some((c) => c.id === row.categoryId)
65
+ );
66
+ if (orphans.length) list.push({ category: null, rows: orphans });
67
+ return list;
68
+ }, [group, groupFilterId, categories, filtered, newGroupId, rows.length]);
69
+ const isEmpty = !loading && !error && rows.length === 0;
70
+ const narrowed = !!search.trim() || !!status || !!locationId;
71
+ const showBands = !group && (categories.length > 0 || sections.some((s) => !s.category));
72
+ const targetGroup = group ?? categories[0] ?? null;
73
+ const handleDelete = async (row) => {
74
+ const ok = await confirm({
75
+ title: `Delete ${row.name}?`,
76
+ description: "Bookings already taken keep their record. This cannot be undone.",
77
+ confirmLabel: "Delete",
78
+ tone: "danger"
79
+ });
80
+ if (ok) await deleteResource(row.id);
81
+ };
82
+ const handleBlock = async (data) => {
83
+ setBlockError(null);
84
+ try {
85
+ await blockTime(data);
86
+ } catch (err) {
87
+ setBlockError(
88
+ err instanceof Error ? err.message : "Could not block that time."
89
+ );
90
+ return;
91
+ }
92
+ await refetchBlocks();
93
+ setBlockingFor(null);
94
+ };
95
+ return {
96
+ pageTitle,
97
+ groupId: groupFilterId,
98
+ group,
99
+ setGroup,
100
+ view,
101
+ setView,
102
+ weekStart,
103
+ setWeekStart,
104
+ search,
105
+ setSearch,
106
+ status,
107
+ setStatus,
108
+ locationId,
109
+ setLocationId,
110
+ today,
111
+ blocks,
112
+ refetchBlocks,
113
+ addingTo,
114
+ setAddingTo,
115
+ editingGroup,
116
+ setEditingGroup,
117
+ addingGroup,
118
+ setAddingGroup,
119
+ blockingFor,
120
+ setBlockingFor,
121
+ blockError,
122
+ setBlockError,
123
+ editingDay,
124
+ setEditingDay,
125
+ filtered,
126
+ sections,
127
+ isEmpty,
128
+ narrowed,
129
+ showBands,
130
+ targetGroup,
131
+ handleDelete,
132
+ handleBlock
133
+ };
134
+ }
135
+ export {
136
+ useRosterPage
137
+ };
138
+ //# sourceMappingURL=use-roster-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/resources/_hooks/use-roster-page.ts"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport { useSearchParams } from 'next/navigation';\nimport { useConfirm } from '@withpotter/ui-kit/confirm-dialog';\nimport type { ResourceCategory } from '@withpotter/lib/resource-types';\nimport { rosterLabel } from '@withpotter/lib/roster-label';\nimport { useRoster, useTimeOff, type RosterRow } from './use-roster';\nimport { addDays, isoDay, startOfWeek } from '../_lib/week';\n\nexport type View = 'grid' | 'week';\n\n/** One group and the rows in it. `category: null` is the ungrouped tail. */\nexport type RosterSection = {\n category: ResourceCategory | null;\n rows: RosterRow[];\n};\n\n/**\n * Everything the roster screen holds that is not the roster itself: which\n * group it is scoped to, how it is drawn, what is narrowing it, and which of\n * the four overlays is open.\n *\n * Split from the page because the page was over the 500-line rule, and this is\n * the half that is genuinely one thing — screen state — against the half that\n * is a frame with sections in it.\n */\nexport function useRosterPage(\n roster: ReturnType<typeof useRoster>,\n /** The archetype's word, for a business that has only ever had one group. */\n defaultTitle: string,\n /** The plain word, for a business whose groups no longer share a noun. */\n generic: string,\n) {\n const searchParams = useSearchParams();\n const confirm = useConfirm();\n const { categories, rows, loading, error, deleteResource, blockTime } =\n roster;\n\n /**\n * Which group this page is showing, from the URL.\n *\n * The sidebar row is unscoped once there are several groups, but a link, a\n * filter or a bookmark can still carry `?group=`, so the scope lives where\n * all three can read it back.\n */\n const groupId = searchParams.get('group') ?? '';\n const newGroupId = searchParams.get('newGroup') ?? '';\n const group = categories.find((c) => c.id === groupId) ?? null;\n const [groupFilterId, setGroupFilterId] = useState(groupId);\n /**\n * The title names what is on the page, which is not one word for everybody\n * — and above all it is the word on the row that opened it. `rosterLabel`\n * is that agreement; see the note there for why it stopped being one.\n */\n const pageTitle =\n group?.labelPlural ?? rosterLabel(categories, defaultTitle, generic);\n const setGroup = (next: string) => {\n setGroupFilterId(next);\n };\n\n const [view, setView] = useState<View>('grid');\n const [weekStart, setWeekStart] = useState(() => startOfWeek(new Date()));\n const [search, setSearch] = useState('');\n const [status, setStatus] = useState('');\n /** Which branch, on a business that has more than one. */\n const [locationId, setLocationId] = useState('');\n\n /** Only the window on screen: today for the list, the week for the grid. */\n const today = isoDay(new Date());\n const from = view === 'week' ? isoDay(weekStart) : today;\n const to = view === 'week' ? isoDay(addDays(weekStart, 6)) : today;\n const { blocks, refetch: refetchBlocks } = useTimeOff(from, to);\n\n const [addingTo, setAddingTo] = useState<ResourceCategory | null>(null);\n const [editingGroup, setEditingGroup] = useState<ResourceCategory | null>(\n null,\n );\n const [addingGroup, setAddingGroup] = useState(false);\n const [blockingFor, setBlockingFor] = useState<RosterRow | null>(null);\n const [blockError, setBlockError] = useState<string | null>(null);\n const [editingDay, setEditingDay] = useState<{\n row: RosterRow;\n date: Date;\n } | null>(null);\n\n const filtered = useMemo(() => {\n const term = search.trim().toLowerCase();\n return rows.filter((row) => {\n if (groupFilterId && row.categoryId !== groupFilterId) return false;\n if (status && row.status !== status) return false;\n if (locationId && row.locationId !== locationId) return false;\n if (!term) return true;\n return (\n row.name.toLowerCase().includes(term) ||\n row.skills?.some((skill) => skill.toLowerCase().includes(term))\n );\n });\n }, [rows, search, groupFilterId, status, locationId]);\n\n /**\n * The groups this view is drawing, each with its own rows.\n *\n * Scoped to one group there is one section and its header IS the page title,\n * so it is not drawn twice. Unscoped with several groups, the sections are\n * the whole point: Courts and Coaches are different questions and a merchant\n * reads them apart. A business with one group sees no header at all — that\n * was the duplication the last pass removed, and it stays removed.\n */\n const sections = useMemo<RosterSection[]>(() => {\n const shown = group\n ? [group]\n : groupFilterId\n ? categories.filter((category) => category.id === groupFilterId)\n : categories.filter(\n (category) =>\n // With no units anywhere, every group is drawn: its heading is\n // where \"Add\" lives, and a group that vanished until it had a\n // row left nobody a way to add the first one.\n rows.length === 0 ||\n filtered.some((row) => row.categoryId === category.id) ||\n category.id === newGroupId,\n );\n const ordered = [...shown].sort(\n (a, b) => Number(b.id === newGroupId) - Number(a.id === newGroupId),\n );\n const list: RosterSection[] = ordered.map((category) => ({\n category,\n rows: filtered.filter((row) => row.categoryId === category.id),\n }));\n /* Rows in no group at all — written before groups existed, or orphaned.\n A tail band rather than a second table, so it shares the one header. */\n const orphans = group\n ? []\n : filtered.filter(\n (row) => !categories.some((c) => c.id === row.categoryId),\n );\n if (orphans.length) list.push({ category: null, rows: orphans });\n return list;\n }, [group, groupFilterId, categories, filtered, newGroupId, rows.length]);\n\n const isEmpty = !loading && !error && rows.length === 0;\n /** Whether the list is short because of the controls, or because it is new. */\n const narrowed = !!search.trim() || !!status || !!locationId;\n const showBands =\n !group && (categories.length > 0 || sections.some((s) => !s.category));\n const targetGroup = group ?? categories[0] ?? null;\n\n const handleDelete = async (row: RosterRow) => {\n const ok = await confirm({\n title: `Delete ${row.name}?`,\n description:\n 'Bookings already taken keep their record. This cannot be undone.',\n confirmLabel: 'Delete',\n tone: 'danger',\n });\n if (ok) await deleteResource(row.id);\n };\n\n const handleBlock = async (data: {\n resourceId: string;\n date: string;\n startTime: string;\n endTime: string;\n reason?: string;\n }) => {\n setBlockError(null);\n try {\n await blockTime(data);\n } catch (err) {\n setBlockError(\n err instanceof Error ? err.message : 'Could not block that time.',\n );\n return;\n }\n await refetchBlocks();\n setBlockingFor(null);\n };\n\n return {\n pageTitle,\n groupId: groupFilterId,\n group,\n setGroup,\n view,\n setView,\n weekStart,\n setWeekStart,\n search,\n setSearch,\n status,\n setStatus,\n locationId,\n setLocationId,\n today,\n blocks,\n refetchBlocks,\n addingTo,\n setAddingTo,\n editingGroup,\n setEditingGroup,\n addingGroup,\n setAddingGroup,\n blockingFor,\n setBlockingFor,\n blockError,\n setBlockError,\n editingDay,\n setEditingDay,\n filtered,\n sections,\n isEmpty,\n narrowed,\n showBands,\n targetGroup,\n handleDelete,\n handleBlock,\n };\n}\n"],"mappings":"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","names":[]}