@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,71 @@
1
+ # Pricing Plans — seeding
2
+
3
+ Seed by **running `seed-pricing-plans.mjs` with a plan file** — don't hand-write the REST
4
+ calls. The script mints its own site token via the Wix CLI (logged-in session +
5
+ `wix.config.json` required), installs the Pricing Plans app if needed, and creates everything
6
+ in the right order.
7
+
8
+ ```bash
9
+ # from the project root (where wix.config.json lives):
10
+ node <SKILL_ROOT>/references/pricing-plans/seed/seed-pricing-plans.mjs plan.json
11
+ ```
12
+
13
+ `plan.json` is plain data — write it from the brief. **Default to 3 plans** — a tier ladder
14
+ the grid can render (e.g. free / monthly / yearly), each with 3–4 perks; together they
15
+ exercise every price shape the UI handles. Plans have no seedable images (the owner adds one
16
+ per plan in the dashboard).
17
+
18
+ ```json
19
+ {
20
+ "plans": [
21
+ { "name": "Community", "type": "free",
22
+ "description": "Get a taste — member perks, zero commitment.",
23
+ "perks": ["Member-only newsletter", "Community events access"] },
24
+ { "name": "Studio Membership", "price": "29.00",
25
+ "type": "recurring", "billingCycle": { "period": "MONTH", "count": 1 },
26
+ "description": "The full experience, month to month.",
27
+ "perks": ["Unlimited group classes", "10% off workshops", "Priority booking"] },
28
+ { "name": "Annual Pass", "price": "290.00",
29
+ "type": "recurring", "billingCycle": { "period": "YEAR", "count": 1 },
30
+ "description": "Two months free, billed yearly.",
31
+ "perks": ["Everything in Studio Membership", "2 guest passes", "Annual member gift"] }
32
+ ]
33
+ }
34
+ ```
35
+
36
+ - `type` — `"recurring"` (default; `billingCycle` defaults to `{ "period": "MONTH", "count": 1 }`),
37
+ `"one-time"` (bills once, then ends; `billingCycle: null` makes it never expire), or
38
+ `"free"` (amount forced to `"0"` + a per-member-lifetime purchase limit).
39
+ - `price` — a decimal string (`"29.00"`; a number is stringified). Currency is site-derived —
40
+ never sent.
41
+ - `perks` — display-only bullets on the plan card; they grant nothing by themselves.
42
+ - `termsAndConditions` (plain text), `visibility` (`"PUBLIC"`), `buyable` (`true`) — optional
43
+ overrides. A `buyable: false` plan renders without a subscribe CTA (merchant-assigned).
44
+
45
+ ## Covering bookings services (only when bookings is also seeded)
46
+
47
+ A plan can COVER bookings services — members then book them with the membership. The link
48
+ goes through the Benefit Programs API, not the plan object, keyed by the **bookings seed's
49
+ service ids** — so seed bookings FIRST, then pass the ids:
50
+
51
+ ```json
52
+ { "name": "Studio Membership", "price": "29.00",
53
+ "perks": ["Unlimited group classes"],
54
+ "coveredServiceIds": ["<bookings service id>", "…"] }
55
+ ```
56
+
57
+ Unlimited coverage is the default; a limited pack (e.g. 8 sessions) instead uses
58
+ `"bookingsCoverage": { "serviceIds": [...], "creditAmount": 8 }`. A plans-only run just
59
+ omits both — coverage is skipped automatically.
60
+
61
+ **Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
62
+ seems needed.
63
+
64
+ ## Escape hatch — individual functions
65
+ `setupPricingPlans` composes exported steps — `installPricingPlansApp`, `createPlans`,
66
+ `attachBookingsCoverage` (and its `getProgramDefinition`, `createPoolDefinition`,
67
+ `createBenefitItems` sub-steps), plus `makeCtx()` — import them only for a partial re-seed.
68
+
69
+ ## Reference
70
+ Unexpected shape or an uncovered operation → read the live Wix API reference; the
71
+ authoritative source recipe is `wix-headless/references/inline-recipes/setup-pricing-plans.md`.
@@ -0,0 +1,279 @@
1
+ // Pricing Plans seed — a BUILD-TIME script, never shipped in the app. Run from the project
2
+ // root (where wix.config.json lives) with a plan file:
3
+ //
4
+ // node <SKILL_ROOT>/references/pricing-plans/seed/seed-pricing-plans.mjs plan.json
5
+ //
6
+ // It mints its own site token via the Wix CLI, installs the Wix Pricing Plans app if needed,
7
+ // creates the plans (Plans V3 — one create call per plan; there is no bulk-create), and —
8
+ // only when a plan carries bookings service ids — wires the plan to COVER those services
9
+ // through the Benefit Programs API. Prints a JSON result to stdout.
10
+ //
11
+ // Plan shape (see SEED.md):
12
+ // { "plans": [{ "name", "description"?, "price"? (decimal string; a number is stringified),
13
+ // "type"?: "recurring"|"one-time"|"free",
14
+ // "billingCycle"?: { "period": "DAY"|"WEEK"|"MONTH"|"YEAR", "count" } | null,
15
+ // "perks"?: ["..."], "termsAndConditions"?, "visibility"?, "buyable"?,
16
+ // "coveredServiceIds"?: ["<bookings service id>"],
17
+ // "bookingsCoverage"?: { "serviceIds"?, "creditAmount"? } }] }
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-pricing-plans.md.
22
+ import { execFileSync } from "node:child_process";
23
+ import { readFileSync } from "node:fs";
24
+ import { randomUUID } from "node:crypto";
25
+
26
+ const API = "https://www.wixapis.com";
27
+ const PRICING_PLANS_APP_ID = "1522827f-c56c-a5c9-2ac9-00f9e6ae12d3";
28
+ const BOOKINGS_APP_ID = "13d21c63-b5ec-5912-8397-c3a5ddb27a97"; // coverage providerAppId — NOT the Plans id
29
+ const PP_NAMESPACE = "@wix/pricing-plans"; // literal, with the @ and the slash, in every coverage call
30
+
31
+ export function makeCtx({ cwd = process.cwd() } = {}) {
32
+ const config = JSON.parse(readFileSync(`${cwd}/wix.config.json`, "utf8"));
33
+ const siteId = config.siteId ?? config.projectId;
34
+ if (!siteId) throw new Error("wix.config.json has no siteId — is this a Wix CLI project?");
35
+ const token = execFileSync("npx", ["@wix/cli@latest", "token", "--site", siteId], {
36
+ encoding: "utf8",
37
+ cwd,
38
+ }).trim();
39
+ if (!token) throw new Error("The Wix CLI returned no token — run `npx @wix/cli@latest login` first.");
40
+ return { token, siteId };
41
+ }
42
+
43
+ async function req(ctx, path, { method = "POST", body } = {}) {
44
+ const res = await fetch(API + path, {
45
+ method,
46
+ headers: {
47
+ Authorization: `Bearer ${ctx.token}`,
48
+ "wix-site-id": ctx.siteId,
49
+ "Content-Type": "application/json",
50
+ },
51
+ body: body ? JSON.stringify(body) : undefined,
52
+ });
53
+ const json = await res.json().catch(() => ({}));
54
+ if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
55
+ return json;
56
+ }
57
+
58
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
59
+
60
+ // billingTerms selects the plan type (recurring | one-time | free). recurring: billingCycle
61
+ // {period,count} (default MONTH/1) + ON_PURCHASE + UNTIL_CANCELLED. one-time: endType
62
+ // CYCLES_COMPLETED + billingCycleCount 1 (bill once, then ends); an unlimited one-time
63
+ // instead sets billingCycle:null + UNTIL_CANCELLED. free: MUST be the no-cycle unlimited
64
+ // shape — a $0 variant with a billingCycle is rejected ("Free pricing variant cannot be
65
+ // recurring").
66
+ function buildBillingTerms(plan) {
67
+ const type = plan.type || "recurring";
68
+ if (type === "free") {
69
+ return { billingCycle: null, startType: "ON_PURCHASE", endType: "UNTIL_CANCELLED" };
70
+ }
71
+ if (type === "one-time") {
72
+ if (plan.billingCycle === null) {
73
+ return { billingCycle: null, startType: "ON_PURCHASE", endType: "UNTIL_CANCELLED" };
74
+ }
75
+ const cycle = plan.billingCycle || { period: "MONTH", count: 1 };
76
+ return {
77
+ billingCycle: cycle,
78
+ startType: "ON_PURCHASE",
79
+ endType: "CYCLES_COMPLETED",
80
+ cyclesCompletedDetails: { billingCycleCount: 1 },
81
+ };
82
+ }
83
+ // recurring
84
+ const cycle = plan.billingCycle || { period: "MONTH", count: 1 };
85
+ return { billingCycle: cycle, startType: "ON_PURCHASE", endType: "UNTIL_CANCELLED" };
86
+ }
87
+
88
+ // One pricingVariant with one pricingStrategy (schema allows ≤20 but is "currently limited
89
+ // to 1"). Amounts are decimal STRINGS ("20.00"); the variant id is a REQUIRED
90
+ // client-supplied GUID — omitting it returns 400.
91
+ function buildPricingVariant(plan) {
92
+ const free = (plan.type || "recurring") === "free";
93
+ const amount = free ? "0" : String(plan.price);
94
+ return {
95
+ id: randomUUID(),
96
+ name: plan.variantName || "Standard",
97
+ billingTerms: buildBillingTerms(plan),
98
+ pricingStrategies: [{ flatRate: { amount } }],
99
+ };
100
+ }
101
+
102
+ // plain plan -> Plans V3 create body. status:"ACTIVE" is REQUIRED (omitting → 400
103
+ // "status value is required"); currency is NOT sent (read-only, site-derived); perks are
104
+ // display-only bullets, each with a REQUIRED client-supplied GUID.
105
+ function buildPlan(plan) {
106
+ const free = (plan.type || "recurring") === "free";
107
+ return {
108
+ name: plan.name,
109
+ description: plan.description,
110
+ status: "ACTIVE",
111
+ visibility: plan.visibility || "PUBLIC",
112
+ buyable: plan.buyable ?? true,
113
+ buyerCanCancel: plan.buyerCanCancel ?? true,
114
+ ...(plan.termsAndConditions ? { termsAndConditions: plan.termsAndConditions } : {}),
115
+ pricingVariants: [buildPricingVariant(plan)],
116
+ perks: (plan.perks ?? []).map((p) => ({
117
+ id: randomUUID(),
118
+ description: typeof p === "string" ? p : p.description,
119
+ })),
120
+ // free: cap lifetime reuse. Array + maxCount per the SDK schema (PurchaseLimit[]); the
121
+ // recipe's older `{ type, count }` object form predates it.
122
+ ...(free ? { purchaseLimits: [{ type: "PER_MEMBER_LIFETIME", maxCount: 1 }] } : {}),
123
+ };
124
+ }
125
+
126
+ // ---- operations ----------------------------------------------------------------------------------
127
+
128
+ // docs: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix.md
129
+ export async function installPricingPlansApp(ctx) {
130
+ try {
131
+ await req(ctx, "/apps-installer-service/v1/app-instance/install", { body: {
132
+ tenant: { tenantType: "SITE", id: ctx.siteId },
133
+ appInstance: { appDefId: PRICING_PLANS_APP_ID, enabled: true },
134
+ } });
135
+ } catch {
136
+ /* already installed is fine */
137
+ }
138
+ }
139
+
140
+ // Create the plan(s) — Plans V3 has NO bulk-create: one POST per plan. Keep plan.id: the
141
+ // frontend orders by it AND it is the coverage externalId.
142
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/create-plan.md
143
+ export async function createPlans(ctx, plans) {
144
+ const out = [];
145
+ for (const plan of plans) {
146
+ const r = await req(ctx, "/pricing-plans/v3/plans", { body: { plan: buildPlan(plan) } });
147
+ out.push({
148
+ id: r.plan?.id,
149
+ slug: r.plan?.slug,
150
+ name: plan.name,
151
+ coveredServiceIds: plan.coveredServiceIds,
152
+ });
153
+ }
154
+ return out;
155
+ }
156
+
157
+ // ---- bookings coverage via Benefit Programs (SKIP when no bookings in the run) -------------------
158
+ // Strictly ordered: plan.id -> programDefinition.id -> itemSetId -> items. Do NOT parallelize.
159
+
160
+ // 2a: READ the auto-created program definition (the Plans app creates it; you never create
161
+ // it). Provisioning is ~immediate but async — retry ONCE after a short backoff, don't loop.
162
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/benefit-programs/program-definitions/introduction.md
163
+ export async function getProgramDefinition(ctx, planId) {
164
+ const path = `/benefit-programs/v1/program-definitions/by-namespace-and-external-id?externalId=${planId}&namespace=${encodeURIComponent(PP_NAMESPACE)}`;
165
+ try {
166
+ const r = await req(ctx, path, { method: "GET" });
167
+ if (r.programDefinition?.id) return r.programDefinition.id;
168
+ } catch {
169
+ /* fall through to the single insurance retry */
170
+ }
171
+ await sleep(1000);
172
+ const r = await req(ctx, path, { method: "GET" });
173
+ return r.programDefinition?.id;
174
+ }
175
+
176
+ // 2b: create ONE pool definition with EXACTLY ONE benefit naming Bookings as the provider.
177
+ // price "0" = unlimited (default; no creditConfiguration). Limited pack: pass creditAmount →
178
+ // price "1" + details.creditConfiguration (a SIBLING of benefits[], NOT inside a benefit —
179
+ // nesting it 400s with "Price should be 0 when credit pool is not set up").
180
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/benefit-programs/pool-definitions/create-pool-definition.md
181
+ export async function createPoolDefinition(ctx, programDefinitionId, { creditAmount } = {}) {
182
+ const limited = creditAmount != null;
183
+ const details = {
184
+ ...(limited ? { creditConfiguration: { amount: String(creditAmount) } } : {}),
185
+ benefits: [
186
+ {
187
+ benefitKey: randomUUID(),
188
+ displayName: "Bookings sessions",
189
+ providerAppId: BOOKINGS_APP_ID,
190
+ price: limited ? "1" : "0",
191
+ },
192
+ ],
193
+ };
194
+ const r = await req(ctx, "/benefit-programs/v1/pool-definitions", {
195
+ body: {
196
+ poolDefinition: {
197
+ namespace: PP_NAMESPACE,
198
+ displayName: "Bookings benefit",
199
+ programDefinitionIds: [programDefinitionId],
200
+ details,
201
+ },
202
+ cascade: "IMMEDIATELY",
203
+ },
204
+ });
205
+ // itemSetId lives at poolDefinition.details.benefits[i].itemSetId — one benefit here, so [0].
206
+ return r.poolDefinition?.details?.benefits?.[0]?.itemSetId;
207
+ }
208
+
209
+ // 2c: bulk-create the benefit items — ONE item per covered service (externalId = bookings
210
+ // service id). Up to 100 per call; category is an empty string; namespace/providerAppId
211
+ // repeat 2b's values.
212
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/benefit-programs/items/bulk-create-items.md
213
+ export async function createBenefitItems(ctx, itemSetId, serviceIds) {
214
+ return req(ctx, "/benefit-programs/v1/bulk/items/create", {
215
+ body: {
216
+ items: serviceIds.map((externalId) => ({
217
+ namespace: PP_NAMESPACE,
218
+ category: "",
219
+ providerAppId: BOOKINGS_APP_ID,
220
+ itemSetId,
221
+ externalId,
222
+ })),
223
+ returnEntity: true,
224
+ },
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Wire a plan to COVER bookings services (per plan). Runs 2a → 2b → 2c in order.
230
+ * serviceIds come from the BOOKINGS seed — seed bookings first.
231
+ */
232
+ export async function attachBookingsCoverage(ctx, planId, serviceIds, { creditAmount } = {}) {
233
+ const programDefinitionId = await getProgramDefinition(ctx, planId);
234
+ if (!programDefinitionId) throw new Error(`No program definition for plan ${planId} — is the Pricing Plans app installed?`);
235
+ const itemSetId = await createPoolDefinition(ctx, programDefinitionId, { creditAmount });
236
+ await createBenefitItems(ctx, itemSetId, serviceIds);
237
+ return { itemSetId, serviceIds };
238
+ }
239
+
240
+ /**
241
+ * ONE-CALL seed: install → create plans (ids kept in memory) → per covering plan, wire
242
+ * bookings coverage (2a → 2b → 2c, strictly ordered). The default path.
243
+ */
244
+ export async function setupPricingPlans(ctx, { plans = [] } = {}) {
245
+ await installPricingPlansApp(ctx);
246
+ const created = await createPlans(ctx, plans);
247
+ const coverageAttached = [];
248
+ for (let i = 0; i < created.length; i++) {
249
+ const cov = plans[i].bookingsCoverage || {};
250
+ const serviceIds = cov.serviceIds || created[i].coveredServiceIds;
251
+ if (!serviceIds?.length) continue; // plans-only plan — coverage skipped
252
+ const r = await attachBookingsCoverage(ctx, created[i].id, serviceIds, { creditAmount: cov.creditAmount });
253
+ coverageAttached.push({ planId: created[i].id, ...r });
254
+ }
255
+ return {
256
+ plans: created,
257
+ coverageAttached,
258
+ benefitsCreated: coverageAttached.reduce((n, c) => n + c.serviceIds.length, 0),
259
+ };
260
+ }
261
+
262
+ // ---- CLI entry ----------------------------------------------------------------------------------
263
+
264
+ const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
265
+ if (invokedDirectly) {
266
+ const planPath = process.argv[2];
267
+ if (!planPath) {
268
+ console.error("usage: node seed-pricing-plans.mjs <plan.json> (run from the project root)");
269
+ process.exit(1);
270
+ }
271
+ const plan = JSON.parse(readFileSync(planPath, "utf8"));
272
+ const ctx = makeCtx();
273
+ setupPricingPlans(ctx, plan)
274
+ .then((result) => console.log(JSON.stringify(result, null, 2)))
275
+ .catch((e) => {
276
+ console.error(e.message);
277
+ process.exit(1);
278
+ });
279
+ }
@@ -0,0 +1,165 @@
1
+ # Restaurants — playbook
2
+
3
+ The restaurant machinery ships as files — the assembled menu tree (menus → sections → items
4
+ with variants, modifiers, labels), the dish-ordering cart on the eCom current cart with the
5
+ exact restaurant `catalogReference`, the hosted checkout, and the table-reservation
6
+ hold → reserve flow, typed end-to-end. **The presentation is yours**: you design and
7
+ implement the dish card, the menu surface, the order-cart chrome, and the reservations
8
+ surface on the shipped hooks/DTOs, plus the home page and the brand. You never write
9
+ ordering or reservation logic; you never skip designing.
10
+
11
+ ## The file map (deployed into `src/`)
12
+
13
+ **Don't read the shipped files** — this table and the contracts below are everything you
14
+ need. Open a shipped file's source only on a real fallback (runtime error / uncovered field),
15
+ or to read a reference component's pattern.
16
+
17
+ | file | what it is |
18
+ |---|---|
19
+ | `wix/config.ts` · `wix/sdk.ts` · `wix/media.ts` · `wix/money.ts` | shared auth seam + helpers (deploy configures; nothing to set) |
20
+ | `wix/restaurants/types.ts` | the DTOs (`MenuData`, `MenuSection`, `MenuItem`, `OrderCart`, `ReservationSlot`, …) — contracts below |
21
+ | `wix/restaurants/menu.ts` | `fetchMenus` — the whole display-ordered menu tree, one call |
22
+ | `wix/restaurants/ordering.ts` · `order-store.ts` | dish add-to-cart (Orders-app catalogReference) + eCom Cart V2 + shared cart state (module store — spans Astro islands) |
23
+ | `wix/restaurants/reservations.ts` | locations, AVAILABLE slots, `holdReservation`, `completeReservation` — the exact hold→reserve sequence lives here |
24
+ | `hooks/restaurants/useMenus.ts` | menu browsing + menu switching — contract below |
25
+ | `hooks/restaurants/useOrderCart.ts` | order-cart state + actions — contract below |
26
+ | `hooks/restaurants/useReservation.ts` | the whole reservation state machine — contract below |
27
+ | `components/restaurants/MenuView.tsx` (+ `MenuItemCard`) · `OrderCartButton.tsx` · `OrderCartDrawer.tsx` · `ReservationView.tsx` | **REFERENCE implementations** — correct, plain; build your own instead of shipping them |
28
+ | `styles/global.css` | the design system: Tailwind v4 + the `@theme` token block (shared across verticals) |
29
+
30
+ Astro stack additionally gets:
31
+
32
+ | file | what it is |
33
+ |---|---|
34
+ | `layouts/SiteLayout.astro` | site chrome — **yours to brand** (keep the `seo-tags` slot, global.css import, and one OrderCartButton + one OrderCartDrawer, both `client:only`). If another vertical is also deployed, its layout won — merge the Menu/Reservations links + cart mounts there |
35
+ | `pages/menu.astro` | SSR menu — **keep the frontmatter**, swap the island import to YOUR component |
36
+ | `pages/reservations.astro` | reservations — the island stays `client:only="react"` (availability is timezone-specific); swap the import to YOUR component |
37
+
38
+ ## What you build — the design job
39
+
40
+ 1. **The dish card + menu surface** — your card (photo treatment, price/variants, labels,
41
+ sold-out state, add-to-order) and your menu layout (menu tabs when >1, section navigation,
42
+ section rhythm), with skeletons while loading and an honest empty state — on `useMenus` +
43
+ `useOrderCart`.
44
+ 2. **The order-cart chrome** — your header order button (live count) and your cart panel
45
+ (lines, quantity stepper, remove, subtotal, checkout CTA) — on `useOrderCart`, which owns
46
+ ALL cart logic; you own how it looks.
47
+ 3. **The reservations surface** — party/date/time query, slot pills, the 10-minute-hold
48
+ details form (first name + phone required), and the confirmed vs pending-approval states —
49
+ on `useReservation`.
50
+ 4. **The home page** — hero, a featured-dishes strip (fetch `fetchMenus()` in frontmatter →
51
+ your cards; `item.featured` marks highlights), hours/location story, reserve CTA.
52
+
53
+ Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
54
+ Style everything with Tailwind utilities on the tokens.
55
+
56
+ ### The contracts your components consume
57
+
58
+ ```ts
59
+ // MenuData → sections → items, all display-ordered:
60
+ // MenuItem = { id, name, description, price /* display string; null when variant-priced */,
61
+ // marketPrice /* true → "Market price", not orderable */,
62
+ // variants: [{ variantId, name, price }], imageUrl, labels: [{ id, name, iconUrl }],
63
+ // modifierGroups: [{ id, name, required, minSelections, maxSelections,
64
+ // modifiers: [{ id, name, preSelected, additionalCharge, inStock }] }],
65
+ // inStock, featured }
66
+ // ⚠ MENU prices carry NO currency symbol unless the platform formatted them — render as
67
+ // given; if plain decimals, prefix the brand's currency yourself. Order-cart prices ARE
68
+ // formatted. Modifier groups are DISPLAY-ONLY (selections aren't sent on the cart line).
69
+
70
+ // useMenus({ initialMenus? }) →
71
+ // { menus: MenuData[]|null /* null = loading → skeletons */,
72
+ // activeMenuId, setActiveMenuId(id), activeMenu: MenuData|null, error }
73
+
74
+ // useOrderCart() →
75
+ // { cart: { lines, itemCount, subtotal, currency }|null,
76
+ // ordering: boolean|null, // false → show "ordering unavailable"; null = resolving
77
+ // busy, error, open,
78
+ // addToOrder(itemId, { menuId, sectionId }, qty?), // ids from the render context — see hard rules
79
+ // updateQuantity(lineItemId, qty), removeLine(lineItemId),
80
+ // checkout(), // browser redirects to the Wix-hosted checkout
81
+ // openCart(), closeCart(), refresh() }
82
+ // OrderLine = { lineItemId, itemName, quantity, unitPrice, linePrice, imageUrl,
83
+ // descriptionLines, status /* not "IN_STOCK" → can't check out */ }
84
+
85
+ // useReservation() →
86
+ // { locations: [{ id, partySizeMin, partySizeMax, approvalMode, onlineReservationsEnabled }]|null,
87
+ // location, setLocationId(id), // picker only when locations.length > 1
88
+ // date, setDate("YYYY-MM-DD"), time, setTime("HH:mm"), partySize, setPartySize(n),
89
+ // slots: ReservationSlot[]|null, findSlots(), // AVAILABLE only; null until findSlots ran
90
+ // held, holdSlot(slot), // 10-minute hold → render the details form
91
+ // reservee, setReserveeField(field, value), // firstName + phone (E.164) required
92
+ // canConfirm, confirm(), // gate the CTA on canConfirm
93
+ // confirmed: { reservationId, status: "RESERVED"|"REQUESTED" }|null,
94
+ // reset(), loading, error }
95
+ ```
96
+
97
+ ### Wiring — Astro (default)
98
+
99
+ 1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
100
+ winning layout instead if another vertical is also deployed).
101
+ 2. Write your components under `src/components/restaurants/` (new names — don't overwrite the
102
+ references), swap the island imports in `pages/menu.astro` and `pages/reservations.astro`.
103
+ Menu island: `client:load` with the SSR props; reservations island and the cart chrome:
104
+ `client:only="react"`. **Author your surfaces in as few messages as possible** — batch
105
+ multiple Writes per message.
106
+ 3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
107
+
108
+ ### Wiring — React SPA (Vite etc.)
109
+
110
+ Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
111
+ plugins — deploy added the dep). Routes: `/menu` → your menu surface (`useMenus()` fetches
112
+ client-side when no `initialMenus`); `/reservations` → your reservation surface. Mount your
113
+ order button in the header and your drawer once.
114
+
115
+ ## Hard rules
116
+
117
+ - **Ordering logic only through the shipped exports** — `useOrderCart`/`addToOrder` own the
118
+ restaurant `catalogReference` (the Orders app id + `operationId`/`menuId`/`sectionId` — all
119
+ three, no `variantId`), the line-refusal checks, and the checkout redirect. Never re-derive
120
+ any of it, never hand-build a checkout URL.
121
+ - **Thread `menuId` + `sectionId` from the render context** — each dish is rendered inside a
122
+ known section of a known menu (the `fetchMenus` tree); pass those ids to `addToOrder`.
123
+ Never look them up again.
124
+ - **Modifier groups are display-only** — show them on the dish (diners read them; staff sees
125
+ choices at the counter), but don't invent a way to send selections: that cart-line shape
126
+ isn't documented. Send quantity only, as shipped.
127
+ - **Reservations only through `useReservation`** — AVAILABLE-only slots, the hold's
128
+ `revision`, the firstName+phone requirement, and the RESERVED/REQUESTED split all live in
129
+ the data layer. Gate the CTA on `canConfirm`, surface `error` (holds expire in 10 minutes —
130
+ the hook already restarts the flow).
131
+ - **The confirmed state must reflect REAL success**: render it only from `confirmed`, and
132
+ render `REQUESTED` as "pending the restaurant's approval", never as confirmed. A visitor
133
+ returning from the hosted checkout is NOT an order-success signal.
134
+ - **Honest unavailability**: `ordering === false` → an "ordering unavailable" state on the
135
+ add button; `onlineReservationsEnabled === false` → a "call us to book" notice (the toggle
136
+ is premium-gated). Never mock menus, dishes, prices, slots, or availability.
137
+ - Theme via the `@theme` tokens; no parallel theme files, no hardcoded palettes.
138
+
139
+ ## Point the user to their dashboard
140
+
141
+ Give the owner the dashboard link (`https://manage.wix.com/dashboard/<siteId>`) plus:
142
+ `…/wix-restaurants-menus-new` (edit the menu), `…/wix-restaurants-orders-new/settings`
143
+ (fulfillment: pickup/delivery hours, fees), `…/wix-table-reservations/table-reservations`
144
+ (tables, availability). Real paid orders need a premium plan + a connected payment method,
145
+ and the online-reservations toggle itself is premium — mention both.
146
+
147
+ ## Seeding
148
+
149
+ Per `seed/SEED.md` — plain-data `plan.json` into `seed-restaurants.mjs` from the project
150
+ root. Seed a menu that exercises the UI (a few sections, an image per dish) and turn on the
151
+ ordering + reservations add-ons when the restaurant takes orders/bookings.
152
+
153
+ ## Verify (before declaring done)
154
+
155
+ - [ ] `/menu` renders the live menu SSR (view-source shows dish names) through YOUR
156
+ components, sections in seeded order; an empty backend shows your honest empty state.
157
+ - [ ] Add to order works (drawer opens, count badge is live); quantity ± / remove work; the
158
+ order survives a reload (same visitor token); checkout redirects to the Wix-hosted
159
+ checkout — or, with no ordering operation, your "ordering unavailable" state shows.
160
+ - [ ] `/reservations`: only AVAILABLE times offered; hold → details form → confirm produces
161
+ your RESERVED or REQUESTED state; a non-premium site shows your honest
162
+ "reservations aren't open yet" notice instead of a broken form.
163
+ - [ ] Dish card / menu / cart chrome / reservations / home are YOUR designs on the tokens;
164
+ data-layer/hook files unedited.
165
+ - [ ] Dashboard links handed to the owner, with the premium notes.
@@ -0,0 +1,142 @@
1
+ // REFERENCE menu surface: menu tabs (when >1), section nav, and the dish card, on the
2
+ // @theme tokens. Correct and complete; per the skill's model you design and build your own
3
+ // on useMenus + useOrderCart. Note the load-bearing wiring: each card threads its menuId +
4
+ // sectionId from the render context into addToOrder — never re-derive them.
5
+ import { useState } from "react";
6
+ import { useMenus } from "../../hooks/restaurants/useMenus";
7
+ import { useOrderCart } from "../../hooks/restaurants/useOrderCart";
8
+ import type { MenuData, MenuItem } from "../../wix/restaurants/types";
9
+
10
+ export interface MenuItemCardProps {
11
+ item: MenuItem;
12
+ menuId: string;
13
+ sectionId: string;
14
+ }
15
+
16
+ export function MenuItemCard({ item, menuId, sectionId }: MenuItemCardProps) {
17
+ const { addToOrder, ordering, busy } = useOrderCart();
18
+ const [error, setError] = useState<string | null>(null);
19
+ const canAdd = ordering === true && item.inStock && !item.marketPrice && !busy;
20
+
21
+ return (
22
+ <div className="flex gap-4 rounded-lg border border-border p-4">
23
+ {item.imageUrl && (
24
+ <img
25
+ src={item.imageUrl}
26
+ alt={item.name}
27
+ loading="lazy"
28
+ className="h-24 w-24 flex-shrink-0 rounded-md bg-secondary object-cover"
29
+ />
30
+ )}
31
+ <div className="min-w-0 flex-1">
32
+ <div className="flex items-baseline justify-between gap-3">
33
+ <p className="text-sm font-semibold">{item.name}</p>
34
+ <p className="whitespace-nowrap text-sm text-foreground">
35
+ {item.marketPrice ? "Market price" : (item.price ?? "")}
36
+ </p>
37
+ </div>
38
+ {item.labels.length > 0 && (
39
+ <p className="mt-0.5 text-xs text-muted-foreground">{item.labels.map((l) => l.name).join(" · ")}</p>
40
+ )}
41
+ {item.description && (
42
+ <p className="mt-1 text-xs leading-relaxed text-muted-foreground">{item.description}</p>
43
+ )}
44
+ {item.variants.length > 0 && (
45
+ <p className="mt-1 text-xs text-muted-foreground">
46
+ {item.variants.map((v) => `${v.name} ${v.price}`).join(" · ")}
47
+ </p>
48
+ )}
49
+ {item.modifierGroups.length > 0 && (
50
+ <p className="mt-1 text-xs text-muted-foreground">
51
+ {/* Modifier groups are DISPLAY-ONLY — selections aren't sent on the cart line. */}
52
+ Options: {item.modifierGroups.map((g) => g.name).join(", ")}
53
+ </p>
54
+ )}
55
+ <div className="mt-2 flex items-center gap-3">
56
+ {ordering !== null && !item.marketPrice && (
57
+ <button
58
+ type="button"
59
+ disabled={!canAdd}
60
+ onClick={() =>
61
+ addToOrder(item.id, { menuId, sectionId }).catch((e: unknown) =>
62
+ setError(e instanceof Error ? e.message : String(e)),
63
+ )
64
+ }
65
+ className="rounded-full bg-primary px-4 py-1.5 text-xs font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40"
66
+ >
67
+ {!item.inStock ? "Sold out" : ordering === false ? "Ordering unavailable" : "Add to order"}
68
+ </button>
69
+ )}
70
+ {error && <p className="text-xs text-red-600">{error}</p>}
71
+ </div>
72
+ </div>
73
+ </div>
74
+ );
75
+ }
76
+
77
+ export interface MenuViewProps {
78
+ initialMenus?: MenuData[];
79
+ emptyMessage?: string;
80
+ }
81
+
82
+ const tab = (active: boolean) =>
83
+ `rounded-full border px-4 py-1.5 text-sm font-medium transition-colors ${
84
+ active
85
+ ? "border-primary bg-primary text-primary-foreground"
86
+ : "border-border text-foreground hover:bg-secondary"
87
+ }`;
88
+
89
+ export default function MenuView({
90
+ initialMenus,
91
+ emptyMessage = "The menu is being written — check back soon.",
92
+ }: MenuViewProps) {
93
+ const { menus, activeMenuId, setActiveMenuId, activeMenu, error } = useMenus({ initialMenus });
94
+
95
+ if (menus === null) {
96
+ return (
97
+ <div aria-busy="true">
98
+ {Array.from({ length: 4 }, (_, i) => (
99
+ <div key={i} className="mb-4 h-24 animate-pulse rounded-lg bg-secondary" />
100
+ ))}
101
+ </div>
102
+ );
103
+ }
104
+ if (menus.length === 0) {
105
+ return <p className="py-16 text-center text-muted-foreground">{error ?? emptyMessage}</p>;
106
+ }
107
+
108
+ return (
109
+ <div>
110
+ {menus.length > 1 && (
111
+ <div className="mb-8 flex flex-wrap gap-2" role="group" aria-label="Menus">
112
+ {menus.map((m) => (
113
+ <button key={m.id} type="button" className={tab(m.id === activeMenuId)} onClick={() => setActiveMenuId(m.id)}>
114
+ {m.name}
115
+ </button>
116
+ ))}
117
+ </div>
118
+ )}
119
+ {activeMenu && activeMenu.sections.length > 1 && (
120
+ <nav className="mb-8 flex flex-wrap gap-x-5 gap-y-1 text-sm" aria-label="Sections">
121
+ {activeMenu.sections.map((s) => (
122
+ <a key={s.id} href={`#section-${s.id}`} className="text-muted-foreground no-underline transition-colors hover:text-foreground">
123
+ {s.name}
124
+ </a>
125
+ ))}
126
+ </nav>
127
+ )}
128
+ {error && <p className="mb-4 text-sm text-red-600">{error}</p>}
129
+ {activeMenu?.sections.map((section) => (
130
+ <section key={section.id} id={`section-${section.id}`} className="mb-12">
131
+ <h2 className="text-lg font-semibold tracking-tight">{section.name}</h2>
132
+ {section.description && <p className="mt-1 text-sm text-muted-foreground">{section.description}</p>}
133
+ <div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
134
+ {section.items.map((item) => (
135
+ <MenuItemCard key={item.id} item={item} menuId={activeMenu.id} sectionId={section.id} />
136
+ ))}
137
+ </div>
138
+ </section>
139
+ ))}
140
+ </div>
141
+ );
142
+ }