@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,84 @@
1
+ const RANGE_OPTIONS = [
2
+ { value: "day", label: "Day" },
3
+ { value: "week", label: "Week" },
4
+ { value: "month", label: "Month" },
5
+ { value: "year", label: "Year" }
6
+ ];
7
+ function toISODate(d) {
8
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
9
+ }
10
+ function addDays(iso, n) {
11
+ const [y, m, d] = iso.split("-").map(Number);
12
+ return toISODate(new Date(y, m - 1, d + n));
13
+ }
14
+ function addMonths(iso, n) {
15
+ const [y, m, d] = iso.split("-").map(Number);
16
+ return toISODate(new Date(y, m - 1 + n, d));
17
+ }
18
+ function addYears(iso, n) {
19
+ const [y, m, d] = iso.split("-").map(Number);
20
+ return toISODate(new Date(y + n, m - 1, d));
21
+ }
22
+ function parseISO(iso) {
23
+ const [y, m, d] = iso.split("-").map(Number);
24
+ return new Date(y, m - 1, d);
25
+ }
26
+ function weekOf(iso) {
27
+ const base = parseISO(iso);
28
+ const start = new Date(base);
29
+ start.setDate(start.getDate() - start.getDay());
30
+ return Array.from({ length: 7 }, (_, i) => {
31
+ const day = new Date(start);
32
+ day.setDate(start.getDate() + i);
33
+ return toISODate(day);
34
+ });
35
+ }
36
+ function monthDays(iso) {
37
+ const base = parseISO(iso);
38
+ const first = new Date(base.getFullYear(), base.getMonth(), 1);
39
+ const last = new Date(base.getFullYear(), base.getMonth() + 1, 0);
40
+ return Array.from(
41
+ { length: last.getDate() },
42
+ (_, i) => toISODate(new Date(first.getFullYear(), first.getMonth(), i + 1))
43
+ );
44
+ }
45
+ function rangeWindow(range, anchor) {
46
+ if (range === "day") return [anchor, addDays(anchor, 1)];
47
+ if (range === "week") {
48
+ const w = weekOf(anchor);
49
+ return [w[0], addDays(w[6], 1)];
50
+ }
51
+ if (range === "month") {
52
+ const days = monthDays(anchor);
53
+ return [days[0], addDays(days[days.length - 1], 1)];
54
+ }
55
+ const y = parseISO(anchor).getFullYear();
56
+ return [`${y}-01-01`, `${y + 1}-01-01`];
57
+ }
58
+ function bookingsByDay(events) {
59
+ const counts = /* @__PURE__ */ new Map();
60
+ for (const e of events) {
61
+ if (e.type !== "booking") continue;
62
+ const d = e.start.slice(0, 10);
63
+ counts.set(d, (counts.get(d) ?? 0) + 1);
64
+ }
65
+ return counts;
66
+ }
67
+ function fullness(booked, resourceCount) {
68
+ const capacity = Math.max(resourceCount * 8, 1);
69
+ return Math.min(booked / capacity, 1);
70
+ }
71
+ export {
72
+ RANGE_OPTIONS,
73
+ addDays,
74
+ addMonths,
75
+ addYears,
76
+ bookingsByDay,
77
+ fullness,
78
+ monthDays,
79
+ parseISO,
80
+ rangeWindow,
81
+ toISODate,
82
+ weekOf
83
+ };
84
+ //# sourceMappingURL=calendar-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/calendar-range.ts"],"sourcesContent":["import type { CalendarEventItem } from '@withpotter/lib/api/types';\n\nexport type CalendarRange = 'day' | 'week' | 'month' | 'year';\n\nexport const RANGE_OPTIONS: { value: CalendarRange; label: string }[] = [\n { value: 'day', label: 'Day' },\n { value: 'week', label: 'Week' },\n { value: 'month', label: 'Month' },\n { value: 'year', label: 'Year' },\n];\n\nexport function toISODate(d: Date) {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\nexport function addDays(iso: string, n: number) {\n const [y, m, d] = iso.split('-').map(Number);\n return toISODate(new Date(y, m - 1, d + n));\n}\n\nexport function addMonths(iso: string, n: number) {\n const [y, m, d] = iso.split('-').map(Number);\n return toISODate(new Date(y, m - 1 + n, d));\n}\n\nexport function addYears(iso: string, n: number) {\n const [y, m, d] = iso.split('-').map(Number);\n return toISODate(new Date(y + n, m - 1, d));\n}\n\nexport function parseISO(iso: string) {\n const [y, m, d] = iso.split('-').map(Number);\n return new Date(y, m - 1, d);\n}\n\n/** Sunday-to-Saturday week containing `iso`. */\nexport function weekOf(iso: string) {\n const base = parseISO(iso);\n const start = new Date(base);\n start.setDate(start.getDate() - start.getDay());\n return Array.from({ length: 7 }, (_, i) => {\n const day = new Date(start);\n day.setDate(start.getDate() + i);\n return toISODate(day);\n });\n}\n\n/** Every day in the month containing `iso`. */\nexport function monthDays(iso: string) {\n const base = parseISO(iso);\n const first = new Date(base.getFullYear(), base.getMonth(), 1);\n const last = new Date(base.getFullYear(), base.getMonth() + 1, 0);\n return Array.from({ length: last.getDate() }, (_, i) =>\n toISODate(new Date(first.getFullYear(), first.getMonth(), i + 1)),\n );\n}\n\n/**\n * The window of data a range needs, as [startISO, endExclusiveISO].\n *\n * One place so every view asks the API for exactly the span it draws, rather\n * than each grid inventing its own arithmetic and quietly disagreeing at the\n * month boundary.\n */\nexport function rangeWindow(range: CalendarRange, anchor: string) {\n if (range === 'day') return [anchor, addDays(anchor, 1)] as const;\n if (range === 'week') {\n const w = weekOf(anchor);\n return [w[0], addDays(w[6], 1)] as const;\n }\n if (range === 'month') {\n const days = monthDays(anchor);\n return [days[0], addDays(days[days.length - 1], 1)] as const;\n }\n const y = parseISO(anchor).getFullYear();\n return [`${y}-01-01`, `${y + 1}-01-01`] as const;\n}\n\n/** Bookings per day. The single measure every range renders its fullness from. */\nexport function bookingsByDay(events: CalendarEventItem[]) {\n const counts = new Map<string, number>();\n for (const e of events) {\n if (e.type !== 'booking') continue;\n const d = e.start.slice(0, 10);\n counts.set(d, (counts.get(d) ?? 0) + 1);\n }\n return counts;\n}\n\n/**\n * How full a day is, 0 to 1.\n *\n * Capacity is resources × an assumed eight sellable hours. Deliberately rough:\n * this drives a bar's width and a tint's opacity, not a number anyone reads,\n * and a precise figure would need each resource's own schedule for each day.\n */\nexport function fullness(booked: number, resourceCount: number) {\n const capacity = Math.max(resourceCount * 8, 1);\n return Math.min(booked / capacity, 1);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,279 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useMemo, useState } from "react";
4
+ import { motion, AnimatePresence, useReducedMotion } from "motion/react";
5
+ import { ChevronLeft, ChevronRight } from "lucide-react";
6
+ import { useApiQuery } from "@withpotter/hooks/use-api-query";
7
+ import { useAuth } from "@withpotter/lib/auth-context";
8
+ import { useConfirm } from "@withpotter/ui-kit/confirm-dialog";
9
+ import { useToast } from "@withpotter/ui-kit/use-toast";
10
+ import { bookingsApi } from "@withpotter/lib/api/bookings";
11
+ import { formatTime } from "./format";
12
+ function formatClock(iso) {
13
+ const d = new Date(iso);
14
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
15
+ }
16
+ import { bookingCalendarApi } from "@withpotter/lib/api/booking-calendar";
17
+ import { resourcesApi } from "@withpotter/lib/api/resources";
18
+ import { contentApi } from "@withpotter/lib/api/content";
19
+ import { useRouter } from "next/navigation";
20
+ import { useResourceLabel } from "@withpotter/lib/intents/use-resource-label";
21
+ import { springs, eases } from "@withpotter/lib/motion";
22
+ import { cn } from "@withpotter/lib/utils";
23
+ import { ResourceDayGrid } from "./resource-day-grid";
24
+ import { EventDetailModal } from "./event-detail-modal";
25
+ import { WeekGrid } from "./week-grid";
26
+ import { MonthGrid } from "./month-grid";
27
+ import { YearGrid } from "./year-grid";
28
+ import {
29
+ toISODate,
30
+ addDays,
31
+ weekOf,
32
+ rangeWindow,
33
+ bookingsByDay,
34
+ fullness
35
+ } from "./calendar-range";
36
+ import { asList } from "@withpotter/lib/utils";
37
+ function DayBoardView({ nav }) {
38
+ const reduce = useReducedMotion();
39
+ const { date, range, direction, openDay } = nav;
40
+ const router = useRouter();
41
+ const openCreate = (p) => {
42
+ const params = new URLSearchParams({ date: p.date });
43
+ if (p.startTime) params.set("start", p.startTime);
44
+ if (p.endTime) params.set("end", p.endTime);
45
+ if (p.resourceId) params.set("resource", p.resourceId);
46
+ router.push(`/dashboard/bookings/new?${params.toString()}`);
47
+ };
48
+ const [detail, setDetail] = useState(null);
49
+ const [refreshTick, setRefreshTick] = useState(0);
50
+ const resourceLabel = useResourceLabel();
51
+ const confirm = useConfirm();
52
+ const { tenant } = useAuth();
53
+ const { toast } = useToast();
54
+ const moveEvent = async (event, next) => {
55
+ if (!tenant?.slug) return false;
56
+ const eventDate = event.start.slice(0, 10);
57
+ const movedTime = next.startTime !== formatClock(event.start);
58
+ const who = event.customerName || event.title;
59
+ const ok = await confirm({
60
+ title: next.resourceName ? `Move to ${next.resourceName}?` : `Move to ${next.startTime}?`,
61
+ description: [
62
+ `${who} moves`,
63
+ next.resourceName ? `to ${next.resourceName}` : null,
64
+ movedTime ? `from ${formatTime(event.start)} to ${next.startTime}` : "at the same time"
65
+ ].filter(Boolean).join(" "),
66
+ confirmLabel: "Move it"
67
+ });
68
+ if (!ok) return false;
69
+ try {
70
+ await bookingsApi.reschedule(tenant.slug, event.id, {
71
+ date: eventDate,
72
+ startTime: next.startTime,
73
+ endTime: next.endTime,
74
+ ...next.resourceId ? { resourceId: next.resourceId } : {}
75
+ });
76
+ setRefreshTick((t) => t + 1);
77
+ return true;
78
+ } catch (e) {
79
+ toast({
80
+ title: e?.message || "That time could not be taken.",
81
+ variant: "destructive"
82
+ });
83
+ return false;
84
+ }
85
+ };
86
+ const week = useMemo(() => weekOf(date), [date]);
87
+ const { data: resourcesData, isLoading: resourcesLoading } = useApiQuery(["resources"], (slug) => resourcesApi.list(slug));
88
+ const bookableResources = useMemo(
89
+ () => (resourcesData?.data ?? []).filter((r) => r.status === "active"),
90
+ [resourcesData]
91
+ );
92
+ const { data: rentableData } = useApiQuery(
93
+ ["calendar-rentable-content"],
94
+ (slug) => contentApi.list(slug, "product", {
95
+ behaviors: ["rentable"],
96
+ limit: 100
97
+ }),
98
+ { enabled: bookableResources.length === 0 }
99
+ );
100
+ const usesContentColumns = bookableResources.length === 0;
101
+ const resources = useMemo(
102
+ () => usesContentColumns ? (rentableData?.data ?? []).map(
103
+ (item) => ({
104
+ id: item.id,
105
+ name: item.title,
106
+ status: "active"
107
+ })
108
+ ) : bookableResources,
109
+ [usesContentColumns, rentableData, bookableResources]
110
+ );
111
+ const [winStart, winEnd] = useMemo(
112
+ () => rangeWindow(range, date),
113
+ [range, date]
114
+ );
115
+ const { data: eventsRaw, isLoading: eventsLoading } = useApiQuery(
116
+ ["calendar-events", range, winStart, winEnd, refreshTick],
117
+ (slug) => bookingCalendarApi.getEvents(slug, winStart, winEnd)
118
+ );
119
+ const rawEvents = asList(eventsRaw);
120
+ const events = useMemo(
121
+ () => usesContentColumns ? rawEvents.map(
122
+ (e) => e.contentId ? { ...e, resourceId: e.contentId } : e
123
+ ) : rawEvents,
124
+ [usesContentColumns, rawEvents]
125
+ );
126
+ const dayEvents = useMemo(
127
+ () => events.filter((e) => e.start.slice(0, 10) === date),
128
+ [events, date]
129
+ );
130
+ const loadByDay = useMemo(() => bookingsByDay(events), [events]);
131
+ const today = toISODate(/* @__PURE__ */ new Date());
132
+ const stepWeek = (n) => {
133
+ const target = addDays(date, n * 7);
134
+ openDay(target);
135
+ };
136
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
137
+ range === "day" && /* @__PURE__ */ jsxs("div", { className: "flex items-stretch gap-2", children: [
138
+ /* @__PURE__ */ jsx(
139
+ "button",
140
+ {
141
+ type: "button",
142
+ onClick: () => stepWeek(-1),
143
+ "aria-label": "Previous week",
144
+ className: "surface grid w-8 place-items-center text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)] hover:text-[var(--text-primary)]",
145
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx("div", { className: "grid flex-1 grid-cols-7 gap-2", children: week.map((d) => {
149
+ const active = d === date;
150
+ const booked = loadByDay.get(d) ?? 0;
151
+ const fill = fullness(booked, resources.length);
152
+ const label = /* @__PURE__ */ new Date(`${d}T00:00:00`);
153
+ return /* @__PURE__ */ jsxs(
154
+ motion.button,
155
+ {
156
+ onClick: () => openDay(d),
157
+ whileTap: reduce ? void 0 : { scale: 0.97 },
158
+ transition: springs.snappy,
159
+ className: cn(
160
+ "surface relative overflow-hidden px-2 py-2 text-left",
161
+ active ? (
162
+ /* The selected day tints the surface rather than
163
+ replacing it: a translucent brand fill would drop the
164
+ grey the other six are standing on, so today's box
165
+ would read as the one that failed to paint. */
166
+ "border-brand-500/50 bg-[color-mix(in_srgb,var(--brand-500)_8%,var(--card-bg))]"
167
+ ) : "hover:bg-[var(--interactive-hover)]"
168
+ ),
169
+ children: [
170
+ /* @__PURE__ */ jsx("span", { className: "block text-3xs uppercase tracking-wide text-[var(--text-muted)]", children: label.toLocaleDateString("en-US", { weekday: "short" }) }),
171
+ /* @__PURE__ */ jsx(
172
+ "span",
173
+ {
174
+ className: cn(
175
+ "block text-lg font-semibold tabular-nums",
176
+ d === today ? "text-brand-500" : "text-[var(--text-primary)]"
177
+ ),
178
+ children: label.getDate()
179
+ }
180
+ ),
181
+ /* @__PURE__ */ jsx("span", { className: "mt-2 block h-1 rounded-full bg-[var(--bg-muted)]", children: /* @__PURE__ */ jsx(
182
+ motion.span,
183
+ {
184
+ className: "block h-1 rounded-full bg-brand-500",
185
+ initial: reduce ? false : { scaleX: 0 },
186
+ animate: { scaleX: fill },
187
+ style: { transformOrigin: "left" },
188
+ transition: { duration: 0.4, ease: eases.settle }
189
+ }
190
+ ) })
191
+ ]
192
+ },
193
+ d
194
+ );
195
+ }) }),
196
+ /* @__PURE__ */ jsx(
197
+ "button",
198
+ {
199
+ type: "button",
200
+ onClick: () => stepWeek(1),
201
+ "aria-label": "Next week",
202
+ className: "surface grid w-8 place-items-center text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)] hover:text-[var(--text-primary)]",
203
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
204
+ }
205
+ )
206
+ ] }),
207
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, custom: direction, children: /* @__PURE__ */ jsxs(
208
+ motion.div,
209
+ {
210
+ initial: reduce ? false : { opacity: 0, x: direction >= 0 ? 24 : -24 },
211
+ animate: { opacity: 1, x: 0 },
212
+ exit: reduce ? void 0 : { opacity: 0, x: direction >= 0 ? -16 : 16 },
213
+ transition: { duration: 0.22, ease: eases.settle },
214
+ children: [
215
+ range === "day" && /* @__PURE__ */ jsx(
216
+ ResourceDayGrid,
217
+ {
218
+ onMoveEvent: moveEvent,
219
+ date,
220
+ resources,
221
+ events: dayEvents,
222
+ resourceLabel,
223
+ loading: resourcesLoading || eventsLoading,
224
+ onSelectEvent: setDetail,
225
+ onBookSlot: (resourceId, startTime, endTime) => openCreate({ date, startTime, endTime, resourceId })
226
+ }
227
+ ),
228
+ range === "week" && /* @__PURE__ */ jsx(
229
+ WeekGrid,
230
+ {
231
+ anchor: date,
232
+ events,
233
+ onSelectEvent: setDetail,
234
+ onOpenDay: openDay,
235
+ onBookSlot: (d, startTime, endTime) => openCreate({
236
+ date: d,
237
+ startTime,
238
+ endTime,
239
+ resourceId: resources[0]?.id
240
+ })
241
+ }
242
+ ),
243
+ range === "month" && /* @__PURE__ */ jsx(
244
+ MonthGrid,
245
+ {
246
+ anchor: date,
247
+ events,
248
+ resourceCount: resources.length,
249
+ onOpenDay: openDay
250
+ }
251
+ ),
252
+ range === "year" && /* @__PURE__ */ jsx(
253
+ YearGrid,
254
+ {
255
+ anchor: date,
256
+ events,
257
+ resourceCount: resources.length,
258
+ onOpenDay: openDay
259
+ }
260
+ )
261
+ ]
262
+ },
263
+ `${range}-${date}`
264
+ ) }),
265
+ /* @__PURE__ */ jsx(
266
+ EventDetailModal,
267
+ {
268
+ state: { open: !!detail, event: detail },
269
+ onClose: () => setDetail(null),
270
+ onRemoveBlock: () => setDetail(null),
271
+ isRemoving: false
272
+ }
273
+ )
274
+ ] });
275
+ }
276
+ export {
277
+ DayBoardView
278
+ };
279
+ //# sourceMappingURL=day-board-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/day-board-view.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport { motion, AnimatePresence, useReducedMotion } from 'motion/react';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { useApiQuery } from '@withpotter/hooks/use-api-query';\nimport { useAuth } from '@withpotter/lib/auth-context';\nimport { useConfirm } from '@withpotter/ui-kit/confirm-dialog';\nimport { useToast } from '@withpotter/ui-kit/use-toast';\nimport { bookingsApi } from '@withpotter/lib/api/bookings';\nimport { formatTime } from './format';\n\n/** `HH:MM` local, for comparing an ISO start against a dragged one. */\nfunction formatClock(iso: string) {\n const d = new Date(iso);\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;\n}\nimport { bookingCalendarApi } from '@withpotter/lib/api/booking-calendar';\nimport { resourcesApi } from '@withpotter/lib/api/resources';\nimport { contentApi } from '@withpotter/lib/api/content';\nimport type { CalendarEventItem, ResourceItem } from '@withpotter/lib/api/types';\nimport { useRouter } from 'next/navigation';\nimport { useResourceLabel } from '@withpotter/lib/intents/use-resource-label';\nimport { springs, eases } from '@withpotter/lib/motion';\nimport { cn } from '@withpotter/lib/utils';\nimport { ResourceDayGrid } from './resource-day-grid';\nimport { EventDetailModal } from './event-detail-modal';\nimport { WeekGrid } from './week-grid';\nimport { MonthGrid } from './month-grid';\nimport { YearGrid } from './year-grid';\nimport {\n toISODate,\n addDays,\n weekOf,\n rangeWindow,\n bookingsByDay,\n fullness,\n} from './calendar-range';\nimport type { CalendarNav } from './use-calendar-nav';\nimport { asList } from '@withpotter/lib/utils';\n\n/**\n * The calendar, rebuilt around the question a front desk actually asks.\n *\n * The old surface was a FullCalendar week grid: a diary. It drew a booked hour\n * and a free hour as the same kind of cell, which is exactly backwards for a\n * business, because the free one is the only hour still for sale. This board\n * inverts that — resources across, time down, and the gaps are the element that\n * invites the press.\n *\n * The week strip above is not navigation decoration: each day carries how full\n * it is, so a week reads as a business rather than a set of dates.\n */\nexport function DayBoardView({ nav }: { nav: CalendarNav }) {\n const reduce = useReducedMotion();\n /* Where the calendar is pointed is the page header's state now — the range\n switch, the arrows and Today live up there beside the view switch. This\n board draws whatever it is pointed at. */\n const { date, range, direction, openDay } = nav;\n const router = useRouter();\n\n /**\n * A pressed gap opens the create screen with the gap already filled in.\n *\n * It used to open a slide-over — a second create form beside the one the\n * list header opened, which is how the same booking could be made three\n * different ways. One screen, and the click still carries what it knew.\n */\n const openCreate = (p: {\n date: string;\n startTime?: string;\n endTime?: string;\n resourceId?: string;\n }) => {\n const params = new URLSearchParams({ date: p.date });\n if (p.startTime) params.set('start', p.startTime);\n if (p.endTime) params.set('end', p.endTime);\n if (p.resourceId) params.set('resource', p.resourceId);\n router.push(`/dashboard/bookings/new?${params.toString()}`);\n };\n const [detail, setDetail] = useState<CalendarEventItem | null>(null);\n // Kept as a query-key member so anything that needs to force a refetch can,\n // now that creating a booking leaves this screen rather than closing over it.\n const [refreshTick, setRefreshTick] = useState(0);\n\n const resourceLabel = useResourceLabel();\n const confirm = useConfirm();\n const { tenant } = useAuth();\n const { toast } = useToast();\n\n /**\n * DRAG A BOOKING, THEN SAY YES.\n *\n * Moving somebody's appointment is not a thing to do by accident with a\n * slipped mouse, and it is not a thing to make somebody open a modal for\n * either. So the drag does the arithmetic — snapped to the quarter hour the\n * grid draws — and the drop asks one question with the answer already on\n * screen: the block is sitting in its new slot while the dialog names the\n * old time and the new one. Cancel, and it travels back.\n *\n * `false` from here is the revert signal: the grid animates the block home.\n */\n const moveEvent = async (\n event: CalendarEventItem,\n next: {\n startTime: string;\n endTime: string;\n resourceId?: string;\n resourceName?: string;\n },\n ) => {\n if (!tenant?.slug) return false;\n const eventDate = event.start.slice(0, 10);\n const movedTime = next.startTime !== formatClock(event.start);\n const who = event.customerName || event.title;\n /* The question names only what actually changed. Dragged straight down it\n is a time; dragged sideways it is a person; dragged diagonally it is\n both, and saying all three every time trains people to stop reading. */\n const ok = await confirm({\n title: next.resourceName\n ? `Move to ${next.resourceName}?`\n : `Move to ${next.startTime}?`,\n description: [\n `${who} moves`,\n next.resourceName ? `to ${next.resourceName}` : null,\n movedTime\n ? `from ${formatTime(event.start)} to ${next.startTime}`\n : 'at the same time',\n ]\n .filter(Boolean)\n .join(' '),\n confirmLabel: 'Move it',\n });\n if (!ok) return false;\n try {\n await bookingsApi.reschedule(tenant.slug, event.id, {\n date: eventDate,\n startTime: next.startTime,\n endTime: next.endTime,\n ...(next.resourceId ? { resourceId: next.resourceId } : {}),\n });\n /* The board redraws from the server rather than trusting the block where\n it was dropped: a reschedule can be refused for a reason this screen\n cannot see (a clash, an opening hour), and the honest position is\n whatever came back. */\n setRefreshTick((t) => t + 1);\n return true;\n } catch (e) {\n toast({\n title: (e as Error)?.message || 'That time could not be taken.',\n variant: 'destructive',\n });\n return false;\n }\n };\n const week = useMemo(() => weekOf(date), [date]);\n\n const { data: resourcesData, isLoading: resourcesLoading } = useApiQuery<{\n data: ResourceItem[];\n }>(['resources'], (slug) => resourcesApi.list(slug));\n const bookableResources = useMemo(\n () => (resourcesData?.data ?? []).filter((r) => r.status === 'active'),\n [resourcesData],\n );\n\n /**\n * What this business lets, when it lets catalogue items rather than\n * resources.\n *\n * A short-let's properties are content carrying `rentable` and never rows in\n * bookable_resources, so the board built its columns from an empty list and\n * told a landlord with ten flats to go and add the properties they already\n * had. The Today board was fixed for exactly this and the calendar never was.\n *\n * Asked for only when there are no resources: a salon has chairs and does not\n * need the request.\n */\n const { data: rentableData } = useApiQuery(\n ['calendar-rentable-content'],\n (slug) =>\n contentApi.list(slug, 'product', {\n behaviors: ['rentable'],\n limit: 100,\n }),\n { enabled: bookableResources.length === 0 },\n );\n\n const usesContentColumns = bookableResources.length === 0;\n\n const resources: ResourceItem[] = useMemo(\n () =>\n usesContentColumns\n ? (rentableData?.data ?? []).map(\n (item) =>\n ({\n id: item.id,\n name: item.title,\n status: 'active',\n }) as ResourceItem,\n )\n : bookableResources,\n [usesContentColumns, rentableData, bookableResources],\n );\n\n // Ask for exactly the span the active range draws. A year view that fetched\n // a week would render an empty heat map; a day view that fetched a year would\n // pull 365 days of events to draw one column.\n const [winStart, winEnd] = useMemo(\n () => rangeWindow(range, date),\n [range, date],\n );\n const { data: eventsRaw, isLoading: eventsLoading } = useApiQuery<\n CalendarEventItem[]\n >(['calendar-events', range, winStart, winEnd, refreshTick], (slug) =>\n bookingCalendarApi.getEvents(slug, winStart, winEnd),\n );\n const rawEvents = asList<CalendarEventItem>(eventsRaw);\n\n /**\n * The grid matches an event to a column by `resourceId`. When the columns\n * ARE the catalogue items, the id that identifies the column is `contentId`,\n * so the events are keyed to it here rather than teaching the grid a second\n * matching rule it would have to be told about at every call site.\n */\n const events = useMemo(\n () =>\n usesContentColumns\n ? rawEvents.map((e) =>\n e.contentId ? { ...e, resourceId: e.contentId } : e,\n )\n : rawEvents,\n [usesContentColumns, rawEvents],\n );\n\n const dayEvents = useMemo(\n () => events.filter((e) => e.start.slice(0, 10) === date),\n [events, date],\n );\n\n /** Bookings per day, for the strip's fullness bar. */\n const loadByDay = useMemo(() => bookingsByDay(events), [events]);\n const today = toISODate(new Date());\n\n /* The strip moves a WEEK. In day range the header carries no arrows, so\n this pair is the only one on screen and there is nothing to confuse it\n with — see `CalendarNav`. */\n const stepWeek = (n: number) => {\n const target = addDays(date, n * 7);\n openDay(target);\n };\n\n return (\n <div className=\"space-y-4\">\n {/* Week strip, day range only. In week/month/year the grid itself\n already carries per-day load, so a second strip would repeat it. */}\n {range === 'day' && (\n <div className=\"flex items-stretch gap-2\">\n <button\n type=\"button\"\n onClick={() => stepWeek(-1)}\n aria-label=\"Previous week\"\n className=\"surface grid w-8 place-items-center text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)] hover:text-[var(--text-primary)]\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n\n <div className=\"grid flex-1 grid-cols-7 gap-2\">\n {week.map((d) => {\n const active = d === date;\n const booked = loadByDay.get(d) ?? 0;\n const fill = fullness(booked, resources.length);\n const label = new Date(`${d}T00:00:00`);\n return (\n <motion.button\n key={d}\n onClick={() => openDay(d)}\n whileTap={reduce ? undefined : { scale: 0.97 }}\n transition={springs.snappy}\n /* The strip is the date control, so its boxes are SURFACES:\n the house's lifted grey and hairline, the same fill every\n card on the page carries. Drawn with a bare border on the\n page wash they were outlines of nothing — a row of empty\n rectangles where the one control the day view navigates by\n should be the most solid thing on the screen. */\n className={cn(\n 'surface relative overflow-hidden px-2 py-2 text-left',\n active\n ? /* The selected day tints the surface rather than\n replacing it: a translucent brand fill would drop the\n grey the other six are standing on, so today's box\n would read as the one that failed to paint. */\n 'border-brand-500/50 bg-[color-mix(in_srgb,var(--brand-500)_8%,var(--card-bg))]'\n : 'hover:bg-[var(--interactive-hover)]',\n )}\n >\n <span className=\"block text-3xs uppercase tracking-wide text-[var(--text-muted)]\">\n {label.toLocaleDateString('en-US', { weekday: 'short' })}\n </span>\n <span\n className={cn(\n 'block text-lg font-semibold tabular-nums',\n d === today\n ? 'text-brand-500'\n : 'text-[var(--text-primary)]',\n )}\n >\n {label.getDate()}\n </span>\n <span className=\"mt-2 block h-1 rounded-full bg-[var(--bg-muted)]\">\n <motion.span\n className=\"block h-1 rounded-full bg-brand-500\"\n initial={reduce ? false : { scaleX: 0 }}\n animate={{ scaleX: fill }}\n style={{ transformOrigin: 'left' }}\n transition={{ duration: 0.4, ease: eases.settle }}\n />\n </span>\n </motion.button>\n );\n })}\n </div>\n\n <button\n type=\"button\"\n onClick={() => stepWeek(1)}\n aria-label=\"Next week\"\n className=\"surface grid w-8 place-items-center text-[var(--text-secondary)] hover:bg-[var(--interactive-hover)] hover:text-[var(--text-primary)]\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* The board itself slides in the direction you travelled, so moving\n through days feels like moving along a week. */}\n <AnimatePresence mode=\"wait\" initial={false} custom={direction}>\n <motion.div\n key={`${range}-${date}`}\n initial={\n reduce ? false : { opacity: 0, x: direction >= 0 ? 24 : -24 }\n }\n animate={{ opacity: 1, x: 0 }}\n exit={\n reduce ? undefined : { opacity: 0, x: direction >= 0 ? -16 : 16 }\n }\n transition={{ duration: 0.22, ease: eases.settle }}\n >\n {range === 'day' && (\n <ResourceDayGrid\n onMoveEvent={moveEvent}\n date={date}\n resources={resources}\n events={dayEvents}\n resourceLabel={resourceLabel}\n loading={resourcesLoading || eventsLoading}\n onSelectEvent={setDetail}\n onBookSlot={(resourceId, startTime, endTime) =>\n openCreate({ date, startTime, endTime, resourceId })\n }\n />\n )}\n {range === 'week' && (\n <WeekGrid\n anchor={date}\n events={events}\n onSelectEvent={setDetail}\n onOpenDay={openDay}\n onBookSlot={(d, startTime, endTime) =>\n openCreate({\n date: d,\n startTime,\n endTime,\n resourceId: resources[0]?.id,\n })\n }\n />\n )}\n {range === 'month' && (\n <MonthGrid\n anchor={date}\n events={events}\n resourceCount={resources.length}\n onOpenDay={openDay}\n />\n )}\n {range === 'year' && (\n <YearGrid\n anchor={date}\n events={events}\n resourceCount={resources.length}\n onOpenDay={openDay}\n />\n )}\n </motion.div>\n </AnimatePresence>\n\n <EventDetailModal\n state={{ open: !!detail, event: detail }}\n onClose={() => setDetail(null)}\n onRemoveBlock={() => setDetail(null)}\n isRemoving={false}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,113 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import Link from "next/link";
4
+ import { Loader2, Mail, Phone, Video } from "lucide-react";
5
+ import { joinLabelOf, usableMeetingLink } from "@withpotter/lib/booking-meeting-link";
6
+ import {
7
+ Avatar,
8
+ Dialog,
9
+ DialogContent,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle
13
+ } from "@withpotter/ui-kit";
14
+ import { Button } from "@withpotter/ui-kit/button";
15
+ import { StatusBadge } from "@withpotter/components/shared/status-badge";
16
+ import { formatDatetime } from "./format";
17
+ function EventDetailModal({
18
+ state,
19
+ onClose,
20
+ onRemoveBlock,
21
+ isRemoving
22
+ }) {
23
+ const { event } = state;
24
+ const joinHref = event ? usableMeetingLink(event.meetingLink, event.status) : null;
25
+ return /* @__PURE__ */ jsx(Dialog, { open: state.open, onOpenChange: (next) => !next && onClose(), children: /* @__PURE__ */ jsx(DialogContent, { className: "max-w-sm", children: event && /* @__PURE__ */ jsxs(Fragment, { children: [
26
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-3", children: [
27
+ event.type === "booking" ? /* @__PURE__ */ jsx(Avatar, { name: event.customerName || event.title, size: "sm" }) : /* @__PURE__ */ jsx(
28
+ "span",
29
+ {
30
+ "aria-hidden": true,
31
+ className: "size-8 shrink-0 rounded-lg",
32
+ style: {
33
+ background: event.color ?? "var(--bg-muted)",
34
+ opacity: 0.5
35
+ }
36
+ }
37
+ ),
38
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
39
+ /* @__PURE__ */ jsx("span", { className: "block truncate", children: event.customerName || event.title }),
40
+ /* @__PURE__ */ jsx("span", { className: "block text-xs font-normal text-[var(--text-tertiary)]", children: formatDatetime(event.start, event.end) })
41
+ ] })
42
+ ] }) }),
43
+ event.type === "booking" && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
44
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
45
+ event.status && /* @__PURE__ */ jsx(StatusBadge, { status: event.status }),
46
+ event.serviceName && /* @__PURE__ */ jsx("span", { className: "text-sm text-[var(--text-secondary)]", children: event.serviceName })
47
+ ] }),
48
+ (event.customerPhone || event.customerEmail) && /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-[var(--border-subtle)] pt-3", children: [
49
+ event.customerPhone && /* @__PURE__ */ jsxs(
50
+ "a",
51
+ {
52
+ href: `tel:${event.customerPhone}`,
53
+ className: "flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]",
54
+ children: [
55
+ /* @__PURE__ */ jsx(Phone, { className: "shrink-0 text-[var(--text-tertiary)]" }),
56
+ event.customerPhone
57
+ ]
58
+ }
59
+ ),
60
+ event.customerEmail && /* @__PURE__ */ jsxs(
61
+ "a",
62
+ {
63
+ href: `mailto:${event.customerEmail}`,
64
+ className: "flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]",
65
+ children: [
66
+ /* @__PURE__ */ jsx(Mail, { className: "shrink-0 text-[var(--text-tertiary)]" }),
67
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: event.customerEmail })
68
+ ]
69
+ }
70
+ )
71
+ ] }),
72
+ event.customerNote && /* @__PURE__ */ jsxs("div", { className: "border-t border-[var(--border-subtle)] pt-3", children: [
73
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)]", children: "What they told you" }),
74
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-[var(--text-primary)]", children: event.customerNote })
75
+ ] })
76
+ ] }),
77
+ event.type === "synced" && /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-sm", children: [
78
+ event.calendarName && /* @__PURE__ */ jsx("p", { className: "text-[var(--text-secondary)]", children: event.calendarName }),
79
+ event.description && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap border-t border-[var(--border-subtle)] pt-3 text-[var(--text-primary)]", children: event.description }),
80
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)]", children: "Imported from Google Calendar \xB7 read-only" })
81
+ ] }),
82
+ event.type === "block" && event.blockReason && /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-secondary)]", children: event.blockReason }),
83
+ /* @__PURE__ */ jsx(DialogFooter, { children: event.type === "block" ? /* @__PURE__ */ jsx(
84
+ Button,
85
+ {
86
+ variant: "danger",
87
+ onClick: () => onRemoveBlock(event),
88
+ disabled: isRemoving,
89
+ children: isRemoving ? /* @__PURE__ */ jsx(Loader2, { className: "mx-auto size-4 animate-spin" }) : "Remove block"
90
+ }
91
+ ) : event.type === "booking" ? (
92
+ /* THE DOOR. Everything you might actually want to do to this
93
+ booking — take a payment, move it, cancel it, read its
94
+ history — lives on its own screen, and this panel exists to
95
+ get you there in one press. */
96
+ /* @__PURE__ */ jsxs(Fragment, { children: [
97
+ joinHref && /* @__PURE__ */ jsx(Button, { variant: "secondary", asChild: true, children: /* @__PURE__ */ jsxs("a", { href: joinHref, target: "_blank", rel: "noreferrer", children: [
98
+ /* @__PURE__ */ jsx(Video, {}),
99
+ joinLabelOf(joinHref)
100
+ ] }) }),
101
+ /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsxs(Link, { href: `/dashboard/bookings/${event.id}`, children: [
102
+ "Open",
103
+ " ",
104
+ event.bookingNumber ? `#${event.bookingNumber}` : "booking"
105
+ ] }) })
106
+ ] })
107
+ ) : null })
108
+ ] }) }) });
109
+ }
110
+ export {
111
+ EventDetailModal
112
+ };
113
+ //# sourceMappingURL=event-detail-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/event-detail-modal.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport { Loader2, Mail, Phone, Video } from 'lucide-react';\nimport { joinLabelOf, usableMeetingLink } from '@withpotter/lib/booking-meeting-link';\nimport type { CalendarEventItem } from '@withpotter/lib/api/types';\nimport {\n Avatar,\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@withpotter/ui-kit';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { StatusBadge } from '@withpotter/components/shared/status-badge';\nimport { formatDatetime } from './format';\n\ninterface DetailModalState {\n open: boolean;\n event: CalendarEventItem | null;\n}\n\n/**\n * One event on the calendar, opened.\n *\n * IT WAS NOT A DIALOG. It was a hand-rolled fixed overlay with\n * `background: var(--bg-muted)` written inline — which is why it came out a\n * grey no other modal in the app uses — and because it never called\n * `Dialog`/`useModalBehaviour`, it did not close on Escape, trap Tab, lock the\n * page behind it or return focus. It is the app's `Dialog` now, so all of that\n * is inherited rather than remembered.\n *\n * AND IT WAS A DEAD END. A booking you pressed on the calendar showed you six\n * label/value rows and offered exactly one thing to do: Close. The record it is\n * pointing at is a whole screen — payment, history, the customer, reschedule,\n * cancel — so the panel's job is to say enough to recognise the booking and\n * then hand you the door.\n *\n * The layout is the create screen's summary aside, deliberately: the same\n * person, the same day, the same shape. A booking should look like itself\n * wherever it is being read.\n */\nexport function EventDetailModal({\n state,\n onClose,\n onRemoveBlock,\n isRemoving,\n}: {\n state: DetailModalState;\n onClose: () => void;\n onRemoveBlock: (event: CalendarEventItem) => void;\n isRemoving: boolean;\n}) {\n const { event } = state;\n\n const joinHref = event\n ? usableMeetingLink(event.meetingLink, event.status)\n : null;\n\n return (\n <Dialog open={state.open} onOpenChange={(next) => !next && onClose()}>\n <DialogContent className=\"max-w-sm\">\n {event && (\n <>\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-3\">\n {event.type === 'booking' ? (\n <Avatar name={event.customerName || event.title} size=\"sm\" />\n ) : (\n <span\n aria-hidden\n className=\"size-8 shrink-0 rounded-lg\"\n style={{\n background: event.color ?? 'var(--bg-muted)',\n opacity: 0.5,\n }}\n />\n )}\n <span className=\"min-w-0\">\n <span className=\"block truncate\">\n {event.customerName || event.title}\n </span>\n <span className=\"block text-xs font-normal text-[var(--text-tertiary)]\">\n {formatDatetime(event.start, event.end)}\n </span>\n </span>\n </DialogTitle>\n </DialogHeader>\n\n {event.type === 'booking' && (\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {event.status && <StatusBadge status={event.status} />}\n {event.serviceName && (\n <span className=\"text-sm text-[var(--text-secondary)]\">\n {event.serviceName}\n </span>\n )}\n </div>\n\n {(event.customerPhone || event.customerEmail) && (\n <div className=\"space-y-2 border-t border-[var(--border-subtle)] pt-3\">\n {event.customerPhone && (\n <a\n href={`tel:${event.customerPhone}`}\n className=\"flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]\"\n >\n <Phone className=\"shrink-0 text-[var(--text-tertiary)]\" />\n {event.customerPhone}\n </a>\n )}\n {event.customerEmail && (\n <a\n href={`mailto:${event.customerEmail}`}\n className=\"flex items-center gap-2 text-sm text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]\"\n >\n <Mail className=\"shrink-0 text-[var(--text-tertiary)]\" />\n <span className=\"truncate\">{event.customerEmail}</span>\n </a>\n )}\n </div>\n )}\n\n {event.customerNote && (\n <div className=\"border-t border-[var(--border-subtle)] pt-3\">\n <p className=\"text-xs text-[var(--text-tertiary)]\">\n What they told you\n </p>\n <p className=\"mt-1 text-sm text-[var(--text-primary)]\">\n {event.customerNote}\n </p>\n </div>\n )}\n </div>\n )}\n\n {event.type === 'synced' && (\n <div className=\"space-y-2 text-sm\">\n {event.calendarName && (\n <p className=\"text-[var(--text-secondary)]\">\n {event.calendarName}\n </p>\n )}\n {event.description && (\n <p className=\"whitespace-pre-wrap border-t border-[var(--border-subtle)] pt-3 text-[var(--text-primary)]\">\n {event.description}\n </p>\n )}\n <p className=\"text-xs text-[var(--text-tertiary)]\">\n Imported from Google Calendar · read-only\n </p>\n </div>\n )}\n\n {event.type === 'block' && event.blockReason && (\n <p className=\"text-sm text-[var(--text-secondary)]\">\n {event.blockReason}\n </p>\n )}\n\n <DialogFooter>\n {event.type === 'block' ? (\n <Button\n variant=\"danger\"\n onClick={() => onRemoveBlock(event)}\n disabled={isRemoving}\n >\n {isRemoving ? (\n <Loader2 className=\"mx-auto size-4 animate-spin\" />\n ) : (\n 'Remove block'\n )}\n </Button>\n ) : event.type === 'booking' ? (\n /* THE DOOR. Everything you might actually want to do to this\n booking — take a payment, move it, cancel it, read its\n history — lives on its own screen, and this panel exists to\n get you there in one press. */\n <>\n {/* THE ROOM, at the hour it matters.\n The calendar is where a merchant looks when a call is\n about to start, and this panel could not offer the one\n thing that hour needs — the link lived on the record a\n click further in. Secondary, because \"open the booking\"\n is still the general-purpose door; this is the specific\n one. Cancelled and no-show answer null, so a call nobody\n is coming to gets no way in. */}\n {joinHref && (\n <Button variant=\"secondary\" asChild>\n <a href={joinHref} target=\"_blank\" rel=\"noreferrer\">\n <Video />\n {joinLabelOf(joinHref)}\n </a>\n </Button>\n )}\n <Button asChild>\n <Link href={`/dashboard/bookings/${event.id}`}>\n Open{' '}\n {event.bookingNumber\n ? `#${event.bookingNumber}`\n : 'booking'}\n </Link>\n </Button>\n </>\n ) : null}\n </DialogFooter>\n </>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,22 @@
1
+ function formatTime(iso) {
2
+ return new Date(iso).toLocaleTimeString("en-US", {
3
+ hour: "numeric",
4
+ minute: "2-digit",
5
+ hour12: true
6
+ });
7
+ }
8
+ function formatDatetime(start, end) {
9
+ const s = new Date(start);
10
+ const e = new Date(end);
11
+ const date = s.toLocaleDateString("en-US", {
12
+ weekday: "short",
13
+ month: "short",
14
+ day: "numeric"
15
+ });
16
+ return `${date} \xB7 ${formatTime(start)} \u2013 ${formatTime(end)}`;
17
+ }
18
+ export {
19
+ formatDatetime,
20
+ formatTime
21
+ };
22
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/calendar/_components/format.ts"],"sourcesContent":["/** Date formatting shared by the calendar grid and its event detail modal. */\n\nexport function formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n}\n\nexport function formatDatetime(start: string, end: string): string {\n const s = new Date(start);\n const e = new Date(end);\n const date = s.toLocaleDateString('en-US', {\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n });\n return `${date} · ${formatTime(start)} – ${formatTime(end)}`;\n}\n"],"mappings":"AAEO,SAAS,WAAW,KAAqB;AAC9C,SAAO,IAAI,KAAK,GAAG,EAAE,mBAAmB,SAAS;AAAA,IAC/C,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,eAAe,OAAe,KAAqB;AACjE,QAAM,IAAI,IAAI,KAAK,KAAK;AACxB,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,QAAM,OAAO,EAAE,mBAAmB,SAAS;AAAA,IACzC,SAAS;AAAA,IACT,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACD,SAAO,GAAG,IAAI,SAAM,WAAW,KAAK,CAAC,WAAM,WAAW,GAAG,CAAC;AAC5D;","names":[]}