@wix/agent-skills 1.16.3 → 1.18.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 (283) 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 +145 -127
  9. package/skills/wix-app/references/SITE_PLUGIN.md +14 -2
  10. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
  11. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
  12. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
  13. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
  14. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
  15. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
  16. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
  17. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +94 -49
  18. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +16 -6
  19. package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
  20. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
  21. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +35 -40
  22. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +167 -445
  23. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +56 -29
  24. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
  25. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
  26. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
  27. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
  28. package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
  29. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
  30. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
  31. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
  32. package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
  33. package/skills/wix-base44-connector/SKILL.md +156 -50
  34. package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
  35. package/skills/wix-base44-connector/scripts/utils.js +239 -45
  36. package/skills/wix-headless/entry/bootstrap.mjs +9 -2
  37. package/skills/wix-headless/entry/skill.md +1 -1
  38. package/skills/wix-headless/references/CAPABILITIES.md +9 -1
  39. package/skills/wix-headless/references/DESIGN.md +1 -0
  40. package/skills/wix-headless/references/DISCOVERY.md +2 -1
  41. package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
  42. package/skills/wix-headless/references/SDK_HANDOFF.md +5 -2
  43. package/skills/wix-headless/references/SEED.md +2 -1
  44. package/skills/wix-headless/references/SETUP.md +1 -0
  45. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
  46. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +68 -31
  47. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
  48. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
  49. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
  50. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
  51. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
  52. package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
  53. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
  54. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
  55. package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
  56. package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
  57. package/skills/wix-headless/references/non-astro.md +1 -1
  58. package/skills/wix-headless-fast/SKILL.md +166 -0
  59. package/skills/wix-headless-fast/entry/skill.md +99 -0
  60. package/skills/wix-headless-fast/install/deploy.mjs +433 -0
  61. package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
  62. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
  63. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
  64. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
  65. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
  66. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
  67. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
  68. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
  69. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
  70. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
  71. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
  72. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
  73. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
  74. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
  75. package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
  76. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
  77. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
  78. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
  79. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
  80. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
  81. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
  82. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
  83. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
  84. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
  85. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
  86. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
  87. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
  88. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
  89. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
  90. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
  91. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
  92. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
  93. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
  94. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
  95. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
  96. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
  97. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
  98. package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
  99. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
  100. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
  101. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
  102. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
  103. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
  104. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
  105. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
  106. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
  107. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
  108. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
  109. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
  110. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
  111. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
  112. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
  113. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
  114. package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
  115. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
  116. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
  117. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
  118. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
  119. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
  120. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
  121. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
  122. package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
  123. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
  124. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
  125. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
  126. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
  127. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
  128. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
  129. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
  130. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
  131. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
  132. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
  133. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
  134. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
  135. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
  136. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
  137. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
  138. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
  139. package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
  140. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
  141. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
  142. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
  143. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
  144. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
  145. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
  146. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
  147. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
  148. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
  149. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
  150. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
  151. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
  152. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
  153. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
  154. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
  155. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
  156. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
  157. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
  158. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
  159. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
  160. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
  161. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
  162. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
  163. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
  164. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
  165. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
  166. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
  167. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
  168. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
  169. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
  170. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
  171. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
  172. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
  173. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
  174. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
  175. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
  176. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
  177. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
  178. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
  179. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
  180. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
  181. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
  182. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
  183. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
  184. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
  185. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
  186. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
  187. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
  188. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
  189. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
  190. package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
  191. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
  192. package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
  193. package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
  194. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
  195. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
  196. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
  197. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
  198. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
  199. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
  200. package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
  201. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
  202. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
  203. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
  204. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
  205. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
  206. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
  207. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
  208. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
  209. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
  210. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
  211. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
  212. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
  213. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
  214. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
  215. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
  216. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
  217. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
  218. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
  219. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
  220. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
  221. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
  222. package/skills/wix-manage/SKILL.md +28 -2
  223. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
  224. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
  225. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
  226. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
  227. package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
  228. package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
  229. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
  230. package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
  231. package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
  232. package/skills/wix-manage/references/sites/query-sites.md +72 -161
  233. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +21 -6
  234. package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
  235. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
  236. package/skills/wix-vibe-headless/SKILL.md +18 -4
  237. package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
  238. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
  239. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +16 -10
  240. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +13 -8
  241. package/skills/wix-vibe-headless/platforms/base44.md +27 -62
  242. package/skills/wix-vibe-headless/platforms/generic.md +6 -3
  243. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +45 -0
  244. package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
  245. package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
  246. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
  247. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
  248. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
  249. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
  250. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
  251. package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
  252. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
  253. package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +470 -0
  254. package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
  255. package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
  256. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
  257. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
  258. package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1762 -0
  259. package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
  260. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
  261. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
  262. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
  263. package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
  264. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +152 -92
  265. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
  266. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
  267. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
  268. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
  269. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
  270. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
  271. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
  272. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
  273. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
  274. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
  275. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
  276. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
  277. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
  278. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
  279. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
  280. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
  281. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
  282. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
  283. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
@@ -0,0 +1,72 @@
1
+ # Blog — seeding
2
+
3
+ Seed by **running `seed-blog.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 Blog app if needed, resolves a real author memberId (every post
6
+ create requires one), and creates everything in the right order — categories/tags first,
7
+ then **published** posts, then imported cover images (PATCH + re-publish).
8
+
9
+ ```bash
10
+ # from the project root (where wix.config.json lives):
11
+ node <SKILL_ROOT>/references/blog/seed/seed-blog.mjs plan.json
12
+ ```
13
+
14
+ `plan.json` is plain data — write it from the brief. **Default to 3 posts** (the seed shows
15
+ the shape; the owner writes the rest in the dashboard) and make them exercise the UI: group
16
+ them into 2 categories when the brief has natural sections, tag a couple, vary the content
17
+ blocks (heading + paragraphs + a quote or list per post), and give every post a cover — a
18
+ feed without covers looks broken.
19
+
20
+ ```json
21
+ {
22
+ "categories": ["Brewing", "Stories"],
23
+ "posts": [
24
+ { "title": "How We Roast Our Single-Origin Beans", "category": "Stories", "tags": ["coffee"],
25
+ "coverImageUrl": "https://…",
26
+ "content": [
27
+ { "type": "heading", "text": "From farm to cup", "level": 2 },
28
+ { "type": "paragraph", "text": "Every batch starts with beans sourced from a single estate." },
29
+ { "type": "quote", "text": "Great coffee is grown, not made." }
30
+ ] },
31
+ { "title": "The Pour-Over, Step by Step", "category": "Brewing", "tags": ["guides"],
32
+ "coverImageUrl": "https://…",
33
+ "content": [
34
+ { "type": "paragraph", "text": "A repeatable ritual in five minutes." },
35
+ { "type": "ordered", "items": ["Rinse the filter", "Bloom 30 seconds", "Pour in circles"] }
36
+ ] },
37
+ { "title": "Why Water Matters More Than You Think", "category": "Brewing",
38
+ "coverImageUrl": "https://…",
39
+ "content": [
40
+ { "type": "paragraph", "text": "Coffee is 98% water — its minerals decide the cup." },
41
+ { "type": "bulleted", "items": ["Filtered, not distilled", "Aim for ~150 ppm hardness"] }
42
+ ] }
43
+ ]
44
+ }
45
+ ```
46
+
47
+ - `content` blocks: `{type:"heading",text,level?}` · `{type:"paragraph",text}` ·
48
+ `{type:"quote",text}` · `{type:"bulleted"|"ordered",items:[…]}`. For node types these don't
49
+ cover (code, inline images), pass a pre-built Ricos `richContent` on the post instead.
50
+ - `category`/`categories`/`tags` are display **names** — created idempotently and resolved to
51
+ ids internally. Optional: skip them entirely when the brief doesn't group posts.
52
+ - Cover — the default is a `coverImagePrompt` (AI-generated, ~1 Wix AI credit per image,
53
+ account-billed): brand-contextual — subject, aesthetic/mood, palette, lighting — always
54
+ 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
55
+ `coverImagePath` (a file on this machine — uploaded to Wix Media) or `coverImageUrl` (their
56
+ own hosted URL; verify it with `curl -sI` → 200) — never a stock-photo or guessed URL. Covers resolve
57
+ in parallel and never block the seed; a failed cover leaves that post text-only (the script
58
+ re-publishes each post it covers).
59
+ - Posts are created **published** — an unpublished post never reaches visitors. The bulk
60
+ create returns 200 even on partial failure: check each `posts[].success` in the result.
61
+
62
+ **Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
63
+ seems needed.
64
+
65
+ ## Escape hatch — individual functions
66
+ `setupBlog` composes exported steps — `installBlogApp`, `getAuthorMemberId`, `createPosts`,
67
+ `createCategories`, `createTags`, `importImage`, `attachPostCovers`, plus `makeCtx()` —
68
+ import them only for a partial re-seed.
69
+
70
+ ## Reference
71
+ Unexpected shape or an uncovered operation → read the live Wix API reference; the
72
+ authoritative source recipe is `wix-headless/references/inline-recipes/setup-blog.md`.
@@ -0,0 +1,287 @@
1
+ // Blog 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/blog/seed/seed-blog.mjs plan.json
5
+ //
6
+ // It mints its own site token via the Wix CLI, installs the Wix Blog app if needed, resolves
7
+ // a real author memberId (every post create requires one), creates categories/tags (idempotent
8
+ // by label, with a fresh-install verify-retry), bulk-creates PUBLISHED posts with Ricos
9
+ // richContent, and imports+attaches cover images (PATCH + re-publish). Prints a JSON result
10
+ // to stdout.
11
+ //
12
+ // Plan shape (see SEED.md):
13
+ // { "categories"?: [name], "tags"?: [name],
14
+ // "posts": [{ "title", "content": [blocks] | "richContent"?, "category"?|"categories"?,
15
+ // "tags"?, "coverImageUrl"? | "coverImagePrompt"? }] }
16
+ // content blocks: { type:"heading", text, level? } | { type:"paragraph", text }
17
+ // | { type:"quote", text } | { type:"bulleted"|"ordered", items:[text,…] }
18
+ //
19
+ // Seeding is ADDITIVE — never deletes or overwrites existing content. Unexpected shapes →
20
+ // read the live API reference; authoritative source recipe:
21
+ // wix-headless/references/inline-recipes/setup-blog.md.
22
+ import { execFileSync } from "node:child_process";
23
+ import { readFileSync } from "node:fs";
24
+ import { resolveItemImages } from "../../shared/seed/images.mjs";
25
+
26
+ const API = "https://www.wixapis.com";
27
+ const BLOG_APP_ID = "14bcded7-0066-7c35-14d7-466cb3f09103";
28
+
29
+ export function makeCtx({ cwd = process.cwd() } = {}) {
30
+ const config = JSON.parse(readFileSync(`${cwd}/wix.config.json`, "utf8"));
31
+ const siteId = config.siteId ?? config.projectId;
32
+ if (!siteId) throw new Error("wix.config.json has no siteId — is this a Wix CLI project?");
33
+ const token = execFileSync("npx", ["@wix/cli@latest", "token", "--site", siteId], {
34
+ encoding: "utf8",
35
+ cwd,
36
+ }).trim();
37
+ if (!token) throw new Error("The Wix CLI returned no token — run `npx @wix/cli@latest login` first.");
38
+ return { token, siteId };
39
+ }
40
+
41
+ async function req(ctx, path, { method = "POST", body } = {}) {
42
+ const res = await fetch(API + path, {
43
+ method,
44
+ headers: {
45
+ Authorization: `Bearer ${ctx.token}`,
46
+ "wix-site-id": ctx.siteId,
47
+ "Content-Type": "application/json",
48
+ },
49
+ body: body ? JSON.stringify(body) : undefined,
50
+ });
51
+ const json = await res.json().catch(() => ({}));
52
+ if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
53
+ return json;
54
+ }
55
+
56
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
57
+
58
+ // ---- Ricos richContent builder (setup-blog.md § "CRITICAL RICOS NESTING") --------------------
59
+ // Rules baked in: TEXT is always a leaf inside a container; BLOCKQUOTE / LIST_ITEM wrap a
60
+ // PARAGRAPH; BULLETED_LIST / ORDERED_LIST wrap LIST_ITEM -> PARAGRAPH -> TEXT; every container
61
+ // node gets a unique id, TEXT leaves use id "". For node types not covered here (code, images)
62
+ // pass a pre-built `richContent` on the post instead — it's used verbatim.
63
+ const mkText = (text) => ({ type: "TEXT", id: "", nodes: [], textData: { text: text || "", decorations: [] } });
64
+ const mkParagraph = (id, text) => ({ type: "PARAGRAPH", id, nodes: [mkText(text)], paragraphData: {} });
65
+
66
+ function mkRichContent(blocks = [], postIdx = 0) {
67
+ let n = 0;
68
+ const id = () => `p${postIdx}-n${n++}`;
69
+ const nodes = [];
70
+ for (const b of blocks) {
71
+ switch (b.type) {
72
+ case "heading":
73
+ nodes.push({ type: "HEADING", id: id(), nodes: [mkText(b.text)], headingData: { level: b.level ?? 2 } });
74
+ break;
75
+ case "quote":
76
+ nodes.push({ type: "BLOCKQUOTE", id: id(), nodes: [mkParagraph(id(), b.text)], blockquoteData: { indentation: 1 } });
77
+ break;
78
+ case "bulleted":
79
+ case "ordered": {
80
+ const listType = b.type === "bulleted" ? "BULLETED_LIST" : "ORDERED_LIST";
81
+ nodes.push({
82
+ type: listType, id: id(),
83
+ nodes: (b.items ?? []).map((item) => ({ type: "LIST_ITEM", id: id(), nodes: [mkParagraph(id(), item)] })),
84
+ });
85
+ break;
86
+ }
87
+ case "paragraph":
88
+ default:
89
+ nodes.push(mkParagraph(id(), b.text));
90
+ }
91
+ }
92
+ return { nodes };
93
+ }
94
+
95
+ // One post's plain data -> a flat Blog V3 draft-post object. media is omitted — covers are a
96
+ // separate pass (attachPostCovers), per the recipe.
97
+ function buildPost(p, i, memberId) {
98
+ return {
99
+ title: p.title,
100
+ memberId,
101
+ richContent: p.richContent ?? mkRichContent(p.content, i),
102
+ ...(p.categoryIds ? { categoryIds: p.categoryIds } : {}),
103
+ ...(p.tagIds ? { tagIds: p.tagIds } : {}),
104
+ };
105
+ }
106
+
107
+ // ---- operations ----------------------------------------------------------------------------
108
+
109
+ // docs: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix.md
110
+ export async function installBlogApp(ctx) {
111
+ try {
112
+ await req(ctx, "/apps-installer-service/v1/app-instance/install", { body: {
113
+ tenant: { tenantType: "SITE", id: ctx.siteId },
114
+ appInstance: { appDefId: BLOG_APP_ID, enabled: true },
115
+ } });
116
+ } catch {
117
+ /* already installed is fine */
118
+ }
119
+ }
120
+
121
+ // Every post create needs a REAL author memberId — a fabricated id fails with
122
+ // "memberIds ... do not exist". A provisioned site has the owner as members[0].
123
+ // docs: https://dev.wix.com/docs/api-reference/crm/members-contacts/members/members/list-members.md
124
+ export async function getAuthorMemberId(ctx) {
125
+ const r = await req(ctx, "/members/v1/members?fieldsets=PUBLIC&paging.limit=1", { method: "GET" });
126
+ const id = r.members?.[0]?.id;
127
+ if (!id) throw new Error(`No site member found for author attribution: ${JSON.stringify(r).slice(0, 400)}`);
128
+ return id;
129
+ }
130
+
131
+ /**
132
+ * Create posts, PUBLISHED (publish:true — unpublished posts never reach visitors).
133
+ * Endpoint auto-selected per the recipe: single-post endpoint for exactly one (nested
134
+ * `{ draftPost }` envelope), bulk for >= 2 — `bulk` sits BETWEEN v3 and draft-posts, and each
135
+ * bulk item is FLAT (wrapping it in `draftPost` 400s). Returns [{ id, index, success }].
136
+ * docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/create-draft-post.md
137
+ * docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/bulk-create-draft-posts.md
138
+ */
139
+ export async function createPosts(ctx, posts, { memberId, publish = true } = {}) {
140
+ if (!memberId) throw new Error("createPosts requires opts.memberId (see getAuthorMemberId)");
141
+ if (posts.length === 1) {
142
+ const r = await req(ctx, "/blog/v3/draft-posts", { body: { draftPost: buildPost(posts[0], 0, memberId), publish } });
143
+ return [{ id: r.draftPost?.id, index: 0, success: !!r.draftPost?.id }];
144
+ }
145
+ const r = await req(ctx, "/blog/v3/bulk/draft-posts/create", {
146
+ body: { draftPosts: posts.map((p, i) => buildPost(p, i, memberId)), publish },
147
+ });
148
+ // Bulk returns 200 even on partial failure — read per-item results[].itemMetadata.success.
149
+ return (r.results ?? []).map((x) => ({
150
+ id: x.itemMetadata?.id, index: x.itemMetadata?.originalIndex, success: !!x.itemMetadata?.success,
151
+ }));
152
+ }
153
+
154
+ // Existing label -> id, straight from the query (the source of truth for what persisted).
155
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/query-categories.md
156
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/query-tags.md
157
+ async function labelIdMap(ctx, kind) {
158
+ const path = kind === "categories" ? "/blog/v3/categories/query" : "/v3/tags/query";
159
+ const r = await req(ctx, path, { body: { query: { paging: { limit: 100 } } } });
160
+ return new Map((r[kind] ?? []).map((x) => [x.label, x.id]));
161
+ }
162
+
163
+ // Create category/tag labels resiliently. TWO hazards this absorbs:
164
+ // 1. Fresh-install provisioning window — for a few seconds after the Blog app installs,
165
+ // per-item category/tag creates return 200 with an id but DON'T persist (the id is a lie).
166
+ // So the create response is never trusted — re-query, treat the query as truth, re-create
167
+ // what's still missing until it sticks.
168
+ // 2. Idempotency — an already-present label (a partial-failure re-run) is skipped.
169
+ // Category bodies are NESTED (`{ category: { label } }`); tag bodies are FLAT (`{ label }`) —
170
+ // a `{ tag: { label } }` body sends an empty top-level label and 400s. Returns [{ id, name }].
171
+ async function ensureLabels(ctx, kind, createPath, mkBody, names) {
172
+ let map = await labelIdMap(ctx, kind);
173
+ for (let attempt = 0; attempt < 8; attempt++) {
174
+ const missing = names.filter((n) => !map.has(n));
175
+ if (!missing.length) break;
176
+ if (attempt) await sleep(1500); // backoff only between retries — happy path pays nothing
177
+ for (const name of missing) {
178
+ try { await req(ctx, createPath, { body: mkBody(name) }); }
179
+ catch (e) { if (!String(e.message).includes("-> 409")) throw e; } // 409 = raced, already there
180
+ }
181
+ map = await labelIdMap(ctx, kind);
182
+ }
183
+ return names.map((name) => ({ id: map.get(name), name }));
184
+ }
185
+
186
+ /** Create categories idempotently by label (no bulk endpoint). Feed ids into post.categoryIds. */
187
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/create-category.md
188
+ export async function createCategories(ctx, names) {
189
+ return ensureLabels(ctx, "categories", "/blog/v3/categories", (name) => ({ category: { label: name } }), names);
190
+ }
191
+
192
+ /** Create tags idempotently by label. Feed ids into post.tagIds. */
193
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/create-tag.md
194
+ export async function createTags(ctx, names) {
195
+ return ensureLabels(ctx, "tags", "/blog/v3/tags", (name) => ({ label: name }), names);
196
+ }
197
+
198
+ // Blog binds a post cover by Wix Media file ID — an external url must be imported first; a
199
+ // plan `coverImagePrompt` is generated (Wix AI, 1 credit) then imported. Both live in the
200
+ // shared util (parallel, resilient, never blocks the seed).
201
+ export { importImage } from "../../shared/seed/images.mjs";
202
+
203
+ // covers: [{ postId, fileId }] where fileId is the Wix Media file.id from importImage. Per
204
+ // post: PATCH /blog/v3/draft-posts/{id} (NOT POST …/{id}/update — that 404s), setting
205
+ // media.displayed:true + media.custom:true + wixMedia.image.id (the id ALONE is a silent
206
+ // no-op), then RE-PUBLISH — the PATCH sets hasUnpublishedChanges, so the live post stays
207
+ // cover-less until republished. Image failures never block the run.
208
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/update-draft-post.md
209
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/publish-draft-post.md
210
+ export async function attachPostCovers(ctx, covers) {
211
+ let attached = 0;
212
+ for (const { postId, fileId } of covers) {
213
+ try {
214
+ await req(ctx, `/blog/v3/draft-posts/${postId}`, {
215
+ method: "PATCH",
216
+ body: { draftPost: { media: { displayed: true, custom: true, wixMedia: { image: { id: fileId } } } } },
217
+ });
218
+ await req(ctx, `/blog/v3/draft-posts/${postId}/publish`, { method: "POST" });
219
+ attached++;
220
+ } catch (e) {
221
+ console.error(`cover attach skipped for post ${postId}: ${e.message}`);
222
+ }
223
+ }
224
+ return attached;
225
+ }
226
+
227
+ /**
228
+ * ONE-CALL seed: install → author memberId → categories/tags (names resolved to ids) →
229
+ * published posts → covers, ids threaded in memory. The default path.
230
+ */
231
+ export async function setupBlog(ctx, { posts = [], categories = [], tags = [] } = {}) {
232
+ await installBlogApp(ctx);
233
+ await sleep(3000); // let a fresh Blog install settle so the first category/tag writes stick
234
+ // (correctness is still guaranteed by ensureLabels' verify-retry).
235
+ const memberId = await getAuthorMemberId(ctx);
236
+
237
+ const catNames = [...new Set([...categories, ...posts.flatMap((p) => [].concat(p.category ?? [], p.categories ?? []))])];
238
+ const tagNames = [...new Set([...tags, ...posts.flatMap((p) => [].concat(p.tags ?? []))])];
239
+ const cats = catNames.length ? await createCategories(ctx, catNames) : [];
240
+ const tgs = tagNames.length ? await createTags(ctx, tagNames) : [];
241
+ const catId = new Map(cats.map((c) => [c.name, c.id]));
242
+ const tagId = new Map(tgs.map((t) => [t.name, t.id]));
243
+
244
+ const created = await createPosts(ctx, posts.map((p) => {
245
+ const cn = [].concat(p.category ?? [], p.categories ?? []);
246
+ const tn = [].concat(p.tags ?? []);
247
+ return {
248
+ ...p,
249
+ ...(cn.length ? { categoryIds: cn.map((n) => catId.get(n)).filter(Boolean) } : {}),
250
+ ...(tn.length ? { tagIds: tn.map((n) => tagId.get(n)).filter(Boolean) } : {}),
251
+ };
252
+ }), { memberId });
253
+
254
+ // Pass 2 — covers: resolve (import by url / generate by prompt) in one parallel wave, then
255
+ // attach (PATCH + re-publish per post). Failures leave the post text-only; the seed's exit
256
+ // never depends on images.
257
+ const files = await resolveItemImages(ctx, created.map((c, i) => (
258
+ c?.id && c?.success
259
+ ? { path: posts[i]?.coverImagePath, url: posts[i]?.coverImageUrl, prompt: posts[i]?.coverImagePrompt, displayName: `post-${i}.png` }
260
+ : null
261
+ )));
262
+ const covers = created
263
+ .map((c, i) => (files[i] ? { postId: c.id, fileId: files[i].id } : null))
264
+ .filter(Boolean);
265
+ const coversAttached = covers.length ? await attachPostCovers(ctx, covers) : 0;
266
+
267
+ return { posts: created, categories: cats, tags: tgs, coversAttached };
268
+ }
269
+
270
+ // ---- CLI entry ----------------------------------------------------------------------------------
271
+
272
+ const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
273
+ if (invokedDirectly) {
274
+ const planPath = process.argv[2];
275
+ if (!planPath) {
276
+ console.error("usage: node seed-blog.mjs <plan.json> (run from the project root)");
277
+ process.exit(1);
278
+ }
279
+ const plan = JSON.parse(readFileSync(planPath, "utf8"));
280
+ const ctx = makeCtx();
281
+ setupBlog(ctx, plan)
282
+ .then((result) => console.log(JSON.stringify(result, null, 2)))
283
+ .catch((e) => {
284
+ console.error(e.message);
285
+ process.exit(1);
286
+ });
287
+ }
@@ -0,0 +1,129 @@
1
+ # Bookings — playbook
2
+
3
+ The booking machinery ships as files — services reads, availability (appointment AND class),
4
+ the schema-driven booking form, and the exact `createBooking → cart → checkout-or-place`
5
+ sequence, typed end-to-end. **The presentation is yours**: you design and implement the
6
+ service card, the listing surface, and the booking surface on the shipped hooks/DTOs, plus
7
+ the home page and the brand. You never write booking 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/bookings/types.ts` | the DTOs (`ServiceSummary`, `ServiceDetail`, `Slot`, `BookingFormField`, `BookingResult`) — contracts below |
19
+ | `wix/bookings/services.ts` | `fetchServices`, `fetchServiceBySlug`, `fetchBookingCategories` |
20
+ | `wix/bookings/booking.ts` | `fetchSlots`, `fetchBookingForm`, `bookService` — the exact booking sequence lives here |
21
+ | `hooks/bookings/useServices.ts` | listing + category filter — contract below |
22
+ | `hooks/bookings/useBookingFlow.ts` | the whole booking state machine — contract below |
23
+ | `components/bookings/ServicesView.tsx` (+ `ServiceCard`) · `ServiceBookingView.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 storefront is also deployed, its layout won — add a Services nav link there |
31
+ | `pages/services.astro` | SSR listing — **keep the frontmatter**, swap the island import to YOUR component |
32
+ | `pages/services/[slug].astro` | SSR detail + booking with owner-editable SEO — **keep the frontmatter and the SEO pieces** (`wixMetadata`, `loadSEOTagsServiceConfig`, `<SEO.Tags>`) exactly; swap the island import. The booking island stays `client:only="react"` (availability is timezone-specific) |
33
+
34
+ ## What you build — the design job
35
+
36
+ 1. **The service card + listing surface** — your tile (image, type badge, duration/price
37
+ presentation) and rhythm, with skeletons while loading and an honest empty state — on
38
+ `useServices`.
39
+ 2. **The booking surface** — day-grouped slot picking, week paging, staff filter (only when
40
+ >1 staff), the schema-driven form, the book CTA (label free vs priced), and the confirmed
41
+ state — on `useBookingFlow`, which owns ALL booking logic; you own how it looks.
42
+ 3. **The home page** — hero, featured services (fetch in frontmatter → your components),
43
+ brand story.
44
+
45
+ Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
46
+ Style everything with Tailwind utilities on the tokens.
47
+
48
+ ### The contracts your components consume
49
+
50
+ ```ts
51
+ // ServiceSummary (tiles) — display-ready:
52
+ // { id, slug, name, tagLine, type: "APPOINTMENT"|"CLASS", price /* "€75.00" | "Free" */,
53
+ // free, durationMinutes|null, imageUrl, categoryId|null, staff: [{id,name}] }
54
+ // ServiceDetail adds: description, formId, paymentOption, cancellationFeeEnabled.
55
+
56
+ // useServices({ initialServices?, initialCategories? }) →
57
+ // { services: ServiceSummary[]|null /* null = loading → skeletons */,
58
+ // categories: [{id,name}], activeCategoryId, setActiveCategoryId(id|null), error }
59
+
60
+ // useBookingFlow(service: ServiceDetail) →
61
+ // { days: [{ dayKey, dayLabel, slots: Slot[] }] | null, // day-grouped; null = loading
62
+ // windowStart, nextWeek(), prevWeek(), // 7-day paging (prev clamps to today)
63
+ // staffId, setStaffId(id|undefined), // show a picker only when service.staff.length > 1
64
+ // selectedSlot, setSelectedSlot(slot|null), // Slot = { startLocal, endLocal, dayKey, label, … }
65
+ // formFields: [{ target, label, type, options? }], // never empty (contact-basics fallback)
66
+ // values, setValue(target, value), // inputs write here, keyed by target
67
+ // canBook, // gate the CTA on this
68
+ // book(): Promise<BookingResult>, // paid → the browser redirects to Wix checkout;
69
+ // booking, confirmed, error } // free/offline → confirmed is set (REAL success)
70
+ ```
71
+
72
+ ### Wiring — Astro (default)
73
+
74
+ 1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
75
+ storefront layout instead if both verticals are deployed).
76
+ 2. Write your components under `src/components/bookings/` (new names — don't overwrite the
77
+ references), swap the island imports in `pages/services.astro` and
78
+ `pages/services/[slug].astro`. Listing island: `client:load` with the SSR props; booking
79
+ island: `client:only="react"`. **Author your surfaces in as few messages as possible** —
80
+ batch multiple Writes per message.
81
+ 3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
82
+
83
+ ### Wiring — React SPA (Vite etc.)
84
+
85
+ Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
86
+ plugins — deploy added the dep). Routes: `/services` → your listing; `/services/:slug` →
87
+ fetch with `fetchServiceBySlug(slug)` client-side, then your booking surface.
88
+
89
+ ## Hard rules
90
+
91
+ - **Booking logic only through the shipped exports** — `useBookingFlow`/`bookService` own the
92
+ sequence (createBooking → cart holds the seat → checkout-or-place), the payment-option
93
+ derivation, ANY_RESOURCE, and the formSubmission shape. Never re-derive any of it, never
94
+ call `confirmBooking`, never hand-build a checkout URL.
95
+ - **The form is schema-driven** — render `formFields` as given (values keyed by `target`);
96
+ never hardcode field names beyond what the fallback already guarantees.
97
+ - **Gate the CTA on `canBook`** and surface `error` — `book()` can reject (slot taken,
98
+ validation); that message is for the visitor.
99
+ - **The confirmed state must reflect REAL success**: render it only from `confirmed` (set by
100
+ the free/offline branch). A visitor returning from the hosted checkout redirect is NOT a
101
+ success signal — don't fake a confirmation page off the return URL.
102
+ - Theme via the `@theme` tokens; no parallel theme files, no hardcoded palettes.
103
+ - Live data or an honest empty state — never mock services, slots, or availability.
104
+ - Keep the detail page's SEO pieces exactly as shipped.
105
+
106
+ ## Point the user to their dashboard
107
+
108
+ Give the owner the dashboard link plus the Bookings services/calendar pages — the deploy
109
+ step's JSON printed `dashboardUrl`; append `/bookings/services` for service management.
110
+ Taking real online payments needs a premium plan + a connected payment method — mention it.
111
+
112
+ ## Seeding
113
+
114
+ Per `seed/SEED.md` — plain-data `plan.json` into `seed-bookings.mjs` from the project root.
115
+ Seed services that exercise the UI (an APPOINTMENT with duration+price, a free one, a CLASS
116
+ with future sessions when it fits the business; an image per service).
117
+
118
+ ## Verify (before declaring done)
119
+
120
+ - [ ] `/services` renders live services SSR (view-source shows names) through YOUR components;
121
+ empty catalog shows your honest empty state.
122
+ - [ ] A service page shows day-grouped bookable times; week paging works; the form renders
123
+ (schema or fallback) and the CTA stays disabled until a slot + all fields are set.
124
+ - [ ] A FREE service books end-to-end: `book()` resolves, your confirmed state renders.
125
+ - [ ] A PAID service redirects to the Wix-hosted checkout.
126
+ - [ ] Service page view-source carries the SEO tags (Astro).
127
+ - [ ] Card/listing/booking surfaces/home are YOUR designs on the tokens; data-layer/hook files
128
+ unedited.
129
+ - [ ] Dashboard links handed to the owner.
@@ -0,0 +1,143 @@
1
+ // REFERENCE booking surface: service info + day-grouped slot picker + staff filter +
2
+ // schema-driven form + book CTA, on the @theme tokens. Correct and complete; per the
3
+ // skill's model you design and build your own on useBookingFlow. Mount client:only —
4
+ // availability is timezone/session-specific.
5
+ import { useBookingFlow } from "../../hooks/bookings/useBookingFlow";
6
+ import type { ServiceDetail } from "../../wix/bookings/types";
7
+
8
+ const chip = (selected: boolean) =>
9
+ `rounded-full border px-4 py-1.5 text-sm transition-colors ${
10
+ selected
11
+ ? "border-primary bg-primary text-primary-foreground"
12
+ : "border-border text-foreground hover:bg-secondary"
13
+ }`;
14
+
15
+ export default function ServiceBookingView({ service }: { service: ServiceDetail }) {
16
+ const {
17
+ days,
18
+ nextWeek,
19
+ prevWeek,
20
+ staffId,
21
+ setStaffId,
22
+ selectedSlot,
23
+ setSelectedSlot,
24
+ formFields,
25
+ values,
26
+ setValue,
27
+ canBook,
28
+ book,
29
+ booking,
30
+ confirmed,
31
+ error,
32
+ } = useBookingFlow(service);
33
+
34
+ if (confirmed) {
35
+ return (
36
+ <div className="rounded-lg border border-border bg-secondary p-8 text-center">
37
+ <p className="text-lg font-semibold">You're booked! 🎉</p>
38
+ <p className="mt-2 text-sm text-muted-foreground">
39
+ {service.name}
40
+ {selectedSlot ? ` — ${selectedSlot.dayKey} at ${selectedSlot.label}` : ""}. A confirmation
41
+ email is on its way.
42
+ </p>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ return (
48
+ <div>
49
+ {service.staff.length > 1 && (
50
+ <div className="mb-5">
51
+ <p className="mb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Staff</p>
52
+ <div className="flex flex-wrap gap-2">
53
+ <button type="button" className={chip(staffId === undefined)} onClick={() => setStaffId(undefined)}>
54
+ Anyone
55
+ </button>
56
+ {service.staff.map((m) => (
57
+ <button key={m.id} type="button" className={chip(staffId === m.id)} onClick={() => setStaffId(m.id)}>
58
+ {m.name}
59
+ </button>
60
+ ))}
61
+ </div>
62
+ </div>
63
+ )}
64
+
65
+ <div className="mb-2 flex items-center justify-between">
66
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Pick a time</p>
67
+ <div className="flex gap-2">
68
+ <button type="button" onClick={prevWeek} aria-label="Previous week" className="rounded-full border border-border px-3 py-1 text-sm text-foreground transition-colors hover:bg-secondary">←</button>
69
+ <button type="button" onClick={nextWeek} aria-label="Next week" className="rounded-full border border-border px-3 py-1 text-sm text-foreground transition-colors hover:bg-secondary">→</button>
70
+ </div>
71
+ </div>
72
+
73
+ {days === null ? (
74
+ <div className="space-y-3" aria-busy="true">
75
+ {Array.from({ length: 3 }, (_, i) => (
76
+ <div key={i} className="h-10 animate-pulse rounded-md bg-secondary" />
77
+ ))}
78
+ </div>
79
+ ) : days.length === 0 ? (
80
+ <p className="rounded-md border border-border p-4 text-sm text-muted-foreground">
81
+ No times in this week — try the next one.
82
+ </p>
83
+ ) : (
84
+ <div className="space-y-4">
85
+ {days.map((day) => (
86
+ <div key={day.dayKey}>
87
+ <p className="mb-2 text-sm font-medium">{day.dayLabel}</p>
88
+ <div className="flex flex-wrap gap-2">
89
+ {day.slots.map((s) => (
90
+ <button
91
+ key={s.startLocal + (s.eventId ?? "")}
92
+ type="button"
93
+ className={chip(selectedSlot?.startLocal === s.startLocal)}
94
+ onClick={() => setSelectedSlot(s)}
95
+ >
96
+ {s.label}
97
+ </button>
98
+ ))}
99
+ </div>
100
+ </div>
101
+ ))}
102
+ </div>
103
+ )}
104
+
105
+ <div className="mt-6 grid max-w-md gap-3">
106
+ {formFields.map((f) => (
107
+ <label key={f.target} className="block">
108
+ <span className="mb-1 block text-xs font-semibold uppercase tracking-wider text-muted-foreground">{f.label}</span>
109
+ {f.options?.length ? (
110
+ <select
111
+ value={values[f.target] ?? ""}
112
+ onChange={(e) => setValue(f.target, e.target.value)}
113
+ className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none transition-shadow focus:ring-2 focus:ring-primary"
114
+ >
115
+ <option value="">Choose…</option>
116
+ {f.options.map((o) => (
117
+ <option key={o} value={o}>{o}</option>
118
+ ))}
119
+ </select>
120
+ ) : (
121
+ <input
122
+ type={f.type === "EMAIL" ? "email" : f.type === "PHONE" ? "tel" : f.type === "NUMBER" ? "number" : f.type === "URL" ? "url" : "text"}
123
+ value={values[f.target] ?? ""}
124
+ onChange={(e) => setValue(f.target, e.target.value)}
125
+ className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none transition-shadow focus:ring-2 focus:ring-primary"
126
+ />
127
+ )}
128
+ </label>
129
+ ))}
130
+ </div>
131
+
132
+ {error && <p className="mt-3 text-sm text-red-600">{error}</p>}
133
+ <button
134
+ type="button"
135
+ disabled={!canBook || booking}
136
+ onClick={() => book().catch(() => {})}
137
+ className="mt-5 rounded-full bg-primary px-8 py-3 text-sm font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-50"
138
+ >
139
+ {booking ? "Booking…" : service.free ? "Book — free" : `Book · ${service.price}`}
140
+ </button>
141
+ </div>
142
+ );
143
+ }