@wix/agent-skills 1.17.0 → 1.18.1

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 (253) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +115 -12
  3. package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
  4. package/skills/wix-app/references/BACKEND_API.md +18 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
  7. package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +74 -83
  9. package/skills/wix-app/references/SITE_PLUGIN.md +12 -0
  10. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
  11. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
  12. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
  13. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
  14. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
  15. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +12 -11
  16. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +1 -0
  17. package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
  18. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +16 -8
  19. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +47 -14
  20. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +3 -0
  21. package/skills/wix-base44-connector/SKILL.md +133 -44
  22. package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
  23. package/skills/wix-base44-connector/scripts/utils.js +216 -30
  24. package/skills/wix-headless/entry/skill.md +1 -1
  25. package/skills/wix-headless/references/CAPABILITIES.md +9 -1
  26. package/skills/wix-headless/references/DESIGN.md +1 -0
  27. package/skills/wix-headless/references/DISCOVERY.md +2 -1
  28. package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
  29. package/skills/wix-headless/references/SDK_HANDOFF.md +4 -1
  30. package/skills/wix-headless/references/SEED.md +2 -1
  31. package/skills/wix-headless/references/SETUP.md +1 -0
  32. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
  33. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +26 -8
  34. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
  35. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
  36. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
  37. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
  38. package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
  39. package/skills/wix-headless/references/inline-recipes/setup-forms.md +57 -10
  40. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
  41. package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
  42. package/skills/wix-headless/references/non-astro.md +1 -1
  43. package/skills/wix-headless-fast/SKILL.md +166 -0
  44. package/skills/wix-headless-fast/entry/skill.md +99 -0
  45. package/skills/wix-headless-fast/install/deploy.mjs +433 -0
  46. package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
  47. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
  48. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
  49. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
  50. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
  51. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
  52. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
  53. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
  54. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
  55. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
  56. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
  57. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
  58. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
  59. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
  60. package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
  61. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
  62. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
  63. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
  64. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
  65. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
  66. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
  67. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
  68. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
  69. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
  70. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
  71. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
  72. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
  73. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
  74. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
  75. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
  76. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
  77. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
  78. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
  79. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
  80. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
  81. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
  82. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
  83. package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
  84. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
  85. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
  86. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
  87. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
  88. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
  89. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
  90. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
  91. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
  92. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
  93. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
  94. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
  95. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
  96. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
  97. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
  98. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
  99. package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
  100. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
  101. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
  102. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
  103. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
  104. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
  105. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
  106. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
  107. package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
  108. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
  109. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
  110. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
  111. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
  112. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
  113. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
  114. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
  115. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
  116. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
  117. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
  118. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
  119. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
  120. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
  121. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
  122. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
  123. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
  124. package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
  125. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
  126. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
  127. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
  128. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
  129. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
  130. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
  131. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
  132. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
  133. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
  134. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
  135. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
  136. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
  137. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
  138. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
  139. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
  140. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
  141. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
  142. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
  143. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
  144. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
  145. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
  146. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
  147. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
  148. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
  149. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
  150. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
  151. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
  152. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
  153. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
  154. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
  155. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
  156. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
  157. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
  158. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
  159. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
  160. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
  161. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
  162. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
  163. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
  164. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
  165. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
  166. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
  167. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
  168. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
  169. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
  170. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
  171. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
  172. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
  173. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
  174. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
  175. package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
  176. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
  177. package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
  178. package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
  179. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
  180. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
  181. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
  182. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
  183. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
  184. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
  185. package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
  186. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
  187. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
  188. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
  189. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
  190. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
  191. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
  192. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
  193. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
  194. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
  195. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
  196. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
  197. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
  198. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
  199. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
  200. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
  201. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
  202. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
  203. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
  204. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
  205. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
  206. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
  207. package/skills/wix-manage/SKILL.md +113 -89
  208. package/skills/wix-manage/references/dashboard-navigation/routes.json +12 -52
  209. package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-api.md +0 -2
  210. package/skills/wix-manage/references/forms/create-form.md +272 -184
  211. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +13 -10
  212. package/skills/wix-manage/references/forms/update-form.md +122 -0
  213. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
  214. package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
  215. package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
  216. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
  217. package/skills/wix-manage/references/media/generate-image-with-ai.md +86 -0
  218. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +37 -7
  219. package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
  220. package/skills/wix-vibe-headless/SKILL.md +18 -4
  221. package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
  222. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
  223. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
  224. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +3 -1
  225. package/skills/wix-vibe-headless/platforms/base44.md +27 -61
  226. package/skills/wix-vibe-headless/platforms/generic.md +6 -3
  227. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +43 -0
  228. package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
  229. package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
  230. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
  231. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
  232. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
  233. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
  234. package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
  235. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
  236. package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +486 -0
  237. package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
  238. package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
  239. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
  240. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
  241. package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1836 -0
  242. package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
  243. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +137 -84
  244. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
  245. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
  246. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
  247. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
  248. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
  249. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
  250. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
  251. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
  252. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
  253. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
@@ -0,0 +1,103 @@
1
+ # CMS — seeding
2
+
3
+ Seed by **running `seed-cms.mjs` with a plan file** — don't hand-write the REST calls.
4
+ The script mints its own site token via the Wix CLI (logged-in session + `wix.config.json`
5
+ required), installs the Wix Data (CMS) app if needed, resolves every IMAGE value into Wix
6
+ Media in one parallel wave, and creates everything in order: per collection — create
7
+ (schema + permissions) → bulk-insert items → wire multi-references → verify persistence.
8
+
9
+ ```bash
10
+ # from the project root (where wix.config.json lives):
11
+ node <SKILL_ROOT>/references/cms/seed/seed-cms.mjs plan.json
12
+ ```
13
+
14
+ `plan.json` is plain data — **it IS the site's content model**: the collections, their field
15
+ schemas, and the items the pages will render. Write it from the brief. Default to **one or
16
+ two content collections with ~3–6 items each** (the seed shows the shape; the owner adds the
17
+ rest in the dashboard). Give any collection that gets a detail page a `slug` TEXT field, and
18
+ every content item an image on an IMAGE field (a content site without images looks broken).
19
+
20
+ ```json
21
+ {
22
+ "collections": [
23
+ {
24
+ "id": "categories", "displayName": "Categories",
25
+ "fields": [{ "key": "name", "type": "TEXT" }],
26
+ "items": [{ "name": "Cakes" }, { "name": "Breads" }]
27
+ },
28
+ {
29
+ "id": "recipes", "displayName": "Recipes",
30
+ "fields": [
31
+ { "key": "title", "type": "TEXT" },
32
+ { "key": "slug", "type": "TEXT" },
33
+ { "key": "summary", "type": "TEXT" },
34
+ { "key": "body", "type": "RICH_TEXT" },
35
+ { "key": "photo", "type": "IMAGE" },
36
+ { "key": "publishDate", "type": "DATE" },
37
+ { "key": "categories", "type": "MULTI_REFERENCE", "referencedCollectionId": "categories" }
38
+ ],
39
+ "items": [
40
+ { "title": "Chocolate Layer Cake", "slug": "chocolate-layer-cake",
41
+ "summary": "Three layers, one ganache.", "body": "<p>Cream the butter…</p>",
42
+ "photo": "https://…", "publishDate": "2026-08-01", "categories": [0] },
43
+ { "title": "Country Sourdough", "slug": "country-sourdough",
44
+ "summary": "A 24-hour loaf.", "body": "<p>Feed the starter…</p>",
45
+ "photo": "https://…", "publishDate": "2026-08-10", "categories": [1] },
46
+ { "title": "Pavlova", "slug": "pavlova",
47
+ "summary": "Crisp shell, soft heart.", "body": "<p>Whip the whites…</p>",
48
+ "photo": "https://…", "publishDate": "2026-08-20", "categories": [0] }
49
+ ]
50
+ }
51
+ ]
52
+ }
53
+ ```
54
+
55
+ - `id` — the collection id the frontend binds to, verbatim (no namespace; Wix doesn't rename
56
+ it). Item keys must match the field `key`s exactly — the script fails loud on a key the
57
+ schema doesn't have (the API would silently drop it).
58
+ - Field `type` — `TEXT`, `NUMBER`, `BOOLEAN`, `DATE`, `DATETIME`, `URL`, `EMAIL`, `IMAGE`,
59
+ `RICH_TEXT` (an HTML string, stored verbatim), `REFERENCE`, `MULTI_REFERENCE`.
60
+ - `IMAGE` values — the default is `{ "prompt": "..." }` (AI-generated, ~1 Wix AI credit per
61
+ image, account-billed): brand-contextual — subject, aesthetic/mood, palette, lighting —
62
+ always ending "no text, no watermarks". At least one image in the set shows the real subject of the business — the actual product/space/service, not abstract decoration. For an asset the user actually supplied use
63
+ `{ "path": "..." }` (a file on this machine — uploaded to Wix Media) or an https URL string
64
+ (their own hosted URL; verify it with `curl -sI` → 200) — never a stock-photo or guessed URL. Images
65
+ resolve in parallel and never block the seed; a failed image leaves that field unset (the
66
+ item stays text-only).
67
+ - `DATE`/`DATETIME` values are ISO strings — the script wraps them as `{ "$date": iso }`.
68
+ - References: **order collections so targets come first.** A `REFERENCE` value is the target
69
+ item's index in its collection's `items` array; `MULTI_REFERENCE` is an array of indices
70
+ (set at insert it would be silently dropped — the script wires these via
71
+ `POST /wix-data/v2/bulk/items/insert-references`).
72
+ - `permissions` — omit for the **public-read** default
73
+ (`read: ANYONE`, writes `ADMIN`). Other shapes (per action: `ANYONE` › `SITE_MEMBER` ›
74
+ `SITE_MEMBER_AUTHOR` › `ADMIN`):
75
+
76
+ | preset | `read` / `insert` / `update` / `remove` | use |
77
+ |---|---|---|
78
+ | public-read (default) | `ANYONE` / `ADMIN` / `ADMIN` / `ADMIN` | admin content, anyone reads |
79
+ | collaborative | `ANYONE` / `ANYONE` / `ANYONE` / `ANYONE` | visitor-written shared board (anonymous, unscoped) |
80
+ | member-private | `SITE_MEMBER_AUTHOR` / `SITE_MEMBER` / `SITE_MEMBER_AUTHOR` / `SITE_MEMBER_AUTHOR` | per-user "my…" rows — **seed it EMPTY** (rows seeded here would be owned by the admin, invisible to members) |
81
+ | member-shared-read-only | `SITE_MEMBER` / `ADMIN` / `ADMIN` / `ADMIN` | gated: any member reads, seed/admin writes |
82
+ | public-wall | `ANYONE` / `SITE_MEMBER` / `SITE_MEMBER_AUTHOR` / `SITE_MEMBER_AUTHOR` | members post, everyone reads |
83
+
84
+ `read` is the privacy decision — a public collection's `read` MUST be `ANYONE` or the
85
+ visitor frontend reads **zero items with no error**.
86
+
87
+ **Seeding is additive — never delete or overwrite existing content** (an existing collection
88
+ is left as-is; its items are appended); ask first if a cleanup seems needed.
89
+
90
+ ## Escape hatch — individual functions
91
+ `setupCms` composes exported steps — `installDataApp`, `createCollection`, `importImage`,
92
+ `bulkInsertItems`, `insertReferences`, `verifyItems`, plus `makeCtx()` — import them only
93
+ for a partial re-seed.
94
+
95
+ ## Reference
96
+ Unexpected shape or an uncovered operation → read the live Wix API reference; the
97
+ authoritative source recipe is `wix-headless/references/inline-recipes/setup-cms.md`.
98
+ Endpoints used: `POST /wix-data/v2/collections` (Create Data Collection),
99
+ `POST /wix-data/v2/bulk/items/insert` (Bulk Insert Data Items),
100
+ `POST /wix-data/v2/bulk/items/insert-references` (Bulk Insert Data Item References),
101
+ `POST /wix-data/v2/items/query` (Query Data Items — the verify step),
102
+ `POST /site-media/v1/files/import` (Import File),
103
+ `POST /apps-installer-service/v1/app-instance/install` (Install App).
@@ -0,0 +1,324 @@
1
+ // CMS seed — a BUILD-TIME script, never shipped in the app. Run from the project root
2
+ // (where wix.config.json lives) with a plan file:
3
+ //
4
+ // node <SKILL_ROOT>/references/cms/seed/seed-cms.mjs plan.json
5
+ //
6
+ // It mints its own site token via the Wix CLI, installs the Wix Data (CMS) app if needed,
7
+ // resolves every IMAGE value into Wix Media (url import / AI generation, one parallel wave),
8
+ // creates each collection (field schema + permissions; an existing collection is left
9
+ // as-is), bulk-inserts items, wires multi-references, and verifies persistence. Prints a
10
+ // JSON result to stdout.
11
+ //
12
+ // Plan shape (see SEED.md):
13
+ // { "collections": [{ "id", "displayName"?, "permissions"?,
14
+ // "fields": [{ "key", "displayName"?, "type", "referencedCollectionId"? }],
15
+ // "items": [{ "<fieldKey>": value, ... }] }] }
16
+ // Reference fields: order collections so targets come FIRST. A REFERENCE value is the
17
+ // target item's index in ITS collection's items array; MULTI_REFERENCE is an array of
18
+ // indices. An IMAGE value is a verified https url STRING, { "prompt": "..." }
19
+ // (AI-generated), or { "path": "..." } (a local file the user supplied, uploaded).
20
+ //
21
+ // Seeding is ADDITIVE — never deletes or overwrites existing content. Unexpected shapes →
22
+ // read the live API reference; authoritative source recipe:
23
+ // wix-headless/references/inline-recipes/setup-cms.md.
24
+ import { execFileSync } from "node:child_process";
25
+ import { readFileSync } from "node:fs";
26
+ import { resolveItemImages } from "../../shared/seed/images.mjs";
27
+
28
+ const API = "https://www.wixapis.com";
29
+ const WIX_DATA_APP_ID = "e593b0bd-b783-45b8-97c2-873d42aacaf4";
30
+
31
+ // Public collection default: read MUST be "ANYONE" or a visitor query silently returns 0
32
+ // items (the single most common "empty page" cause). Other presets: SEED.md.
33
+ const DEFAULT_PERMISSIONS = { insert: "ADMIN", update: "ADMIN", remove: "ADMIN", read: "ANYONE" };
34
+
35
+ export function makeCtx({ cwd = process.cwd() } = {}) {
36
+ const config = JSON.parse(readFileSync(`${cwd}/wix.config.json`, "utf8"));
37
+ const siteId = config.siteId ?? config.projectId;
38
+ if (!siteId) throw new Error("wix.config.json has no siteId — is this a Wix CLI project?");
39
+ const token = execFileSync("npx", ["@wix/cli@latest", "token", "--site", siteId], {
40
+ encoding: "utf8",
41
+ cwd,
42
+ }).trim();
43
+ if (!token) throw new Error("The Wix CLI returned no token — run `npx @wix/cli@latest login` first.");
44
+ return { token, siteId };
45
+ }
46
+
47
+ async function req(ctx, path, { method = "POST", body } = {}) {
48
+ const res = await fetch(API + path, {
49
+ method,
50
+ headers: {
51
+ Authorization: `Bearer ${ctx.token}`,
52
+ "wix-site-id": ctx.siteId,
53
+ "Content-Type": "application/json",
54
+ },
55
+ body: body ? JSON.stringify(body) : undefined,
56
+ });
57
+ const json = await res.json().catch(() => ({}));
58
+ if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
59
+ return json;
60
+ }
61
+
62
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
63
+
64
+ // A fresh site's Wix Data backend can transiently fail its FIRST calls while provisioning —
65
+ // 403, 400 WDE0117 ("MetaSite not found"), or 5xx. Retry the same body ONCE after ~3s, then
66
+ // fail loud (never loop).
67
+ async function reqRetryOnce(ctx, path, opts) {
68
+ try {
69
+ return await req(ctx, path, opts);
70
+ } catch (e) {
71
+ const m = String(e.message);
72
+ if (/-> (403|5\d\d):/.test(m) || m.includes("WDE0117")) {
73
+ await sleep(3000);
74
+ return req(ctx, path, opts);
75
+ }
76
+ throw e;
77
+ }
78
+ }
79
+
80
+ // ---- operations ----------------------------------------------------------------------------------
81
+
82
+ // Idempotent; strictly only needed when a data call errors WDE0110 (app not installed).
83
+ // docs: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix.md
84
+ export async function installDataApp(ctx) {
85
+ try {
86
+ await req(ctx, "/apps-installer-service/v1/app-instance/install", { body: {
87
+ tenant: { tenantType: "SITE", id: ctx.siteId },
88
+ appInstance: { appDefId: WIX_DATA_APP_ID, enabled: true },
89
+ } });
90
+ } catch {
91
+ /* already installed is fine */
92
+ }
93
+ }
94
+
95
+ // The binding key is referencedCollectionId — the docs' stale `referencedCollection` is
96
+ // accepted with a 200 but stores an EMPTY target, leaving every later link silently dead.
97
+ // MULTI_REFERENCE additionally REQUIRES referencingFieldKey — the auto-created back-reference
98
+ // field on the referenced collection (400 without it); synthesized from the owning
99
+ // collection + field when the plan doesn't name one.
100
+ function buildField(f, collectionId) {
101
+ const out = { key: f.key, displayName: f.displayName ?? f.key, type: f.type };
102
+ if (f.type === "MULTI_REFERENCE" || f.type === "REFERENCE") {
103
+ if (!f.referencedCollectionId) {
104
+ throw new Error(`field "${f.key}": ${f.type} requires referencedCollectionId`);
105
+ }
106
+ out.typeMetadata =
107
+ f.type === "MULTI_REFERENCE"
108
+ ? { multiReference: {
109
+ referencedCollectionId: f.referencedCollectionId,
110
+ referencingFieldKey: f.referencingFieldKey ?? `${collectionId}_${f.key}`.replace(/[^a-zA-Z0-9_]/g, "_"),
111
+ referencingDisplayName: f.referencingDisplayName ?? `${displayNameOf(collectionId)} (${f.key})`,
112
+ } }
113
+ : { reference: { referencedCollectionId: f.referencedCollectionId } };
114
+ }
115
+ return out;
116
+ }
117
+
118
+ const displayNameOf = (id) => String(id).replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
119
+
120
+ // The permissions block is MANDATORY. 409 WDE0104 (already exists) is fine — additive.
121
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-collections/create-data-collection.md
122
+ export async function createCollection(ctx, { id, displayName, fields = [], permissions }) {
123
+ try {
124
+ await reqRetryOnce(ctx, "/wix-data/v2/collections", { body: { collection: {
125
+ id,
126
+ displayName: displayName ?? id,
127
+ fields: fields.map((f) => buildField(f, id)),
128
+ permissions: permissions ?? DEFAULT_PERMISSIONS,
129
+ } } });
130
+ return { id, created: true };
131
+ } catch (e) {
132
+ const m = String(e.message);
133
+ if (m.includes("WDE0104") || m.includes("-> 409:")) return { id, created: false };
134
+ throw e;
135
+ }
136
+ }
137
+
138
+ // An IMAGE field stores a permanent Wix Media URL — an external url must be imported first;
139
+ // a { "prompt": ... } value is generated (Wix AI, 1 credit) then imported. Both live in the
140
+ // shared util (parallel, resilient, never blocks the seed).
141
+ export { importImage } from "../../shared/seed/images.mjs";
142
+
143
+ // Ids come from results[].dataItem.id (there is no results[].item key).
144
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/bulk-insert-data-items.md
145
+ export async function bulkInsertItems(ctx, dataCollectionId, dataItems) {
146
+ const r = await reqRetryOnce(ctx, "/wix-data/v2/bulk/items/insert", { body: {
147
+ dataCollectionId,
148
+ dataItems: dataItems.map((data) => ({ data })),
149
+ returnEntity: true,
150
+ } });
151
+ const results = [...(r.results ?? [])].sort(
152
+ (a, b) => (a.itemMetadata?.originalIndex ?? 0) - (b.itemMetadata?.originalIndex ?? 0),
153
+ );
154
+ return {
155
+ ids: results.map((res) => res.dataItem?.id ?? res.itemMetadata?.id),
156
+ failures: r.bulkActionMetadata?.totalFailures ?? 0,
157
+ };
158
+ }
159
+
160
+ // Body key is dataItemReferences with referringItemFieldName/referringItemId/referencedItemId
161
+ // — the natural-looking `references` shape is rejected with 400 WDE0080.
162
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/bulk-insert-data-item-references.md
163
+ export async function insertReferences(ctx, dataCollectionId, dataItemReferences) {
164
+ if (!dataItemReferences.length) return 0;
165
+ const r = await req(ctx, "/wix-data/v2/bulk/items/insert-references", {
166
+ body: { dataCollectionId, dataItemReferences },
167
+ });
168
+ return r.bulkActionMetadata?.totalSuccesses ?? dataItemReferences.length;
169
+ }
170
+
171
+ // A 200 on insert does NOT prove persistence — query back and count.
172
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/query-data-items.md
173
+ export async function verifyItems(ctx, dataCollectionId) {
174
+ const r = await reqRetryOnce(ctx, "/wix-data/v2/items/query", { body: { dataCollectionId } });
175
+ return (r.dataItems ?? []).length;
176
+ }
177
+
178
+ // plan item -> insert `data`, per field type. MULTI_REFERENCE values are silently dropped by
179
+ // the insert endpoint (200, no error) — stripped here and wired after; a single REFERENCE is
180
+ // set at insert as the target item's _id. DATE/DATETIME wrap as { "$date": iso }; RICH_TEXT
181
+ // is an HTML string stored verbatim; IMAGE values were resolved to Wix Media files up front
182
+ // (imageFiles, keyed by imageKey) — a failed image leaves the field unset.
183
+ function buildItemData(col, item, idsByCollection, multiRefs, itemIndex, counters, imageFiles) {
184
+ const fieldsByKey = new Map((col.fields ?? []).map((f) => [f.key, f]));
185
+ const data = {};
186
+ for (const [key, value] of Object.entries(item)) {
187
+ const f = fieldsByKey.get(key);
188
+ // A key the schema doesn't have is silently dropped by the API — fail loud instead.
189
+ if (!f) throw new Error(`"${col.id}" item ${itemIndex}: key "${key}" is not in the collection's fields`);
190
+ if (value == null) continue;
191
+ if (f.type === "MULTI_REFERENCE") {
192
+ for (const targetIndex of [].concat(value)) {
193
+ multiRefs.push({ itemIndex, fieldKey: key, targetCollectionId: f.referencedCollectionId, targetIndex });
194
+ }
195
+ continue;
196
+ }
197
+ if (f.type === "REFERENCE") {
198
+ const targetId = (idsByCollection.get(f.referencedCollectionId) ?? [])[value];
199
+ if (!targetId) {
200
+ throw new Error(
201
+ `"${col.id}" item ${itemIndex}: REFERENCE "${key}" -> "${f.referencedCollectionId}"[${value}] — ` +
202
+ `target not created yet (order collections so targets come first)`,
203
+ );
204
+ }
205
+ data[key] = targetId;
206
+ continue;
207
+ }
208
+ if (f.type === "IMAGE") {
209
+ const file = imageFiles.get(imageKey(col.id, itemIndex, key));
210
+ if (file) {
211
+ data[key] = file.url;
212
+ counters.imagesImported++;
213
+ }
214
+ continue;
215
+ }
216
+ if (f.type === "DATE" || f.type === "DATETIME") {
217
+ data[key] = { $date: new Date(value).toISOString() };
218
+ continue;
219
+ }
220
+ data[key] = value;
221
+ }
222
+ return data;
223
+ }
224
+
225
+ const imageKey = (colId, itemIndex, fieldKey) => `${colId}${itemIndex}${fieldKey}`;
226
+
227
+ // Every IMAGE value across the plan (a url string or { prompt }), resolved to Wix Media files
228
+ // in ONE parallel wave before any insert. Returns Map<imageKey, { id, url } | absent>.
229
+ async function resolveAllImages(ctx, collections) {
230
+ const keys = [];
231
+ const specs = [];
232
+ for (const col of collections) {
233
+ const imageFields = new Set((col.fields ?? []).filter((f) => f.type === "IMAGE").map((f) => f.key));
234
+ (col.items ?? []).forEach((item, i) => {
235
+ for (const [key, value] of Object.entries(item)) {
236
+ if (!imageFields.has(key) || value == null) continue;
237
+ keys.push(imageKey(col.id, i, key));
238
+ specs.push({
239
+ url: typeof value === "string" ? value : undefined,
240
+ path: typeof value === "object" ? value.path : undefined,
241
+ prompt: typeof value === "object" ? value.prompt : undefined,
242
+ displayName: `${col.id}-${i}-${key}.png`,
243
+ });
244
+ }
245
+ });
246
+ }
247
+ const files = specs.length ? await resolveItemImages(ctx, specs) : [];
248
+ const out = new Map();
249
+ keys.forEach((k, i) => { if (files[i]) out.set(k, files[i]); });
250
+ return out;
251
+ }
252
+
253
+ /**
254
+ * ONE-CALL seed: install → resolve every IMAGE value in one parallel wave → per collection
255
+ * (in plan order): create → bulk-insert → wire multi-references → verify; ids threaded in
256
+ * memory. The default path.
257
+ */
258
+ export async function setupCms(ctx, { collections = [] } = {}) {
259
+ await installDataApp(ctx);
260
+
261
+ const imageFiles = await resolveAllImages(ctx, collections);
262
+
263
+ const idsByCollection = new Map();
264
+ const out = { collections: [] };
265
+ for (const col of collections) {
266
+ const created = await createCollection(ctx, col);
267
+
268
+ const counters = { imagesImported: 0 };
269
+ const multiRefs = [];
270
+ const dataItems = [];
271
+ const planItems = col.items ?? [];
272
+ for (let i = 0; i < planItems.length; i++) {
273
+ dataItems.push(buildItemData(col, planItems[i], idsByCollection, multiRefs, i, counters, imageFiles));
274
+ }
275
+
276
+ let ids = [];
277
+ let failures = 0;
278
+ if (dataItems.length) ({ ids, failures } = await bulkInsertItems(ctx, col.id, dataItems));
279
+ idsByCollection.set(col.id, ids);
280
+
281
+ const refs = multiRefs.map(({ itemIndex, fieldKey, targetCollectionId, targetIndex }) => {
282
+ const referringItemId = ids[itemIndex];
283
+ const referencedItemId = (idsByCollection.get(targetCollectionId) ?? [])[targetIndex];
284
+ if (!referringItemId || !referencedItemId) {
285
+ throw new Error(
286
+ `"${col.id}" item ${itemIndex}: multi-reference "${fieldKey}" -> "${targetCollectionId}"[${targetIndex}] ` +
287
+ `has no created id (order collections so targets come first)`,
288
+ );
289
+ }
290
+ return { referringItemFieldName: fieldKey, referringItemId, referencedItemId };
291
+ });
292
+ const referencesLinked = await insertReferences(ctx, col.id, refs);
293
+
294
+ out.collections.push({
295
+ id: col.id,
296
+ created: created.created,
297
+ inserted: ids.length,
298
+ failures,
299
+ imagesImported: counters.imagesImported,
300
+ referencesLinked,
301
+ itemsInCollection: await verifyItems(ctx, col.id),
302
+ });
303
+ }
304
+ return out;
305
+ }
306
+
307
+ // ---- CLI entry ----------------------------------------------------------------------------------
308
+
309
+ const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
310
+ if (invokedDirectly) {
311
+ const planPath = process.argv[2];
312
+ if (!planPath) {
313
+ console.error("usage: node seed-cms.mjs <plan.json> (run from the project root)");
314
+ process.exit(1);
315
+ }
316
+ const plan = JSON.parse(readFileSync(planPath, "utf8"));
317
+ const ctx = makeCtx();
318
+ setupCms(ctx, plan)
319
+ .then((result) => console.log(JSON.stringify(result, null, 2)))
320
+ .catch((e) => {
321
+ console.error(e.message);
322
+ process.exit(1);
323
+ });
324
+ }
@@ -0,0 +1,149 @@
1
+ # Events — playbook
2
+
3
+ The events machinery ships as files — event reads (list, by slug, by id), the visitor-public
4
+ ticket-tier read, the exact `reserve → hosted-checkout redirect` sequence, and RSVP, typed
5
+ end-to-end. **The presentation is yours**: you design and implement the event card, the
6
+ events index, and the event page's registration surface on the shipped hooks/DTOs, plus the
7
+ home page and the brand. You never write registration logic; you never skip designing.
8
+
9
+ ## The file map (deployed into `src/`)
10
+
11
+ **Don't read the shipped files** — this table and the contracts below are everything you
12
+ need. Open a shipped file's source only on a real fallback (runtime error / uncovered field),
13
+ or to read a reference component's pattern.
14
+
15
+ | file | what it is |
16
+ |---|---|
17
+ | `wix/config.ts` · `wix/sdk.ts` · `wix/media.ts` · `wix/money.ts` | shared auth seam + helpers (deploy configures; nothing to set) |
18
+ | `wix/events/types.ts` | the DTOs (`EventSummary`, `EventDetail`, `TicketTier`, `RegistrationResult`) — contracts below |
19
+ | `wix/events/events.ts` | `fetchEvents`, `fetchEventBySlug`, `fetchEventById` (post-checkout confirmation read) |
20
+ | `wix/events/registration.ts` | `fetchTicketTiers`, `startTicketCheckout`, `submitRsvp` — the exact reserve→redirect sequence lives here |
21
+ | `hooks/events/useEvents.ts` | listing + category filter — contract below |
22
+ | `hooks/events/useEventRegistration.ts` | the whole registration state machine — contract below |
23
+ | `components/events/EventsView.tsx` (+ `EventCard`) · `EventRegistrationView.tsx` · `EventConfirmationView.tsx` | **REFERENCE implementations** — correct, plain; build your own instead of shipping them |
24
+ | `styles/global.css` | the design system: Tailwind v4 + the `@theme` token block (shared across verticals) |
25
+
26
+ Astro stack additionally gets:
27
+
28
+ | file | what it is |
29
+ |---|---|
30
+ | `layouts/SiteLayout.astro` | site chrome — **yours to brand** (keep the `seo-tags` slot + global.css import). If another vertical is also deployed, its layout won — add an Events nav link there |
31
+ | `pages/events.astro` | SSR listing — **keep the frontmatter**, swap the island import to YOUR component |
32
+ | `pages/events/[slug].astro` | SSR detail + registration with owner-editable SEO — **keep the frontmatter and the SEO pieces** (`wixMetadata`, `loadSEOTagsServiceConfig`, `<SEO.Tags>`) exactly; swap the island import. The registration island stays `client:only="react"` |
33
+ | `pages/event-confirmation.astro` | the hosted checkout's thank-you landing (`?orderNumber=&eventId=`) — **keep the route**; the shipped checkout callbacks point at it |
34
+
35
+ ## What you build — the design job
36
+
37
+ 1. **The event card + events index** — your tile (image, date eyebrow, title,
38
+ venue/online, price-from, sold-out badge) and rhythm, with the category filter (only when
39
+ >1 category), skeletons while loading, and an honest empty state — on `useEvents`.
40
+ 2. **The event page's registration surface** — branch on `event.registrationType`:
41
+ `TICKETING` → your tier picker (name, description, price, quantity stepper capped by
42
+ `limitPerCheckout`, non-`SALE_STARTED` tiers unbuyable) and the checkout CTA; `RSVP` →
43
+ the built-in first/last/email form (a "can't make it" option only when
44
+ `rsvpResponseType === "YES_AND_NO"`) and the confirmed/waitlist states; `EXTERNAL` →
45
+ link out; closed → an honest closed state — on `useEventRegistration`, which owns ALL
46
+ registration logic; you own how it looks.
47
+ 3. **The home page** — hero, featured/next events (fetch in frontmatter → your components),
48
+ brand story.
49
+
50
+ Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
51
+ Style everything with Tailwind utilities on the tokens.
52
+
53
+ ### The contracts your components consume
54
+
55
+ ```ts
56
+ // EventSummary (tiles) — display-ready:
57
+ // { id, slug, title, shortDescription /* plain text */, dateLabel /* "Sep 26, 2026, 7:00 PM" */,
58
+ // startDateIso, locationName, locationType: "VENUE"|"ONLINE"|"TBD", imageUrl,
59
+ // registrationType: "RSVP"|"TICKETING"|"EXTERNAL"|"NONE",
60
+ // priceLabel /* "From €25.00" | "Free" | "" */, soldOut, categories: [{id,name}] }
61
+ // EventDetail adds: aboutParagraphs: string[], registrationOpen, rsvpResponseType,
62
+ // externalUrl, addToCalendar: { google, ics }.
63
+ // TicketTier: { id, name, description, price /* "€45.00" | "Free" */, free,
64
+ // limitPerCheckout, saleStatus /* only "SALE_STARTED" is buyable */ }
65
+
66
+ // useEvents({ initialEvents? }) →
67
+ // { events: EventSummary[]|null /* null = loading → skeletons */,
68
+ // categories: [{id,name}] /* derived from the loaded events */,
69
+ // activeCategoryId, setActiveCategoryId(id|null), error }
70
+
71
+ // useEventRegistration(event: EventDetail) →
72
+ // { tiers: TicketTier[]|null, // TICKETING only; null = loading
73
+ // quantities, setQuantity(tierId, qty), // clamped; sale-status gated
74
+ // ticketCount, canCheckout, // gate the tickets CTA on canCheckout
75
+ // checkout(): Promise<RegistrationResult>, // reserve → the browser redirects to Wix checkout
76
+ // rsvpValues, setRsvpValue(field, value), // built-in fields: firstName/lastName/email
77
+ // canRsvp, // gate the RSVP CTA on this
78
+ // rsvp(attending?): Promise<RegistrationResult>, // attending=false only for YES_AND_NO
79
+ // submitting, confirmed, error } // confirmed: rsvpConfirmed with status
80
+ // // "YES" | "NO" | "WAITLIST" (tell the guest!)
81
+ ```
82
+
83
+ ### Wiring — Astro (default)
84
+
85
+ 1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
86
+ existing layout instead if another vertical is deployed).
87
+ 2. Write your components under `src/components/events/` (new names — don't overwrite the
88
+ references), swap the island imports in `pages/events.astro` and
89
+ `pages/events/[slug].astro`. Listing island: `client:load` with the SSR props;
90
+ registration island: `client:only="react"`. Keep `pages/event-confirmation.astro`'s route.
91
+ **Author your surfaces in as few messages as possible** — batch multiple Writes per
92
+ message.
93
+ 3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
94
+
95
+ ### Wiring — React SPA (Vite etc.)
96
+
97
+ Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
98
+ plugins — deploy added the dep). Routes: `/events` → your listing; `/events/:slug` → fetch
99
+ with `fetchEventBySlug(slug)` client-side, then your registration surface;
100
+ `/event-confirmation` → the confirmation view (the checkout callbacks point at that path).
101
+
102
+ ## Hard rules
103
+
104
+ - **Registration logic only through the shipped exports** — `useEventRegistration` /
105
+ `startTicketCheckout` / `submitRsvp` own the sequence (visitor-public tier read, reserve,
106
+ `createRedirectSession({ eventsCheckout })`, rsvpV2). Never re-derive any of it, never
107
+ hand-build a checkout/ticket-form URL, never route it through an API route or elevate —
108
+ the whole flow runs client-side as the visitor.
109
+ - **Branch on `registrationType`** — never render an RSVP event with a ticket picker or a
110
+ ticketed event with an RSVP form; respect `registrationOpen`.
111
+ - **The RSVP form is built-in** — exactly first name, last name, email; never fetch a form
112
+ schema or add fields.
113
+ - **Gate CTAs on `canCheckout` / `canRsvp`** and surface `error` — `checkout()`/`rsvp()` can
114
+ reject (sold out, sale ended, duplicate email, payment method not configured); the message
115
+ is for the visitor.
116
+ - **Confirmed states reflect REAL success**: RSVP → render only from `confirmed` (and say
117
+ "waitlisted", not "confirmed", for status `WAITLIST`). Tickets → the only success surface
118
+ is `/event-confirmation` with Wix's `?orderNumber=` params; a visitor merely returning to
119
+ the event page is NOT a success signal.
120
+ - Theme via the `@theme` tokens; no parallel theme files, no hardcoded palettes.
121
+ - Live data or an honest empty state — never mock events, tiers, or "X spots left".
122
+ - Keep the detail page's SEO pieces exactly as shipped.
123
+
124
+ ## Point the user to their dashboard
125
+
126
+ Give the owner the dashboard link plus the Events page — the deploy step's JSON printed
127
+ `dashboardUrl`; append `/events` for event management. **Selling paid tickets needs a premium
128
+ plan + a connected payment method** (free/RSVP events work without) — mention it.
129
+
130
+ ## Seeding
131
+
132
+ Per `seed/SEED.md` — plain-data `plan.json` into `seed-events.mjs` from the project root.
133
+ Seed events that exercise the UI (a ticketed event with 2 tiers, another ticketed one, a free
134
+ RSVP event; future dates; an image per event).
135
+
136
+ ## Verify (before declaring done)
137
+
138
+ - [ ] `/events` renders live events SSR (view-source shows titles) through YOUR components;
139
+ empty catalog shows your honest empty state.
140
+ - [ ] An event page branches correctly: ticketed shows your tier picker (prices, steppers,
141
+ CTA disabled at zero tickets); RSVP shows the three-field form.
142
+ - [ ] An RSVP submits end-to-end: `rsvp()` resolves, your confirmed state renders.
143
+ - [ ] A ticketed checkout reserves and redirects to the Wix-hosted checkout (or surfaces the
144
+ "connect a payment method" message when the site has none — that's correct behavior).
145
+ - [ ] `/event-confirmation` renders (the honest no-order state on a direct visit).
146
+ - [ ] Event page view-source carries the SEO tags (Astro).
147
+ - [ ] Card/index/registration surfaces/home are YOUR designs on the tokens; data-layer/hook
148
+ files unedited.
149
+ - [ ] Dashboard links handed to the owner (+ the paid-tickets premium note when relevant).
@@ -0,0 +1,66 @@
1
+ // REFERENCE post-checkout confirmation: the Wix-hosted checkout redirects to
2
+ // /event-confirmation?orderNumber=&eventId= on success — this island reads those params and
3
+ // fetches the event for context. Mount client:only (it reads the browser URL). Landing here
4
+ // IS the success signal for a ticket order (Wix redirects only after checkout completes);
5
+ // the ticket PDF/QR arrives by email — echo the order number, don't invent order details.
6
+ import { useEffect, useState } from "react";
7
+ import { fetchEventById } from "../../wix/events/events";
8
+ import type { EventDetail } from "../../wix/events/types";
9
+
10
+ export default function EventConfirmationView({ eventsHref = "/events" }: { eventsHref?: string }) {
11
+ const [params] = useState(() => {
12
+ if (typeof window === "undefined") return { orderNumber: "", eventId: "" };
13
+ const q = new URLSearchParams(window.location.search);
14
+ return { orderNumber: q.get("orderNumber") ?? "", eventId: q.get("eventId") ?? "" };
15
+ });
16
+ const [event, setEvent] = useState<EventDetail | null>(null);
17
+
18
+ useEffect(() => {
19
+ let alive = true;
20
+ if (params.eventId) {
21
+ fetchEventById(params.eventId).then((e) => alive && setEvent(e));
22
+ }
23
+ return () => {
24
+ alive = false;
25
+ };
26
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27
+ }, [params.eventId]);
28
+
29
+ if (!params.orderNumber) {
30
+ // Direct visit with no order in the URL — an honest state, not a fake confirmation.
31
+ return (
32
+ <div className="mx-auto max-w-lg py-16 text-center">
33
+ <p className="text-lg font-semibold">No order to show</p>
34
+ <a href={eventsHref} className="mt-4 inline-block text-sm text-foreground underline">
35
+ Browse events
36
+ </a>
37
+ </div>
38
+ );
39
+ }
40
+
41
+ return (
42
+ <div className="mx-auto max-w-lg py-16 text-center">
43
+ <p className="eyebrow">Order {params.orderNumber}</p>
44
+ <h1 className="mt-2 text-2xl font-semibold tracking-tight">You're going! 🎟️</h1>
45
+ <p className="mt-3 text-sm text-muted-foreground">
46
+ {event ? `${event.title}${event.dateLabel ? ` — ${event.dateLabel}` : ""}. ` : ""}
47
+ Your tickets are on their way to your email.
48
+ </p>
49
+ {event?.addToCalendar.google && (
50
+ <a
51
+ href={event.addToCalendar.google}
52
+ target="_blank"
53
+ rel="noreferrer"
54
+ className="mt-6 inline-block rounded-full border border-border px-6 py-2.5 text-sm font-medium text-foreground no-underline transition-colors hover:bg-secondary"
55
+ >
56
+ Add to Google Calendar
57
+ </a>
58
+ )}
59
+ <div className="mt-4">
60
+ <a href={eventsHref} className="text-sm text-muted-foreground underline">
61
+ Back to events
62
+ </a>
63
+ </div>
64
+ </div>
65
+ );
66
+ }