@wix/agent-skills 1.20.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-headless-fast/SKILL.md +200 -34
  3. package/skills/wix-headless-fast/entry/skill.md +10 -2
  4. package/skills/wix-headless-fast/install/attach.mjs +253 -0
  5. package/skills/wix-headless-fast/install/deploy.mjs +109 -9
  6. package/skills/wix-headless-fast/install/fast-path.mjs +29 -34
  7. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +224 -60
  8. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +2 -3
  9. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +2 -3
  10. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +24 -116
  11. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +16 -64
  12. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +137 -0
  13. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +78 -0
  14. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +117 -0
  15. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +13 -60
  16. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +47 -0
  17. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +10 -28
  18. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +2 -4
  19. package/skills/wix-headless-fast/references/blog/rest/posts.ts +42 -0
  20. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +62 -0
  21. package/skills/wix-headless-fast/references/blog/seed/SEED.md +9 -0
  22. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +179 -33
  23. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +2 -1
  24. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +26 -132
  25. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +18 -49
  26. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +218 -0
  27. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +169 -0
  28. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +57 -142
  29. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +92 -0
  30. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +90 -0
  31. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +22 -61
  32. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +3 -1
  33. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +113 -0
  34. package/skills/wix-headless-fast/references/bookings/rest/services.ts +55 -0
  35. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +10 -0
  36. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +236 -62
  37. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +19 -52
  38. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +16 -36
  39. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +158 -0
  40. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +93 -0
  41. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +177 -0
  42. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +13 -41
  43. package/skills/wix-headless-fast/references/cms/rest/items.ts +125 -0
  44. package/skills/wix-headless-fast/references/cms/seed/SEED.md +9 -0
  45. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +239 -83
  46. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +1 -1
  47. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +7 -5
  48. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +2 -2
  49. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +28 -110
  50. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +19 -54
  51. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +130 -0
  52. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +97 -0
  53. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +13 -94
  54. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +113 -0
  55. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +156 -0
  56. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +38 -69
  57. package/skills/wix-headless-fast/references/events/rest/events.ts +57 -0
  58. package/skills/wix-headless-fast/references/events/rest/registration.ts +83 -0
  59. package/skills/wix-headless-fast/references/events/seed/SEED.md +9 -0
  60. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +214 -26
  61. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +35 -267
  62. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +332 -0
  63. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +238 -0
  64. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +28 -243
  65. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +216 -0
  66. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +32 -204
  67. package/skills/wix-headless-fast/references/forms/rest/forms.ts +34 -0
  68. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +56 -0
  69. package/skills/wix-headless-fast/references/forms/seed/SEED.md +8 -0
  70. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +15 -8
  71. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +314 -63
  72. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +1 -1
  73. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +105 -0
  74. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +36 -65
  75. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +1 -1
  76. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +43 -0
  77. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +11 -32
  78. package/skills/wix-headless-fast/references/members/rest/auth.ts +215 -0
  79. package/skills/wix-headless-fast/references/members/rest/members.ts +26 -0
  80. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +238 -59
  81. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +2 -2
  82. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +2 -2
  83. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +35 -0
  84. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +8 -38
  85. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +23 -50
  86. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +16 -34
  87. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +22 -49
  88. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +82 -0
  89. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +58 -0
  90. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +177 -0
  91. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +31 -118
  92. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +81 -0
  93. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +75 -0
  94. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +8 -0
  95. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +212 -51
  96. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +9 -20
  97. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +7 -32
  98. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +41 -0
  99. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +12 -33
  100. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +17 -34
  101. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +54 -0
  102. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +106 -0
  103. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +64 -0
  104. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +7 -55
  105. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +43 -0
  106. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +11 -34
  107. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +31 -0
  108. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +20 -0
  109. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +8 -0
  110. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +240 -47
  111. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +2 -2
  112. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +2 -2
  113. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +14 -35
  114. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +28 -171
  115. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +155 -0
  116. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +89 -0
  117. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +23 -117
  118. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +124 -0
  119. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +45 -114
  120. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +193 -0
  121. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +94 -0
  122. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +15 -87
  123. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +60 -0
  124. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +169 -0
  125. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +68 -0
  126. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +8 -0
  127. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +23 -0
  128. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +45 -4
  129. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +13 -0
  130. package/skills/wix-headless-fast/references/shared/rest/client.ts +155 -0
  131. package/skills/wix-headless-fast/references/shared/rest/config.ts +3 -0
  132. package/skills/wix-headless-fast/references/shared/rest/media.ts +65 -0
  133. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +182 -63
  134. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +95 -0
  135. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +29 -58
  136. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +29 -163
  137. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +26 -300
  138. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +121 -0
  139. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +49 -162
  140. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +309 -0
  141. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +47 -370
  142. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +147 -0
  143. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +289 -0
  144. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +132 -0
  145. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +123 -0
  146. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +25 -9
  147. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +6 -35
  148. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  149. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +0 -40
  150. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +3 -0
  151. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.cjs +6 -0
  152. package/skills/wix-headless-fast/install/pin-agents-md.mjs +0 -57
@@ -10,28 +10,40 @@ ordering or reservation logic; you never skip designing.
10
10
 
11
11
  ## The file map (deployed into `src/`)
12
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.
13
+ **On Astro and React the shipped files are tested and work as they are** — this table and the
14
+ contracts below are everything you need to use them, so don't spend the run reading their source;
15
+ wire them and build your surfaces. Reading them is the right move when something is off (a runtime
16
+ error, a field this playbook doesn't cover) or when the brief wants a behaviour they don't offer —
17
+ then read the file that owns it and change or extend it. On `lib`, `static`, and a port the
18
+ components don't deploy at all, and each wiring section below opens with the files to read before
19
+ writing their equivalents. Files you edit: `SiteLayout.astro`, `styles/global.css`, and the two
20
+ pages' island imports. Files you **create**: your menu, cart-chrome, and reservation components,
21
+ plus your home page.
16
22
 
17
23
  | file | what it is |
18
24
  |---|---|
19
- | `wix/config.ts` · `wix/sdk.ts` · `wix/media.ts` · `wix/money.ts` | shared auth seam + helpers (deploy configures; nothing to set) |
25
+ | `wix/config.ts` · `wix/sdk.ts` | shared auth seam (deploy configures it — nothing to set by hand) |
26
+ | `wix/media.ts` · `wix/money.ts` | `imgAttrs(url, sizes)` — every `<img>` attribute for a DTO image (`src`, `srcSet`, `sizes`, lazy): `<img {...imgAttrs(item.imageUrl, "6rem")} alt={item.name} />`; `imgSrc()` / `imgSrcSet()` / `formatMoney()` underneath, already used by everything shipped |
20
27
  | `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) |
28
+ | `wix/restaurants/menu.ts` | `fetchMenus` — the whole display-ordered menu tree, one call; the transport only — the id-array stitching and item mapping are in `menu-core.ts` beside it (shared with the REST layer) |
29
+ | `wix/restaurants/ordering.ts` · `order-store.ts` | dish add-to-cart (Orders-app `catalogReference`) + eCom Cart V2 + the hosted checkout, and the shared cart state (module store — spans Astro islands); the request shapes and refusal checks are in `ordering-core.ts` |
30
+ | `wix/restaurants/reservations.ts` | locations, AVAILABLE slots, `holdReservation`, `completeReservation` — the exact hold → reserve sequence; the mappers and the reservee body are in `reservations-core.ts` |
31
+ | `wix/restaurants/menu-store.ts` · `reservation-store.ts` | the menu-browsing and reservation state machines, framework-free (`createMenuStore()`, `createReservationStore()` — `getState`/`subscribe` + actions, one instance per surface); the hooks below bind them to React, every other stack uses them directly |
32
+ | `hooks/restaurants/useMenus.ts` | React binding of `menu-store.ts`: menu browsing + menu switching — contract below |
33
+ | `hooks/restaurants/useOrderCart.ts` | React binding of `order-store.ts`: order-cart state + actions — contract below |
34
+ | `hooks/restaurants/useReservation.ts` | React binding of `reservation-store.ts`: the whole reservation state machine — contract below |
35
+ | `components/restaurants/MenuView.tsx` (+ `MenuItemCard`) · `OrderCartButton.tsx` · `OrderCartDrawer.tsx` · `ReservationView.tsx` | **reference implementations** — tested, plain, on the tokens; the layout mounts the cart chrome as shipped, and you replace all four with your own designs (new file names) |
36
+ | `styles/global.css` | **the design system**: Tailwind v4 + the `@theme` token block (colors, radii, fonts — shared across verticals). Everything, shipped and yours, styles from these tokens |
37
+
38
+ The same data layer ships a second time as REST in `references/restaurants/rest/` (`menu.ts`,
39
+ `ordering.ts`, `reservations.ts` — the same exports over `fetch`, importing the same `*-core.ts`);
40
+ `deploy.mjs --stack static` composes it with the stores into `js/wix/` (wiring below).
29
41
 
30
42
  Astro stack additionally gets:
31
43
 
32
44
  | file | what it is |
33
45
  |---|---|
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 |
46
+ | `layouts/SiteLayout.astro` | site chrome — **yours to brand** (keep the `seo-tags` slot, the 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
47
  | `pages/menu.astro` | SSR menu — **keep the frontmatter**, swap the island import to YOUR component |
36
48
  | `pages/reservations.astro` | reservations — the island stays `client:only="react"` (availability is timezone-specific); swap the import to YOUR component |
37
49
 
@@ -51,9 +63,30 @@ Astro stack additionally gets:
51
63
  your cards; `item.featured` marks highlights), hours/location story, reserve CTA.
52
64
 
53
65
  Plus the **theme** (`@theme` block, one edit) and the **chrome** (`SiteLayout`, one pass).
54
- Style everything with Tailwind utilities on the tokens.
55
66
 
56
- ### The contracts your components consume
67
+ ### What a complete restaurant site shows (recommended defaults)
68
+
69
+ Defaults for a brief that says nothing about them; the prompt wins when it asks for something
70
+ else. Look at the seeded menu before designing (how many menus, sections, photos, variants).
71
+
72
+ - **Menu:** dish names in view-source (the page fetches server-side and passes `initialMenus`);
73
+ sections in the menu's own order; a dish card shows name, description, price (or its
74
+ variants, or "Market price"), labels, and the add control; skeletons while `menus === null`,
75
+ an honest empty state for `[]`.
76
+ - **Add control:** three states from the data — "Add to order", "Sold out" (`!inStock`),
77
+ "Ordering unavailable" (`ordering === false`); a market-priced dish has no control. Adding
78
+ opens the cart drawer on its own; the header badge is the live `itemCount`.
79
+ - **Cart:** lines with quantity stepper and remove, `subtotal` as given, checkout as a button in
80
+ the drawer; the order survives a reload (same visitor token) — nothing to wire.
81
+ - **Reservations:** only AVAILABLE times offered; hold → details form → confirm; `RESERVED`
82
+ reads as confirmed, `REQUESTED` as "pending the restaurant's approval"; the toggle-off and
83
+ not-set-up cases read as "call us to book", never as a broken form.
84
+ - **Overlays you build** (cart drawer, mobile nav): mount at the document root, lock background
85
+ scroll, close on Escape, return focus on close — as the shipped `OrderCartDrawer` does.
86
+ - **Copy:** nothing the restaurant didn't supply — no invented hours, reviews, or delivery
87
+ promises; no Wix IDs or technical words in visible text.
88
+
89
+ ### The contracts your components consume (tested and work as they are; read the source when something is off or the brief wants more)
57
90
 
58
91
  ```ts
59
92
  // MenuData → sections → items, all display-ordered:
@@ -63,9 +96,9 @@ Style everything with Tailwind utilities on the tokens.
63
96
  // modifierGroups: [{ id, name, required, minSelections, maxSelections,
64
97
  // modifiers: [{ id, name, preSelected, additionalCharge, inStock }] }],
65
98
  // 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).
99
+ // MENU prices carry NO currency symbol unless the platform formatted them — render as given;
100
+ // if plain decimals, prefix the brand's currency yourself. Order-cart prices ARE formatted.
101
+ // Modifier groups are DISPLAY-ONLY (selections aren't sent on the cart line).
69
102
 
70
103
  // useMenus({ initialMenus? }) →
71
104
  // { menus: MenuData[]|null /* null = loading → skeletons */,
@@ -81,6 +114,8 @@ Style everything with Tailwind utilities on the tokens.
81
114
  // openCart(), closeCart(), refresh() }
82
115
  // OrderLine = { lineItemId, itemName, quantity, unitPrice, linePrice, imageUrl,
83
116
  // descriptionLines, status /* not "IN_STOCK" → can't check out */ }
117
+ // addToOrder rejects on refusal (no ordering operation, a sold-out dish) AND records .error,
118
+ // opening the drawer on success — render .error in your cart surface and beside the add control.
84
119
 
85
120
  // useReservation() →
86
121
  // { locations: [{ id, partySizeMin, partySizeMax, approvalMode, onlineReservationsEnabled }]|null,
@@ -92,8 +127,76 @@ Style everything with Tailwind utilities on the tokens.
92
127
  // canConfirm, confirm(), // gate the CTA on canConfirm
93
128
  // confirmed: { reservationId, status: "RESERVED"|"REQUESTED" }|null,
94
129
  // reset(), loading, error }
130
+ // ReservationSlot = { startIso, label /* "7:00 PM" */, dayKey, durationMinutes, manualApproval }.
131
+ // The hold and reserve calls are premium-gated: on a non-premium site they fail with
132
+ // "site must be premium" in .error — render it, don't retry.
133
+ ```
134
+
135
+ ### The islands you create — skeletons
136
+
137
+ The class names in the shipped components are the Astro/React spelling of layout rules that hold
138
+ on every stack; on a stack where they don't deploy, keep the rule and write it in your own CSS.
139
+ Hooks first, branches after (an early return above a hook changes hook order and React throws).
140
+ The menu island renders on the server too (`client:load`); nothing in a render path may throw.
141
+
142
+ ```tsx
143
+ // src/components/restaurants/YourMenu.tsx — YOU build it; pages/menu.astro mounts it with initialMenus.
144
+ import { useMenus } from "../../hooks/restaurants/useMenus";
145
+ import { useOrderCart } from "../../hooks/restaurants/useOrderCart";
146
+ import { imgAttrs } from "../../wix/media";
147
+ import type { MenuData } from "../../wix/restaurants/types";
148
+
149
+ export default function YourMenu({ initialMenus }: { initialMenus?: MenuData[] }) {
150
+ const { menus, activeMenuId, setActiveMenuId, activeMenu, error } = useMenus({ initialMenus });
151
+ const { addToOrder, ordering, busy } = useOrderCart();
152
+ // …you implement the render:
153
+ // • menus === null → skeletons; [] → your empty state (error when set)
154
+ // • menu tabs when menus.length > 1 (setActiveMenuId); a section nav when activeMenu.sections.length > 1
155
+ // • per section, YOUR dish card: <img {...imgAttrs(item.imageUrl, "6rem")} alt={item.name} /> when
156
+ // item.imageUrl, name, description, item.marketPrice ? "Market price" : item.price ?? variants,
157
+ // labels, modifier groups as text (display-only)
158
+ // • the add control calls addToOrder(item.id, { menuId: activeMenu.id, sectionId: section.id }) —
159
+ // the ids of the menu and section the card is rendered under, never looked up again; disabled
160
+ // when !item.inStock ("Sold out"), ordering === false ("Ordering unavailable"), or busy; hidden
161
+ // for item.marketPrice; the rejection message rendered beside it
162
+ }
163
+ ```
164
+
165
+ ```tsx
166
+ // src/components/restaurants/YourReservations.tsx — YOU build it; pages/reservations.astro mounts it client:only.
167
+ import { useReservation } from "../../hooks/restaurants/useReservation";
168
+
169
+ export default function YourReservations() {
170
+ const r = useReservation(); // full contract above — the flow lives HERE
171
+ // …you implement the render, in this order:
172
+ // r.locations === null → loading; [] or !r.location → "call us to book";
173
+ // !r.location.onlineReservationsEnabled → "online reservations aren't open yet";
174
+ // r.confirmed → RESERVED as confirmed, REQUESTED as pending approval, r.reset() to start over;
175
+ // else: guests (bounded by partySizeMin/Max), date, time → r.findSlots(); r.slots as pills →
176
+ // r.holdSlot(slot); r.held → the details form (firstName + phone required) and the confirm
177
+ // button gated by r.canConfirm; r.error inline; a location picker only when locations.length > 1
178
+ }
95
179
  ```
96
180
 
181
+ ### The reference files for stacks where the components don't deploy
182
+
183
+ On `lib`, `static`, and a port, nothing under `components/` or `hooks/` arrives. The state
184
+ machines behind the hooks do arrive — `wix/restaurants/menu-store.ts`, `reservation-store.ts`,
185
+ `order-store.ts` — so you never rewrite them: create a store per surface, `subscribe`, render from
186
+ `getState()`, call its actions. Their `*State` interfaces are the render contract; read those.
187
+ What you write is the rendering — dish card, menu, cart chrome, reservation form — and for that
188
+ read these first; they are tested code for exactly that behaviour:
189
+
190
+ 1. `components/restaurants/MenuView.tsx` — the menu tabs / section nav / dish card, and the
191
+ load-bearing wiring: each card threads its `menuId` + `sectionId` from the render context into
192
+ `addToOrder`; the add control's three states; the rejection message beside it.
193
+ 2. `components/restaurants/OrderCartDrawer.tsx` — the cart overlay as working code: lines with
194
+ stepper and remove, `status !== "IN_STOCK"` flagged, subtotal, checkout, `error` rendered.
195
+ 3. `components/restaurants/ReservationView.tsx` — the state ladder in order: loading → not set up →
196
+ toggle off → confirmed → query → slots → hold → details form; the confirm gate.
197
+
198
+ All under `references/restaurants/app/`.
199
+
97
200
  ### Wiring — Astro (default)
98
201
 
99
202
  1. Set the `@theme` tokens (one edit); brand `SiteLayout.astro` (one pass — merge into the
@@ -105,61 +208,151 @@ Style everything with Tailwind utilities on the tokens.
105
208
  multiple Writes per message.
106
209
  3. Write `pages/index.astro` (home) — it exists from the scaffold; Read it before overwriting.
107
210
 
211
+ ### Wiring — another JS framework (`--stack lib`: Vue, Svelte, Solid, plain Vite)
212
+
213
+ Read the reference files listed above before writing any surface.
214
+
215
+ `deploy.mjs restaurants --stack lib` put the data layer in `src/wix/` and nothing else: `sdk.ts`
216
+ (the visitor client, configured with the public client id), `media.ts`, `money.ts`, and
217
+ `wix/restaurants/` — `menu.ts`, `ordering.ts`, `reservations.ts`, `types.ts`, the `*-core.ts`
218
+ rules, and the three stores `menu-store.ts`, `order-store.ts`, `reservation-store.ts`. None of it
219
+ is React. The hooks and components don't ship on this stack; the stores replace the hooks, and you
220
+ write the components in your framework to the contracts on this page:
221
+
222
+ - bind the stores with your framework's external-store primitive (Vue: `shallowRef` updated in
223
+ `subscribe`; Svelte: `readable(store.getState(), (set) => store.subscribe(() => set(store.getState())))`;
224
+ Solid: a signal set in `subscribe`). `createMenuStore({ initialMenus? })` per menu surface
225
+ (`start()` when mounted, `stop()` when unmounted), `createReservationStore()` per reservation
226
+ surface, the order store as-is (module-level: `subscribeOrderCart`/`getOrderCartState`,
227
+ `addOrderLine`, `updateOrderLineQuantity`, `removeLineFromOrder`, `goToOrderCheckout`,
228
+ `setOrderCartOpen`). State in, actions out — exactly the hooks' contracts above;
229
+ - your dish card, cart drawer, and reservation form to the recommended defaults above — the
230
+ shipped `MenuView.tsx`, `OrderCartDrawer.tsx`, `ReservationView.tsx` are readable as behaviour
231
+ specs.
232
+
233
+ Routes `/menu`, `/reservations`; dev server on 4321; a static build goes through
234
+ `npx @wix/cli@latest release` with `site.outputDirectory` pointing at the build folder, an SSR
235
+ build is hosted by you.
236
+
237
+ ### Wiring — static site (`--stack static`, no bundler)
238
+
239
+ Read the reference files listed above before writing any surface.
240
+
241
+ `deploy.mjs restaurants --stack static --out site` put the REST layer in `site/js/wix/` (browser
242
+ ESM, the `.ts` beside each `.js` for reading). Everything the visitor loads lives under `site/` —
243
+ pages, styles, `js/` — and `wix.config.json`'s `site.outputDirectory` is `"./site"`; the project
244
+ root (config, plan, seed output) is never the upload. Same function names and DTOs as the table
245
+ above, so the contracts on this page hold unchanged: `fetchMenus` from `./js/wix/menu.js`;
246
+ `resolveOperationId`, `fetchFulfillmentMethods`, `fetchOrderCart`, `addToOrder`,
247
+ `updateOrderQuantity`, `removeOrderLine`, `orderCheckoutUrl` from `./js/wix/ordering.js`;
248
+ `fetchReservationLocations`, `fetchReservationSlots`, `holdReservation`, `completeReservation`
249
+ from `./js/wix/reservations.js`. The state machines ship too: `createMenuStore` from
250
+ `./js/wix/menu-store.js` (`start()` once the page is up; `initialMenus` when you already have
251
+ them), `./js/wix/order-store.js` (the cart — `subscribeOrderCart`/`getOrderCartState`,
252
+ `addOrderLine`, `updateOrderLineQuantity`, `removeLineFromOrder`, `goToOrderCheckout`,
253
+ `setOrderCartOpen`), and `createReservationStore` from `./js/wix/reservation-store.js` (the whole
254
+ reservation flow). No components ship — you write the rendering in plain JS: one render function
255
+ per surface that reads `getState()`, called from `subscribe`, with the surface's controls calling
256
+ the store's actions. The drawer opens after every add on its own; overlays follow the
257
+ OrderCartDrawer contract (root-level, scroll lock, Escape, focus back). Pages are `menu.html`
258
+ and `reservations.html` (a menu switch is local state, or `menu.html?menu=<slug>` read from the
259
+ query string). Wix static hosting serves files, not directories — name the file and link to it.
260
+ There are no item pages here: set `document.title` and the meta description per page yourself,
261
+ from the menu's `name` once it loads. The visitor token persists in `localStorage` on its own;
262
+ never mint per page. `npx @wix/cli@latest release` uploads `site/`.
263
+
264
+ ### Wiring — server-rendered, another language (Flask, Laravel, Rails, …)
265
+
266
+ Read the reference files listed above before writing any surface.
267
+
268
+ Run `deploy.mjs restaurants --stack static` in the project folder anyway: `js/wix/` is both the
269
+ browser-side code and the readable spec. Then split by where the call runs. **The menu on the
270
+ server:** port `js/wix/menu.ts` and `menu-core.ts` to your language — seven GETs with literal
271
+ paths and query params (arrays repeat the key: `?variantIds=a&variantIds=b`), then the id-array
272
+ stitching from the core — returning the same `MenuData` tree as dicts, one anonymous visitor token
273
+ per process for these public reads (mint and refresh per `client.ts`) — and render the menu and
274
+ the home page's featured dishes in your templates, so dish names are in the HTML. **Ordering and
275
+ reservations in the browser:** the cart button and drawer on `./js/wix/order-store.js`, each dish
276
+ card's add control calling `addOrderLine(itemId, { menuId, sectionId })` with the ids the template
277
+ rendered it under (data attributes), the reservation form on `./js/wix/reservation-store.js` —
278
+ exactly as the static wiring above; the browser owns the visitor's token, so the server never
279
+ handles per-visitor tokens. Routes stay `/menu`, `/reservations`. Add your public https origin to
280
+ the OAuth app's allowed domains before checkout can return.
281
+
282
+ **Pre-rendered (Frozen-Flask, Pelican, any static-site generator) → Wix-hosted.** Same port for
283
+ the menu read, run at build time with one anonymous token; the generator emits the menu page(s)
284
+ and the home page. Run `deploy.mjs restaurants --stack static --out <build dir>` so `js/wix/` is
285
+ inside the output the pages import from, point `site.outputDirectory` at that folder,
286
+ `wix release`. Pages sit at different depths: give the templates one base path to `js/wix/` (a
287
+ template variable, or root-relative `/js/wix/…`), never a relative `./js/wix/` — it breaks one
288
+ level down. The frozen menu is the first paint; the add controls, cart, and reservation flow run
289
+ client-side on it from the same modules, so the contracts above apply. Close with the live URL,
290
+ the rebuild + release command, and one line for the owner: dashboard edits to the menu reach the
291
+ site when that command runs; ordering and reservations are live regardless.
292
+
108
293
  ### Wiring — React SPA (Vite etc.)
109
294
 
110
295
  Import `./styles/global.css` once at the app entry (needs `@tailwindcss/vite` in the vite
111
296
  plugins — deploy added the dep). Routes: `/menu` → your menu surface (`useMenus()` fetches
112
297
  client-side when no `initialMenus`); `/reservations` → your reservation surface. Mount your
113
- order button in the header and your drawer once.
298
+ order button in the header and your drawer once. Deploy wrote the public client id into
299
+ `wix/config.ts`; nothing else to configure.
114
300
 
115
301
  ## Hard rules
116
302
 
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.
303
+ - **Data and ordering logic only through the shipped exports** — `useOrderCart`/`addToOrder`
304
+ own the restaurant `catalogReference` (the Orders app id + `operationId`/`menuId`/`sectionId`
305
+ — all three, no `variantId`), the line-refusal checks, and the checkout redirect. Never
306
+ re-derive any of it, never hand-build a checkout URL; extend by adding a function in
307
+ `wix/restaurants/` for what they don't cover (API contracts: the `wix-docs` skill).
121
308
  - **Thread `menuId` + `sectionId` from the render context** — each dish is rendered inside a
122
309
  known section of a known menu (the `fetchMenus` tree); pass those ids to `addToOrder`.
123
310
  Never look them up again.
124
311
  - **Modifier groups are display-only** — show them on the dish (diners read them; staff sees
125
312
  choices at the counter), but don't invent a way to send selections: that cart-line shape
126
313
  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).
314
+ - **Reservations only through `useReservation`** (or its store) — AVAILABLE-only slots, the
315
+ hold's `revision`, the firstName+phone requirement, and the RESERVED/REQUESTED split all live
316
+ in the data layer. Gate the CTA on `canConfirm`, surface `error` (holds expire in 10 minutes —
317
+ the store already restarts the flow).
131
318
  - **The confirmed state must reflect REAL success**: render it only from `confirmed`, and
132
319
  render `REQUESTED` as "pending the restaurant's approval", never as confirmed. A visitor
133
320
  returning from the hosted checkout is NOT an order-success signal.
134
321
  - **Honest unavailability**: `ordering === false` → an "ordering unavailable" state on the
135
322
  add button; `onlineReservationsEnabled === false` → a "call us to book" notice (the toggle
136
323
  is premium-gated). Never mock menus, dishes, prices, slots, or availability.
137
- - Theme via the `@theme` tokens; no parallel theme files, no hardcoded palettes.
324
+ - Don't wrap shipped calls in your own API routes — they run client-side by design.
325
+ - **Cart totals come from `cart`** — never summed or hardcoded in the client; fees, tax, and
326
+ delivery resolve on the hosted checkout.
327
+ - **Browsing, ordering and reserving need no login.** They run on the visitor session the
328
+ shipped client already holds; don't add a members/auth flow unless the brief asks for accounts.
329
+ - **Call every hook before any conditional return.** Hooks first, branches after.
330
+ - Where the shipped components deploy (Astro, React): theme via the `@theme` tokens, and your
331
+ markup uses Tailwind utilities on the same tokens — one design system across shipped and written
332
+ code. No parallel theme files, no hardcoded palette values. Where they don't (`lib`, `static`,
333
+ a port): style with whatever your stack does well, on one token set of your own; the rule that
334
+ survives is the token set, not Tailwind.
138
335
 
139
336
  ## Point the user to their dashboard
140
337
 
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.
338
+ Hand the owner these links — `{siteId}` is `siteId` in `wix.config.json` (the deploy JSON prints it as
339
+ `dashboardUrl`); a menu id fills the placeholder from the seed result.
340
+
341
+ | page | `https://manage.wix.com/dashboard/{siteId}/` + |
342
+ |---|---|
343
+ | Menus | `wix-restaurants-menus-new` |
344
+ | Edit a menu | `wix-restaurants-menus-new/menu/{menuId}` |
345
+ | Items | `wix-restaurants-menus-new/items` |
346
+ | Online orders board | `wix-restaurants-orders-new` |
347
+ | Ordering settings (pickup/delivery hours, fees) | `wix-restaurants-orders-new/settings` |
348
+ | Reservations | `wix-table-reservations/table-reservations` |
349
+ | Floor plan | `wix-table-reservations/floor-plan` |
350
+
351
+ Real paid orders need a premium plan + a connected payment method, and holding or completing an online
352
+ reservation is premium-gated — mention both.
146
353
 
147
354
  ## Seeding
148
355
 
149
356
  Per `seed/SEED.md` — plain-data `plan.json` into `seed-restaurants.mjs` from the project
150
357
  root. Seed a menu that exercises the UI (a few sections, an image per dish) and turn on the
151
358
  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.
@@ -5,6 +5,7 @@
5
5
  import { useState } from "react";
6
6
  import { useMenus } from "../../hooks/restaurants/useMenus";
7
7
  import { useOrderCart } from "../../hooks/restaurants/useOrderCart";
8
+ import { imgAttrs } from "../../wix/media";
8
9
  import type { MenuData, MenuItem } from "../../wix/restaurants/types";
9
10
 
10
11
  export interface MenuItemCardProps {
@@ -22,9 +23,8 @@ export function MenuItemCard({ item, menuId, sectionId }: MenuItemCardProps) {
22
23
  <div className="flex gap-4 rounded-lg border border-border p-4">
23
24
  {item.imageUrl && (
24
25
  <img
25
- src={item.imageUrl}
26
+ {...imgAttrs(item.imageUrl, "6rem")}
26
27
  alt={item.name}
27
- loading="lazy"
28
28
  className="h-24 w-24 flex-shrink-0 rounded-md bg-secondary object-cover"
29
29
  />
30
30
  )}
@@ -2,6 +2,7 @@
2
2
  // Wix-hosted checkout. Mount ONCE per page; opens via useOrderCart().openCart(). Correct and
3
3
  // complete; per the skill's model you design your own chrome on useOrderCart.
4
4
  import { useOrderCart } from "../../hooks/restaurants/useOrderCart";
5
+ import { imgAttrs } from "../../wix/media";
5
6
 
6
7
  export default function OrderCartDrawer() {
7
8
  const { cart, open, closeCart, busy, error, updateQuantity, removeLine, checkout } = useOrderCart();
@@ -41,9 +42,8 @@ export default function OrderCartDrawer() {
41
42
  <div className="mb-6 flex gap-4" key={line.lineItemId}>
42
43
  {line.imageUrl ? (
43
44
  <img
44
- src={line.imageUrl}
45
+ {...imgAttrs(line.imageUrl, "4rem")}
45
46
  alt=""
46
- loading="lazy"
47
47
  className="h-16 w-16 flex-shrink-0 rounded-md bg-secondary object-cover"
48
48
  />
49
49
  ) : (
@@ -1,8 +1,9 @@
1
- // Menu browsing. SSR-friendly: pass server-fetched menus as `initialMenus` (Astro
2
- // frontmatter) and no client fetch happens; a SPA passes nothing. Menu switching is
3
- // client-side (the whole tree is fetched once).
4
- import { useEffect, useMemo, useState } from "react";
5
- import { fetchMenus } from "../../wix/restaurants/menu";
1
+ // React binding of the menu store (wix/restaurants/menu-store.ts) — menu browsing and switching
2
+ // live there, framework-free; this hook subscribes to one instance per mounted surface. SSR-friendly:
3
+ // pass server-fetched menus as `initialMenus` (Astro frontmatter) and no client fetch happens; a SPA
4
+ // passes nothing. Astro islands and React SPAs use this; a static page, Vue, or Svelte uses the store.
5
+ import { useEffect, useRef, useSyncExternalStore } from "react";
6
+ import { createMenuStore, type MenuStore } from "../../wix/restaurants/menu-store";
6
7
  import type { MenuData } from "../../wix/restaurants/types";
7
8
 
8
9
  export interface UseMenusOptions {
@@ -21,35 +22,13 @@ export interface UseMenus {
21
22
  }
22
23
 
23
24
  export function useMenus({ initialMenus }: UseMenusOptions = {}): UseMenus {
24
- const [menus, setMenus] = useState<MenuData[] | null>(initialMenus ?? null);
25
- const [activeMenuId, setActiveMenuId] = useState<string | null>(initialMenus?.[0]?.id ?? null);
26
- const [error, setError] = useState<string | null>(null);
27
-
25
+ const ref = useRef<MenuStore | null>(null);
26
+ if (!ref.current) ref.current = createMenuStore({ initialMenus });
27
+ const store = ref.current;
28
28
  useEffect(() => {
29
- let alive = true;
30
- if (!initialMenus) {
31
- fetchMenus()
32
- .then((m) => {
33
- if (!alive) return;
34
- setMenus(m);
35
- setActiveMenuId((id) => id ?? m[0]?.id ?? null);
36
- })
37
- .catch((e) => {
38
- if (!alive) return;
39
- setMenus([]);
40
- setError(e instanceof Error ? e.message : String(e));
41
- });
42
- }
43
- return () => {
44
- alive = false;
45
- };
46
- // eslint-disable-next-line react-hooks/exhaustive-deps
47
- }, []);
48
-
49
- const activeMenu = useMemo(() => {
50
- if (!menus) return null;
51
- return menus.find((m) => m.id === activeMenuId) ?? menus[0] ?? null;
52
- }, [menus, activeMenuId]);
53
-
54
- return { menus, activeMenuId: activeMenu?.id ?? null, setActiveMenuId, activeMenu, error };
29
+ store.start();
30
+ return () => store.stop();
31
+ }, [store]);
32
+ const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
33
+ return { ...state, setActiveMenuId: store.setActiveMenuId };
55
34
  }