@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,209 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { motion, AnimatePresence, useReducedMotion } from "motion/react";
5
+ import { X, CalendarPlus, Ban, Loader2 } from "lucide-react";
6
+ import { Select } from "@withpotter/ui-kit/select";
7
+ import { springs, PRESS_SCALE_LARGE } from "@withpotter/lib/motion";
8
+ import { Button } from "@withpotter/ui-kit/button";
9
+ import { Input } from "@withpotter/ui-kit";
10
+ function formatDay(dateStr) {
11
+ return new Date(dateStr).toLocaleDateString("en-US", {
12
+ weekday: "long",
13
+ month: "long",
14
+ day: "numeric"
15
+ });
16
+ }
17
+ function formatClock(time) {
18
+ const [h, m] = time.split(":").map(Number);
19
+ if (Number.isNaN(h)) return time;
20
+ const suffix = h >= 12 ? "pm" : "am";
21
+ const hour = h % 12 === 0 ? 12 : h % 12;
22
+ return `${hour}:${String(m).padStart(2, "0")}${suffix}`;
23
+ }
24
+ function SlotActionSheet({
25
+ slot,
26
+ resources,
27
+ resourcesLoading,
28
+ resourceId,
29
+ onResourceChange,
30
+ onBook,
31
+ onBlock,
32
+ blocking,
33
+ onClose,
34
+ resourceLabel = { singular: "Resource", plural: "Resources" }
35
+ }) {
36
+ const reduce = useReducedMotion();
37
+ const [mode, setMode] = useState("choose");
38
+ const [reason, setReason] = useState("");
39
+ const close = () => {
40
+ setMode("choose");
41
+ setReason("");
42
+ onClose();
43
+ };
44
+ const needsResource = resources.length > 1 && !resourceId;
45
+ const noResources = !resourcesLoading && resources.length === 0;
46
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: slot && /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsx(
48
+ motion.div,
49
+ {
50
+ initial: reduce ? false : { opacity: 0 },
51
+ animate: { opacity: 1 },
52
+ exit: { opacity: 0 },
53
+ transition: { duration: 0.16 },
54
+ onClick: close,
55
+ className: "fixed inset-0 z-[var(--z-modal)] bg-black/65"
56
+ }
57
+ ),
58
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-0 z-[var(--z-modal)] flex items-center justify-center px-4", children: /* @__PURE__ */ jsxs(
59
+ motion.div,
60
+ {
61
+ role: "dialog",
62
+ "aria-modal": "true",
63
+ "aria-label": "Slot actions",
64
+ initial: reduce ? false : { opacity: 0, y: 12, scale: 0.97 },
65
+ animate: { opacity: 1, y: 0, scale: 1 },
66
+ exit: reduce ? void 0 : { opacity: 0, y: 8, scale: 0.98 },
67
+ transition: springs.gentle,
68
+ className: "pointer-events-auto w-full max-w-sm overflow-hidden rounded-2xl border border-[var(--border-strong)] bg-[var(--bg-muted)] shadow-2xl",
69
+ children: [
70
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between border-b border-[var(--border-default)] px-4 py-4", children: [
71
+ /* @__PURE__ */ jsxs("div", { children: [
72
+ /* @__PURE__ */ jsx("h2", { className: "font-semibold text-[var(--text-primary)]", children: formatDay(slot.date) }),
73
+ /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-[var(--text-secondary)]", children: [
74
+ formatClock(slot.startTime),
75
+ " to ",
76
+ formatClock(slot.endTime)
77
+ ] })
78
+ ] }),
79
+ /* @__PURE__ */ jsx(
80
+ Button,
81
+ {
82
+ variant: "ghost",
83
+ size: "icon",
84
+ onClick: close,
85
+ "aria-label": "Close",
86
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
87
+ }
88
+ )
89
+ ] }),
90
+ resources.length > 1 && /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4", children: [
91
+ /* @__PURE__ */ jsx("label", { className: "mb-2 block text-xs font-medium text-[var(--text-secondary)]", children: resourceLabel.singular }),
92
+ /* @__PURE__ */ jsx(
93
+ Select,
94
+ {
95
+ value: resourceId,
96
+ onChange: onResourceChange,
97
+ options: resources.map((r) => ({
98
+ value: r.id,
99
+ label: r.name
100
+ })),
101
+ placeholder: `Select a ${resourceLabel.singular.toLowerCase()}`,
102
+ searchable: resources.length > 15
103
+ }
104
+ )
105
+ ] }),
106
+ noResources && /* @__PURE__ */ jsxs("p", { className: "mx-4 mt-4 rounded-lg bg-[var(--warning-bg)] px-3 py-2 text-xs text-[var(--warning)]", children: [
107
+ "No ",
108
+ resourceLabel.plural.toLowerCase(),
109
+ " configured yet. Add one before booking or blocking time."
110
+ ] }),
111
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: mode === "choose" ? /* @__PURE__ */ jsxs(
112
+ motion.div,
113
+ {
114
+ initial: reduce ? false : { opacity: 0, x: -8 },
115
+ animate: { opacity: 1, x: 0 },
116
+ exit: reduce ? void 0 : { opacity: 0, x: -8 },
117
+ transition: springs.snappy,
118
+ className: "flex flex-col gap-2 p-4",
119
+ children: [
120
+ /* @__PURE__ */ jsxs(
121
+ motion.button,
122
+ {
123
+ onClick: onBook,
124
+ disabled: noResources || needsResource,
125
+ whileTap: reduce ? void 0 : { scale: PRESS_SCALE_LARGE },
126
+ transition: springs.snappy,
127
+ className: "flex items-center justify-center gap-2 rounded-xl bg-brand-500 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-brand-600 disabled:cursor-not-allowed disabled:opacity-50",
128
+ children: [
129
+ /* @__PURE__ */ jsx(CalendarPlus, { className: "h-[15px] w-[15px]" }),
130
+ "Book this time"
131
+ ]
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxs(
135
+ Button,
136
+ {
137
+ variant: "secondary",
138
+ onClick: () => setMode("block"),
139
+ disabled: noResources,
140
+ children: [
141
+ /* @__PURE__ */ jsx(Ban, {}),
142
+ "Block it instead"
143
+ ]
144
+ }
145
+ )
146
+ ]
147
+ },
148
+ "choose"
149
+ ) : /* @__PURE__ */ jsxs(
150
+ motion.div,
151
+ {
152
+ initial: reduce ? false : { opacity: 0, x: 8 },
153
+ animate: { opacity: 1, x: 0 },
154
+ exit: reduce ? void 0 : { opacity: 0, x: 8 },
155
+ transition: springs.snappy,
156
+ className: "p-4",
157
+ children: [
158
+ /* @__PURE__ */ jsxs("label", { className: "mb-2 block text-xs font-medium text-[var(--text-secondary)]", children: [
159
+ "Reason",
160
+ " ",
161
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--text-tertiary)]", children: "(optional)" })
162
+ ] }),
163
+ /* @__PURE__ */ jsx(
164
+ Input,
165
+ {
166
+ type: "text",
167
+ value: reason,
168
+ autoFocus: true,
169
+ onChange: (e) => setReason(e.target.value),
170
+ placeholder: "Lunch break, maintenance, staff training",
171
+ className: "w-full"
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-[var(--text-tertiary)]", children: "Blocked time stops new bookings from landing here." }),
175
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-2", children: [
176
+ /* @__PURE__ */ jsx(
177
+ Button,
178
+ {
179
+ variant: "secondary",
180
+ className: "flex-1",
181
+ onClick: () => setMode("choose"),
182
+ children: "Back"
183
+ }
184
+ ),
185
+ /* @__PURE__ */ jsx(
186
+ motion.button,
187
+ {
188
+ onClick: () => onBlock(reason),
189
+ disabled: blocking || resourcesLoading || needsResource,
190
+ whileTap: reduce ? void 0 : { scale: PRESS_SCALE_LARGE },
191
+ transition: springs.snappy,
192
+ className: "flex-1 rounded-xl bg-[var(--text-primary)] px-4 py-3 text-sm font-medium text-[var(--bg-base)] disabled:opacity-50",
193
+ children: blocking ? /* @__PURE__ */ jsx(Loader2, { className: "mx-auto size-4 animate-spin" }) : "Block time"
194
+ }
195
+ )
196
+ ] })
197
+ ]
198
+ },
199
+ "block"
200
+ ) })
201
+ ]
202
+ }
203
+ ) })
204
+ ] }) });
205
+ }
206
+ export {
207
+ SlotActionSheet
208
+ };
209
+ //# sourceMappingURL=slot-action-sheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/slot-action-sheet.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { motion, AnimatePresence, useReducedMotion } from 'motion/react';\nimport { X, CalendarPlus, Ban, Loader2 } from 'lucide-react';\nimport { Select } from '@withpotter/ui-kit/select';\nimport { springs, PRESS_SCALE_LARGE } from '@withpotter/lib/motion';\nimport type { ResourceItem } from '@withpotter/lib/api/types';\nimport type { EntityLabel } from '@withpotter/lib/intents/types';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input } from '@withpotter/ui-kit';\n\nexport interface SlotSelection {\n date: string;\n startTime: string;\n endTime: string;\n}\n\nexport interface SlotActionSheetProps {\n slot: SlotSelection | null;\n resources: ResourceItem[];\n resourcesLoading: boolean;\n resourceId: string;\n onResourceChange: (id: string) => void;\n onBook: () => void;\n onBlock: (reason: string) => void;\n blocking: boolean;\n onClose: () => void;\n /**\n * What this business calls the thing being booked, from the archetype config.\n * Passed in rather than read from a hook here so the sheet stays a pure\n * primitive: the intent hooks depend on AuthProvider, which only exists\n * inside /dashboard, and a primitive that cannot render in a lab is a\n * primitive nobody can review in isolation.\n */\n resourceLabel?: EntityLabel;\n}\n\nfunction formatDay(dateStr: string) {\n return new Date(dateStr).toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n });\n}\n\nfunction formatClock(time: string) {\n const [h, m] = time.split(':').map(Number);\n if (Number.isNaN(h)) return time;\n const suffix = h >= 12 ? 'pm' : 'am';\n const hour = h % 12 === 0 ? 12 : h % 12;\n return `${hour}:${String(m).padStart(2, '0')}${suffix}`;\n}\n\n/**\n * What happens when staff drag a gap on the calendar.\n *\n * It used to be one thing: block it. That made the only place in the product\n * where free time is visible a place where the sole verb was \"make this gap\n * permanent\". Booking the gap is the reason anyone drags it, so booking is the\n * primary action and blocking steps behind a second press.\n */\nexport function SlotActionSheet({\n slot,\n resources,\n resourcesLoading,\n resourceId,\n onResourceChange,\n onBook,\n onBlock,\n blocking,\n onClose,\n resourceLabel = { singular: 'Resource', plural: 'Resources' },\n}: SlotActionSheetProps) {\n const reduce = useReducedMotion();\n const [mode, setMode] = useState<'choose' | 'block'>('choose');\n const [reason, setReason] = useState('');\n\n const close = () => {\n setMode('choose');\n setReason('');\n onClose();\n };\n\n const needsResource = resources.length > 1 && !resourceId;\n const noResources = !resourcesLoading && resources.length === 0;\n\n return (\n <AnimatePresence>\n {slot && (\n <>\n <motion.div\n initial={reduce ? false : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.16 }}\n onClick={close}\n className=\"fixed inset-0 z-[var(--z-modal)] bg-black/65\"\n />\n <div className=\"pointer-events-none fixed inset-0 z-[var(--z-modal)] flex items-center justify-center px-4\">\n <motion.div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Slot actions\"\n initial={reduce ? false : { opacity: 0, y: 12, scale: 0.97 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={reduce ? undefined : { opacity: 0, y: 8, scale: 0.98 }}\n transition={springs.gentle}\n className=\"pointer-events-auto w-full max-w-sm overflow-hidden rounded-2xl border border-[var(--border-strong)] bg-[var(--bg-muted)] shadow-2xl\"\n >\n <div className=\"flex items-start justify-between border-b border-[var(--border-default)] px-4 py-4\">\n <div>\n <h2 className=\"font-semibold text-[var(--text-primary)]\">\n {formatDay(slot.date)}\n </h2>\n <p className=\"mt-0.5 text-xs text-[var(--text-secondary)]\">\n {formatClock(slot.startTime)} to {formatClock(slot.endTime)}\n </p>\n </div>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={close}\n aria-label=\"Close\"\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n\n {resources.length > 1 && (\n <div className=\"px-4 pt-4\">\n <label className=\"mb-2 block text-xs font-medium text-[var(--text-secondary)]\">\n {resourceLabel.singular}\n </label>\n <Select\n value={resourceId}\n onChange={onResourceChange}\n options={resources.map((r) => ({\n value: r.id,\n label: r.name,\n }))}\n placeholder={`Select a ${resourceLabel.singular.toLowerCase()}`}\n searchable={resources.length > 15}\n />\n </div>\n )}\n\n {noResources && (\n <p className=\"mx-4 mt-4 rounded-lg bg-[var(--warning-bg)] px-3 py-2 text-xs text-[var(--warning)]\">\n No {resourceLabel.plural.toLowerCase()} configured yet. Add\n one before booking or blocking time.\n </p>\n )}\n\n <AnimatePresence mode=\"wait\" initial={false}>\n {mode === 'choose' ? (\n <motion.div\n key=\"choose\"\n initial={reduce ? false : { opacity: 0, x: -8 }}\n animate={{ opacity: 1, x: 0 }}\n exit={reduce ? undefined : { opacity: 0, x: -8 }}\n transition={springs.snappy}\n className=\"flex flex-col gap-2 p-4\"\n >\n <motion.button\n onClick={onBook}\n disabled={noResources || needsResource}\n whileTap={\n reduce ? undefined : { scale: PRESS_SCALE_LARGE }\n }\n transition={springs.snappy}\n className=\"flex items-center justify-center gap-2 rounded-xl bg-brand-500 px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-brand-600 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <CalendarPlus className=\"h-[15px] w-[15px]\" />\n Book this time\n </motion.button>\n <Button\n variant=\"secondary\"\n onClick={() => setMode('block')}\n disabled={noResources}\n >\n <Ban />\n Block it instead\n </Button>\n </motion.div>\n ) : (\n <motion.div\n key=\"block\"\n initial={reduce ? false : { opacity: 0, x: 8 }}\n animate={{ opacity: 1, x: 0 }}\n exit={reduce ? undefined : { opacity: 0, x: 8 }}\n transition={springs.snappy}\n className=\"p-4\"\n >\n <label className=\"mb-2 block text-xs font-medium text-[var(--text-secondary)]\">\n Reason{' '}\n <span className=\"text-[var(--text-tertiary)]\">\n (optional)\n </span>\n </label>\n <Input\n type=\"text\"\n value={reason}\n autoFocus\n onChange={(e) => setReason(e.target.value)}\n placeholder=\"Lunch break, maintenance, staff training\"\n className=\"w-full\"\n />\n <p className=\"mt-2 text-xs text-[var(--text-tertiary)]\">\n Blocked time stops new bookings from landing here.\n </p>\n <div className=\"mt-4 flex gap-2\">\n <Button\n variant=\"secondary\"\n className=\"flex-1\"\n onClick={() => setMode('choose')}\n >\n Back\n </Button>\n <motion.button\n onClick={() => onBlock(reason)}\n disabled={blocking || resourcesLoading || needsResource}\n whileTap={\n reduce ? undefined : { scale: PRESS_SCALE_LARGE }\n }\n transition={springs.snappy}\n className=\"flex-1 rounded-xl bg-[var(--text-primary)] px-4 py-3 text-sm font-medium text-[var(--bg-base)] disabled:opacity-50\"\n >\n {blocking ? (\n <Loader2 className=\"mx-auto size-4 animate-spin\" />\n ) : (\n 'Block time'\n )}\n </motion.button>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </motion.div>\n </div>\n </>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":";AA0FQ,mBACE,KAwBQ,YAzBV;AAxFR,SAAS,gBAAgB;AACzB,SAAS,QAAQ,iBAAiB,wBAAwB;AAC1D,SAAS,GAAG,cAAc,KAAK,eAAe;AAC9C,SAAS,cAAc;AACvB,SAAS,SAAS,yBAAyB;AAG3C,SAAS,cAAc;AACvB,SAAS,aAAa;AA4BtB,SAAS,UAAU,SAAiB;AAClC,SAAO,IAAI,KAAK,OAAO,EAAE,mBAAmB,SAAS;AAAA,IACnD,SAAS;AAAA,IACT,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACH;AAEA,SAAS,YAAY,MAAc;AACjC,QAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AACzC,MAAI,OAAO,MAAM,CAAC,EAAG,QAAO;AAC5B,QAAM,SAAS,KAAK,KAAK,OAAO;AAChC,QAAM,OAAO,IAAI,OAAO,IAAI,KAAK,IAAI;AACrC,SAAO,GAAG,IAAI,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,MAAM;AACvD;AAUO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB,EAAE,UAAU,YAAY,QAAQ,YAAY;AAC9D,GAAyB;AACvB,QAAM,SAAS,iBAAiB;AAChC,QAAM,CAAC,MAAM,OAAO,IAAI,SAA6B,QAAQ;AAC7D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AAEvC,QAAM,QAAQ,MAAM;AAClB,YAAQ,QAAQ;AAChB,cAAU,EAAE;AACZ,YAAQ;AAAA,EACV;AAEA,QAAM,gBAAgB,UAAU,SAAS,KAAK,CAAC;AAC/C,QAAM,cAAc,CAAC,oBAAoB,UAAU,WAAW;AAE9D,SACE,oBAAC,mBACE,kBACC,iCACE;AAAA;AAAA,MAAC,OAAO;AAAA,MAAP;AAAA,QACC,SAAS,SAAS,QAAQ,EAAE,SAAS,EAAE;AAAA,QACvC,SAAS,EAAE,SAAS,EAAE;AAAA,QACtB,MAAM,EAAE,SAAS,EAAE;AAAA,QACnB,YAAY,EAAE,UAAU,KAAK;AAAA,QAC7B,SAAS;AAAA,QACT,WAAU;AAAA;AAAA,IACZ;AAAA,IACA,oBAAC,SAAI,WAAU,8FACb;AAAA,MAAC,OAAO;AAAA,MAAP;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,cAAW;AAAA,QACX,SAAS,SAAS,QAAQ,EAAE,SAAS,GAAG,GAAG,IAAI,OAAO,KAAK;AAAA,QAC3D,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,OAAO,EAAE;AAAA,QACtC,MAAM,SAAS,SAAY,EAAE,SAAS,GAAG,GAAG,GAAG,OAAO,KAAK;AAAA,QAC3D,YAAY,QAAQ;AAAA,QACpB,WAAU;AAAA,QAEV;AAAA,+BAAC,SAAI,WAAU,sFACb;AAAA,iCAAC,SACC;AAAA,kCAAC,QAAG,WAAU,4CACX,oBAAU,KAAK,IAAI,GACtB;AAAA,cACA,qBAAC,OAAE,WAAU,+CACV;AAAA,4BAAY,KAAK,SAAS;AAAA,gBAAE;AAAA,gBAAK,YAAY,KAAK,OAAO;AAAA,iBAC5D;AAAA,eACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,cAAW;AAAA,gBAEX,8BAAC,KAAE,WAAU,UAAS;AAAA;AAAA,YACxB;AAAA,aACF;AAAA,UAEC,UAAU,SAAS,KAClB,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,+DACd,wBAAc,UACjB;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,gBACP,UAAU;AAAA,gBACV,SAAS,UAAU,IAAI,CAAC,OAAO;AAAA,kBAC7B,OAAO,EAAE;AAAA,kBACT,OAAO,EAAE;AAAA,gBACX,EAAE;AAAA,gBACF,aAAa,YAAY,cAAc,SAAS,YAAY,CAAC;AAAA,gBAC7D,YAAY,UAAU,SAAS;AAAA;AAAA,YACjC;AAAA,aACF;AAAA,UAGD,eACC,qBAAC,OAAE,WAAU,uFAAsF;AAAA;AAAA,YAC7F,cAAc,OAAO,YAAY;AAAA,YAAE;AAAA,aAEzC;AAAA,UAGF,oBAAC,mBAAgB,MAAK,QAAO,SAAS,OACnC,mBAAS,WACR;AAAA,YAAC,OAAO;AAAA,YAAP;AAAA,cAEC,SAAS,SAAS,QAAQ,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,cAC9C,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,cAC5B,MAAM,SAAS,SAAY,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,cAC/C,YAAY,QAAQ;AAAA,cACpB,WAAU;AAAA,cAEV;AAAA;AAAA,kBAAC,OAAO;AAAA,kBAAP;AAAA,oBACC,SAAS;AAAA,oBACT,UAAU,eAAe;AAAA,oBACzB,UACE,SAAS,SAAY,EAAE,OAAO,kBAAkB;AAAA,oBAElD,YAAY,QAAQ;AAAA,oBACpB,WAAU;AAAA,oBAEV;AAAA,0CAAC,gBAAa,WAAU,qBAAoB;AAAA,sBAAE;AAAA;AAAA;AAAA,gBAEhD;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,SAAS,MAAM,QAAQ,OAAO;AAAA,oBAC9B,UAAU;AAAA,oBAEV;AAAA,0CAAC,OAAI;AAAA,sBAAE;AAAA;AAAA;AAAA,gBAET;AAAA;AAAA;AAAA,YA1BI;AAAA,UA2BN,IAEA;AAAA,YAAC,OAAO;AAAA,YAAP;AAAA,cAEC,SAAS,SAAS,QAAQ,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,cAC7C,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,cAC5B,MAAM,SAAS,SAAY,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,cAC9C,YAAY,QAAQ;AAAA,cACpB,WAAU;AAAA,cAEV;AAAA,qCAAC,WAAM,WAAU,+DAA8D;AAAA;AAAA,kBACtE;AAAA,kBACP,oBAAC,UAAK,WAAU,+BAA8B,wBAE9C;AAAA,mBACF;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,OAAO;AAAA,oBACP,WAAS;AAAA,oBACT,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,oBACzC,aAAY;AAAA,oBACZ,WAAU;AAAA;AAAA,gBACZ;AAAA,gBACA,oBAAC,OAAE,WAAU,4CAA2C,gEAExD;AAAA,gBACA,qBAAC,SAAI,WAAU,mBACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,WAAU;AAAA,sBACV,SAAS,MAAM,QAAQ,QAAQ;AAAA,sBAChC;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC,OAAO;AAAA,oBAAP;AAAA,sBACC,SAAS,MAAM,QAAQ,MAAM;AAAA,sBAC7B,UAAU,YAAY,oBAAoB;AAAA,sBAC1C,UACE,SAAS,SAAY,EAAE,OAAO,kBAAkB;AAAA,sBAElD,YAAY,QAAQ;AAAA,sBACpB,WAAU;AAAA,sBAET,qBACC,oBAAC,WAAQ,WAAU,+BAA8B,IAEjD;AAAA;AAAA,kBAEJ;AAAA,mBACF;AAAA;AAAA;AAAA,YA/CI;AAAA,UAgDN,GAEJ;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GAEJ;AAEJ;","names":[]}
@@ -0,0 +1,77 @@
1
+ "use client";
2
+ import { useEffect, useRef, useState } from "react";
3
+ const SNAP_MINUTES = 15;
4
+ function shiftTime(iso, minutes) {
5
+ const d = new Date(new Date(iso).getTime() + minutes * 6e4);
6
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
7
+ }
8
+ function useBlockDrag({
9
+ resources,
10
+ gridHeight,
11
+ hourPx,
12
+ onMoveEvent
13
+ }) {
14
+ const [moving, setMoving] = useState(null);
15
+ const [dragging, setDragging] = useState(null);
16
+ const columnRefs = useRef(/* @__PURE__ */ new Map());
17
+ const dragged = useRef(false);
18
+ useEffect(() => {
19
+ if (!dragging) return;
20
+ const previous = document.body.style.cursor;
21
+ document.body.style.cursor = "grabbing";
22
+ return () => {
23
+ document.body.style.cursor = previous;
24
+ };
25
+ }, [dragging]);
26
+ const startDrag = (id) => {
27
+ dragged.current = true;
28
+ setDragging(id);
29
+ };
30
+ const canMove = (e) => Boolean(onMoveEvent) && e.type !== "block" && e.type !== "synced";
31
+ const handleDrop = async (e, offset, dropX, top, height) => {
32
+ setDragging(null);
33
+ setTimeout(() => {
34
+ dragged.current = false;
35
+ }, 0);
36
+ if (!onMoveEvent) return;
37
+ const stepPx = hourPx / 60 * SNAP_MINUTES;
38
+ let snapped = Math.round(offset.y / stepPx) * stepPx;
39
+ snapped = Math.max(-top, Math.min(snapped, gridHeight - top - height));
40
+ let target = null;
41
+ for (const r of resources) {
42
+ const el = columnRefs.current.get(r.id);
43
+ if (!el) continue;
44
+ const rect = el.getBoundingClientRect();
45
+ if (dropX >= rect.left && dropX <= rect.right) {
46
+ target = { id: r.id, name: r.name };
47
+ break;
48
+ }
49
+ }
50
+ const movedColumn = target != null && target.id !== e.resourceId;
51
+ if (snapped === 0 && !movedColumn) return;
52
+ const deltaMinutes = Math.round(snapped / hourPx * 60);
53
+ const start = shiftTime(e.start, deltaMinutes);
54
+ const end = shiftTime(e.end, deltaMinutes);
55
+ setMoving({ id: e.id, dx: movedColumn ? offset.x : 0, dy: snapped });
56
+ const kept = await onMoveEvent(e, {
57
+ startTime: start,
58
+ endTime: end,
59
+ ...movedColumn && target ? { resourceId: target.id, resourceName: target.name } : {}
60
+ });
61
+ setMoving(null);
62
+ if (kept) return;
63
+ };
64
+ return {
65
+ moving,
66
+ dragging,
67
+ dragged,
68
+ columnRefs,
69
+ canMove,
70
+ startDrag,
71
+ handleDrop
72
+ };
73
+ }
74
+ export {
75
+ useBlockDrag
76
+ };
77
+ //# sourceMappingURL=use-block-drag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/use-block-drag.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport type { CalendarEventItem, ResourceItem } from '@withpotter/lib/api/types';\n\n/** The unit a diary is kept in, and what a drag snaps to. */\nconst SNAP_MINUTES = 15;\n\n/** An ISO timestamp, moved by minutes, as `HH:MM` local. */\nfunction shiftTime(iso: string, minutes: number) {\n const d = new Date(new Date(iso).getTime() + minutes * 60_000);\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n}\n\nexport type MoveEvent = (\n event: CalendarEventItem,\n next: {\n startTime: string;\n endTime: string;\n /** Set when the block was dropped in a different column. */\n resourceId?: string;\n resourceName?: string;\n },\n) => Promise<boolean>;\n\n/**\n * Dragging a booking to another time, or another person's day.\n *\n * The grid draws; this decides what a drop MEANS. Kept apart from the markup\n * because the two are read for different reasons — one is \"what does the board\n * look like\", the other is \"what happens when I let go\" — and together they put\n * the day grid over the house's 500-line limit.\n */\nexport function useBlockDrag({\n resources,\n gridHeight,\n hourPx,\n onMoveEvent,\n}: {\n resources: ResourceItem[];\n gridHeight: number;\n hourPx: number;\n onMoveEvent?: MoveEvent;\n}) {\n /**\n * A booking being moved, and where it was dropped.\n *\n * Held here rather than snapped straight back, because the confirmation is\n * about the thing you just did: the block stays under your cursor while the\n * dialog asks, and only travels back if the answer is no. `offset` is in\n * pixels so the block can be animated home on the same axis it came down.\n */\n const [moving, setMoving] = useState<{\n id: string;\n dx: number;\n dy: number;\n } | null>(null);\n /** The block under the hand right now, so its column can be lifted above the\n * others and the page can wear the grabbing cursor. */\n const [dragging, setDragging] = useState<string | null>(null);\n /** Column element per resource, for working out where a drop landed. */\n const columnRefs = useRef(new Map<string, HTMLElement | null>());\n /* A drag ends with a click event the browser fires anyway. Without this the\n block you just moved also opens its detail panel. */\n const dragged = useRef(false);\n\n /**\n * THE WHOLE PAGE HOLDS IT.\n *\n * `cursor-grab active:cursor-grabbing` on the block is not enough: the moment\n * the pointer leaves the block's own box — which is immediately, because the\n * block is travelling under it — the cursor reverts to the arrow and the drag\n * stops looking like a drag. The grabbing hand belongs to the document while\n * a drag is live, which is what every editor does.\n */\n useEffect(() => {\n if (!dragging) return;\n const previous = document.body.style.cursor;\n document.body.style.cursor = 'grabbing';\n return () => {\n document.body.style.cursor = previous;\n };\n }, [dragging]);\n\n /**\n * A drag begins: the block is under the hand, and the click the browser will\n * fire at the end of it is already spoken for.\n *\n * Both flags together, because `handleDrop` clears both together. Split\n * across the grid and this hook, the setting half went missing — the grid\n * reached for a `setDragging` that was never handed to it.\n */\n const startDrag = (id: string) => {\n dragged.current = true;\n setDragging(id);\n };\n\n /** Whose time can be moved by dragging it. */\n const canMove = (e: CalendarEventItem) =>\n Boolean(onMoveEvent) && e.type !== 'block' && e.type !== 'synced';\n\n /**\n * Where a drop lands, and what it means.\n *\n * SNAPPED TO A QUARTER HOUR. Pixel-accurate dragging on a 60px hour would\n * book somebody in at 10:07, and no desk in the world says that. Fifteen\n * minutes is the unit a diary is kept in, and it makes the block visibly\n * click into place as you let go.\n *\n * The block is left where it landed while `onMoveEvent` asks the question,\n * and travels home on the house spring if the answer is no.\n */\n const handleDrop = async (\n e: CalendarEventItem,\n offset: { x: number; y: number },\n dropX: number,\n top: number,\n height: number,\n ) => {\n /* The click the browser fires after a drag is suppressed by this flag; it\n is released a frame later so a real click still opens the detail. */\n setDragging(null);\n setTimeout(() => {\n dragged.current = false;\n }, 0);\n if (!onMoveEvent) return;\n\n const stepPx = (hourPx / 60) * SNAP_MINUTES;\n let snapped = Math.round(offset.y / stepPx) * stepPx;\n // Never off the board: the day ends where the grid ends.\n snapped = Math.max(-top, Math.min(snapped, gridHeight - top - height));\n\n /**\n * WHICH COLUMN IT LANDED IN, which is to say WHOSE DAY it is now.\n *\n * Dragging sideways is the other half of what a desk does with a diary —\n * \"give that one to Ìtura\" — and it was the half the first pass left out.\n * The target is read from the pointer's own x against the columns' boxes\n * rather than from arithmetic on widths, because the board scrolls\n * horizontally and its columns are `minmax`, so their widths are not known\n * here.\n */\n let target: { id: string; name: string } | null = null;\n for (const r of resources) {\n const el = columnRefs.current.get(r.id);\n if (!el) continue;\n const rect = el.getBoundingClientRect();\n if (dropX >= rect.left && dropX <= rect.right) {\n target = { id: r.id, name: r.name };\n break;\n }\n }\n const movedColumn = target != null && target.id !== e.resourceId;\n if (snapped === 0 && !movedColumn) return;\n\n const deltaMinutes = Math.round((snapped / hourPx) * 60);\n const start = shiftTime(e.start, deltaMinutes);\n const end = shiftTime(e.end, deltaMinutes);\n\n setMoving({ id: e.id, dx: movedColumn ? offset.x : 0, dy: snapped });\n const kept = await onMoveEvent(e, {\n startTime: start,\n endTime: end,\n ...(movedColumn && target\n ? { resourceId: target.id, resourceName: target.name }\n : {}),\n });\n setMoving(null);\n if (kept) return;\n /* Nothing else to do on a refusal: clearing `moving` animates the block\n back down its own axes, which is the revert. */\n };\n\n return {\n moving,\n dragging,\n dragged,\n columnRefs,\n canMove,\n startDrag,\n handleDrop,\n };\n}\n"],"mappings":";AAEA,SAAS,WAAW,QAAQ,gBAAgB;AAI5C,MAAM,eAAe;AAGrB,SAAS,UAAU,KAAa,SAAiB;AAC/C,QAAM,IAAI,IAAI,KAAK,IAAI,KAAK,GAAG,EAAE,QAAQ,IAAI,UAAU,GAAM;AAC7D,SAAO,GAAG,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAC5F;AAqBO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AASD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAIlB,IAAI;AAGd,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAE5D,QAAM,aAAa,OAAO,oBAAI,IAAgC,CAAC;AAG/D,QAAM,UAAU,OAAO,KAAK;AAW5B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,UAAM,WAAW,SAAS,KAAK,MAAM;AACrC,aAAS,KAAK,MAAM,SAAS;AAC7B,WAAO,MAAM;AACX,eAAS,KAAK,MAAM,SAAS;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAUb,QAAM,YAAY,CAAC,OAAe;AAChC,YAAQ,UAAU;AAClB,gBAAY,EAAE;AAAA,EAChB;AAGA,QAAM,UAAU,CAAC,MACf,QAAQ,WAAW,KAAK,EAAE,SAAS,WAAW,EAAE,SAAS;AAa3D,QAAM,aAAa,OACjB,GACA,QACA,OACA,KACA,WACG;AAGH,gBAAY,IAAI;AAChB,eAAW,MAAM;AACf,cAAQ,UAAU;AAAA,IACpB,GAAG,CAAC;AACJ,QAAI,CAAC,YAAa;AAElB,UAAM,SAAU,SAAS,KAAM;AAC/B,QAAI,UAAU,KAAK,MAAM,OAAO,IAAI,MAAM,IAAI;AAE9C,cAAU,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,SAAS,aAAa,MAAM,MAAM,CAAC;AAYrE,QAAI,SAA8C;AAClD,eAAW,KAAK,WAAW;AACzB,YAAM,KAAK,WAAW,QAAQ,IAAI,EAAE,EAAE;AACtC,UAAI,CAAC,GAAI;AACT,YAAM,OAAO,GAAG,sBAAsB;AACtC,UAAI,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO;AAC7C,iBAAS,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK;AAClC;AAAA,MACF;AAAA,IACF;AACA,UAAM,cAAc,UAAU,QAAQ,OAAO,OAAO,EAAE;AACtD,QAAI,YAAY,KAAK,CAAC,YAAa;AAEnC,UAAM,eAAe,KAAK,MAAO,UAAU,SAAU,EAAE;AACvD,UAAM,QAAQ,UAAU,EAAE,OAAO,YAAY;AAC7C,UAAM,MAAM,UAAU,EAAE,KAAK,YAAY;AAEzC,cAAU,EAAE,IAAI,EAAE,IAAI,IAAI,cAAc,OAAO,IAAI,GAAG,IAAI,QAAQ,CAAC;AACnE,UAAM,OAAO,MAAM,YAAY,GAAG;AAAA,MAChC,WAAW;AAAA,MACX,SAAS;AAAA,MACT,GAAI,eAAe,SACf,EAAE,YAAY,OAAO,IAAI,cAAc,OAAO,KAAK,IACnD,CAAC;AAAA,IACP,CAAC;AACD,cAAU,IAAI;AACd,QAAI,KAAM;AAAA,EAGZ;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { useMemo, useState } from "react";
3
+ import {
4
+ toISODate,
5
+ addDays,
6
+ addMonths,
7
+ addYears,
8
+ weekOf,
9
+ parseISO
10
+ } from "./calendar-range";
11
+ function useCalendarNav() {
12
+ const [date, setDate] = useState(() => toISODate(/* @__PURE__ */ new Date()));
13
+ const [range, setRange] = useState("day");
14
+ const [direction, setDirection] = useState(0);
15
+ const step = (n) => {
16
+ setDirection(n);
17
+ setDate(
18
+ (d) => range === "day" ? addDays(d, n) : range === "week" ? addDays(d, n * 7) : range === "month" ? addMonths(d, n) : addYears(d, n)
19
+ );
20
+ };
21
+ const openDay = (d) => {
22
+ setDirection(d > date ? 1 : -1);
23
+ setDate(d);
24
+ setRange("day");
25
+ };
26
+ const periodLabel = useMemo(() => {
27
+ const d = parseISO(date);
28
+ if (range === "day")
29
+ return d.toLocaleDateString("en-US", { month: "long", year: "numeric" });
30
+ if (range === "week") {
31
+ const w = weekOf(date);
32
+ const a = parseISO(w[0]);
33
+ const b = parseISO(w[6]);
34
+ const sameMonth = a.getMonth() === b.getMonth();
35
+ return `${a.toLocaleDateString("en-US", { month: "short", day: "numeric" })} to ${b.toLocaleDateString(
36
+ "en-US",
37
+ sameMonth ? { day: "numeric" } : { month: "short", day: "numeric" }
38
+ )}`;
39
+ }
40
+ if (range === "month")
41
+ return d.toLocaleDateString("en-US", { month: "long", year: "numeric" });
42
+ return String(d.getFullYear());
43
+ }, [date, range]);
44
+ const today = toISODate(/* @__PURE__ */ new Date());
45
+ const atNow = useMemo(() => {
46
+ if (range === "day") return date === today;
47
+ if (range === "week") return weekOf(date).includes(today);
48
+ const a = parseISO(date);
49
+ const b = parseISO(today);
50
+ if (range === "month")
51
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
52
+ return a.getFullYear() === b.getFullYear();
53
+ }, [range, date, today]);
54
+ return {
55
+ date,
56
+ range,
57
+ direction,
58
+ today,
59
+ periodLabel,
60
+ atNow,
61
+ setRange,
62
+ step,
63
+ openDay
64
+ };
65
+ }
66
+ export {
67
+ useCalendarNav
68
+ };
69
+ //# sourceMappingURL=use-calendar-nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/use-calendar-nav.ts"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport {\n toISODate,\n addDays,\n addMonths,\n addYears,\n weekOf,\n parseISO,\n type CalendarRange,\n} from './calendar-range';\n\nexport interface CalendarNav {\n date: string;\n range: CalendarRange;\n /** -1 or 1: which way the last move went, so the board slides that way. */\n direction: number;\n /** Today, as an ISO date, for \"am I on it\" and for the Today control. */\n today: string;\n /** Where you are, in the units the active range is measured in. */\n periodLabel: string;\n /** Whether the period on screen is the one containing today. */\n atNow: boolean;\n setRange: (range: CalendarRange) => void;\n /** Move one unit of the active range. */\n step: (n: number) => void;\n /** Jump to a date and read it as a day. */\n openDay: (date: string) => void;\n}\n\n/**\n * Where the calendar is pointed, held outside the board that draws it.\n *\n * The range switch, the arrows and Today used to sit in a row of their own\n * INSIDE the board, under a `Monday, August 24` heading — so the page carried\n * two control rows stacked eight pixels apart, one of them repeating the date\n * the strip beneath it was already showing in bold. The controls belong on the\n * page's own header row, beside the Today/List/Calendar switch, because they\n * are the same kind of decision: which cut of the same bookings you are looking\n * at.\n *\n * That means the state has to live above both. It is a hook rather than a\n * context because there is exactly one consumer pair — the header group and the\n * board — and a provider for two siblings is ceremony.\n */\nexport function useCalendarNav(): CalendarNav {\n const [date, setDate] = useState(() => toISODate(new Date()));\n const [range, setRange] = useState<CalendarRange>('day');\n const [direction, setDirection] = useState(0);\n\n const step = (n: number) => {\n setDirection(n);\n setDate((d) =>\n range === 'day'\n ? addDays(d, n)\n : range === 'week'\n ? addDays(d, n * 7)\n : range === 'month'\n ? addMonths(d, n)\n : addYears(d, n),\n );\n };\n\n const openDay = (d: string) => {\n setDirection(d > date ? 1 : -1);\n setDate(d);\n setRange('day');\n };\n\n /**\n * In DAY range this says the month, not the day.\n *\n * It used to read \"Monday, August 24\" above a strip whose selected box says\n * MON 24 in brand blue — the same fact twice, and the larger, louder copy of\n * it was the one carrying no extra information. The month is the part the\n * strip cannot tell you, so the month is what is left.\n */\n const periodLabel = useMemo(() => {\n const d = parseISO(date);\n if (range === 'day')\n return d.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });\n if (range === 'week') {\n const w = weekOf(date);\n const a = parseISO(w[0]);\n const b = parseISO(w[6]);\n const sameMonth = a.getMonth() === b.getMonth();\n return `${a.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} to ${b.toLocaleDateString(\n 'en-US',\n sameMonth ? { day: 'numeric' } : { month: 'short', day: 'numeric' },\n )}`;\n }\n if (range === 'month')\n return d.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });\n return String(d.getFullYear());\n }, [date, range]);\n\n /**\n * Is today inside what is drawn?\n *\n * The control that jumps back to now only earns its place when there is\n * somewhere to jump back FROM — see `CalendarNav`, where this decides whether\n * the period label is a button or a fact.\n */\n const today = toISODate(new Date());\n const atNow = useMemo(() => {\n if (range === 'day') return date === today;\n if (range === 'week') return weekOf(date).includes(today);\n const a = parseISO(date);\n const b = parseISO(today);\n if (range === 'month')\n return (\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth()\n );\n return a.getFullYear() === b.getFullYear();\n }, [range, date, today]);\n\n return {\n date,\n range,\n direction,\n today,\n periodLabel,\n atNow,\n setRange,\n step,\n openDay,\n };\n}\n"],"mappings":";AAEA,SAAS,SAAS,gBAAgB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAmCA,SAAS,iBAA8B;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM,UAAU,oBAAI,KAAK,CAAC,CAAC;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,KAAK;AACvD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,CAAC;AAE5C,QAAM,OAAO,CAAC,MAAc;AAC1B,iBAAa,CAAC;AACd;AAAA,MAAQ,CAAC,MACP,UAAU,QACN,QAAQ,GAAG,CAAC,IACZ,UAAU,SACR,QAAQ,GAAG,IAAI,CAAC,IAChB,UAAU,UACR,UAAU,GAAG,CAAC,IACd,SAAS,GAAG,CAAC;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,MAAc;AAC7B,iBAAa,IAAI,OAAO,IAAI,EAAE;AAC9B,YAAQ,CAAC;AACT,aAAS,KAAK;AAAA,EAChB;AAUA,QAAM,cAAc,QAAQ,MAAM;AAChC,UAAM,IAAI,SAAS,IAAI;AACvB,QAAI,UAAU;AACZ,aAAO,EAAE,mBAAmB,SAAS,EAAE,OAAO,QAAQ,MAAM,UAAU,CAAC;AACzE,QAAI,UAAU,QAAQ;AACpB,YAAM,IAAI,OAAO,IAAI;AACrB,YAAM,IAAI,SAAS,EAAE,CAAC,CAAC;AACvB,YAAM,IAAI,SAAS,EAAE,CAAC,CAAC;AACvB,YAAM,YAAY,EAAE,SAAS,MAAM,EAAE,SAAS;AAC9C,aAAO,GAAG,EAAE,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC,CAAC,OAAO,EAAE;AAAA,QAClF;AAAA,QACA,YAAY,EAAE,KAAK,UAAU,IAAI,EAAE,OAAO,SAAS,KAAK,UAAU;AAAA,MACpE,CAAC;AAAA,IACH;AACA,QAAI,UAAU;AACZ,aAAO,EAAE,mBAAmB,SAAS,EAAE,OAAO,QAAQ,MAAM,UAAU,CAAC;AACzE,WAAO,OAAO,EAAE,YAAY,CAAC;AAAA,EAC/B,GAAG,CAAC,MAAM,KAAK,CAAC;AAShB,QAAM,QAAQ,UAAU,oBAAI,KAAK,CAAC;AAClC,QAAM,QAAQ,QAAQ,MAAM;AAC1B,QAAI,UAAU,MAAO,QAAO,SAAS;AACrC,QAAI,UAAU,OAAQ,QAAO,OAAO,IAAI,EAAE,SAAS,KAAK;AACxD,UAAM,IAAI,SAAS,IAAI;AACvB,UAAM,IAAI,SAAS,KAAK;AACxB,QAAI,UAAU;AACZ,aACE,EAAE,YAAY,MAAM,EAAE,YAAY,KAAK,EAAE,SAAS,MAAM,EAAE,SAAS;AAEvE,WAAO,EAAE,YAAY,MAAM,EAAE,YAAY;AAAA,EAC3C,GAAG,CAAC,OAAO,MAAM,KAAK,CAAC;AAEvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,202 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from "react";
4
+ import { motion, useReducedMotion } from "motion/react";
5
+ import { Plus } from "lucide-react";
6
+ import { springs, eases, PRESS_SCALE_LARGE } from "@withpotter/lib/motion";
7
+ import { cn } from "@withpotter/lib/utils";
8
+ import { weekOf, parseISO, toISODate } from "./calendar-range";
9
+ const HOUR_PX = 48;
10
+ function clockLabel(h) {
11
+ const suffix = h >= 12 ? "pm" : "am";
12
+ const hour = h % 12 === 0 ? 12 : h % 12;
13
+ return `${hour}${suffix}`;
14
+ }
15
+ function hourOf(iso) {
16
+ const d = new Date(iso);
17
+ return d.getHours() + d.getMinutes() / 60;
18
+ }
19
+ function WeekGrid({
20
+ anchor,
21
+ events,
22
+ openHour = 8,
23
+ closeHour = 20,
24
+ onBookSlot,
25
+ onSelectEvent,
26
+ onOpenDay
27
+ }) {
28
+ const reduce = useReducedMotion();
29
+ const days = useMemo(() => weekOf(anchor), [anchor]);
30
+ const hours = useMemo(() => {
31
+ const out = [];
32
+ for (let h = openHour; h < closeHour; h += 1) out.push(h);
33
+ return out;
34
+ }, [openHour, closeHour]);
35
+ const byDay = useMemo(() => {
36
+ const map = /* @__PURE__ */ new Map();
37
+ for (const d of days) map.set(d, []);
38
+ for (const e of events) {
39
+ if (e.isAllDay) continue;
40
+ const d = e.start.slice(0, 10);
41
+ if (map.has(d)) map.get(d).push(e);
42
+ }
43
+ return map;
44
+ }, [events, days]);
45
+ const gridHeight = hours.length * HOUR_PX;
46
+ const today = toISODate(/* @__PURE__ */ new Date());
47
+ const col = {
48
+ hidden: {},
49
+ shown: { transition: { staggerChildren: reduce ? 0 : 0.02 } }
50
+ };
51
+ const blockV = {
52
+ hidden: reduce ? {} : { opacity: 0, y: 6 },
53
+ shown: {
54
+ opacity: 1,
55
+ y: 0,
56
+ transition: { duration: 0.22, ease: eases.settle }
57
+ }
58
+ };
59
+ return (
60
+ /* ONE GREY ACROSS THE CALENDAR. The day board is `surface`, the house card
61
+ fill; this drew itself on `--bg-elevated` and the month and year grids on
62
+ something else again, so stepping Day → Week changed the colour of the
63
+ board under you. */
64
+ /* @__PURE__ */ jsx("div", { className: "surface overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "max-h-[calc(100dvh-15rem)] overflow-auto", children: /* @__PURE__ */ jsxs(
65
+ "div",
66
+ {
67
+ className: "grid min-w-max",
68
+ style: { gridTemplateColumns: `56px repeat(7, minmax(130px, 1fr))` },
69
+ children: [
70
+ /* @__PURE__ */ jsx("div", { className: "sticky left-0 top-0 z-40 border-b border-r border-[var(--border-default)] bg-[var(--card-bg)]" }),
71
+ days.map((d) => {
72
+ const dt = parseISO(d);
73
+ return (
74
+ /* A HEADER CELL, not a button in a box. `Button variant="secondary"`
75
+ gave each day its own border and radius, so the header read as
76
+ seven pills floating over a grid whose columns they were supposed
77
+ to be labelling — and the pill's edges did not line up with the
78
+ column edges below them. It is still pressable; it just looks
79
+ like what it is. */
80
+ /* @__PURE__ */ jsxs(
81
+ "button",
82
+ {
83
+ type: "button",
84
+ className: "sticky top-0 z-30 flex flex-col items-start border-b border-r border-[var(--border-default)] bg-[var(--card-bg)] px-3 py-2 text-left transition-colors last:border-r-0 hover:bg-[var(--interactive-hover)]",
85
+ onClick: () => onOpenDay(d),
86
+ children: [
87
+ /* @__PURE__ */ jsx("span", { className: "block text-3xs uppercase tracking-wide text-[var(--text-muted)]", children: dt.toLocaleDateString("en-US", { weekday: "short" }) }),
88
+ /* @__PURE__ */ jsx(
89
+ "span",
90
+ {
91
+ className: cn(
92
+ "block text-lg font-semibold tabular-nums",
93
+ d === today ? "text-brand-500" : "text-[var(--text-primary)]"
94
+ ),
95
+ children: dt.getDate()
96
+ }
97
+ )
98
+ ]
99
+ },
100
+ d
101
+ )
102
+ );
103
+ }),
104
+ /* @__PURE__ */ jsx(
105
+ "div",
106
+ {
107
+ className: "sticky left-0 z-20 border-r border-[var(--border-subtle)] bg-[var(--card-bg)]",
108
+ style: { height: gridHeight },
109
+ children: hours.map((h) => /* @__PURE__ */ jsx(
110
+ "div",
111
+ {
112
+ className: "relative border-b border-[var(--border-subtle)] last:border-b-0",
113
+ style: { height: HOUR_PX },
114
+ children: /* @__PURE__ */ jsx(
115
+ "span",
116
+ {
117
+ className: cn(
118
+ "absolute right-2 text-2xs tabular-nums text-[var(--text-muted)]",
119
+ h === hours[0] ? "top-1" : "-top-2"
120
+ ),
121
+ children: clockLabel(h)
122
+ }
123
+ )
124
+ },
125
+ h
126
+ ))
127
+ }
128
+ ),
129
+ days.map((d) => /* @__PURE__ */ jsxs(
130
+ motion.div,
131
+ {
132
+ variants: col,
133
+ initial: "hidden",
134
+ animate: "shown",
135
+ className: "relative border-r border-[var(--border-subtle)] last:border-r-0",
136
+ style: { height: gridHeight },
137
+ children: [
138
+ hours.map((h) => /* @__PURE__ */ jsx(
139
+ motion.button,
140
+ {
141
+ type: "button",
142
+ "aria-label": `Book ${clockLabel(h)}`,
143
+ onClick: () => onBookSlot(
144
+ d,
145
+ `${String(h).padStart(2, "0")}:00`,
146
+ `${String(h + 1).padStart(2, "0")}:00`
147
+ ),
148
+ whileHover: reduce ? void 0 : { scale: 1.02 },
149
+ whileTap: reduce ? void 0 : { scale: PRESS_SCALE_LARGE },
150
+ transition: springs.snappy,
151
+ className: "group absolute inset-x-1 flex items-center justify-center rounded-md border border-transparent transition-colors duration-[var(--motion-fast)] hover:border-brand-500/30 hover:bg-brand-500/[0.06]",
152
+ style: {
153
+ top: (h - openHour) * HOUR_PX + 1,
154
+ height: HOUR_PX - 2
155
+ },
156
+ children: /* @__PURE__ */ jsx(Plus, { className: "text-brand-500 opacity-0 transition-opacity duration-[var(--motion-fast)] group-hover:opacity-100" })
157
+ },
158
+ h
159
+ )),
160
+ (byDay.get(d) ?? []).map((e) => {
161
+ const top = (hourOf(e.start) - openHour) * HOUR_PX;
162
+ const height = Math.max(
163
+ (hourOf(e.end) - hourOf(e.start)) * HOUR_PX,
164
+ 20
165
+ );
166
+ if (top + height < 0 || top > gridHeight) return null;
167
+ const isBlock = e.type === "block";
168
+ return /* @__PURE__ */ jsx(
169
+ motion.button,
170
+ {
171
+ type: "button",
172
+ variants: blockV,
173
+ onClick: () => onSelectEvent(e),
174
+ whileHover: reduce ? void 0 : { scale: 1.01 },
175
+ transition: springs.snappy,
176
+ className: cn(
177
+ "absolute inset-x-1 z-10 overflow-hidden rounded-md px-2 py-1 text-left",
178
+ isBlock ? "border border-dashed border-[var(--warning)]/40 bg-[var(--warning-bg)] text-[var(--warning)]" : e.type === "synced" ? "border border-[var(--border-default)] bg-[var(--bg-muted)] text-[var(--text-secondary)]" : "bg-brand-500/[0.16] text-[var(--text-primary)] ring-1 ring-inset ring-brand-500/30"
179
+ ),
180
+ style: {
181
+ top,
182
+ height,
183
+ boxShadow: isBlock || e.type === "synced" ? void 0 : "var(--shadow-md)"
184
+ },
185
+ children: /* @__PURE__ */ jsx("span", { className: "block truncate text-2xs font-medium", children: e.customerName || e.title })
186
+ },
187
+ e.id
188
+ );
189
+ })
190
+ ]
191
+ },
192
+ d
193
+ ))
194
+ ]
195
+ }
196
+ ) }) })
197
+ );
198
+ }
199
+ export {
200
+ WeekGrid
201
+ };
202
+ //# sourceMappingURL=week-grid.js.map