@wix/agent-skills 1.21.0 → 1.22.0

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 (258) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +60 -4
  3. package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
  4. package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
  5. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
  6. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
  7. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
  8. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
  9. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
  10. package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
  11. package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
  12. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
  13. package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
  14. package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
  15. package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
  16. package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
  17. package/skills/wix-headless-fast/SKILL.md +61 -223
  18. package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
  19. package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +11 -12
  20. package/skills/wix-headless-fast/guides/existing-site.md +76 -0
  21. package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
  22. package/skills/wix-headless-fast/install/AGENTS.md +6 -3
  23. package/skills/wix-headless-fast/install/attach.mjs +15 -47
  24. package/skills/wix-headless-fast/install/deploy.mjs +21 -60
  25. package/skills/wix-headless-fast/install/lock.mjs +55 -0
  26. package/skills/wix-headless-fast/install/setup.mjs +32 -12
  27. package/skills/wix-headless-fast/install/templates.mjs +168 -0
  28. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
  29. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
  30. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -303
  31. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
  32. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
  33. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
  34. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
  35. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
  36. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
  37. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
  38. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
  39. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
  40. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
  41. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
  42. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
  43. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
  44. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
  45. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
  46. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
  47. package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
  48. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
  49. package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
  50. package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +0 -22
  51. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
  52. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -277
  53. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
  54. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
  55. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
  56. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
  57. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
  58. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
  59. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
  60. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
  61. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
  62. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
  63. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
  64. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
  65. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
  66. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
  67. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
  68. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
  69. package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
  70. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
  71. package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +0 -28
  72. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
  73. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -355
  74. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
  75. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
  76. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
  77. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
  78. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
  79. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
  80. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
  81. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
  82. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
  83. package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
  84. package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
  85. package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +0 -20
  86. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
  87. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -307
  88. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
  89. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
  90. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
  91. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
  92. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
  93. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
  94. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
  95. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
  96. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
  97. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
  98. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
  99. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
  100. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
  101. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
  102. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
  103. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
  104. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
  105. package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
  106. package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
  107. package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
  108. package/skills/wix-headless-fast/references/events/seed/read-site.mjs +0 -26
  109. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
  110. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -340
  111. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
  112. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
  113. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
  114. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
  115. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
  116. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
  117. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
  118. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
  119. package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
  120. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
  121. package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
  122. package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +0 -20
  123. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
  124. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -316
  125. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
  126. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
  127. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
  128. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
  129. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
  130. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
  131. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
  132. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
  133. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
  134. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
  135. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
  136. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
  137. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
  138. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
  139. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
  140. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
  141. package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
  142. package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
  143. package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
  144. package/skills/wix-headless-fast/references/members/seed/read-site.mjs +0 -15
  145. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
  146. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -315
  147. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
  148. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
  149. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
  150. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
  151. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
  152. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
  153. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
  154. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
  155. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
  156. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
  157. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
  158. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
  159. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
  160. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
  161. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
  162. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
  163. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
  164. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
  165. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
  166. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
  167. package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +0 -20
  168. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -256
  169. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -296
  170. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
  171. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
  172. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
  173. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
  174. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
  175. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
  176. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
  177. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
  178. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
  179. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
  180. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
  181. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
  182. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
  183. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
  184. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
  185. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
  186. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
  187. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
  188. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
  189. package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +0 -21
  190. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
  191. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -360
  192. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
  193. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
  194. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
  195. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
  196. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
  197. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
  198. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
  199. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
  200. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
  201. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
  202. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
  203. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
  204. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
  205. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
  206. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
  207. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
  208. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
  209. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
  210. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
  211. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
  212. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
  213. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
  214. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
  215. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
  216. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
  217. package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +0 -25
  218. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -499
  219. package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
  220. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
  221. package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
  222. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
  223. package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
  224. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
  225. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
  226. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
  227. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
  228. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
  229. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
  230. package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
  231. package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
  232. package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
  233. package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
  234. package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +0 -99
  235. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -612
  236. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
  237. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
  238. package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
  239. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
  240. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
  241. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
  242. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
  243. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
  244. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
  245. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
  246. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
  247. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -314
  248. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
  249. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
  250. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
  251. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -169
  252. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
  253. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
  254. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
  255. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
  256. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -130
  257. package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +0 -38
  258. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -561
@@ -1,103 +0,0 @@
1
- // Client-side order-cart state — a module-scope store, deliberately NOT a React context.
2
- // A context can't span Astro islands (each island is its own React root); a module singleton
3
- // is shared by every island in the page bundle, and works identically in a single-root SPA.
4
- // Consume it through useOrderCart() (hooks/), or subscribe directly.
5
- import type { OrderCart } from "./types";
6
- import {
7
- addToOrder as apiAdd,
8
- fetchOrderCart,
9
- orderCheckoutUrl,
10
- removeOrderLine as apiRemove,
11
- resolveOperationId,
12
- updateOrderQuantity as apiUpdate,
13
- } from "./ordering";
14
-
15
- export interface OrderCartState {
16
- cart: OrderCart | null;
17
- /** null while resolving; false → no ordering operation configured (show "unavailable"). */
18
- ordering: boolean | null;
19
- /** True while any cart operation is in flight. */
20
- busy: boolean;
21
- /** Last failed operation's message — render it; a new operation clears it. */
22
- error: string | null;
23
- /** Order drawer visibility (OrderCartButton opens it, OrderCartDrawer renders by it). */
24
- open: boolean;
25
- }
26
-
27
- const EMPTY: OrderCartState = { cart: null, ordering: null, busy: false, error: null, open: false };
28
-
29
- let state: OrderCartState = EMPTY;
30
- const listeners = new Set<() => void>();
31
- let loaded = false;
32
-
33
- function setState(patch: Partial<OrderCartState>): void {
34
- state = { ...state, ...patch };
35
- for (const l of listeners) l();
36
- }
37
-
38
- export function getOrderCartState(): OrderCartState {
39
- return state;
40
- }
41
-
42
- export function subscribeOrderCart(listener: () => void): () => void {
43
- listeners.add(listener);
44
- // First subscriber triggers the initial load (browser only — SSR renders the empty state).
45
- if (!loaded && typeof window !== "undefined") {
46
- loaded = true;
47
- void refreshOrderCart();
48
- void resolveOperationId().then((id) => setState({ ordering: id !== null }));
49
- }
50
- return () => listeners.delete(listener);
51
- }
52
-
53
- async function run(op: () => Promise<OrderCart>): Promise<void> {
54
- setState({ busy: true, error: null });
55
- try {
56
- setState({ cart: await op(), busy: false });
57
- } catch (e) {
58
- setState({ busy: false, error: e instanceof Error ? e.message : String(e) });
59
- throw e;
60
- }
61
- }
62
-
63
- export async function refreshOrderCart(): Promise<void> {
64
- try {
65
- setState({ cart: await fetchOrderCart() });
66
- } catch {
67
- /* no cart yet — leave the empty state */
68
- }
69
- }
70
-
71
- /** Add a menu item to the order and open the drawer. Throws (and sets .error) on refusal. */
72
- export async function addOrderLine(
73
- itemId: string,
74
- context: { menuId: string; sectionId: string },
75
- quantity = 1,
76
- ): Promise<void> {
77
- await run(() => apiAdd(itemId, context, quantity));
78
- setState({ open: true });
79
- }
80
-
81
- export async function updateOrderLineQuantity(lineItemId: string, quantity: number): Promise<void> {
82
- await run(() => apiUpdate(lineItemId, quantity));
83
- }
84
-
85
- export async function removeLineFromOrder(lineItemId: string): Promise<void> {
86
- await run(() => apiRemove(lineItemId));
87
- }
88
-
89
- /** Navigate to the Wix-hosted checkout. Never hand-build a checkout URL. */
90
- export async function goToOrderCheckout(): Promise<void> {
91
- setState({ busy: true, error: null });
92
- try {
93
- const url = await orderCheckoutUrl();
94
- window.location.href = url;
95
- } catch (e) {
96
- setState({ busy: false, error: e instanceof Error ? e.message : String(e) });
97
- throw e;
98
- }
99
- }
100
-
101
- export function setOrderCartOpen(open: boolean): void {
102
- setState({ open });
103
- }
@@ -1,124 +0,0 @@
1
- // Online-ordering rules and DTO mapping — transport-agnostic, imported by both ./ordering.ts (SDK)
2
- // and the REST twin in references/restaurants/rest/ordering.ts (fetch). The restaurant cart rides
3
- // on the eCom current cart (Cart V2); what makes a line a RESTAURANT line is the catalogReference
4
- // built here: the Orders app id plus options { operationId, menuId, sectionId } — all three, and
5
- // no variantId. Raw entities carry `_id` (SDK) or `id` (REST). Has its own formatMoney (a copy of
6
- // ../money.ts) so it stands alone when stripped. Imports are type-only.
7
- import type { FulfillmentMethodInfo, OrderCart, OrderLine } from "./types";
8
- import type { ImgSrc, Raw } from "./menu-core";
9
-
10
- /** The Restaurants Orders app id — every restaurant cart line's catalogReference.appId. */
11
- export const RESTAURANTS_ORDERS_APP_ID = "9a5d83fd-8570-482e-81ab-cfa88942ee60";
12
-
13
- export const rawId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
14
-
15
- /**
16
- * Cart V2 money is ConvertedMoney { amount, convertedAmount } with NO formatted string, and the
17
- * currency lives on the cart, not on the money. Never hardcode a symbol or assume USD.
18
- */
19
- export function formatMoney(money: Raw | null | undefined, currencyCode: string | null | undefined): string {
20
- const value = money?.convertedAmount ?? money?.amount;
21
- if (value == null || value === "") return "";
22
- const currency = currencyCode || "USD";
23
- try {
24
- return new Intl.NumberFormat(undefined, { style: "currency", currency }).format(Number(value));
25
- } catch {
26
- return `${value} ${currency}`;
27
- }
28
- }
29
-
30
- export const cartCurrency = (raw: Raw | null | undefined): string =>
31
- raw?.customerInfo?.currencyCode ?? raw?.businessInfo?.currencyCode ?? "";
32
-
33
- /** The operation to order through: ENABLED, else the default, else the first; null when none exists. */
34
- export function pickOperationId(operations: Raw[]): string | null {
35
- const op = operations.find((o) => o.onlineOrderingStatus === "ENABLED") ?? operations.find((o) => o.default) ?? operations[0];
36
- return op ? rawId(op) || null : null;
37
- }
38
-
39
- /** Enabled pickup/delivery methods, for display — fees and minimums as decimal strings. */
40
- export function toFulfillmentMethods(raws: Raw[]): FulfillmentMethodInfo[] {
41
- return raws
42
- .filter((m) => m.enabled === true)
43
- .map((m): FulfillmentMethodInfo => ({
44
- id: rawId(m),
45
- type: m.type === "DELIVERY" ? "DELIVERY" : "PICKUP",
46
- name: m.name ?? "",
47
- fee: m.fee ?? "0",
48
- minOrderPrice: m.minOrderPrice ?? "0",
49
- }))
50
- .filter((m) => m.id);
51
- }
52
-
53
- export function toOrderLine(raw: Raw, currency: string, imgSrc: ImgSrc): OrderLine {
54
- return {
55
- lineItemId: rawId(raw), // the LINE id — what update/remove take, never the menu item id
56
- itemName: raw.name?.original ?? "",
57
- quantity: raw.quantityInfo?.confirmedQuantity ?? 0,
58
- unitPrice: formatMoney(raw.pricing?.unitPrice, currency),
59
- linePrice: formatMoney(raw.pricing?.totalPrice, currency),
60
- imageUrl: imgSrc(raw.attributes?.image, 300, 300),
61
- descriptionLines: ((raw.attributes?.descriptionLines ?? []) as Raw[])
62
- .map((d) => {
63
- const label = d.name?.original ?? "", value = d.plainText?.original ?? d.colorInfo?.original ?? "";
64
- return label && value ? `${label}: ${value}` : value || label;
65
- })
66
- .filter(Boolean),
67
- status: raw.status ?? "IN_STOCK", // not IN_STOCK → the line can't be checked out as-is
68
- };
69
- }
70
-
71
- export function toOrderCart(raw: Raw | null, subtotal: string, imgSrc: ImgSrc): OrderCart {
72
- const currency = cartCurrency(raw);
73
- const lines = ((raw?.lineItems ?? []) as Raw[]).map((l) => toOrderLine(l, currency, imgSrc));
74
- return { lines, itemCount: lines.reduce((n, l) => n + l.quantity, 0), subtotal, currency };
75
- }
76
-
77
- /** The after-discount subtotal from a cart estimate; "" when unknown. Fees, tax, delivery resolve at checkout. */
78
- export function estimateSubtotal(estimate: Raw | null | undefined, raw: Raw): string {
79
- return formatMoney(estimate?.summary?.priceSummary?.subtotal, cartCurrency(raw));
80
- }
81
-
82
- /** The line-refusal reasons an add can't recover from — checked before any call. */
83
- export function assertOrderContext(itemId: string, menuId: string, sectionId: string): void {
84
- if (!itemId || !menuId || !sectionId) throw new Error("addToOrder needs the item, menu, and section ids.");
85
- }
86
-
87
- /**
88
- * The one catalogItems entry of an add: the Orders app id and the three context ids — the
89
- * restaurant analog of the store's variantId. Modifier/variant selections are NOT sent (that
90
- * options shape isn't documented for a client add); quantity only.
91
- */
92
- export function orderCatalogItem(itemId: string, ctx: { operationId: string; menuId: string; sectionId: string }, quantity: number): Raw {
93
- return {
94
- quantity,
95
- catalogReference: {
96
- catalogItemId: itemId,
97
- appId: RESTAURANTS_ORDERS_APP_ID,
98
- options: { operationId: ctx.operationId, menuId: ctx.menuId, sectionId: ctx.sectionId },
99
- },
100
- };
101
- }
102
-
103
- /** Read the add result — a refused add still returns 200: a line whose status isn't IN_STOCK, or no line, is a refusal. */
104
- export function assertOrderAdded(cart: Raw | null | undefined, itemId: string): void {
105
- // V2 nests the reference under `source` — a top-level lineItem.catalogReference no longer exists.
106
- const line = ((cart?.lineItems ?? []) as Raw[]).find((l) => l.source?.catalogReference?.catalogItemId === itemId);
107
- if (line?.status && line.status !== "IN_STOCK") {
108
- throw new Error(`This dish isn't available right now (${String(line.status).toLowerCase().replace(/_/g, " ")}).`);
109
- }
110
- if (!line || line.quantityInfo?.confirmedQuantity === 0) {
111
- throw new Error("The dish couldn't be added to the order — please try again.");
112
- }
113
- }
114
-
115
- /** Refuse checkout for an empty order or any line not IN_STOCK — say which. */
116
- export function assertOrderCheckoutable(raw: Raw | null): void {
117
- const lines: Raw[] = raw?.lineItems ?? [];
118
- if (!lines.length) throw new Error("Your order is empty.");
119
- const unavailable = lines.filter((l) => l.status && l.status !== "IN_STOCK");
120
- if (unavailable.length) {
121
- throw new Error(`Some dishes are no longer available: ${unavailable.map((l) => l.name?.original).filter(Boolean).join(", ")}.`);
122
- }
123
- if (!rawId(raw)) throw new Error("Checkout couldn't start: the order has no id.");
124
- }
@@ -1,185 +0,0 @@
1
- // Online ordering (Restaurants Orders + Wix eCom Cart V2) over the SDK — the only file that
2
- // touches the raw cart and operation entities on this transport. Rules and mappers live in
3
- // ./ordering-core (shared with the REST twin in references/restaurants/rest/); this file is the
4
- // transport only. Copy as-is; extend by calling these exports, never by editing them. The request
5
- // shapes are exact and rewriting them is how carts break:
6
- // - the catalogReference appId is the ORDERS app (9a5d83fd-…), never the Stores id;
7
- // - options MUST carry operationId + menuId + sectionId (all three) — no variantId;
8
- // - modifier/variant selections are NOT sent on the line (undocumented for a client add).
9
- // Failures are loud: throws on a missing ordering operation, unavailable lines, and an empty
10
- // order at checkout — surface the message, don't swallow it.
11
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/operations/list-operations.md
12
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/fulfillment-methods/list-fulfillment-methods.md
13
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/items/items/list-items.md
14
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md
15
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/add-line-items-to-current-cart.md
16
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/update-line-items.md
17
- // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
18
- import { operations as operationsModule, fulfillmentMethods as fulfillmentModule, items as itemsModule } from "@wix/restaurants";
19
- import { currentCartV2 } from "@wix/ecom";
20
- import { redirects as redirectsModule } from "@wix/redirects";
21
- import { wixModule } from "../sdk";
22
- import { imgSrc } from "../media";
23
- import {
24
- RESTAURANTS_ORDERS_APP_ID,
25
- assertOrderAdded,
26
- assertOrderCheckoutable,
27
- assertOrderContext,
28
- estimateSubtotal,
29
- orderCatalogItem,
30
- pickOperationId,
31
- rawId,
32
- toFulfillmentMethods,
33
- toOrderCart,
34
- } from "./ordering-core";
35
- import type { Raw } from "./menu-core";
36
- import type { FulfillmentMethodInfo, OrderCart } from "./types";
37
-
38
- export { RESTAURANTS_ORDERS_APP_ID };
39
-
40
- const operationsApi = wixModule(operationsModule);
41
- const fulfillmentApi = wixModule(fulfillmentModule);
42
- const itemsApi = wixModule(itemsModule);
43
- const cartApi = wixModule(currentCartV2);
44
- const redirects = wixModule(redirectsModule);
45
-
46
- // The ordering operation is site config — resolve once, reuse for every add.
47
- let operationIdPromise: Promise<string | null> | null = null;
48
-
49
- /**
50
- * The id of the operation to order through (ENABLED, else default, else first) — null when
51
- * the site has no online ordering configured (show an "ordering unavailable" state).
52
- */
53
- export function resolveOperationId(): Promise<string | null> {
54
- operationIdPromise ??= operationsApi
55
- .listOperations()
56
- .then((res: Raw) => pickOperationId(res.operations ?? []))
57
- .catch(() => {
58
- operationIdPromise = null; // transient failure — allow a retry on the next call
59
- return null;
60
- });
61
- return operationIdPromise;
62
- }
63
-
64
- /** Enabled pickup/delivery methods, for display — the buyer picks one on the hosted checkout. */
65
- export async function fetchFulfillmentMethods(): Promise<FulfillmentMethodInfo[]> {
66
- try {
67
- const res: Raw = await fulfillmentApi.listFulfillmentMethods();
68
- return toFulfillmentMethods(res.fulfillmentMethods ?? []);
69
- } catch {
70
- return []; // display nicety — ordering still works without the list
71
- }
72
- }
73
-
74
- // A line's attributes.image may come back absent — join the menu items' images by the line's
75
- // catalogItemId and cache for the session.
76
- const lineImageCache = new Map<string, string>();
77
- async function fillLineImages(cart: OrderCart, raws: Raw[]): Promise<void> {
78
- const wanted = new Map<string, number[]>(); // itemId -> line indexes
79
- raws.forEach((raw, i) => {
80
- if (cart.lines[i].imageUrl) return;
81
- const itemId = raw.source?.catalogReference?.catalogItemId;
82
- if (!itemId) return;
83
- const cached = lineImageCache.get(itemId);
84
- if (cached !== undefined) {
85
- cart.lines[i].imageUrl = cached;
86
- return;
87
- }
88
- wanted.set(itemId, [...(wanted.get(itemId) ?? []), i]);
89
- });
90
- if (!wanted.size) return;
91
- try {
92
- const res: Raw = await itemsApi.listItems({ itemIds: [...wanted.keys()] });
93
- for (const item of (res.items ?? []) as Raw[]) {
94
- const url = imgSrc(item.image, 300, 300);
95
- lineImageCache.set(rawId(item), url);
96
- for (const i of wanted.get(rawId(item)) ?? []) cart.lines[i].imageUrl = url;
97
- }
98
- } catch {
99
- /* images are a nicety — the cart stays correct without them */
100
- }
101
- }
102
-
103
- async function readCartWithSubtotal(raw: Raw | null): Promise<OrderCart> {
104
- // Only estimate a cart WITH lines — on an absent/empty cart the endpoint returns 404.
105
- if (!raw?.lineItems?.length) return toOrderCart(raw, "", imgSrc);
106
- // The authoritative after-discount subtotal comes from the cart estimate, never from
107
- // hand-summing line items (fees, tax, and delivery resolve at checkout).
108
- let subtotal = "";
109
- try {
110
- subtotal = estimateSubtotal(await cartApi.estimateCurrentCart(), raw);
111
- } catch {
112
- /* estimate is a display nicety — the cart itself is still valid */
113
- }
114
- const cart = toOrderCart(raw, subtotal, imgSrc);
115
- await fillLineImages(cart, raw.lineItems as Raw[]);
116
- return cart;
117
- }
118
-
119
- /** Read the visitor's current order cart. An empty cart (not an error) when none exists yet. */
120
- export async function fetchOrderCart(): Promise<OrderCart> {
121
- try {
122
- const { cart } = await cartApi.getCurrentCart();
123
- return readCartWithSubtotal(cart as Raw);
124
- } catch {
125
- return toOrderCart(null, "", imgSrc);
126
- }
127
- }
128
-
129
- /**
130
- * Add a menu item to the current order. `menuId` and `sectionId` are the ids of the menu and
131
- * section the item is RENDERED UNDER — thread them from the render context (the fetchMenus
132
- * tree), never re-derive them. Throws when ordering isn't configured or the line is refused.
133
- */
134
- export async function addToOrder(
135
- itemId: string,
136
- { menuId, sectionId }: { menuId: string; sectionId: string },
137
- quantity = 1,
138
- ): Promise<OrderCart> {
139
- const operationId = await resolveOperationId();
140
- if (!operationId) throw new Error("Online ordering isn't available right now.");
141
- assertOrderContext(itemId, menuId, sectionId);
142
- const { cart } = await cartApi.addLineItemsToCurrentCart({
143
- catalogItems: [orderCatalogItem(itemId, { operationId, menuId, sectionId }, quantity)],
144
- });
145
- assertOrderAdded(cart as Raw, itemId);
146
- return readCartWithSubtotal(cart as Raw);
147
- }
148
-
149
- /** Change a line's quantity. `lineItemId` is OrderLine.lineItemId, never the menu item id. */
150
- export async function updateOrderQuantity(lineItemId: string, quantity: number): Promise<OrderCart> {
151
- const { cart } = await cartApi.updateLineItemsInCurrentCart({
152
- lineItems: [{ lineItemId, quantity: { newQuantity: quantity } }],
153
- });
154
- return readCartWithSubtotal(cart as Raw);
155
- }
156
-
157
- /** Remove a line from the order by OrderLine.lineItemId. */
158
- export async function removeOrderLine(lineItemId: string): Promise<OrderCart> {
159
- const { cart } = await cartApi.removeLineItemsFromCurrentCart([lineItemId]);
160
- return readCartWithSubtotal(cart as Raw);
161
- }
162
-
163
- /**
164
- * Start the Wix-hosted checkout for the current order and return the URL to navigate to.
165
- * The cart's id IS the checkout id — no separate checkout-creation call. Fulfillment
166
- * (pickup/delivery + time) and payment are collected on the hosted page. Call from the
167
- * browser: the return origin must be window.location.origin (https), never a server-derived
168
- * request origin (http behind the proxy → the return redirect 403s).
169
- */
170
- export async function orderCheckoutUrl(): Promise<string> {
171
- const { cart } = await cartApi.getCurrentCart();
172
- const raw = cart as Raw;
173
- assertOrderCheckoutable(raw);
174
- const origin = typeof window !== "undefined" ? window.location.origin : "";
175
- const session = await redirects.createRedirectSession({
176
- ecomCheckout: { checkoutId: rawId(raw) },
177
- callbacks: {
178
- postFlowUrl: origin ? `${origin}/` : undefined,
179
- thankYouPageUrl: origin ? `${origin}/` : undefined,
180
- },
181
- });
182
- const url = session?.redirectSession?.fullUrl;
183
- if (!url) throw new Error("Checkout couldn't start: no redirect URL returned.");
184
- return url;
185
- }
@@ -1,193 +0,0 @@
1
- // The table-reservation state machine as a framework-free store — the logic behind useReservation,
2
- // usable from React (useReservation wraps it), from a static page or Vue/Svelte, or as the
3
- // specification for a port. Location, date + party size, AVAILABLE slots, the 10-minute hold, the
4
- // details form, and confirm. All correctness (AVAILABLE-only slots, hold → reserve with the
5
- // revision, firstName + E.164 phone, RESERVED vs REQUESTED) lives in the data layer; this store
6
- // orchestrates. Browser-only: availability is timezone-specific. One store per mounted surface:
7
- // createReservationStore(), `start()` when mounted.
8
- import { completeReservation, fetchReservationLocations, fetchReservationSlots, holdReservation } from "./reservations";
9
- import type { ReservationConfirmation, ReservationHold, ReservationLocationInfo, ReservationReservee, ReservationSlot } from "./types";
10
-
11
- const todayKey = (): string => {
12
- const d = new Date();
13
- const pad = (n: number) => String(n).padStart(2, "0");
14
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
15
- };
16
-
17
- /** Everything a reservation surface renders from. Read it with getState() or through a subscription. */
18
- export interface ReservationState {
19
- /** null while loading; [] when Table Reservations isn't set up (honest empty state). */
20
- locations: ReservationLocationInfo[] | null;
21
- /** The active location (default first). Render a picker only when locations.length > 1. */
22
- location: ReservationLocationInfo | null;
23
- /** "YYYY-MM-DD" for a date input. */
24
- date: string;
25
- /** "HH:mm" anchor for the slot fan-out. */
26
- time: string;
27
- /** Clamped to the location's partySizeMin/Max. */
28
- partySize: number;
29
- /** AVAILABLE slots for the current query; null until findSlots ran. */
30
- slots: ReservationSlot[] | null;
31
- /** Set after holdSlot — the visitor has 10 minutes to confirm. */
32
- held: ReservationHold | null;
33
- reservee: ReservationReservee;
34
- /** True when a slot is held and firstName + phone are filled — gate the confirm CTA. */
35
- canConfirm: boolean;
36
- /** Set on success. REQUESTED → tell the visitor approval is pending, not confirmed. */
37
- confirmed: ReservationConfirmation | null;
38
- loading: boolean;
39
- error: string | null;
40
- }
41
-
42
- export interface ReservationStore {
43
- getState(): ReservationState;
44
- subscribe(listener: () => void): () => void;
45
- /** Load the locations. Call once when mounted (a browser). */
46
- start(): void;
47
- stop(): void;
48
- setLocationId(id: string): void;
49
- setDate(date: string): void;
50
- setTime(time: string): void;
51
- setPartySize(size: number): void;
52
- findSlots(): Promise<void>;
53
- holdSlot(slot: ReservationSlot): Promise<void>;
54
- setReserveeField(field: keyof ReservationReservee, value: string): void;
55
- confirm(): Promise<void>;
56
- /** Back to slot picking (keeps date/party). */
57
- reset(): void;
58
- }
59
-
60
- export function createReservationStore(): ReservationStore {
61
- let locations: ReservationLocationInfo[] | null = null;
62
- let locationId: string | null = null;
63
- let date = todayKey();
64
- let time = "19:00";
65
- let partySize = 2;
66
- let slots: ReservationSlot[] | null = null;
67
- let held: ReservationHold | null = null;
68
- let reservee: ReservationReservee = { firstName: "", phone: "" };
69
- let confirmed: ReservationConfirmation | null = null;
70
- let loading = false;
71
- let error: string | null = null;
72
- let started = false;
73
- const listeners = new Set<() => void>();
74
- let snapshot: ReservationState | null = null;
75
- const emit = () => {
76
- snapshot = null;
77
- for (const fn of listeners) fn();
78
- };
79
-
80
- const currentLocation = (): ReservationLocationInfo | null => locations?.find((l) => l.id === locationId) ?? locations?.[0] ?? null;
81
-
82
- function getState(): ReservationState {
83
- if (snapshot) return snapshot;
84
- snapshot = {
85
- locations,
86
- location: currentLocation(),
87
- date,
88
- time,
89
- partySize,
90
- slots,
91
- held,
92
- reservee,
93
- canConfirm: !!held && reservee.firstName.trim().length > 0 && reservee.phone.trim().length > 0 && !loading,
94
- confirmed,
95
- loading,
96
- error,
97
- };
98
- return snapshot;
99
- }
100
-
101
- const fail = (e: unknown) => (e instanceof Error ? e.message : String(e));
102
-
103
- return {
104
- getState,
105
- subscribe(fn) {
106
- listeners.add(fn);
107
- return () => listeners.delete(fn);
108
- },
109
- start() {
110
- if (started) return;
111
- started = true;
112
- fetchReservationLocations()
113
- .then((locs) => {
114
- if (!started) return;
115
- locations = locs;
116
- locationId ??= locs[0]?.id ?? null;
117
- emit();
118
- })
119
- .catch((e) => {
120
- if (!started) return;
121
- locations = [];
122
- error = fail(e);
123
- emit();
124
- });
125
- },
126
- stop() {
127
- started = false;
128
- },
129
- setLocationId(id) { locationId = id; emit(); },
130
- setDate(next) { date = next; emit(); },
131
- setTime(next) { time = next; emit(); },
132
- setPartySize(size) {
133
- const loc = currentLocation();
134
- const min = loc?.partySizeMin ?? 1;
135
- const max = loc?.partySizeMax ?? 20;
136
- partySize = Math.min(Math.max(size, min), max);
137
- emit();
138
- },
139
- async findSlots() {
140
- const loc = currentLocation();
141
- if (!loc) return;
142
- error = null; slots = null; held = null; confirmed = null; loading = true;
143
- emit();
144
- try {
145
- const aroundIso = new Date(`${date}T${time}:00`).toISOString();
146
- slots = await fetchReservationSlots(loc.id, aroundIso, partySize);
147
- } catch (e) {
148
- slots = [];
149
- error = fail(e);
150
- } finally {
151
- loading = false;
152
- emit();
153
- }
154
- },
155
- async holdSlot(slot) {
156
- const loc = currentLocation();
157
- if (!loc) return;
158
- error = null; loading = true;
159
- emit();
160
- try {
161
- held = await holdReservation(loc.id, slot.startIso, partySize);
162
- } catch (e) {
163
- error = fail(e);
164
- } finally {
165
- loading = false;
166
- emit();
167
- }
168
- },
169
- setReserveeField(field, value) {
170
- reservee = { ...reservee, [field]: value };
171
- emit();
172
- },
173
- async confirm() {
174
- if (!held) return;
175
- error = null; loading = true;
176
- emit();
177
- try {
178
- confirmed = await completeReservation(held, reservee);
179
- } catch (e) {
180
- // An expired hold can't be reserved — send the visitor back to slot picking.
181
- error = fail(e);
182
- held = null;
183
- } finally {
184
- loading = false;
185
- emit();
186
- }
187
- },
188
- reset() {
189
- held = null; confirmed = null; slots = null; error = null;
190
- emit();
191
- },
192
- };
193
- }