@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,252 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useMemo } from "react";
4
+ import {
5
+ ScanLine,
6
+ Camera,
7
+ QrCode,
8
+ CheckCircle2,
9
+ XCircle,
10
+ ChevronDown,
11
+ Calendar
12
+ } from "lucide-react";
13
+ import { useApiQuery } from "@withpotter/hooks/use-api-query";
14
+ import { useDemoMode } from "@withpotter/hooks/use-demo-mode";
15
+ import {
16
+ DEMO_TICKETED_EVENTS,
17
+ filterDemoAttendees
18
+ } from "../bookings/attendees/demo-data";
19
+ import { useTicketScan } from "@withpotter/hooks/use-ticket-scan";
20
+ import { bookingsApi } from "@withpotter/lib/api/bookings";
21
+ import { contentApi } from "@withpotter/lib/api/content";
22
+ import { useScreenHeader } from "@withpotter/hooks/use-screen-header";
23
+ import { MobilePageHeader } from "@withpotter/components/mobile/mobile-page-header";
24
+ import { useRegisterRefresh } from "@withpotter/components/mobile/pull-to-refresh-context";
25
+ import { MetricRow, MetricTile } from "@withpotter/ui-kit/metric-row";
26
+ import { QrScannerModal } from "@withpotter/pages-bookings/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal";
27
+ import { Button } from "@withpotter/ui-kit/button";
28
+ import { Input } from "@withpotter/ui-kit";
29
+ function CheckInDashboardPage() {
30
+ const [selectedEventId, setSelectedEventId] = useState("");
31
+ const [showScanner, setShowScanner] = useState(false);
32
+ const [showEventDropdown, setShowEventDropdown] = useState(false);
33
+ const [recentScans, setRecentScans] = useState([]);
34
+ useScreenHeader({ title: "Check-in" });
35
+ const { data: eventsData } = useApiQuery(
36
+ ["ticketed-events"],
37
+ (slug) => contentApi.list(slug, "products", {
38
+ behaviors: ["ticketed"],
39
+ limit: 50
40
+ })
41
+ );
42
+ const demoActive = useDemoMode();
43
+ const events = demoActive ? DEMO_TICKETED_EVENTS : eventsData?.data || [];
44
+ const selectedEvent = useMemo(
45
+ () => events.find((e) => e.id === selectedEventId),
46
+ [events, selectedEventId]
47
+ );
48
+ const { data: bookingsData, refetch } = useApiQuery(
49
+ ["check-in-attendees", selectedEventId],
50
+ (slug) => bookingsApi.list(slug, {
51
+ contentId: selectedEventId || void 0,
52
+ type: "event",
53
+ limit: 200
54
+ })
55
+ );
56
+ useRegisterRefresh(refetch);
57
+ const demoAttendees = useMemo(
58
+ () => demoActive ? filterDemoAttendees({ contentId: selectedEventId }) : [],
59
+ [demoActive, selectedEventId]
60
+ );
61
+ const attendees = demoActive ? demoAttendees : bookingsData?.data || [];
62
+ const totalAttendees = demoActive ? demoAttendees.length : bookingsData?.total || 0;
63
+ const checkedInCount = attendees.filter(
64
+ (a) => a.status === "checked_in" || a.checkedInAt
65
+ ).length;
66
+ const checkInRate = totalAttendees > 0 ? Math.round(checkedInCount / totalAttendees * 100) : 0;
67
+ const {
68
+ scanInput,
69
+ setScanInput,
70
+ scanResult,
71
+ scan: handleQrScan,
72
+ submitTyped: handleScan,
73
+ pending: scanPending
74
+ } = useTicketScan({
75
+ invalidate: [["check-in-attendees"], ["attendees"]],
76
+ onScanned: (result) => {
77
+ if (result) {
78
+ setRecentScans((prev) => [
79
+ {
80
+ name: result.booking?.customerName || "Guest",
81
+ success: result.checkedIn,
82
+ time: /* @__PURE__ */ new Date()
83
+ },
84
+ ...prev.slice(0, 9)
85
+ ]);
86
+ }
87
+ refetch();
88
+ }
89
+ });
90
+ const handleEventSelect = (eventId) => {
91
+ setSelectedEventId(eventId);
92
+ setShowEventDropdown(false);
93
+ };
94
+ return /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto space-y-4 lg:space-y-6", children: [
95
+ /* @__PURE__ */ jsx(
96
+ MobilePageHeader,
97
+ {
98
+ title: "Check-in",
99
+ action: {
100
+ label: "Scanner",
101
+ onClick: () => setShowScanner(true)
102
+ }
103
+ }
104
+ ),
105
+ /* @__PURE__ */ jsxs("div", { className: "hidden lg:flex items-center justify-between gap-3", children: [
106
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx("h1", { className: "text-title font-semibold text-[var(--text-primary)]", children: "Check-in" }) }),
107
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 shrink-0", children: /* @__PURE__ */ jsxs(Button, { className: "sm:px-4", onClick: () => setShowScanner(true), children: [
108
+ /* @__PURE__ */ jsx(Camera, { className: "size-4" }),
109
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Open scanner" })
110
+ ] }) })
111
+ ] }),
112
+ /* @__PURE__ */ jsx("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx("div", { className: "bg-[var(--bg-subtle)] rounded-ios-lg p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
113
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 text-center", children: [
114
+ /* @__PURE__ */ jsx("span", { className: "text-xl font-bold text-[var(--text-primary)]", children: totalAttendees }),
115
+ /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--text-muted)] mt-0.5", children: "Total" })
116
+ ] }),
117
+ /* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--border-subtle)]" }),
118
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 text-center", children: [
119
+ /* @__PURE__ */ jsx("span", { className: "text-xl font-bold text-[var(--success)]", children: checkedInCount }),
120
+ /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--text-muted)] mt-0.5", children: "Checked in" })
121
+ ] }),
122
+ /* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--border-subtle)]" }),
123
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 text-center", children: [
124
+ /* @__PURE__ */ jsxs("span", { className: "text-xl font-bold text-brand-500", children: [
125
+ checkInRate,
126
+ "%"
127
+ ] }),
128
+ /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--text-muted)] mt-0.5", children: "Rate" })
129
+ ] })
130
+ ] }) }) }),
131
+ /* @__PURE__ */ jsx("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsxs(MetricRow, { children: [
132
+ /* @__PURE__ */ jsx(MetricTile, { label: "Total attendees", value: totalAttendees }),
133
+ /* @__PURE__ */ jsx(MetricTile, { label: "Checked in", value: checkedInCount }),
134
+ /* @__PURE__ */ jsx(MetricTile, { label: "Check-in rate", value: `${checkInRate}%` })
135
+ ] }) }),
136
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
137
+ /* @__PURE__ */ jsxs(
138
+ Button,
139
+ {
140
+ variant: "secondary",
141
+ className: "w-full justify-between",
142
+ onClick: () => setShowEventDropdown(!showEventDropdown),
143
+ children: [
144
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
145
+ /* @__PURE__ */ jsx(Calendar, { className: "size-4 text-[var(--text-muted)]" }),
146
+ selectedEvent ? selectedEvent.title : "All events"
147
+ ] }),
148
+ /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 text-[var(--text-muted)]" })
149
+ ]
150
+ }
151
+ ),
152
+ showEventDropdown && /* @__PURE__ */ jsxs("div", { className: "absolute z-10 mt-1 w-full bg-[var(--bg-base)] border border-[var(--border-subtle)] rounded-md shadow-lg py-1 max-h-64 overflow-y-auto", children: [
153
+ /* @__PURE__ */ jsx(
154
+ "button",
155
+ {
156
+ type: "button",
157
+ onClick: () => handleEventSelect(""),
158
+ className: `w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-[var(--interactive-hover)] ${!selectedEventId ? "bg-[var(--bg-subtle)] font-medium" : ""}`,
159
+ children: "All events"
160
+ }
161
+ ),
162
+ events.map((event) => {
163
+ const ticketed = event.behaviors?.ticketed;
164
+ const eventDate = ticketed?.eventDate ? new Date(ticketed.eventDate).toLocaleDateString("en-US", {
165
+ month: "short",
166
+ day: "numeric"
167
+ }) : null;
168
+ return /* @__PURE__ */ jsxs(
169
+ "button",
170
+ {
171
+ type: "button",
172
+ onClick: () => handleEventSelect(event.id),
173
+ className: `w-full flex items-center justify-between px-3 py-2 text-sm text-left hover:bg-[var(--interactive-hover)] ${selectedEventId === event.id ? "bg-[var(--bg-subtle)] font-medium" : ""}`,
174
+ children: [
175
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: event.title }),
176
+ eventDate && /* @__PURE__ */ jsx("span", { className: "text-[var(--text-tertiary)] text-xs flex-shrink-0 ml-2", children: eventDate })
177
+ ]
178
+ },
179
+ event.id
180
+ );
181
+ })
182
+ ] })
183
+ ] }),
184
+ /* @__PURE__ */ jsxs("div", { children: [
185
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
186
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
187
+ /* @__PURE__ */ jsx(QrCode, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-[var(--text-muted)]" }),
188
+ /* @__PURE__ */ jsx(
189
+ Input,
190
+ {
191
+ type: "text",
192
+ value: scanInput,
193
+ onChange: (e) => setScanInput(e.target.value),
194
+ onKeyDown: (e) => e.key === "Enter" && handleScan(),
195
+ placeholder: "Enter or scan ticket code...",
196
+ className: "w-full pl-10 pr-4"
197
+ }
198
+ )
199
+ ] }),
200
+ /* @__PURE__ */ jsx(
201
+ Button,
202
+ {
203
+ onClick: handleScan,
204
+ disabled: !scanInput.trim() || scanPending,
205
+ children: "Check in"
206
+ }
207
+ )
208
+ ] }),
209
+ scanResult && /* @__PURE__ */ jsxs(
210
+ "div",
211
+ {
212
+ className: `mt-2 px-3 py-2 rounded-md text-sm flex items-center gap-2 ${scanResult.success ? "bg-[var(--success-bg)] text-[var(--success)]" : "bg-[var(--error-bg)] text-[var(--error)]"}`,
213
+ children: [
214
+ scanResult.success ? /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4 flex-shrink-0" }) : /* @__PURE__ */ jsx(XCircle, { className: "size-4 flex-shrink-0" }),
215
+ scanResult.message
216
+ ]
217
+ }
218
+ )
219
+ ] }),
220
+ recentScans.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "surface p-8 text-center", children: [
221
+ /* @__PURE__ */ jsx(ScanLine, { className: "size-8 text-[var(--text-muted)] mx-auto mb-2" }),
222
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-secondary)]", children: "No scans yet this session" }),
223
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-tertiary)] mt-1", children: "Scan a ticket QR code or enter a code above to check in attendees." })
224
+ ] }) : /* @__PURE__ */ jsx("div", { className: "surface divide-y divide-[var(--border-subtle)]", children: recentScans.map((scan, i) => /* @__PURE__ */ jsxs(
225
+ "div",
226
+ {
227
+ className: "flex items-center gap-3 px-4 py-3",
228
+ children: [
229
+ scan.success ? /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4 text-[var(--success)] flex-shrink-0" }) : /* @__PURE__ */ jsx(XCircle, { className: "size-4 text-[var(--error)] flex-shrink-0" }),
230
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--text-primary)]", children: scan.name }) }),
231
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--text-tertiary)] flex-shrink-0", children: scan.time.toLocaleTimeString("en-US", {
232
+ hour: "numeric",
233
+ minute: "2-digit"
234
+ }) })
235
+ ]
236
+ },
237
+ `${scan.time.getTime()}-${i}`
238
+ )) }),
239
+ /* @__PURE__ */ jsx(
240
+ QrScannerModal,
241
+ {
242
+ open: showScanner,
243
+ onClose: () => setShowScanner(false),
244
+ onScan: handleQrScan
245
+ }
246
+ )
247
+ ] });
248
+ }
249
+ export {
250
+ CheckInDashboardPage as default
251
+ };
252
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/%28bookings%29/check-in/page.tsx"],"sourcesContent":["'use client';\n\n/**\n * Check-In Dashboard — day-of operations surface for event organizers.\n *\n * Surfaces: live check-in counter, QR scanner, manual code entry,\n * recent scans feed, and event selector. This is an intent-specific\n * page registered by the event-tickets intent.\n */\n\nimport { useState, useMemo } from 'react';\nimport {\n ScanLine,\n Camera,\n QrCode,\n CheckCircle2,\n XCircle,\n ChevronDown,\n Calendar,\n} from 'lucide-react';\nimport { useApiQuery } from '@withpotter/hooks/use-api-query';\nimport { useDemoMode } from '@withpotter/hooks/use-demo-mode';\nimport {\n DEMO_TICKETED_EVENTS,\n filterDemoAttendees,\n} from '../bookings/attendees/demo-data';\nimport { useTicketScan } from '@withpotter/hooks/use-ticket-scan';\nimport { bookingsApi } from '@withpotter/lib/api/bookings';\nimport { contentApi } from '@withpotter/lib/api/content';\nimport type { BookingListResponse, ContentListResponse } from '@withpotter/lib/api/types';\nimport { useScreenHeader } from '@withpotter/hooks/use-screen-header';\nimport { MobilePageHeader } from '@withpotter/components/mobile/mobile-page-header';\nimport { useRegisterRefresh } from '@withpotter/components/mobile/pull-to-refresh-context';\nimport { MetricRow, MetricTile } from '@withpotter/ui-kit/metric-row';\nimport { QrScannerModal } from '@withpotter/pages-bookings/dashboard/(bookings)/bookings/attendees/_components/qr-scanner-modal';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Input } from '@withpotter/ui-kit';\n\nexport default function CheckInDashboardPage() {\n const [selectedEventId, setSelectedEventId] = useState('');\n const [showScanner, setShowScanner] = useState(false);\n const [showEventDropdown, setShowEventDropdown] = useState(false);\n const [recentScans, setRecentScans] = useState<\n Array<{ name: string; success: boolean; time: Date }>\n >([]);\n\n useScreenHeader({ title: 'Check-in' });\n\n // Fetch ticketed events for the selector\n const { data: eventsData } = useApiQuery<ContentListResponse>(\n ['ticketed-events'],\n (slug) =>\n contentApi.list(slug, 'products', {\n behaviors: ['ticketed'],\n limit: 50,\n }),\n );\n\n // Same seed the Attendees screen uses. Two modules would let a demo show an\n // event here that does not exist there, and a check-in total that disagrees\n // with the list it was counted from.\n const demoActive = useDemoMode();\n const events = demoActive ? DEMO_TICKETED_EVENTS : eventsData?.data || [];\n\n const selectedEvent = useMemo(\n () => events.find((e) => e.id === selectedEventId),\n [events, selectedEventId],\n );\n\n // Fetch attendees/bookings for the selected event to get check-in stats\n const { data: bookingsData, refetch } = useApiQuery<BookingListResponse>(\n ['check-in-attendees', selectedEventId],\n (slug) =>\n bookingsApi.list(slug, {\n contentId: selectedEventId || undefined,\n type: 'event',\n limit: 200,\n }),\n );\n\n useRegisterRefresh(refetch);\n\n const demoAttendees = useMemo(\n () =>\n demoActive ? filterDemoAttendees({ contentId: selectedEventId }) : [],\n [demoActive, selectedEventId],\n );\n\n const attendees = demoActive ? demoAttendees : bookingsData?.data || [];\n const totalAttendees = demoActive\n ? demoAttendees.length\n : bookingsData?.total || 0;\n const checkedInCount = attendees.filter(\n (a) => a.status === 'checked_in' || a.checkedInAt,\n ).length;\n const checkInRate =\n totalAttendees > 0\n ? Math.round((checkedInCount / totalAttendees) * 100)\n : 0;\n\n // The door's own addition on top of the shared scan: a running feed of who\n // just came through, so whoever is on the entrance can see the last ten\n // without reading the roster.\n const {\n scanInput,\n setScanInput,\n scanResult,\n scan: handleQrScan,\n submitTyped: handleScan,\n pending: scanPending,\n } = useTicketScan({\n invalidate: [['check-in-attendees'], ['attendees']],\n onScanned: (result) => {\n if (result) {\n setRecentScans((prev) => [\n {\n name: result.booking?.customerName || 'Guest',\n success: result.checkedIn,\n time: new Date(),\n },\n ...prev.slice(0, 9),\n ]);\n }\n refetch();\n },\n });\n\n const handleEventSelect = (eventId: string) => {\n setSelectedEventId(eventId);\n setShowEventDropdown(false);\n };\n\n return (\n <div className=\"max-w-7xl mx-auto space-y-4 lg:space-y-6\">\n {/* Mobile header */}\n <MobilePageHeader\n title=\"Check-in\"\n action={{\n label: 'Scanner',\n onClick: () => setShowScanner(true),\n }}\n />\n\n {/* Desktop header */}\n <div className=\"hidden lg:flex items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <h1 className=\"text-title font-semibold text-[var(--text-primary)]\">\n Check-in\n </h1>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <Button className=\"sm:px-4\" onClick={() => setShowScanner(true)}>\n <Camera className=\"size-4\" />\n <span className=\"hidden sm:inline\">Open scanner</span>\n </Button>\n </div>\n </div>\n\n {/* Mobile summary card */}\n <div className=\"lg:hidden\">\n <div className=\"bg-[var(--bg-subtle)] rounded-ios-lg p-4\">\n <div className=\"flex gap-3\">\n <div className=\"flex-1 text-center\">\n <span className=\"text-xl font-bold text-[var(--text-primary)]\">\n {totalAttendees}\n </span>\n <p className=\"text-2xs text-[var(--text-muted)] mt-0.5\">Total</p>\n </div>\n <div className=\"w-px bg-[var(--border-subtle)]\" />\n <div className=\"flex-1 text-center\">\n <span className=\"text-xl font-bold text-[var(--success)]\">\n {checkedInCount}\n </span>\n <p className=\"text-2xs text-[var(--text-muted)] mt-0.5\">\n Checked in\n </p>\n </div>\n <div className=\"w-px bg-[var(--border-subtle)]\" />\n <div className=\"flex-1 text-center\">\n <span className=\"text-xl font-bold text-brand-500\">\n {checkInRate}%\n </span>\n <p className=\"text-2xs text-[var(--text-muted)] mt-0.5\">Rate</p>\n </div>\n </div>\n </div>\n </div>\n\n {/* Desktop stats: the same joined strip Orders uses, not three cards. */}\n <div className=\"hidden lg:block\">\n <MetricRow>\n <MetricTile label=\"Total attendees\" value={totalAttendees} />\n <MetricTile label=\"Checked in\" value={checkedInCount} />\n <MetricTile label=\"Check-in rate\" value={`${checkInRate}%`} />\n </MetricRow>\n </div>\n\n {/* Event selector */}\n <div className=\"relative\">\n <Button\n variant=\"secondary\"\n className=\"w-full justify-between\"\n onClick={() => setShowEventDropdown(!showEventDropdown)}\n >\n <span className=\"flex items-center gap-2\">\n <Calendar className=\"size-4 text-[var(--text-muted)]\" />\n {selectedEvent ? selectedEvent.title : 'All events'}\n </span>\n <ChevronDown className=\"size-4 text-[var(--text-muted)]\" />\n </Button>\n {showEventDropdown && (\n <div className=\"absolute z-10 mt-1 w-full bg-[var(--bg-base)] border border-[var(--border-subtle)] rounded-md shadow-lg py-1 max-h-64 overflow-y-auto\">\n <button\n type=\"button\"\n onClick={() => handleEventSelect('')}\n className={`w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-[var(--interactive-hover)] ${\n !selectedEventId ? 'bg-[var(--bg-subtle)] font-medium' : ''\n }`}\n >\n All events\n </button>\n {events.map((event) => {\n const ticketed = (\n event as {\n behaviors?: { ticketed?: { eventDate?: string } };\n }\n ).behaviors?.ticketed;\n const eventDate = ticketed?.eventDate\n ? new Date(ticketed.eventDate).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n })\n : null;\n return (\n <button\n type=\"button\"\n key={event.id}\n onClick={() => handleEventSelect(event.id)}\n className={`w-full flex items-center justify-between px-3 py-2 text-sm text-left hover:bg-[var(--interactive-hover)] ${\n selectedEventId === event.id\n ? 'bg-[var(--bg-subtle)] font-medium'\n : ''\n }`}\n >\n <span className=\"truncate\">{event.title}</span>\n {eventDate && (\n <span className=\"text-[var(--text-tertiary)] text-xs flex-shrink-0 ml-2\">\n {eventDate}\n </span>\n )}\n </button>\n );\n })}\n </div>\n )}\n </div>\n\n {/* Manual scan bar */}\n <div>\n <div className=\"flex gap-2\">\n <div className=\"relative flex-1\">\n <QrCode className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 text-[var(--text-muted)]\" />\n <Input\n type=\"text\"\n value={scanInput}\n onChange={(e) => setScanInput(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && handleScan()}\n placeholder=\"Enter or scan ticket code...\"\n className=\"w-full pl-10 pr-4\"\n />\n </div>\n <Button\n onClick={handleScan}\n disabled={!scanInput.trim() || scanPending}\n >\n Check in\n </Button>\n </div>\n {scanResult && (\n <div\n className={`mt-2 px-3 py-2 rounded-md text-sm flex items-center gap-2 ${\n scanResult.success\n ? 'bg-[var(--success-bg)] text-[var(--success)]'\n : 'bg-[var(--error-bg)] text-[var(--error)]'\n }`}\n >\n {scanResult.success ? (\n <CheckCircle2 className=\"size-4 flex-shrink-0\" />\n ) : (\n <XCircle className=\"size-4 flex-shrink-0\" />\n )}\n {scanResult.message}\n </div>\n )}\n </div>\n\n {/* Recent scans feed */}\n {recentScans.length === 0 ? (\n <div className=\"surface p-8 text-center\">\n <ScanLine className=\"size-8 text-[var(--text-muted)] mx-auto mb-2\" />\n <p className=\"text-sm text-[var(--text-secondary)]\">\n No scans yet this session\n </p>\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\n Scan a ticket QR code or enter a code above to check in attendees.\n </p>\n </div>\n ) : (\n <div className=\"surface divide-y divide-[var(--border-subtle)]\">\n {recentScans.map((scan, i) => (\n <div\n key={`${scan.time.getTime()}-${i}`}\n className=\"flex items-center gap-3 px-4 py-3\"\n >\n {scan.success ? (\n <CheckCircle2 className=\"size-4 text-[var(--success)] flex-shrink-0\" />\n ) : (\n <XCircle className=\"size-4 text-[var(--error)] flex-shrink-0\" />\n )}\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">\n {scan.name}\n </span>\n </div>\n <span className=\"text-xs text-[var(--text-tertiary)] flex-shrink-0\">\n {scan.time.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n })}\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* QR Scanner Modal */}\n <QrScannerModal\n open={showScanner}\n onClose={() => setShowScanner(false)}\n onScan={handleQrScan}\n />\n </div>\n );\n}\n"],"mappings":";AAuIM,cAgBI,YAhBJ;AA7HN,SAAS,UAAU,eAAe;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,WAAW,kBAAkB;AACtC,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AACvB,SAAS,aAAa;AAEP,SAAR,uBAAwC;AAC7C,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,EAAE;AACzD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAChE,QAAM,CAAC,aAAa,cAAc,IAAI,SAEpC,CAAC,CAAC;AAEJ,kBAAgB,EAAE,OAAO,WAAW,CAAC;AAGrC,QAAM,EAAE,MAAM,WAAW,IAAI;AAAA,IAC3B,CAAC,iBAAiB;AAAA,IAClB,CAAC,SACC,WAAW,KAAK,MAAM,YAAY;AAAA,MAChC,WAAW,CAAC,UAAU;AAAA,MACtB,OAAO;AAAA,IACT,CAAC;AAAA,EACL;AAKA,QAAM,aAAa,YAAY;AAC/B,QAAM,SAAS,aAAa,uBAAuB,YAAY,QAAQ,CAAC;AAExE,QAAM,gBAAgB;AAAA,IACpB,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,eAAe;AAAA,IACjD,CAAC,QAAQ,eAAe;AAAA,EAC1B;AAGA,QAAM,EAAE,MAAM,cAAc,QAAQ,IAAI;AAAA,IACtC,CAAC,sBAAsB,eAAe;AAAA,IACtC,CAAC,SACC,YAAY,KAAK,MAAM;AAAA,MACrB,WAAW,mBAAmB;AAAA,MAC9B,MAAM;AAAA,MACN,OAAO;AAAA,IACT,CAAC;AAAA,EACL;AAEA,qBAAmB,OAAO;AAE1B,QAAM,gBAAgB;AAAA,IACpB,MACE,aAAa,oBAAoB,EAAE,WAAW,gBAAgB,CAAC,IAAI,CAAC;AAAA,IACtE,CAAC,YAAY,eAAe;AAAA,EAC9B;AAEA,QAAM,YAAY,aAAa,gBAAgB,cAAc,QAAQ,CAAC;AACtE,QAAM,iBAAiB,aACnB,cAAc,SACd,cAAc,SAAS;AAC3B,QAAM,iBAAiB,UAAU;AAAA,IAC/B,CAAC,MAAM,EAAE,WAAW,gBAAgB,EAAE;AAAA,EACxC,EAAE;AACF,QAAM,cACJ,iBAAiB,IACb,KAAK,MAAO,iBAAiB,iBAAkB,GAAG,IAClD;AAKN,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,EACX,IAAI,cAAc;AAAA,IAChB,YAAY,CAAC,CAAC,oBAAoB,GAAG,CAAC,WAAW,CAAC;AAAA,IAClD,WAAW,CAAC,WAAW;AACrB,UAAI,QAAQ;AACV,uBAAe,CAAC,SAAS;AAAA,UACvB;AAAA,YACE,MAAM,OAAO,SAAS,gBAAgB;AAAA,YACtC,SAAS,OAAO;AAAA,YAChB,MAAM,oBAAI,KAAK;AAAA,UACjB;AAAA,UACA,GAAG,KAAK,MAAM,GAAG,CAAC;AAAA,QACpB,CAAC;AAAA,MACH;AACA,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,QAAM,oBAAoB,CAAC,YAAoB;AAC7C,uBAAmB,OAAO;AAC1B,yBAAqB,KAAK;AAAA,EAC5B;AAEA,SACE,qBAAC,SAAI,WAAU,4CAEb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,SAAS,MAAM,eAAe,IAAI;AAAA,QACpC;AAAA;AAAA,IACF;AAAA,IAGA,qBAAC,SAAI,WAAU,qDACb;AAAA,0BAAC,SAAI,WAAU,WACb,8BAAC,QAAG,WAAU,uDAAsD,sBAEpE,GACF;AAAA,MACA,oBAAC,SAAI,WAAU,oCACb,+BAAC,UAAO,WAAU,WAAU,SAAS,MAAM,eAAe,IAAI,GAC5D;AAAA,4BAAC,UAAO,WAAU,UAAS;AAAA,QAC3B,oBAAC,UAAK,WAAU,oBAAmB,0BAAY;AAAA,SACjD,GACF;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,aACb,8BAAC,SAAI,WAAU,4CACb,+BAAC,SAAI,WAAU,cACb;AAAA,2BAAC,SAAI,WAAU,sBACb;AAAA,4BAAC,UAAK,WAAU,gDACb,0BACH;AAAA,QACA,oBAAC,OAAE,WAAU,4CAA2C,mBAAK;AAAA,SAC/D;AAAA,MACA,oBAAC,SAAI,WAAU,kCAAiC;AAAA,MAChD,qBAAC,SAAI,WAAU,sBACb;AAAA,4BAAC,UAAK,WAAU,2CACb,0BACH;AAAA,QACA,oBAAC,OAAE,WAAU,4CAA2C,wBAExD;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,kCAAiC;AAAA,MAChD,qBAAC,SAAI,WAAU,sBACb;AAAA,6BAAC,UAAK,WAAU,oCACb;AAAA;AAAA,UAAY;AAAA,WACf;AAAA,QACA,oBAAC,OAAE,WAAU,4CAA2C,kBAAI;AAAA,SAC9D;AAAA,OACF,GACF,GACF;AAAA,IAGA,oBAAC,SAAI,WAAU,mBACb,+BAAC,aACC;AAAA,0BAAC,cAAW,OAAM,mBAAkB,OAAO,gBAAgB;AAAA,MAC3D,oBAAC,cAAW,OAAM,cAAa,OAAO,gBAAgB;AAAA,MACtD,oBAAC,cAAW,OAAM,iBAAgB,OAAO,GAAG,WAAW,KAAK;AAAA,OAC9D,GACF;AAAA,IAGA,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACV,SAAS,MAAM,qBAAqB,CAAC,iBAAiB;AAAA,UAEtD;AAAA,iCAAC,UAAK,WAAU,2BACd;AAAA,kCAAC,YAAS,WAAU,mCAAkC;AAAA,cACrD,gBAAgB,cAAc,QAAQ;AAAA,eACzC;AAAA,YACA,oBAAC,eAAY,WAAU,mCAAkC;AAAA;AAAA;AAAA,MAC3D;AAAA,MACC,qBACC,qBAAC,SAAI,WAAU,yIACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,kBAAkB,EAAE;AAAA,YACnC,WAAW,kGACT,CAAC,kBAAkB,sCAAsC,EAC3D;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACC,OAAO,IAAI,CAAC,UAAU;AACrB,gBAAM,WACJ,MAGA,WAAW;AACb,gBAAM,YAAY,UAAU,YACxB,IAAI,KAAK,SAAS,SAAS,EAAE,mBAAmB,SAAS;AAAA,YACvD,OAAO;AAAA,YACP,KAAK;AAAA,UACP,CAAC,IACD;AACJ,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cAEL,SAAS,MAAM,kBAAkB,MAAM,EAAE;AAAA,cACzC,WAAW,4GACT,oBAAoB,MAAM,KACtB,sCACA,EACN;AAAA,cAEA;AAAA,oCAAC,UAAK,WAAU,YAAY,gBAAM,OAAM;AAAA,gBACvC,aACC,oBAAC,UAAK,WAAU,0DACb,qBACH;AAAA;AAAA;AAAA,YAZG,MAAM;AAAA,UAcb;AAAA,QAEJ,CAAC;AAAA,SACH;AAAA,OAEJ;AAAA,IAGA,qBAAC,SACC;AAAA,2BAAC,SAAI,WAAU,cACb;AAAA,6BAAC,SAAI,WAAU,mBACb;AAAA,8BAAC,UAAO,WAAU,4EAA2E;AAAA,UAC7F;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,cAC5C,WAAW,CAAC,MAAM,EAAE,QAAQ,WAAW,WAAW;AAAA,cAClD,aAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,UAAU,CAAC,UAAU,KAAK,KAAK;AAAA,YAChC;AAAA;AAAA,QAED;AAAA,SACF;AAAA,MACC,cACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,6DACT,WAAW,UACP,iDACA,0CACN;AAAA,UAEC;AAAA,uBAAW,UACV,oBAAC,gBAAa,WAAU,wBAAuB,IAE/C,oBAAC,WAAQ,WAAU,wBAAuB;AAAA,YAE3C,WAAW;AAAA;AAAA;AAAA,MACd;AAAA,OAEJ;AAAA,IAGC,YAAY,WAAW,IACtB,qBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,YAAS,WAAU,gDAA+C;AAAA,MACnE,oBAAC,OAAE,WAAU,wCAAuC,uCAEpD;AAAA,MACA,oBAAC,OAAE,WAAU,4CAA2C,gFAExD;AAAA,OACF,IAEA,oBAAC,SAAI,WAAU,kDACZ,sBAAY,IAAI,CAAC,MAAM,MACtB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAET;AAAA,eAAK,UACJ,oBAAC,gBAAa,WAAU,8CAA6C,IAErE,oBAAC,WAAQ,WAAU,4CAA2C;AAAA,UAEhE,oBAAC,SAAI,WAAU,kBACb,8BAAC,UAAK,WAAU,kDACb,eAAK,MACR,GACF;AAAA,UACA,oBAAC,UAAK,WAAU,qDACb,eAAK,KAAK,mBAAmB,SAAS;AAAA,YACrC,MAAM;AAAA,YACN,QAAQ;AAAA,UACV,CAAC,GACH;AAAA;AAAA;AAAA,MAlBK,GAAG,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC;AAAA,IAmBlC,CACD,GACH;AAAA,IAIF;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,MAAM,eAAe,KAAK;AAAA,QACnC,QAAQ;AAAA;AAAA,IACV;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { Users } from "lucide-react";
5
+ import {
6
+ Button,
7
+ Card,
8
+ Dialog,
9
+ DialogContent,
10
+ DialogHeader,
11
+ DialogTitle,
12
+ StateView
13
+ } from "@withpotter/ui-kit";
14
+ import { StatusBadge } from "@withpotter/components/shared/status-badge";
15
+ import { resolveTicketCode } from "@withpotter/lib/ticket-access";
16
+ import { useApiQuery } from "@withpotter/hooks/use-api-query";
17
+ import { bookingsApi } from "@withpotter/lib/api/bookings";
18
+ const PREVIEW = 5;
19
+ function EventAttendees({
20
+ eventId,
21
+ doorListHref
22
+ }) {
23
+ const [open, setOpen] = useState(false);
24
+ const { data, isLoading } = useApiQuery(
25
+ ["event-attendees", eventId],
26
+ (slug) => bookingsApi.list(slug, {
27
+ contentId: eventId,
28
+ type: "event",
29
+ page: 1,
30
+ limit: 100
31
+ })
32
+ );
33
+ const attendees = data?.data ?? [];
34
+ const total = data?.total ?? attendees.length;
35
+ const checkedIn = attendees.filter((a) => a.checkedInAt).length;
36
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
37
+ /* @__PURE__ */ jsxs(Card, { children: [
38
+ /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-start justify-between gap-4", children: [
39
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
40
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--text-secondary)]", children: "Who is coming" }),
41
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs tabular-nums text-[var(--text-tertiary)]", children: [
42
+ total,
43
+ " ",
44
+ total === 1 ? "ticket" : "tickets",
45
+ checkedIn > 0 && ` \xB7 ${checkedIn} in`
46
+ ] })
47
+ ] }),
48
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", asChild: true, children: /* @__PURE__ */ jsx("a", { href: doorListHref, children: "Open door list" }) })
49
+ ] }),
50
+ isLoading && attendees.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--text-tertiary)]", children: "Reading the list\u2026" }) : attendees.length === 0 ? /* @__PURE__ */ jsx(
51
+ StateView,
52
+ {
53
+ kind: "empty",
54
+ icon: Users,
55
+ title: "Nobody yet",
56
+ description: "Share the link or the code and they will appear here as they buy."
57
+ }
58
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: attendees.slice(0, PREVIEW).map((a) => /* @__PURE__ */ jsx(AttendeeRow, { attendee: a }, a.id)) }),
60
+ total > PREVIEW && /* @__PURE__ */ jsxs(
61
+ Button,
62
+ {
63
+ size: "sm",
64
+ variant: "secondary",
65
+ className: "mt-3",
66
+ onClick: () => setOpen(true),
67
+ children: [
68
+ "View all ",
69
+ total
70
+ ]
71
+ }
72
+ )
73
+ ] })
74
+ ] }),
75
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-lg", children: [
76
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: "Who is coming" }) }),
77
+ /* @__PURE__ */ jsx("ul", { className: "max-h-[60vh] space-y-1 overflow-y-auto", children: attendees.map((a) => /* @__PURE__ */ jsx(AttendeeRow, { attendee: a }, a.id)) }),
78
+ total > attendees.length && /* @__PURE__ */ jsxs("p", { className: "mt-3 text-sm text-[var(--text-tertiary)]", children: [
79
+ "Showing the first ",
80
+ attendees.length,
81
+ " of ",
82
+ total,
83
+ ". The full roster, with search and check-in, is on the attendees screen."
84
+ ] })
85
+ ] }) })
86
+ ] });
87
+ }
88
+ function AttendeeRow({ attendee }) {
89
+ const inAt = attendee.checkedInAt ? new Date(attendee.checkedInAt).toLocaleTimeString("en-GB", {
90
+ hour: "numeric",
91
+ minute: "2-digit"
92
+ }) : null;
93
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3 rounded-lg px-2 py-2", children: [
94
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
95
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm text-[var(--text-primary)]", children: attendee.customerName || attendee.customerEmail || "Guest" }),
96
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-[var(--text-tertiary)]", children: inAt ? [
97
+ `In at ${inAt}`,
98
+ attendee.checkedInVia ? `on ${attendee.checkedInVia}` : null,
99
+ attendee.checkedInSource === "dashboard" ? "from a desk" : null
100
+ ].filter(Boolean).join(" \xB7 ") : resolveTicketCode({ booking: attendee }) || "Not checked in" })
101
+ ] }),
102
+ /* @__PURE__ */ jsx(StatusBadge, { status: attendee.checkedInAt ? "checked_in" : "confirmed" })
103
+ ] });
104
+ }
105
+ export {
106
+ EventAttendees
107
+ };
108
+ //# sourceMappingURL=event-attendees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/events/%5BeventId%5D/_components/event-attendees.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Users } from 'lucide-react';\nimport {\n Button,\n Card,\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n StateView,\n} from '@withpotter/ui-kit';\nimport { StatusBadge } from '@withpotter/components/shared/status-badge';\nimport { resolveTicketCode } from '@withpotter/lib/ticket-access';\nimport { useApiQuery } from '@withpotter/hooks/use-api-query';\nimport { bookingsApi } from '@withpotter/lib/api/bookings';\nimport type { BookingItem } from '@withpotter/lib/api/types';\n\n/** How many stand on the page before the rest go behind View all. */\nconst PREVIEW = 5;\n\n/**\n * WHO IS COMING, on the event they are coming to.\n *\n * John, 2026-09-03: *\"the individual event should have an attendees section,\n * not a button, then we can have view all there which opens up a modal.\"*\n *\n * A button is what you put on a page when the answer lives somewhere else, and\n * the answer to \"is this selling\" is the first thing anybody opens an event to\n * find out. Five rows and a count answer it without leaving; the modal is for\n * the other question — reading down two hundred names looking for one — which\n * is genuinely a different screen and genuinely deserves to interrupt.\n *\n * IT IS NOT A SECOND ROSTER. Same request the attendees page makes, scoped to\n * this event by `contentId`, because an attendee is a customer in relation to\n * one night rather than a record of its own — the reason the global Attendees\n * nav row went in the first place.\n *\n * WHO LET THEM IN RIDES THE ROW. `checkedInVia` is the till, `checkedInSource`\n * says whether a door or a desk did it, and both are on the roster read rather\n * than a request per attendee: the morning-after question is asked of the\n * whole list at once.\n */\nexport function EventAttendees({\n eventId,\n doorListHref,\n}: {\n eventId: string;\n doorListHref: string;\n}) {\n const [open, setOpen] = useState(false);\n\n const { data, isLoading } = useApiQuery(\n ['event-attendees', eventId],\n (slug) =>\n bookingsApi.list(slug, {\n contentId: eventId,\n type: 'event',\n page: 1,\n limit: 100,\n }),\n );\n\n const attendees = (data?.data ?? []) as BookingItem[];\n const total = data?.total ?? attendees.length;\n const checkedIn = attendees.filter((a) => a.checkedInAt).length;\n\n return (\n <>\n <Card>\n <div className=\"mb-4 flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-[var(--text-secondary)]\">\n Who is coming\n </p>\n {/* The two numbers a promoter is watching belong under the\n section label, not between the label and its action. */}\n <p className=\"mt-1 text-xs tabular-nums text-[var(--text-tertiary)]\">\n {total} {total === 1 ? 'ticket' : 'tickets'}\n {checkedIn > 0 && ` · ${checkedIn} in`}\n </p>\n </div>\n <Button variant=\"secondary\" asChild>\n <a href={doorListHref}>Open door list</a>\n </Button>\n </div>\n\n {isLoading && attendees.length === 0 ? (\n <p className=\"text-sm text-[var(--text-tertiary)]\">\n Reading the list…\n </p>\n ) : attendees.length === 0 ? (\n <StateView\n kind=\"empty\"\n icon={Users}\n title=\"Nobody yet\"\n description=\"Share the link or the code and they will appear here as they buy.\"\n />\n ) : (\n <>\n <ul className=\"space-y-1\">\n {attendees.slice(0, PREVIEW).map((a) => (\n <AttendeeRow key={a.id} attendee={a} />\n ))}\n </ul>\n\n {total > PREVIEW && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n className=\"mt-3\"\n onClick={() => setOpen(true)}\n >\n View all {total}\n </Button>\n )}\n </>\n )}\n </Card>\n\n {/* Kept mounted so the exit animation runs — a panel that vanishes on a\n frame reads as a bug because it is one. */}\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>Who is coming</DialogTitle>\n </DialogHeader>\n <ul className=\"max-h-[60vh] space-y-1 overflow-y-auto\">\n {attendees.map((a) => (\n <AttendeeRow key={a.id} attendee={a} />\n ))}\n </ul>\n {total > attendees.length && (\n <p className=\"mt-3 text-sm text-[var(--text-tertiary)]\">\n Showing the first {attendees.length} of {total}. The full roster,\n with search and check-in, is on the attendees screen.\n </p>\n )}\n </DialogContent>\n </Dialog>\n </>\n );\n}\n\nfunction AttendeeRow({ attendee }: { attendee: BookingItem }) {\n const inAt = attendee.checkedInAt\n ? new Date(attendee.checkedInAt).toLocaleTimeString('en-GB', {\n hour: 'numeric',\n minute: '2-digit',\n })\n : null;\n\n return (\n <li className=\"flex items-center gap-3 rounded-lg px-2 py-2\">\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm text-[var(--text-primary)]\">\n {attendee.customerName || attendee.customerEmail || 'Guest'}\n </span>\n {/* WHO LET THEM IN, AND ON WHAT. The whole point of the audit: a name\n and a tick says a ticket was used; this says who was on the door,\n which machine they were holding, and when. Absent on a check-in\n taken before the audit existed, which is why every part of the line\n is conditional rather than a row of em dashes. */}\n <span className=\"block truncate text-xs text-[var(--text-tertiary)]\">\n {inAt\n ? [\n `In at ${inAt}`,\n attendee.checkedInVia ? `on ${attendee.checkedInVia}` : null,\n attendee.checkedInSource === 'dashboard' ? 'from a desk' : null,\n ]\n .filter(Boolean)\n .join(' · ')\n : resolveTicketCode({ booking: attendee }) || 'Not checked in'}\n </span>\n </span>\n <StatusBadge status={attendee.checkedInAt ? 'checked_in' : 'confirmed'} />\n </li>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { QRCodeSVG } from "qrcode.react";
5
+ import { Check, Copy, ExternalLink, Printer } from "lucide-react";
6
+ import { Button, Card } from "@withpotter/ui-kit";
7
+ function EventShare({
8
+ url,
9
+ title,
10
+ hashtag
11
+ }) {
12
+ const [copied, setCopied] = useState(null);
13
+ const copy = async (value, what) => {
14
+ try {
15
+ await navigator.clipboard.writeText(value);
16
+ setCopied(what);
17
+ window.setTimeout(() => setCopied(null), 1600);
18
+ } catch {
19
+ }
20
+ };
21
+ return /* @__PURE__ */ jsxs(Card, { children: [
22
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-sm font-medium text-[var(--text-secondary)]", children: "Share it" }),
23
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
24
+ /* @__PURE__ */ jsx("div", { className: "event-qr grid place-items-center rounded-[var(--radius-card)] bg-white p-3", children: /* @__PURE__ */ jsx(QRCodeSVG, { value: url, size: 148 }) }),
25
+ /* @__PURE__ */ jsx("p", { className: "text-center text-sm text-[var(--text-tertiary)]", children: "Scan for the details and to pay" })
26
+ ] }),
27
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
28
+ /* @__PURE__ */ jsx(
29
+ Button,
30
+ {
31
+ variant: "primary",
32
+ className: "w-full",
33
+ icon: copied === "link" ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(Copy, {}),
34
+ onClick: () => void copy(url, "link"),
35
+ children: copied === "link" ? "Link copied" : "Copy link"
36
+ }
37
+ ),
38
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "w-full", asChild: true, children: /* @__PURE__ */ jsxs("a", { href: url, target: "_blank", rel: "noreferrer", children: [
39
+ /* @__PURE__ */ jsx(ExternalLink, {}),
40
+ "Open event page"
41
+ ] }) }),
42
+ /* @__PURE__ */ jsx(
43
+ Button,
44
+ {
45
+ variant: "secondary",
46
+ className: "w-full",
47
+ icon: /* @__PURE__ */ jsx(Printer, {}),
48
+ onClick: () => window.print(),
49
+ children: "Print the code"
50
+ }
51
+ ),
52
+ /* @__PURE__ */ jsx(
53
+ Button,
54
+ {
55
+ variant: "ghost",
56
+ className: "w-full",
57
+ icon: copied === "tag" ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(Copy, {}),
58
+ onClick: () => void copy(hashtag, "tag"),
59
+ children: copied === "tag" ? "Hashtag copied" : hashtag
60
+ }
61
+ )
62
+ ] }),
63
+ /* @__PURE__ */ jsxs("div", { className: "event-print-sheet hidden", children: [
64
+ /* @__PURE__ */ jsx(QRCodeSVG, { value: url, size: 280 }),
65
+ /* @__PURE__ */ jsx("p", { className: "text-title font-semibold", children: title }),
66
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: url })
67
+ ] })
68
+ ] });
69
+ }
70
+ export {
71
+ EventShare
72
+ };
73
+ //# sourceMappingURL=event-share.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../src/dashboard/%28bookings%29/events/%5BeventId%5D/_components/event-share.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { QRCodeSVG } from 'qrcode.react';\nimport { Check, Copy, ExternalLink, Printer } from 'lucide-react';\nimport { Button, Card } from '@withpotter/ui-kit';\n\n/**\n * THE WAYS AN EVENT LEAVES THIS SCREEN — John, 2026-09-03: *\"each event should\n * also have... copy link, event page, hashtag\"*, and *\"events should have a QR\n * code created too so people can print out and people can scan and pay for it,\n * like see details then pay.\"*\n *\n * All four are the same act — handing somebody the event — and they differ\n * only in what the person is holding. A link goes in a WhatsApp broadcast; the\n * page is what you check looks right before you send it; the hashtag is what\n * goes on the flyer; the QR is for the wall, the flyer and the door of the\n * shop, where there is nothing to click.\n *\n * THE QR IS THE SAME URL, which is the whole reason it works. It resolves to\n * the public event page, which already shows the night, the room, the tiers and\n * a way to pay — so \"scan, see details, then pay\" needs no new surface, only\n * the code. A QR pointing at a bespoke ticket-buying screen would be a second\n * storefront to keep in step with the first.\n *\n * PRINTING IS `window.print()` AND ONE CLASS, not a generated PDF. The thing\n * printed is a square and a line of text; a PDF pipeline for that is a\n * dependency, a font-embedding problem and a filename convention in exchange\n * for nothing a browser does not already do well. The rule lives in the app's\n * print stylesheet with the rest of them rather than in a styled-jsx block\n * nothing else in this codebase uses.\n *\n * The hashtag is DERIVED from the slug rather than stored. A merchant who\n * wants their own can type it into the description today, and inventing a\n * field for it means a second name to keep in step with the first — the wrong\n * trade until somebody asks for it twice.\n */\nexport function EventShare({\n url,\n title,\n hashtag,\n}: {\n url: string;\n title: string;\n hashtag: string;\n}) {\n const [copied, setCopied] = useState<string | null>(null);\n\n const copy = async (value: string, what: string) => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(what);\n window.setTimeout(() => setCopied(null), 1600);\n } catch {\n // A clipboard a browser refuses is not worth an error state: the link is\n // on screen and selectable, which is the fallback either way.\n }\n };\n\n return (\n <Card>\n <p className=\"mb-3 text-sm font-medium text-[var(--text-secondary)]\">\n Share it\n </p>\n\n <div className=\"flex flex-col items-center gap-3\">\n {/* `print:` is the whole print stylesheet: everything else on the page\n is hidden by the utility below, so what comes out of the printer is\n the code, the name and the address under it. */}\n <div className=\"event-qr grid place-items-center rounded-[var(--radius-card)] bg-white p-3\">\n <QRCodeSVG value={url} size={148} />\n </div>\n <p className=\"text-center text-sm text-[var(--text-tertiary)]\">\n Scan for the details and to pay\n </p>\n </div>\n\n <div className=\"mt-4 space-y-2\">\n <Button\n variant=\"primary\"\n className=\"w-full\"\n icon={copied === 'link' ? <Check /> : <Copy />}\n onClick={() => void copy(url, 'link')}\n >\n {copied === 'link' ? 'Link copied' : 'Copy link'}\n </Button>\n\n <Button variant=\"secondary\" className=\"w-full\" asChild>\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n <ExternalLink />\n Open event page\n </a>\n </Button>\n\n <Button\n variant=\"secondary\"\n className=\"w-full\"\n icon={<Printer />}\n onClick={() => window.print()}\n >\n Print the code\n </Button>\n\n <Button\n variant=\"ghost\"\n className=\"w-full\"\n icon={copied === 'tag' ? <Check /> : <Copy />}\n onClick={() => void copy(hashtag, 'tag')}\n >\n {copied === 'tag' ? 'Hashtag copied' : hashtag}\n </Button>\n </div>\n\n {/* Only this prints — see `.event-print-sheet` in globals. A roster, a\n rail and a wall of buttons on an A4 sheet is what a merchant gets\n when nobody thinks about the printer. */}\n <div className=\"event-print-sheet hidden\">\n <QRCodeSVG value={url} size={280} />\n <p className=\"text-title font-semibold\">{title}</p>\n <p className=\"text-sm\">{url}</p>\n </div>\n </Card>\n );\n}\n"],"mappings":";AA6DM,cAIA,YAJA;AA3DN,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,OAAO,MAAM,cAAc,eAAe;AACnD,SAAS,QAAQ,YAAY;AAgCtB,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AAExD,QAAM,OAAO,OAAO,OAAe,SAAiB;AAClD,QAAI;AACF,YAAM,UAAU,UAAU,UAAU,KAAK;AACzC,gBAAU,IAAI;AACd,aAAO,WAAW,MAAM,UAAU,IAAI,GAAG,IAAI;AAAA,IAC/C,QAAQ;AAAA,IAGR;AAAA,EACF;AAEA,SACE,qBAAC,QACC;AAAA,wBAAC,OAAE,WAAU,yDAAwD,sBAErE;AAAA,IAEA,qBAAC,SAAI,WAAU,oCAIb;AAAA,0BAAC,SAAI,WAAU,8EACb,8BAAC,aAAU,OAAO,KAAK,MAAM,KAAK,GACpC;AAAA,MACA,oBAAC,OAAE,WAAU,mDAAkD,6CAE/D;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,kBACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACV,MAAM,WAAW,SAAS,oBAAC,SAAM,IAAK,oBAAC,QAAK;AAAA,UAC5C,SAAS,MAAM,KAAK,KAAK,KAAK,MAAM;AAAA,UAEnC,qBAAW,SAAS,gBAAgB;AAAA;AAAA,MACvC;AAAA,MAEA,oBAAC,UAAO,SAAQ,aAAY,WAAU,UAAS,SAAO,MACpD,+BAAC,OAAE,MAAM,KAAK,QAAO,UAAS,KAAI,cAChC;AAAA,4BAAC,gBAAa;AAAA,QAAE;AAAA,SAElB,GACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACV,MAAM,oBAAC,WAAQ;AAAA,UACf,SAAS,MAAM,OAAO,MAAM;AAAA,UAC7B;AAAA;AAAA,MAED;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACV,MAAM,WAAW,QAAQ,oBAAC,SAAM,IAAK,oBAAC,QAAK;AAAA,UAC3C,SAAS,MAAM,KAAK,KAAK,SAAS,KAAK;AAAA,UAEtC,qBAAW,QAAQ,mBAAmB;AAAA;AAAA,MACzC;AAAA,OACF;AAAA,IAKA,qBAAC,SAAI,WAAU,4BACb;AAAA,0BAAC,aAAU,OAAO,KAAK,MAAM,KAAK;AAAA,MAClC,oBAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MAC/C,oBAAC,OAAE,WAAU,WAAW,eAAI;AAAA,OAC9B;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { FixedIntentScope } from "@withpotter/components/intents/fixed-scope";
4
+ function Layout({ children }) {
5
+ return /* @__PURE__ */ jsx(FixedIntentScope, { intent: "event-tickets", children });
6
+ }
7
+ export {
8
+ Layout as default
9
+ };
10
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/dashboard/%28bookings%29/events/%5BeventId%5D/layout.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { FixedIntentScope } from '@withpotter/components/intents/fixed-scope';\n\n/** This screen belongs to one intent, so it speaks that intent's words. */\nexport default function Layout({ children }: { children: ReactNode }) {\n return <FixedIntentScope intent=\"event-tickets\">{children}</FixedIntentScope>;\n}\n"],"mappings":";AAOS;AAJT,SAAS,wBAAwB;AAGlB,SAAR,OAAwB,EAAE,SAAS,GAA4B;AACpE,SAAO,oBAAC,oBAAiB,QAAO,iBAAiB,UAAS;AAC5D;","names":[]}