@wix/agent-skills 1.13.0 → 1.15.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 (250) hide show
  1. package/README.md +4 -1
  2. package/package.json +1 -1
  3. package/skills/README.md +23 -0
  4. package/skills/wix-app/SKILL.md +10 -2
  5. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
  6. package/skills/wix-app/references/CODE_QUALITY.md +1 -0
  7. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
  8. package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
  9. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
  10. package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
  11. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
  12. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
  13. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
  14. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
  15. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
  16. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
  17. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
  18. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
  19. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
  20. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
  21. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
  22. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
  23. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
  24. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
  25. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
  26. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
  27. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
  28. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
  29. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
  30. package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
  31. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
  32. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
  33. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
  34. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
  35. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
  36. package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
  37. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
  38. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
  39. package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
  40. package/skills/wix-auth/SKILL.md +12 -0
  41. package/skills/wix-auth/references/device-flow.md +140 -0
  42. package/skills/wix-docs/SKILL.md +188 -0
  43. package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
  44. package/skills/wix-docs/references/EXTRACTING.md +120 -0
  45. package/skills/wix-headless/SKILL.md +84 -130
  46. package/skills/wix-headless/entry/bootstrap.mjs +93 -0
  47. package/skills/wix-headless/entry/skill.md +78 -0
  48. package/skills/wix-headless/references/AI_FEATURES.md +178 -0
  49. package/skills/wix-headless/references/CAPABILITIES.md +84 -0
  50. package/skills/wix-headless/references/DISCOVERY.md +34 -56
  51. package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
  52. package/skills/wix-headless/references/FEEDBACK.md +118 -0
  53. package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
  54. package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
  55. package/skills/wix-headless/references/SEED.md +44 -188
  56. package/skills/wix-headless/references/SETUP.md +32 -103
  57. package/skills/wix-headless/references/astro.md +98 -0
  58. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
  59. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
  60. package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
  61. package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
  62. package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
  63. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
  64. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
  65. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
  66. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
  67. package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
  68. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
  69. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
  70. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
  71. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
  72. package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
  73. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
  74. package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
  75. package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
  76. package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
  77. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
  78. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
  79. package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
  80. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
  81. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
  82. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
  83. package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
  84. package/skills/wix-headless/references/managed/CONNECT.md +74 -0
  85. package/skills/wix-headless/references/managed/CREATE.md +130 -0
  86. package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
  87. package/skills/wix-headless/references/non-astro.md +59 -0
  88. package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
  89. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
  90. package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
  91. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
  92. package/skills/wix-manage/SKILL.md +24 -1
  93. package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
  94. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
  95. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
  96. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
  97. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
  98. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
  99. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
  100. package/skills/wix-vibe-headless/SKILL.md +136 -0
  101. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
  102. package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
  103. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
  104. package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
  105. package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
  106. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
  107. package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
  108. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
  109. package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
  110. package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
  111. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
  112. package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
  113. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
  114. package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
  115. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
  116. package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
  117. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
  118. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
  119. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
  120. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
  121. package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
  122. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
  123. package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
  124. package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
  125. package/skills/wix-headless/references/BUILD-astro.md +0 -244
  126. package/skills/wix-headless/references/BUILD-own-build.md +0 -167
  127. package/skills/wix-headless/references/BUILD.md +0 -105
  128. package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
  129. package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
  130. package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
  131. package/skills/wix-headless/references/PLAN-connect.md +0 -19
  132. package/skills/wix-headless/references/PLAN-create.md +0 -17
  133. package/skills/wix-headless/references/PLAN.md +0 -92
  134. package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
  135. package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
  136. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
  137. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
  138. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
  139. package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
  140. package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
  141. package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
  142. package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
  143. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
  144. package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
  145. package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
  146. package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
  147. package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
  148. package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
  149. package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
  150. package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
  151. package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
  152. package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
  153. package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
  154. package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
  155. package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
  156. package/skills/wix-headless/references/astro/templates/Footer.astro +0 -27
  157. package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
  158. package/skills/wix-headless/references/astro/templates/Navigation.astro +0 -38
  159. package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
  160. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
  161. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
  162. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
  163. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
  164. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
  165. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
  166. package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
  167. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
  168. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
  169. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
  170. package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
  171. package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
  172. package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
  173. package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
  174. package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
  175. package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
  176. package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
  177. package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
  178. package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
  179. package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
  180. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
  181. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
  182. package/skills/wix-headless/references/astro/templates/global.css +0 -288
  183. package/skills/wix-headless/references/astro/templates/index.astro +0 -56
  184. package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
  185. package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
  186. package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
  187. package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
  188. package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
  189. package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
  190. package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
  191. package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
  192. package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
  193. package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
  194. package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
  195. package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
  196. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
  197. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
  198. package/skills/wix-headless/references/bookings/FLOW.md +0 -246
  199. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
  200. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
  201. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
  202. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
  203. package/skills/wix-headless/references/commands/known-apps.json +0 -6
  204. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
  205. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
  206. package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
  207. package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
  208. package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
  209. package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
  210. package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
  211. package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
  212. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
  213. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
  214. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
  215. package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
  216. package/skills/wix-headless/references/seed-recipes.md +0 -49
  217. package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
  218. package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
  219. package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
  220. package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
  221. package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
  222. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
  223. package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
  224. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
  225. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
  226. package/skills/wix-headless/references/shared/STYLING.md +0 -141
  227. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
  228. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
  229. package/skills/wix-headless/references/verticals/_schema.json +0 -74
  230. package/skills/wix-headless/references/verticals/_schema.md +0 -95
  231. package/skills/wix-headless/references/verticals/blog.md +0 -31
  232. package/skills/wix-headless/references/verticals/bookings.md +0 -41
  233. package/skills/wix-headless/references/verticals/cms.md +0 -30
  234. package/skills/wix-headless/references/verticals/ecom.md +0 -25
  235. package/skills/wix-headless/references/verticals/forms.md +0 -26
  236. package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
  237. package/skills/wix-headless/references/verticals/stores.md +0 -33
  238. package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
  239. package/skills/wix-headless/scripts/compose.mjs +0 -525
  240. package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
  241. package/skills/wix-headless/scripts/flatten.sh +0 -61
  242. package/skills/wix-headless/scripts/generate-images.mjs +0 -242
  243. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -148
  244. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
  245. package/skills/wix-headless/scripts/scaffold.sh +0 -139
  246. package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
  247. package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
  248. package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
  249. package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
  250. package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
@@ -1,101 +0,0 @@
1
- ---
2
- import Layout from "../../layouts/Layout.astro";
3
- import ProductCard from "../../components/ProductCard.astro";
4
- import CategoryRail from "../../components/CategoryRail.astro";
5
- import { productsV3 } from "@wix/stores";
6
- import { listStoreCategories } from "../../utils/categories";
7
-
8
- const PAGE_SIZE = 24;
9
- const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
10
-
11
- let productList: any[] = [];
12
- let nextCursor: string | null = null;
13
- let prevCursor: string | null = null;
14
- try {
15
- let builder = productsV3
16
- .queryProducts({ fields: ["CURRENCY"] })
17
- .limit(PAGE_SIZE);
18
- if (cursor) builder = builder.skipTo(cursor);
19
- const result = await builder.find();
20
- productList = result.items ?? [];
21
- nextCursor = result.cursors?.next ?? null;
22
- prevCursor = result.cursors?.prev ?? null;
23
- } catch (err) {
24
- console.error("[products] listing query failed:", err);
25
- }
26
-
27
- // Drop the Wix Gift Card app's auto-mirror products. When the app is enabled,
28
- // it provisions 5 DIGITAL Stores products (one per denomination) tagged with
29
- // the "Gift Card" ribbon. Buying them yields a dud line item that does not
30
- // trigger gift-card issuance — the customer-facing surface for gift cards
31
- // is /gift-cards (gift-cards pack), not /products.
32
- productList = productList.filter((p) => p.ribbon?.name !== "Gift Card");
33
-
34
- const allCategories = await listStoreCategories();
35
-
36
- // Payload for the client-side AddProductImpression event.
37
- const impressionContents = productList.map((p, index) => ({
38
- id: p._id,
39
- name: p.name,
40
- price: Number(p.actualPriceRange?.minValue?.amount ?? 0),
41
- currency: p.actualPriceRange?.minValue?.currency ?? undefined,
42
- position: index + 1,
43
- }));
44
-
45
- function pageHref(c: string | null): string | null {
46
- if (!c) return null;
47
- const params = new URLSearchParams();
48
- params.set("cursor", c);
49
- return `/products?${params.toString()}`;
50
- }
51
- ---
52
-
53
- <Layout title="Products">
54
- <section class="page-header">
55
- <div class="container-page">
56
- <h1 class="page-header-title">Our Products</h1>
57
- </div>
58
- </section>
59
-
60
- <CategoryRail
61
- categories={allCategories}
62
- activeSlug={null}
63
- prevHref={pageHref(prevCursor)}
64
- nextHref={pageHref(nextCursor)}
65
- />
66
-
67
- <section class="section-pad">
68
- <div class="container-page">
69
- {productList.length === 0 ? (
70
- <p class="products-empty">
71
- No products yet &mdash; please check back shortly.
72
- </p>
73
- ) : (
74
- <div class="product-grid">
75
- {productList.map((product, idx) => (
76
- <ProductCard product={product} index={idx} />
77
- ))}
78
- </div>
79
- )}
80
- </div>
81
- </section>
82
- </Layout>
83
-
84
- <script
85
- type="application/json"
86
- id="analytics-impressions"
87
- is:inline
88
- set:html={JSON.stringify(impressionContents)}
89
- />
90
- <script>
91
- import { trackEvent } from "../../utils/analytics";
92
- function fireImpressions() {
93
- const el = document.getElementById("analytics-impressions");
94
- if (!el?.textContent) return;
95
- trackEvent("AddProductImpression", {
96
- contents: JSON.parse(el.textContent),
97
- origin: "Product Listing",
98
- });
99
- }
100
- document.addEventListener("astro:page-load", fireImpressions);
101
- </script>
@@ -1,161 +0,0 @@
1
- # Recipe: Seed Initial Blog Posts via REST
2
-
3
- Create 3 on-brand blog posts so the blog has real content on first preview.
4
-
5
- > **Critical Rules — Read Before Starting**
6
- > 1. **Seed content is required** — a blog with zero posts on first preview is a build failure. Do not skip this section.
7
- > 2. **Re-publish after PATCH** — updating a published post sets `hasUnpublishedChanges: true`. Call `publish` again or visitors see the old version.
8
- > 3. **Use `@wix/blog`, not `@wix/data`** — blog posts are NOT CMS collections.
9
- > 4. **`RICH_CONTENT` fieldset required** — without it, `post.richContent` is undefined and rendering fails.
10
-
11
- > **Required in the Seed phase.** When dispatched with `Scope: seed`, the CLI-minted REST token and discovery context are guaranteed available. Always execute this section — do not skip. A blog with zero posts on first preview is a build failure.
12
- >
13
- > **Skip only for standalone invocations** where the Blog skill is invoked directly AND CLI token mint fails after recovery. In that case, the user can create posts manually in the Wix dashboard.
14
-
15
- ## Step 0: Ensure Blog App Is Installed
16
-
17
- Before querying blog data, verify the Blog app is installed:
18
-
19
- 1. **Probe** — `REST: POST https://www.wixapis.com/blog/v3/posts/query`
20
- 2. **If the API returns a "REQUIRED_APP_NOT_INSTALLED" error** → install the Wix Blog app:
21
- ```
22
- REST: POST https://www.wixapis.com/apps-installer-service/v1/app-instance/install
23
- body: {
24
- "tenant": { "tenantType": "SITE", "id": "<siteId>" },
25
- "appInstance": { "appDefId": "14bcded7-0066-7c35-14d7-466cb3f09103", "enabled": true }
26
- }
27
- ```
28
- > Translate this prose-HTTP form into the full `curl` tool-call shape — pass `body` as JSON in `-d` (NOT a stringified JSON). See `../shared/AUTHENTICATION.md` for the standard REST headers.
29
-
30
- Then retry the probe query to confirm installation succeeded.
31
- 3. **If the probe succeeds** → proceed to Step 1.
32
-
33
- ---
34
-
35
- ## Step 1: Get Member ID
36
-
37
- Blog posts require a `memberId` (the post author). Fetch the first site member:
38
-
39
- ```
40
- REST: GET https://www.wixapis.com/members/v1/members
41
- ```
42
-
43
- Extract the first member's `_id` from the response. This will be used as the author for all posts.
44
-
45
- ## Step 2: Design 3 On-Brand Blog Posts
46
-
47
- No API call — use discovery context (business type, brand name, tone, industry) to plan 3 posts:
48
-
49
- - Titles, summaries, and rich content appropriate for the business
50
- - Content should demonstrate different Ricos node types (paragraphs, headings, code blocks, lists, blockquotes)
51
- - Posts should feel like real content a reader would engage with, not placeholder text
52
-
53
- **Post design guidelines by business type:**
54
-
55
- | Business Type | Post 1 | Post 2 | Post 3 |
56
- |--------------|--------|--------|--------|
57
- | AI / tech blog | Architecture deep-dive | Practical comparison (X vs Y) | Lessons learned / field report |
58
- | Skincare / beauty | Ingredient science spotlight | Routine guide (morning/evening) | Myth-busting or FAQ |
59
- | Food / restaurant | Behind the recipe | Seasonal menu spotlight | Sourcing / farm-to-table story |
60
- | Fitness / wellness | Training methodology breakdown | Nutrition or recovery guide | Client transformation story |
61
- | Fashion / retail | Trend analysis | Styling guide | Behind the brand / process |
62
- | General business | Industry insight | How-to guide | Company news / milestone |
63
-
64
- Adapt titles, tone, and content to match the brand's voice and style.
65
-
66
- ## Step 3: Create Posts
67
-
68
- For each post, call `POST /blog/v3/draft-posts` with `publish: true` to create and immediately publish.
69
-
70
- > Do not include the `media` field — cover images are handled separately by the image agent after post creation.
71
-
72
- ```
73
- REST: POST https://www.wixapis.com/blog/v3/draft-posts
74
- body: {
75
- "draftPost": {
76
- "title": "<Post Title>",
77
- "memberId": "<member-id-from-step-1>",
78
- "richContent": {
79
- "nodes": [
80
- {
81
- "type": "HEADING",
82
- "id": "<unique-id>",
83
- "nodes": [
84
- { "type": "TEXT", "id": "", "nodes": [], "textData": { "text": "Section Heading", "decorations": [] } }
85
- ],
86
- "headingData": { "level": 2 }
87
- },
88
- {
89
- "type": "PARAGRAPH",
90
- "id": "<unique-id>",
91
- "nodes": [
92
- { "type": "TEXT", "id": "", "nodes": [], "textData": { "text": "Paragraph content here.", "decorations": [] } }
93
- ],
94
- "paragraphData": {}
95
- }
96
- ]
97
- }
98
- },
99
- "publish": true
100
- }
101
- ```
102
-
103
- ### Ricos JSON Node Reference
104
-
105
- Use these node types to build rich, varied content:
106
-
107
- | Node Type | Structure | Use For |
108
- |-----------|-----------|---------|
109
- | `PARAGRAPH` | `{ type: "PARAGRAPH", id, nodes: [TEXT], paragraphData: {} }` | Body text |
110
- | `HEADING` | `{ type: "HEADING", id, nodes: [TEXT], headingData: { level: 2 } }` | Section headers (level 2–4) |
111
- | `CODE_BLOCK` | `{ type: "CODE_BLOCK", id, nodes: [TEXT], codeBlockData: { language: "javascript" } }` | Code snippets |
112
- | `BULLETED_LIST` | `{ type: "BULLETED_LIST", id, nodes: [LIST_ITEM] }` | Unordered lists |
113
- | `LIST_ITEM` | `{ type: "LIST_ITEM", id, nodes: [PARAGRAPH] }` | Items inside BULLETED_LIST |
114
- | `BLOCKQUOTE` | `{ type: "BLOCKQUOTE", id, nodes: [PARAGRAPH] }` | Pull quotes, callouts |
115
- | `TEXT` | `{ type: "TEXT", id: "", nodes: [], textData: { text: "...", decorations: [] } }` | Inline text (leaf node inside paragraphs, headings, etc.) |
116
-
117
- **Tips:**
118
- - Container nodes (PARAGRAPH, HEADING, etc.) need a unique `id` (use any string, e.g., `"n1"`, `"n2"`). TEXT nodes can use an empty string `""` for `id`.
119
- - TEXT nodes are always leaf nodes inside PARAGRAPH, HEADING, CODE_BLOCK, etc.
120
- - LIST_ITEM nodes contain PARAGRAPH nodes (not TEXT directly)
121
- - Mix at least 3 different node types per post for visual variety
122
- - Create all 3 posts in sequence (one `curl` call per post)
123
-
124
- > **Re-publish after PATCH:** If you update a published post (e.g., the image agent adds a cover image via PATCH after creation), it becomes `hasUnpublishedChanges: true`. The agent that PATCHes must call `POST /blog/v3/draft-posts/{draftPostId}/publish` to re-publish. (This seed scope does not attach media — see Step 3.)
125
-
126
- ## Step 4: Verify
127
-
128
- Query published posts to confirm all 3 exist:
129
-
130
- ```
131
- REST: POST https://www.wixapis.com/blog/v3/posts/query
132
- body: {
133
- "query": {
134
- "paging": { "limit": 10 }
135
- }
136
- }
137
- ```
138
-
139
- Confirm 3 posts are returned. Report post titles to the user.
140
-
141
- ## Step 5: Return Results
142
-
143
- Emit a structured JSON block at the end of your completion message per `../shared/RETURN_CONTRACT.md`. Do **not** write a sidecar file. Include the created posts' `id` and `title` so the image agent can attach cover images by ID:
144
-
145
- ```json
146
- {
147
- "status": "complete",
148
- "phase": "blog-seed",
149
- "scope": "seed",
150
- "summary": "Created and published {n} on-brand blog posts",
151
- "data": {
152
- "blogPosts": [
153
- { "id": "<uuid>", "title": "<title>" }
154
- ]
155
- },
156
- "files": [],
157
- "errors": []
158
- }
159
- ```
160
-
161
- The JSON block MUST be the last content in your message.
@@ -1,32 +0,0 @@
1
- ---
2
- name: blog-implementer
3
- description: "Implements blog vertical via Wix Blog app — @wix/blog SDK, @wix/ricos rich content, RSS/sitemap. Scopes: seed, components, pages. Extends references/shared/IMPLEMENTER.md."
4
- ---
5
-
6
- # Blog Implementer
7
-
8
- Extends `references/shared/IMPLEMENTER.md`. Read that file first for phase routing, REST auth + doc lookups, prompt-inlined inputs (read only your `.wix/seeded.json` slice), return contract, style conventions, and common failure modes.
9
-
10
- ## Scope routing
11
-
12
- | Scope | Phase | Reference |
13
- |-------|-------|-----------|
14
- | `seed` | Seed (post seeding via REST with Ricos content) | `./BLOG_CONTENT.md` |
15
- | `components` | Components (blog service module, RicosViewer, consts, astro.config sitemap) | `../astro/blog/BLOG_SETUP.md` |
16
- | `pages` | Pages (listing, detail, RSS, BlogPost layout — all under `src/pages/blog/*`; no shared-shell patch, so blog merges into one private build agent) | `../astro/blog/BLOG_PAGES.md` |
17
-
18
- Cover images are generated by the shared image agent (`image-phase-2-entity` scope) AFTER `seed` completes — not by this agent.
19
-
20
- ## Files this vertical creates / contributes
21
-
22
- The `components` and `pages` scopes enumerate their own file lists — see `../astro/blog/BLOG_SETUP.md` (components) and `../astro/blog/BLOG_PAGES.md` (pages).
23
-
24
- ## Blog-specific failure modes
25
-
26
- | Wrong | Right |
27
- |---|---|
28
- | `import { items } from "@wix/data"` for blog queries | `import { posts } from "@wix/blog"` — use the Blog SDK |
29
- | `<article set:html={post.content} />` | `<RicosViewer client:only="react" content={post.richContent} />` — content is Ricos format |
30
- | Skip `wixMetadata` on `[...slug].astro` | Required for Wix page routing + SEO |
31
- | Query posts without `RICH_CONTENT` fieldset | Always request `RICH_CONTENT` or `post.richContent` is undefined |
32
- | Scoped `<style>` for RicosViewer overrides | `<style is:global>` — React islands don't inherit scoped Astro styles |
@@ -1,246 +0,0 @@
1
- # Bookings — the booking flow (framework-agnostic logic)
2
-
3
- The booking logic — the step model, the shared state, and the exact `@wix` SDK
4
- sequence — is the **same on every frontend** (astro, react/vite, vue, plain HTML).
5
- This file is that shared logic. The per-framework wiring layers on top:
6
-
7
- - **astro** (`frontendBuild: wix`): `../astro/bookings/SERVICES_PAGES.md` (SSR read pages) + `../astro/bookings/COMPONENTS.md` (the client islands).
8
- - **own / static** (`frontendBuild: own`/`none`): `../custom/bookings/WIRING.md`.
9
-
10
- **Code examples are React** (`../astro/templates/bookings/*.tsx` + `bookingDriver.ts`).
11
- React is directly usable on astro islands and on react/vite. **On any other
12
- framework, translate the examples** — the SDK calls and payloads are identical;
13
- only the UI idiom (`useState`/`useEffect` → a store / `onMounted` / signals) and
14
- the client acquisition differ (see "Client identity" below).
15
-
16
- The flow covers **appointments and classes**. APPOINTMENT and CLASS share the
17
- same booking sequence; they differ only in the availability call (`availabilityTimeSlots`
18
- vs `eventTimeSlots`, noted inline). **Courses and add-ons are out of scope.**
19
-
20
- ---
21
-
22
- ## 1. The step model
23
-
24
- A single customer journey, holding one shared selection. The catalog optionally
25
- filters by **location** and **category**; the slots step optionally filters by
26
- **staff**. All three auto-skip when there's nothing to choose (≤1 location, ≤1
27
- category, ≤1 staff), so a plain single-location single-staff site sees the simple
28
- five-step path:
29
-
30
- ```
31
- 0. Location (optional) pick a location — only shown when the site has >1 locations → scopes the catalog + availability
32
- 1. Catalog list bookable services (optionally filtered by location/category) → pick a service
33
- 2. Slots availability calendar (optionally filtered by staff) → pick a time slot
34
- 3. Details the service's booking form (collect contact) → submit
35
- 4. Book run the SDK sequence (§3)
36
- 5a. paid → redirect to the Wix-hosted checkout → returns to the confirmation page
37
- 5b. free/offline → place the order → confirmation page
38
- ```
39
-
40
- The location/category filters and the staff picker are covered in §§7–8.
41
-
42
- **The catalog is the entry point but optional** — a visitor can land directly on a
43
- service page and start at the Slots step. Every step rehydrates from the URL (§2),
44
- so deep links work.
45
-
46
- Mapping the steps onto pages/routes is the **target framework's choice** — translate
47
- the step model to whatever router the framework uses. The skill recommends the routes
48
- `/services`, `/services/[slug]`, `/booking-confirmation` (advertised in
49
- `../verticals/bookings.md`). On astro specifically, SSR the catalog + detail pages
50
- for SEO and run slots + form + book in a `client:only` island.
51
-
52
- ## 2. Shared booking state
53
-
54
- Steps 1–4 build up one selection (this is exactly `BookParams` + `SelectedSlot`
55
- in `../astro/templates/bookings/bookingDriver.ts`):
56
-
57
- - **`service`** — the chosen service object (the booking step reads `service.payment` + `service.bookingPolicy`; the slots step reads `service.staffMemberDetails.staffMembers` for the staff picker — §8).
58
- - **`slot`** — `{ serviceType, serviceId, localStartDate, localEndDate, timezone, scheduleId?, eventId?, locationId?, locationType?, resource? }`. `resource = { _id, name }` is set only when a specific staff was chosen (§8); otherwise the driver emits the ANY_RESOURCE fallback. `locationId`/`locationType` come from the slot's own `location` (the booking books at that location).
59
- - **`formSubmission`** — the booking-form values, **keyed by each field's `target`** (§4).
60
-
61
- Hold it however the framework prefers (React state lifted to a coordinator, a
62
- store, route loaders + a provider, query-params). **Two rules that bite:**
63
-
64
- 1. **Persist the selection before navigating.** When a step lives on its own
65
- route, write the selection into the shared state (or the URL) *before* moving
66
- on, and let the next step **rehydrate from the slug/URL** on direct load /
67
- refresh. A persistent provider that does not re-init on in-app navigation will
68
- otherwise show an empty next step.
69
- 2. **The slug is the carry-across key.** `serviceSlug` (the service's
70
- `mainSlug.name`) identifies the service across the slots + details steps;
71
- resolve the full service from it when state is lost.
72
-
73
- ## 3. The booking SDK sequence — `bookingDriver.ts`
74
-
75
- The whole booking — `createBooking → createCart → calculateCart → checkout-or-place`
76
- — is in **`../astro/templates/bookings/bookingDriver.ts`**, in plain `@wix` SDK
77
- calls (no React, no UI). **Use it as-is** (it is framework-agnostic); the booking
78
- step calls `book(params)` then branches on the result. Do not re-author the
79
- sequence — the payload shapes are exact and easy to get subtly wrong.
80
-
81
- ```
82
- book({ service, slot, formSubmission, timezone }) →
83
- createBooking(...) // booking lands CREATED — the cart holds the seat
84
- createCart(...) // one catalog item per bookingId, appId = BOOKING_APP_ID, channel WEB
85
- calculateCart(cartId) // → { cart, summary }; totals on summary.priceSummary.total.amount
86
- isCheckoutRequired(...) ?
87
- → { CheckoutRequired, cartId } // paid → navigateToCheckout(cartId, postFlowUrl) → Wix-hosted checkout
88
- : placeOrder(cartId) → { CheckoutSkipped, orderId } // free / pay-in-person → confirmation
89
- ```
90
-
91
- Key facts the driver encodes (do not deviate):
92
- - **No `confirmBooking`** — `confirmBooking` is the classic Bookings server-side
93
- confirm step (it moves a booking from `CREATED` to `CONFIRMED`). Here the **ecom
94
- cart holds the seat** instead — `placeOrder` (free/offline) or the hosted checkout
95
- (paid) drives confirmation — so a client-only site completes the whole flow with no
96
- server elevation.
97
- - **ANY_RESOURCE fallback (staff)** — when no staff is chosen (the default, and on
98
- single-staff services), `createBooking` sends
99
- `resourceSelections:[{ resourceTypeId:"1cd44cf8-756f-41c3-bd90-3e2ffcaf1155", selectionMethod:"ANY_RESOURCE" }]`
100
- and Wix auto-assigns a bookable staff resource (appointment slots return
101
- `availableResources:[]` yet book fine this way). A specific staff choice sets
102
- `slot.resource` instead (§8).
103
- - **Checkout decision** — `isCheckoutRequired`: if the service's booking policy charges
104
- a **cancellation fee** (`service.bookingPolicy.cancellationFeePolicy.enabled`) →
105
- checkout (a card must be on file); else total 0 → place; else `FULL_PAYMENT_OFFLINE`
106
- → place; else checkout.
107
- - **Redirect shape** — paid bookings hand the cart to the Wix-hosted **ecom**
108
- checkout: `createRedirectSession({ ecomCheckout: { checkoutId: cartId }, callbacks:{ postFlowUrl } })`.
109
-
110
- ### Browse + availability (the read calls the steps make)
111
-
112
- Mirror what the Bookings SDK does (`services.queryServices` is the raw SDK, not a component):
113
-
114
- ```js
115
- // Catalog (list) — the filter MUST include appId; pass conditionalFields, then .find().
116
- // Merge the optional category/location filters into the SAME filter object (§7):
117
- services.queryServices({
118
- query: { filter: { appId: BOOKING_APP_ID /* , "category.id": { $eq: catId },
119
- "locations.business.id": { $hasSome: [locId] } */ }, paging: { limit: 100 } },
120
- conditionalFields: ["STAFF_MEMBER_DETAILS"],
121
- }).find(); // → result.items ; filter out s.hidden
122
-
123
- // Single service by slug — the .eq() builder chain:
124
- services.queryServices({ conditionalFields: ["STAFF_MEMBER_DETAILS"] })
125
- .eq("mainSlug.name", slug).eq("appId", BOOKING_APP_ID).limit(1).find();
126
-
127
- // Availability (APPOINTMENT) — serviceId is a single GUID STRING. The staff (§8)
128
- // and location filters are OPTIONAL params on the same call:
129
- availabilityTimeSlots.listAvailabilityTimeSlots({
130
- serviceId, fromLocalDate, toLocalDate, timeZone, bookable: true, cursorPaging: { limit: 100 },
131
- // staff: resourceTypes: [{ resourceTypeId: STAFF_MEMBER_RESOURCE_TYPE_ID, resourceIds: [staffResourceId] }],
132
- // includeResourceTypeIds: [STAFF_MEMBER_RESOURCE_TYPE_ID],
133
- // location: locations: [{ _id: locationId, locationType: "BUSINESS" }],
134
- }); // slots: result.timeSlots[] (localStartDate/localEndDate/scheduleId at top level)
135
-
136
- // Availability (CLASS) — different namespace, PLURAL serviceIds; slots carry eventInfo.eventId, no scheduleId.
137
- // CLASS filters staff + location via eventFilter instead:
138
- eventTimeSlots.listEventTimeSlots({
139
- serviceIds: [serviceId], fromLocalDate, toLocalDate, timeZone, includeNonBookable: false,
140
- // eventFilter: { "resources.id": { $hasSome: [staffResourceId] }, "location.id": [locationId] },
141
- });
142
- ```
143
-
144
- `fromLocalDate`/`toLocalDate` are **local** date strings `YYYY-MM-DDThh:mm:ss`
145
- (no `Z`) with an explicit `timeZone`.
146
-
147
- ## 4. The booking form — schema-driven (`@wix/forms`)
148
-
149
- The booking form is a **`@wix/forms` form** attached to the service
150
- (`service.form._id`, namespace `wix.bookings.v2.bookings`). Render it
151
- **schema-driven** — read the field list and render inputs by field type — the
152
- **same renderer the forms vertical uses** (`../astro/forms/CONTACT_FORM.md`):
153
-
154
- 1. Fetch the form by `service.form._id` (`@wix/forms` `getForm`; server-side/elevated
155
- where the framework allows). Read `form.formFields`.
156
- 2. Keep `fieldType === "INPUT" && !hidden` **and** a recognized string
157
- `componentType` (`TEXT_INPUT` / `PHONE_INPUT` / `DROPDOWN`). For each, take
158
- `inputOptions.target`, `inputOptions.required`, `inputOptions.stringOptions.componentType`,
159
- and the label from `inputOptions.stringOptions.{textInputOptions|dropdownOptions|phoneInputOptions}.label`.
160
- **Skip complex, object-valued fields** — e.g. a multi-line `ADDRESS` — they carry
161
- no string `componentType`; rendering them as a text input sends a string and
162
- `createBooking` rejects it with **"must be object"**. The booking enforces only
163
- the contact basics (`first_name`/`last_name`/`email`), so omitting an optional
164
- complex field is safe (do **not** default unknown field types to a text input).
165
- 3. Render generic inputs by `componentType`: `TEXT_INPUT` → text input,
166
- `DROPDOWN` → select, `PHONE_INPUT` → `type=tel`; treat `identifier === "TEXT_AREA"`
167
- (or `target` containing `message`) as a textarea (its `componentType` is still `TEXT_INPUT`).
168
- 4. Collect the values into an object **keyed by each field's `target`** — that is
169
- `formSubmission`. Pass it to `book()`. Only include fields the visitor filled;
170
- never send a value for a field you didn't render.
171
-
172
- **Do not** submit `contactDetails`, and **do not** hardcode field names — key by
173
- `target`. The default booking form's targets are snake_case `first_name` /
174
- `last_name` / `email` / `phone`. Reference example: `../astro/templates/bookings/BookingForm.tsx`.
175
-
176
- ## 5. The availability calendar (slots step)
177
-
178
- **Group slots by day — don't render a flat list of every slot with time-only
179
- labels** (the visitor can't tell which day a slot is on; that flat grid was the
180
- original usability failure). The calendar **shape is your / the brand's choice** —
181
- week, month, or N-day. The reference example uses a **week view** (a 7-day strip
182
- with week navigation → the picked day's times); fetch availability for the visible
183
- window (`fromLocalDate`/`toLocalDate` = that window's bounds), group by calendar
184
- day, and offer a **"check next availability"** action that probes forward when the
185
- window is empty. Reference example:
186
- `../astro/templates/bookings/AvailabilityCalendar.tsx`.
187
-
188
- ## 6. Client identity (per framework)
189
-
190
- The SDK calls are identical everywhere; only how you get the client differs:
191
- - **astro** — SSR read pages use the ambient `@wix/essentials` client
192
- (`auth.elevate(services.queryServices)(...)`); browser islands call the `@wix`
193
- modules **ambiently** too (the `@wix/astro` visitor client, like the ecom
194
- `CartView` island) — no `createClient`/`OAuthStrategy`.
195
- - **own / static** — acquire a visitor client once:
196
- `createClient({ modules, auth: OAuthStrategy({ clientId: appId }) })` and call
197
- the same functions on it. CDN imports for `none`, bundled for `own`.
198
-
199
- ## 7. Catalog filters — location & category (both auto-skip)
200
-
201
- Both filter the **catalog query** and re-render the list. The cleanest
202
- framework-agnostic shape is a re-query driven by a query param (`?locationId`,
203
- `?category`) — links/SSR on a static catalog, or a store/router on a SPA. **Show
204
- each filter only when there is more than one choice**, exactly as the SoT does.
205
-
206
- **Location** (the SoT is location-first; here it auto-skips ≤1 location):
207
- 1. `services.queryLocations()` → `{ businessLocations: { locations: [{ _id, type, business: { name } }] }, customLocations: { exists }, customerLocations: { exists } }`.
208
- 2. Count = `businessLocations.locations.length + (customLocations.exists ? 1 : 0) + (customerLocations.exists ? 1 : 0)`. **Show the selector only when count > 1.**
209
- 3. The chosen location filters the catalog query:
210
- - a real business id → `filter["locations.business.id"] = { $hasSome: [id] }`;
211
- - the synthetic `"custom"` / `"customer"` → `filter["locations.type"] = { $hasSome: ["CUSTOM"|"CUSTOMER"] }` (the SoT's synthetic-id mapping).
212
- 4. **Scope availability to exactly ONE location — always, on a multi-location service.** `listAvailabilityTimeSlots` returns **one slot per location** per time ("if `locations` is not specified, returns time slots for all locations where the service is available"), so an unscoped call on a 2-location service shows every time **twice**. Pass a single-element filter: APPOINTMENT → `locations: [{ _id, locationType: "BUSINESS" }]`; CLASS → `eventFilter: { "location.id": [id] }`. (Staff does **not** multiply rows — one slot carries many `availableResources`; only location does.) The slots step builds its location list from **`queryLocations()`** (the site's real business locations, whose ids the availability engine recognizes) **intersected with the service's own location ids** — not from `service.locations` alone, whose entries can carry an id the availability engine doesn't recognize (scoping to it returns zero slots). A **location picker** defaults to the catalog-carried location (or the first) and scopes the call when there's a real location to scope to; when the site has no business locations the list is empty and the call stays unscoped (one location → no duplicates). The booked slot carries its own `location`, so the booking books at that location (the driver maps it).
213
-
214
- **Category:**
215
- 1. `categoriesV2.queryCategories().find()` → `result.items: [{ _id, name }]`. **Non-fatal** — if it fails, render the catalog without the bar.
216
- 2. **Show the bar only when `items.length > 1`** (a fresh site has one default category).
217
- 3. The chosen category filters the catalog query: `filter["category.id"] = { $eq: categoryId }`. A service carries its category at `service.category._id`.
218
-
219
- Reference example: `../astro/templates/bookings/services/index.astro` (both filters, link-driven, auto-skipping).
220
-
221
- ## 8. Staff / resource selection (auto-skips ≤1 staff)
222
-
223
- A service carries its staff on the service object via the **`STAFF_MEMBER_DETAILS`
224
- conditional field** (already requested in the catalog/detail query):
225
- `service.staffMemberDetails.staffMembers: [{ staffMemberId, name }]`. The id used
226
- for filtering and booking is **`staffMemberId`** — which, **despite the name, IS the
227
- resource GUID** (it matches the service's `staffMemberIds` and the Staff Members API
228
- `resourceId`). Below, `resourceId` is that value.
229
-
230
- 1. Show a "Any staff member / pick one" control above the calendar **only when
231
- there is more than one staff**.
232
- 2. Selecting a staff re-fetches availability filtered to that resource:
233
- - APPOINTMENT → `resourceTypes: [{ resourceTypeId: STAFF_MEMBER_RESOURCE_TYPE_ID, resourceIds: [resourceId] }]` (plus `includeResourceTypeIds: [STAFF_MEMBER_RESOURCE_TYPE_ID]`);
234
- - CLASS → `eventFilter: { "resources.id": { $hasSome: [resourceId] } }`.
235
- 3. When a slot is picked **with a specific staff selected**, set `slot.resource = { _id: resourceId, name }`. The driver books that resource. With **"any staff"**, leave `resource` unset — the driver emits the **ANY_RESOURCE fallback** and Wix auto-assigns a bookable resource (appointment slots can return `availableResources: []` yet book fine this way).
236
-
237
- `STAFF_MEMBER_RESOURCE_TYPE_ID = "1cd44cf8-756f-41c3-bd90-3e2ffcaf1155"` (exported from `bookingDriver.ts`). Reference example: `../astro/templates/bookings/AvailabilityCalendar.tsx` (the staff `<select>` + the filtered fetch).
238
-
239
- ## 9. Out of scope
240
-
241
- Waitlist, on-site manage/cancel, payment/deposit breakdown, and multi-service /
242
- day-range are out of scope. (Waitlist and manage/cancel have **no headless SoT** —
243
- neither the components nor the vibe plugin implement join/cancel logic, only
244
- display-only policy flags — so they are deliberately not built here.) Show
245
- bookable slots only; post-booking self-service is handled by the Wix-hosted flow /
246
- member area.
@@ -1,95 +0,0 @@
1
- ---
2
- name: bookings-implementer
3
- description: "Implements the Wix Bookings vertical — services catalog (with optional location + category filters), a service detail page with a week-calendar availability picker (with optional staff selection), a schema-driven booking form, and confirmation, for appointments and classes. The booking runs client-side via the @wix SDK (ecom Cart V2 — no confirmBooking). Scopes: seed, components, pages. Extends references/shared/IMPLEMENTER.md."
4
- ---
5
-
6
- # Bookings Implementer
7
-
8
- Extends `references/shared/IMPLEMENTER.md`. Read that file first for phase routing, REST auth + doc lookups, the `.wix/seeded.json` read pattern, the return contract, style conventions, and common failure modes.
9
-
10
- ## The logic lives in one place
11
-
12
- The booking **logic** — the step model, the shared selection state, the exact
13
- `@wix` SDK sequence, and the schema-driven form — is framework-agnostic and lives
14
- in **`./FLOW.md`**. Read it first. The astro guides below are the astro *wiring* of
15
- that logic; the code examples under `<SKILL_ROOT>/references/astro/templates/bookings/`
16
- are React (the astro islands use them directly). For an own/static build, the wiring guide is
17
- `../custom/bookings/WIRING.md` (same logic, client-side `@wix/sdk`).
18
-
19
- ## Scope routing
20
-
21
- | Scope | Phase | Reference |
22
- |-------|-------|-----------|
23
- | `seed` | Seed — create services (and staff) via the Wix Bookings REST API | `./SERVICES_DATA.md` |
24
- | `components` | Components — the client islands (week calendar, schema-driven form, the flow coordinator) | `./FLOW.md` + `../astro/bookings/COMPONENTS.md` |
25
- | `pages` | Pages — `/services` listing, `/services/[slug]` detail, `/booking-confirmation`, + nav/home links | `./FLOW.md` + `../astro/bookings/SERVICES_PAGES.md` |
26
-
27
- ## Templates — read and adapt (don't invent)
28
-
29
- Canonical examples live at `<SKILL_ROOT>/references/astro/templates/bookings/`.
30
- Your `components` and `pages` scopes **read these and adapt them** — adapt brand
31
- copy, headings, and styling; keep the SDK calls, payload shapes, and the data
32
- flow (re-authoring the SDK wiring from scratch is the main source of API-shape bugs).
33
-
34
- Components (`components` scope — TSX only, no CSS):
35
- - `<SKILL_ROOT>/references/astro/templates/bookings/AvailabilityCalendar.tsx` — the week calendar (week strip → the day's slots; APPOINTMENT via `availabilityTimeSlots`, CLASS via `eventTimeSlots`).
36
- - `<SKILL_ROOT>/references/astro/templates/bookings/BookingForm.tsx` — the schema-driven form (renders the `@wix/forms` field list, keys values by `target`) that drives `bookingDriver.book()`.
37
- - `<SKILL_ROOT>/references/astro/templates/bookings/ServiceBookingFlow.tsx` — the coordinator island (holds the selected slot; calendar → form → redirect).
38
-
39
- Pages (`pages` scope):
40
- - `<SKILL_ROOT>/references/astro/templates/bookings/ServiceCard.astro`
41
- - `<SKILL_ROOT>/references/astro/templates/bookings/services/index.astro`, `<SKILL_ROOT>/references/astro/templates/bookings/services/[slug].astro`
42
- - `<SKILL_ROOT>/references/astro/templates/bookings/booking-confirmation.astro`
43
-
44
- ### Pre-copied by the orchestrator (do NOT write these yourself)
45
- Mechanical, brand-agnostic — the orchestrator copies them before dispatch (BUILD-astro.md § build wave). Rely on them at the listed paths:
46
- - `src/components/bookingDriver.ts` ← `<SKILL_ROOT>/references/astro/templates/bookings/bookingDriver.ts` — the booking SDK sequence (`book()`, `navigateToCheckout()`). The islands import it; never re-author it.
47
- - `src/components/SeoTags.astro` ← `<SKILL_ROOT>/references/astro/templates/bookings/SeoTags.astro` — renders `service.seoData.tags`; imported by `services/[slug].astro`.
48
- - `src/styles/components-bookings.css` ← `<SKILL_ROOT>/references/astro/templates/bookings/components-bookings.css` — the flow's component classes.
49
-
50
- If a pre-copied file is missing at runtime, that's an orchestrator-side bug — return `status: "partial"` with `errors: [{code: "UTILITY_TEMPLATE_NOT_PRECOPIED", path: "<missing>"}]`; do not author your own version.
51
-
52
- ## Pre-return file-existence assertion (pages scope)
53
-
54
- Before returning `status: "complete"` from `pages`, verify on disk:
55
- - `src/pages/services/index.astro`
56
- - `src/pages/services/[slug].astro`
57
- - `src/pages/booking-confirmation.astro`
58
-
59
- If any declared file is missing, return `status: "partial"` with `errors: [{ code: "PHASE4_FILE_MISSING", path: "<expected path>" }]`.
60
-
61
- ## Dependencies (Setup installs these — see SETUP.md)
62
-
63
- `@wix/bookings @wix/essentials @wix/forms @wix/redirects @wix/auto_sdk_ecom_cart-v-2`.
64
- `@wix/forms` renders the booking-form schema; `@wix/redirects` + `@wix/auto_sdk_ecom_cart-v-2` run the cart/checkout sequence.
65
-
66
- ## CSS ownership — bookings pack
67
-
68
- Bookings-specific CSS lives in `src/styles/components-bookings.css` (pre-copied — see above), NOT in `global.css`. Classes the pack owns: `.service-card*`, `.service-grid`, `.availability-*`, `.time-slot*`, `.booking-*`. If `global.css` ships a partial rule for any of these, flag it (`{code:"GLOBAL_CSS_LEAK", class:"<name>"}`) and override in `components-bookings.css`.
69
-
70
- ## Bookings-specific failure modes
71
-
72
- | Wrong | Right |
73
- |-------|-------|
74
- | Stop after `createBooking` returns | `createBooking` leaves the booking **`CREATED`**. The seat is held by the **ecom Cart V2**: continue `createCart → calculateCart → isCheckoutRequired ? hosted-checkout redirect : placeOrder`. The whole sequence is in `bookingDriver.ts` — use it. |
75
- | Hardcode `selectedPaymentOption: "ONLINE"` on `createBooking` | **Derive** it from the service: `online && !inPerson → "ONLINE"`, `!online && inPerson → "OFFLINE"`, else `"ONLINE"`. A free / pay-in-person service is the only kind that reaches `placeOrder`, and booking it `ONLINE` makes the cart reject it with **`INSUFFICIENT_INVENTORY`** (`available_quantity: 0`). `bookingDriver.ts` derives this for you (don't pass `selectedPaymentOption` to `book()`). |
76
- | Pass `contactDetails` to `createBooking` | Pass **`formSubmission`**, keyed by each field's **`target`** (default booking form: snake_case `first_name`/`last_name`/`email`/`phone`). `contactDetails` is what Wix derives back onto the response. |
77
- | Hardcode the booking-form fields | Render the form **schema-driven**: read `service.form._id`'s fields via `@wix/forms`, render by `componentType`, key values by `target` (same renderer as `../astro/forms/CONTACT_FORM.md`). |
78
- | Render every form field as a text input (default unknown types to `TEXT_INPUT`) | Render **only** fields with a recognized string `componentType` (`TEXT_INPUT`/`PHONE_INPUT`/`DROPDOWN`). **Skip complex, object-valued fields** (e.g. the default booking form's multi-line `ADDRESS`) — sending a string for them fails `createBooking` with **"must be object"**. Only `first_name`/`last_name`/`email` are enforced, so skipping optional complex fields is safe. |
79
- | Call `queryServices` without an `appId` filter | Always include `appId` (`13d21c63-…`) in the filter. List: `queryServices({ query:{ filter:{ appId }, paging }, conditionalFields:["STAFF_MEMBER_DETAILS"] }).find()`. Single: the `.eq("mainSlug.name", slug).eq("appId", …).limit(1).find()` builder chain. |
80
- | Build `createClient({ auth: OAuthStrategy({ clientId: import.meta.env.* }) })` in `.astro` SSR | The `*_WIX_CLIENT_ID` env var is client-only → `undefined` at server render → 500. SSR reads use the ambient `@wix/essentials`: `auth.elevate(services.queryServices)(...)`. |
81
- | Build an `OAuthStrategy` client inside an astro browser island | Astro islands call the `@wix` modules **ambiently** (the `@wix/astro` visitor client, like the ecom `CartView`) — no `createClient`. (Own/static builds DO use `OAuthStrategy` — `../custom/bookings/WIRING.md`.) |
82
- | Pass UTC ISO strings to `listAvailabilityTimeSlots` | Use **local** date strings `YYYY-MM-DDThh:mm:ss` (no `Z`) + a separate `timeZone`. |
83
- | `availability.queryAvailability` / `import { availability }` | APPOINTMENT → `availabilityTimeSlots.listAvailabilityTimeSlots({ serviceId: <string> })`; CLASS → `eventTimeSlots.listEventTimeSlots({ serviceIds: [<string>] })`. The `availability` namespace does not exist. |
84
- | Read slot time from `timeSlot.slot.startDate` | Slot fields are at the **top level**: `localStartDate`, `localEndDate`, `scheduleId` (APPOINTMENT). CLASS slots carry `eventInfo.eventId` and have **no** `scheduleId`. |
85
- | Dump every slot in one flat, time-only grid | **Group slots by day** — a flat time-only grid hides which day a slot is on. The calendar shape (week / month / N-day) is your choice; the example uses a week strip → the picked day's times. |
86
- | Read the staff id from `staffMember._id` / `.resourceId` on `staffMemberDetails.staffMembers` | The field is **`staffMemberId`** (on `service.staffMemberDetails.staffMembers[]`) — despite the name it IS the resource GUID (matches the service's `staffMemberIds`). Filter availability: APPOINTMENT `resourceTypes:[{ resourceTypeId: STAFF_MEMBER_RESOURCE_TYPE_ID, resourceIds:[staffMemberId] }]`; CLASS `eventFilter:{ "resources.id": { $hasSome:[staffMemberId] } }`. Record the choice as `slot.resource = { _id: staffMemberId, name }`; leave it unset for "any staff" (ANY_RESOURCE fallback). Show the picker only when >1 staff. |
87
- | Always show the location selector / staff picker / category bar | **Auto-skip** each when there's nothing to choose: location count ≤1 (`businessLocations.length + custom?.exists + customer?.exists`), staff ≤1, categories ≤1. Single-location single-staff sites see the simple flow. |
88
- | Filter the catalog by a synthetic location id, or hardcode the location filter | Real business id → `filter["locations.business.id"] = { $hasSome:[id] }`; synthetic `"custom"`/`"customer"` → `filter["locations.type"] = { $hasSome:["CUSTOM"|"CUSTOMER"] }`. Carry the choice to the detail page so availability is scoped too. |
89
- | Call `listAvailabilityTimeSlots` **without** a `locations` filter on a multi-location service | It returns **one slot per location** per time → every time appears **N×** (duplicated rows). **Always scope availability to one business location** (`locations: [{ _id, locationType:"BUSINESS" }]`; CLASS: `eventFilter:{ "location.id":[id] }`). Build the calendar's location list from **`queryLocations()`** (the site's real business locations) intersected with the service's location ids — NOT from `service.locations` alone (its entries can carry an id the availability engine doesn't recognize → scoping to it returns 0 slots even though the service has availability). Default to the carried/first, picker when >1; no business locations → unscoped. Staff does **not** cause duplicates — one slot carries many `availableResources`; only location multiplies rows. |
90
- | Let a `queryCategories` failure break the catalog | Categories are **non-fatal** — wrap in try/catch and render the catalog without the bar. Category filter: `filter["category.id"] = { $eq: categoryId }`; a service's category is `service.category._id`. |
91
- | Read service slug from `service.slug` / name from `service.info.name` | V2 is flat: slug `service.mainSlug.name` (fallback `supportedSlugs[0].name`), `service.name`, `service.description`, `service.tagLine`; duration `service.schedule.availabilityConstraints.sessionDurations[0]`; price `service.payment.fixed.price.value` (string); media `service.media.mainMedia.image.url`. |
92
- | Use `service.id` / `result.booking.id` | Entity ids are `_id` (underscore): `service._id`, `booking._id`. |
93
- | Mount the calendar/form without `client:only="react"` | Availability + booking are timezone/session-specific — always `client:only="react"`. SSR only the read pages (catalog/detail) for SEO. |
94
- | Omit try/catch on the booking | `createBooking` can reject (e.g. a slot taken between fetch and submit, or strict phone validation). Catch and surface a friendly message; don't crash. |
95
- | Ship a payment/deposit breakdown, multi-service stacking, waitlist, or on-site manage/cancel | Out of scope. **Waitlist and manage/cancel have no headless SoT** (the components + vibe plugin expose only display-only policy flags — no join/cancel logic) — do not invent them on the REST/anonymous-token layer. Post-booking self-service is handled by the Wix-hosted flow / member area. |