@wix/agent-skills 1.14.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.
- package/README.md +4 -1
- package/package.json +1 -1
- package/skills/README.md +23 -0
- package/skills/wix-app/SKILL.md +10 -2
- package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
- package/skills/wix-app/references/CODE_QUALITY.md +1 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
- package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
- package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
- package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
- package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
- package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
- package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
- package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
- package/skills/wix-auth/SKILL.md +12 -0
- package/skills/wix-auth/references/device-flow.md +140 -0
- package/skills/wix-docs/SKILL.md +188 -0
- package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
- package/skills/wix-docs/references/EXTRACTING.md +120 -0
- package/skills/wix-headless/SKILL.md +84 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +78 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +84 -0
- package/skills/wix-headless/references/DISCOVERY.md +34 -56
- package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
- package/skills/wix-headless/references/FEEDBACK.md +118 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
- package/skills/wix-headless/references/SEED.md +44 -188
- package/skills/wix-headless/references/SETUP.md +32 -103
- package/skills/wix-headless/references/astro.md +98 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
- package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
- package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
- package/skills/wix-headless/references/managed/CONNECT.md +74 -0
- package/skills/wix-headless/references/managed/CREATE.md +130 -0
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
- package/skills/wix-headless/references/non-astro.md +59 -0
- package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
- package/skills/wix-manage/SKILL.md +24 -1
- package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
- package/skills/wix-vibe-headless/SKILL.md +136 -0
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
- package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
- package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
- package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
- package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
- package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
- package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
- package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
- package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
- package/skills/wix-headless/references/BUILD-astro.md +0 -253
- package/skills/wix-headless/references/BUILD-own-build.md +0 -167
- package/skills/wix-headless/references/BUILD.md +0 -105
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
- package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
- package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
- package/skills/wix-headless/references/PLAN-connect.md +0 -19
- package/skills/wix-headless/references/PLAN-create.md +0 -17
- package/skills/wix-headless/references/PLAN.md +0 -92
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
- package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
- package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
- package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
- package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
- package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
- package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
- package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
- package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
- package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
- package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
- package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
- package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
- package/skills/wix-headless/references/astro/templates/global.css +0 -288
- package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
- package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
- package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
- package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
- package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
- package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
- package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
- package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
- package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
- package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
- package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
- package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
- package/skills/wix-headless/references/bookings/FLOW.md +0 -246
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
- package/skills/wix-headless/references/commands/known-apps.json +0 -6
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
- package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
- package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
- package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
- package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
- package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
- package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
- package/skills/wix-headless/references/seed-recipes.md +0 -49
- package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
- package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
- package/skills/wix-headless/references/shared/STYLING.md +0 -140
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
- package/skills/wix-headless/references/verticals/_schema.json +0 -74
- package/skills/wix-headless/references/verticals/_schema.md +0 -95
- package/skills/wix-headless/references/verticals/blog.md +0 -31
- package/skills/wix-headless/references/verticals/bookings.md +0 -41
- package/skills/wix-headless/references/verticals/cms.md +0 -30
- package/skills/wix-headless/references/verticals/ecom.md +0 -25
- package/skills/wix-headless/references/verticals/forms.md +0 -26
- package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
- package/skills/wix-headless/references/verticals/stores.md +0 -33
- package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
- package/skills/wix-headless/scripts/compose.mjs +0 -520
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
- package/skills/wix-headless/scripts/flatten.sh +0 -61
- package/skills/wix-headless/scripts/generate-images.mjs +0 -242
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
- package/skills/wix-headless/scripts/scaffold.sh +0 -139
- package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
- package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
- package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
- package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
- package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
|
|
2
|
+
# Wix Restaurants Skill
|
|
3
|
+
|
|
4
|
+
> **Source files (in this skill):** the shared transport `references/shared/wix-client.js` and the helper file(s) you need from `references/restaurants/`. All helpers import from `"./wix-client.js"`, so copy them into the same folder (e.g. `src/rest/`).
|
|
5
|
+
>
|
|
6
|
+
> | Need | Copy |
|
|
7
|
+
> |---|---|
|
|
8
|
+
> | Menu display (always) | `wix-restaurants-menu.js` |
|
|
9
|
+
> | Online ordering (cart + checkout) | `wix-restaurants-ordering.js` |
|
|
10
|
+
> | Table reservations | `wix-restaurants-reservations.js` |
|
|
11
|
+
|
|
12
|
+
Builds a real, client-only Wix restaurant experience. The browser talks to Wix directly over a
|
|
13
|
+
public `WIX_CLIENT_ID`. Never mock the menu; never hand-build `/checkout` or reservation URLs —
|
|
14
|
+
always go through the official cart + redirect-session and the reservations hold/reserve flow.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
- User wants a Wix restaurant site, an online food-ordering page, or a table-reservation page.
|
|
18
|
+
- User asks to "connect Wix Restaurants" or replace placeholder menu/ordering/booking UI with live data.
|
|
19
|
+
- Adding a menu, cart + checkout, or reservations over an existing Wix Restaurants setup.
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
1. A Wix site with the **Wix Restaurants Menus** app installed and **menu content already added**
|
|
23
|
+
(this skill is read-only over the menu — it does NOT create menus/items).
|
|
24
|
+
2. For **online ordering**: at least one online-ordering **Operation** configured (Wix Restaurants
|
|
25
|
+
Orders). For **reservations**: the **Table Reservations** app installed with at least one location
|
|
26
|
+
and online reservations enabled. If a flow's backing app/config isn't set up, that flow returns
|
|
27
|
+
empty — flag it and continue; don't fabricate data.
|
|
28
|
+
3. The site's public headless **`WIX_CLIENT_ID`**, provided in the handoff prompt (see the router `SKILL.md`).
|
|
29
|
+
Paste it into `src/rest/wix-client.js` in place of the placeholder. It is a buyer-facing
|
|
30
|
+
credential (it only mints anonymous visitor tokens), **not** a secret — hardcoding/committing
|
|
31
|
+
it is fine.
|
|
32
|
+
4. The deployed app domain must be allow-listed on the OAuth client for Wix-hosted checkout to
|
|
33
|
+
return. This is a **separate Wix setup flow the user completes later** — out of this skill's
|
|
34
|
+
scope. If checkout return fails before that setup is done, that's expected; flag it and continue.
|
|
35
|
+
|
|
36
|
+
## The API (copy as-is; do not re-derive it)
|
|
37
|
+
This skill ships only the REST layer — no UI components. Build the restaurant UI however the
|
|
38
|
+
project wants; wire it to these two snippets. Copy them into the app (e.g. `src/api/`) and only
|
|
39
|
+
adjust import paths:
|
|
40
|
+
- `src/rest/wix-client.js` — visitor-token mint/refresh + transport. Set `WIX_CLIENT_ID` to the id
|
|
41
|
+
from the prompt (replace the `<YOUR-CLIENT-ID>` placeholder). The visitor refresh token IS the
|
|
42
|
+
cart identity; it is persisted to localStorage. Do not re-mint anonymously per load or the cart
|
|
43
|
+
silently empties.
|
|
44
|
+
- `src/rest/wix-restaurants-menu.js` — **Menu (read-only):**
|
|
45
|
+
`getFullMenu` (the assembled tree — start here), `listMenus`, `listSections`, `listItems`,
|
|
46
|
+
`listVariants`, `listModifierGroups`, `listModifiers`, `listLabels`
|
|
47
|
+
- `src/rest/wix-restaurants-ordering.js` — **Online ordering:**
|
|
48
|
+
`listOperations`, `getDefaultOperation`, `addItemToCart`, `getCurrentCart`,
|
|
49
|
+
`updateCartItemQuantity`, `removeFromCart`, `checkout`
|
|
50
|
+
- `src/rest/wix-restaurants-reservations.js` — **Reservations:**
|
|
51
|
+
`listReservationLocations`, `getTimeSlots`, `createHeldReservation`, `reserveReservation`
|
|
52
|
+
|
|
53
|
+
The Menu, Item, ModifierGroup, Operation, Cart, ReservationLocation, TimeSlot, and Reservation
|
|
54
|
+
shapes are documented as JSDoc at the top of each helper file. Read the relevant file(s) before
|
|
55
|
+
building the UI — they describe the key fields and link to the full reference for anything not shown.
|
|
56
|
+
|
|
57
|
+
## How to wire it (UI is the project's choice)
|
|
58
|
+
- **Menu page** — call `getFullMenu()` once. It returns `{ menus: [{ ...menu, sections: [{ ...section,
|
|
59
|
+
items: [assembledItem] }] }] }`, already ordered by `sectionIds` / `itemIds`. Render each item's
|
|
60
|
+
`name`, `description`, `image`, `labels` (`name` + `icon`), and `featured` flag. For price, show
|
|
61
|
+
`item.price` (single) or the `item.variants[]` (each `{ name, price }`). **Restaurants prices are
|
|
62
|
+
plain decimal strings with NO currency symbol** — format with the site's currency in the UI.
|
|
63
|
+
- **Item detail** — render `item.modifierGroups[]`: each group's `name`, its `rule`
|
|
64
|
+
(`required`, `minSelections`, `maxSelections`), and `modifiers[]` (`name`, `additionalCharge`,
|
|
65
|
+
`preSelected`, `inStock`). If `orderSettings.acceptSpecialRequests`, offer a free-text field.
|
|
66
|
+
- **Online ordering** — resolve an operation with `getDefaultOperation()` (or let the user pick from
|
|
67
|
+
`listOperations()`); if it's `null`, show an "ordering unavailable" state. Add a dish with
|
|
68
|
+
`addItemToCart(item.id, { operationId, menuId, sectionId, quantity })` — `menuId`/`sectionId` are
|
|
69
|
+
the menu and section the item was shown under. Read the cart back with `getCurrentCart()`; mutate
|
|
70
|
+
with `updateCartItemQuantity(lineItemId, qty)` / `removeFromCart(lineItemId)` using
|
|
71
|
+
`cart.lineItems[].id` (not the item id).
|
|
72
|
+
- **Checkout** — `window.location.href = await checkout()`. After the visitor returns, the order is
|
|
73
|
+
placed and the cart is empty — re-fetch with `getCurrentCart()` on return (e.g. on mount +
|
|
74
|
+
`visibilitychange`) to clear the UI.
|
|
75
|
+
- **Reservations** — `listReservationLocations()` for the picker (use `location` details for the
|
|
76
|
+
label; if a location's `configuration.onlineReservations.onlineReservationsEnabled` is false, hide
|
|
77
|
+
it). Then `getTimeSlots(locationId, dateISO, partySize)` — render `availableTimeSlots` (already
|
|
78
|
+
filtered to `AVAILABLE`). On slot pick, `createHeldReservation(locationId, slot.startDate,
|
|
79
|
+
partySize)` → keep the returned `id` + `revision`. Collect the visitor's details, then
|
|
80
|
+
`reserveReservation(id, revision, { firstName, phone, lastName?, email? })`. A `RESERVED` status is
|
|
81
|
+
confirmed; `REQUESTED` means the location requires manual approval — tell the user it's pending.
|
|
82
|
+
- **Empty state** — if `getFullMenu()` returns no menus, show an empty state telling the user to add
|
|
83
|
+
a menu in their Wix dashboard. Never invent menu items.
|
|
84
|
+
|
|
85
|
+
## Hard rules (do not violate)
|
|
86
|
+
- ✅ Order ONLY through the cart: `addItemToCart()` → `checkout()` (`create-checkout` →
|
|
87
|
+
`/headless/v1/redirect-session` `fullUrl`), then redirect.
|
|
88
|
+
- ❌ Never hand-build `/checkout`, ordering, or reservation URLs.
|
|
89
|
+
- ❌ Never mock menus, items, prices, operations, locations, or time slots — render live Wix data or
|
|
90
|
+
the empty state.
|
|
91
|
+
- ❌ Never generate fake reviews, ratings, or testimonials. Empty review UI only.
|
|
92
|
+
- ✅ Set `WIX_CLIENT_ID` from the prompt's value (public client id — safe to hardcode).
|
|
93
|
+
- ✅ `addItemToCart` requires `operationId`, `menuId`, and `sectionId` — it throws if any is missing.
|
|
94
|
+
- ✅ `lineItemId` for cart mutations is `cart.lineItems[].id`, not the item id.
|
|
95
|
+
- ✅ Reservations: offer only `AVAILABLE` slots; a HELD reservation expires in 10 minutes — pass the
|
|
96
|
+
`revision` from the hold into `reserveReservation`, and restart the flow if it expired.
|
|
97
|
+
- ✅ Reservee `firstName` + `phone` (E.164, e.g. `+15551234567`) are mandatory to confirm.
|
|
98
|
+
- The engine fails loudly on purpose: `addItemToCart`/`checkout` throw on out-of-stock or empty
|
|
99
|
+
carts; reservation helpers throw on unavailable slots or expired holds. A green path means it is
|
|
100
|
+
really orderable/bookable — don't swallow these.
|
|
101
|
+
|
|
102
|
+
## Beyond the snippets
|
|
103
|
+
The snippets cover the common menu / ordering / reservation paths. For the "20%" they don't cover,
|
|
104
|
+
make the call yourself with `wixApiRequest` — but look up the exact endpoint, HTTP method, and
|
|
105
|
+
request body in the **official Wix API reference** first; never guess:
|
|
106
|
+
- Restaurants API reference: https://dev.wix.com/docs/api-reference/business-solutions/restaurants.md
|
|
107
|
+
- Selecting a specific **price variant** or applying **modifier up-charges** on the cart line: the
|
|
108
|
+
restaurants `catalogReference.options` shape for these is not documented for client add-to-cart.
|
|
109
|
+
The menu UI still displays them; confirm the shape before wiring them into `addItemToCart`:
|
|
110
|
+
https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/sample-flows.md
|
|
111
|
+
- Fulfillment methods, delivery-address validation, scheduled (preorder) time slots, service fees:
|
|
112
|
+
see the Online Orders section of the reference.
|
|
113
|
+
- **Member login + a "my orders" account view** → the **members** vertical
|
|
114
|
+
(`references/members/INSTRUCTIONS.md`): ordering/reserving works anonymously, but signing a member
|
|
115
|
+
in (custom login on your own UI) lets them see their own order/reservation history.
|
|
116
|
+
|
|
117
|
+
Keep the snippets as the default for everything they already do; reach for the API reference only
|
|
118
|
+
for the gap.
|
|
119
|
+
|
|
120
|
+
## Point the user to their dashboard
|
|
121
|
+
In some cases, users need to access the Wix dashboard in order to edit the restaurant content for their site — across up to three apps. To facilitate this, provide the user with deep links directly to the relevant dashboard pages; only mention the apps the project actually uses. Those pages are:
|
|
122
|
+
- **Menu** (always) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-menus-new` (`Dashboard → Restaurant Menus`; click **Manage Items** to add dishes; only visible menus appear in the app)
|
|
123
|
+
- **Online ordering** (if wired) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-orders-new/settings` (`Dashboard → Restaurant Orders → Settings`). Enable at least one fulfillment method before the site accepts orders — each has its own page: pickup `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-orders-new/settings/pickup`, delivery `.../wix-restaurants-orders-new/settings/delivery`, dine-in `.../wix-restaurants-orders-new/settings/dine-in`.
|
|
124
|
+
- **Table reservations** (if wired) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-table-reservations/table-reservations` (`Dashboard → Table Reservations` → **Settings**; configure tables, availability, and enable online reservations)
|
|
125
|
+
|
|
126
|
+
Substitute the site's `metaSiteId` to complete the links (you have it from the handoff / `ListWixSites`). Include the in-dashboard navigation as a fallback.
|
|
127
|
+
|
|
128
|
+
## Verification checklist (before declaring done)
|
|
129
|
+
- [ ] `WIX_CLIENT_ID` set to the prompt's value (not the `<YOUR-CLIENT-ID>` placeholder)
|
|
130
|
+
- [ ] Visitor token persists across reload (cart survives reload, same visitor)
|
|
131
|
+
- [ ] `getFullMenu()` renders real sections/items with prices, variants, modifiers, and labels
|
|
132
|
+
- [ ] Empty state shown when there are no menus (never invented items)
|
|
133
|
+
- [ ] Add to cart works with a real `operationId`/`menuId`/`sectionId`; out-of-stock items throw
|
|
134
|
+
- [ ] Quantity update / remove reflect in `getCurrentCart()`
|
|
135
|
+
- [ ] Checkout redirects via redirect-session `fullUrl` (no hand-built URL); cart re-fetched on return
|
|
136
|
+
- [ ] Reservations: only `AVAILABLE` slots offered; hold → reserve produces `RESERVED`/`REQUESTED`
|
|
137
|
+
- [ ] No mock data anywhere
|
|
138
|
+
- [ ] Told the user at least once that they can continue setting up their restaurant (menu / ordering / reservations) in the dashboard and provided deep links.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { wixApiRequest } from "./wix-client.js";
|
|
2
|
+
|
|
3
|
+
// Data model reference: see INSTRUCTIONS.md
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Menu — top of the hierarchy. One per published menu (e.g. Dinner, Drinks).
|
|
7
|
+
* id {string}, name {string}, description {string}, visible {boolean},
|
|
8
|
+
* sectionIds {string[]} — ordered Section GUIDs,
|
|
9
|
+
* urlQueryParam {string} — URL slug fragment, businessLocationId {string}
|
|
10
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/menus/menu-object.md
|
|
11
|
+
*
|
|
12
|
+
* Section — a group of items within a menu (e.g. Appetizers, Mains).
|
|
13
|
+
* id {string}, name {string}, description {string},
|
|
14
|
+
* image {object} — { id, url, width, height, altText },
|
|
15
|
+
* itemIds {string[]} — ordered Item GUIDs, visible {boolean}
|
|
16
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/sections/section-object.md
|
|
17
|
+
*
|
|
18
|
+
* Item — a single dish/drink. Has EITHER priceInfo (single price) OR priceVariants (one-of).
|
|
19
|
+
* id {string}, name {string}, description {string},
|
|
20
|
+
* image {object} — { id, url, width, height, altText },
|
|
21
|
+
* priceInfo.price {string} — decimal string e.g. "12.50" (NO currency symbol),
|
|
22
|
+
* priceVariants.variants {object[]} — [{ variantId, priceInfo: { price } }],
|
|
23
|
+
* labels {object[]} — [{ id }] resolve via listLabels,
|
|
24
|
+
* visible {boolean}, featured {boolean},
|
|
25
|
+
* orderSettings.inStock {boolean}, orderSettings.acceptSpecialRequests {boolean},
|
|
26
|
+
* modifierGroups {object[]} — [{ id }] resolve via listModifierGroups
|
|
27
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/items/items/item-object.md
|
|
28
|
+
*
|
|
29
|
+
* PriceVariant (from listVariants): { id, name } — name for the variantId in item.priceVariants.
|
|
30
|
+
* ModifierGroup: { id, name, rule: { required, minSelections, maxSelections },
|
|
31
|
+
* modifiers: [{ id, preSelected, additionalChargeInfo: { additionalCharge } }] }
|
|
32
|
+
* Modifier (from listModifiers): { id, name, inStock }
|
|
33
|
+
* Label (from listLabels): { id, name, icon: { url } } — e.g. "Vegan", "Spicy"
|
|
34
|
+
*
|
|
35
|
+
* NOTE: Restaurant prices are plain decimal strings with NO currency symbol.
|
|
36
|
+
* getFullMenu() assembles the full tree and is the recommended entry point.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Internal: fetch a list endpoint by a set of GUIDs, chunked to avoid long query strings.
|
|
41
|
+
*/
|
|
42
|
+
async function fetchAllByIds(path, idParamName, responseKey, ids, extraQuery = {}) {
|
|
43
|
+
const unique = [...new Set((ids ?? []).filter(Boolean))];
|
|
44
|
+
if (!unique.length) return [];
|
|
45
|
+
const out = [];
|
|
46
|
+
for (let i = 0; i < unique.length; i += 100) {
|
|
47
|
+
const chunk = unique.slice(i, i + 100);
|
|
48
|
+
const res = await wixApiRequest(path, {
|
|
49
|
+
method: "GET",
|
|
50
|
+
query: { [idParamName]: chunk, ...extraQuery },
|
|
51
|
+
});
|
|
52
|
+
out.push(...(res?.[responseKey] ?? []));
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* List menus (one page). Pass `onlyVisible: true` for visitor-facing menus.
|
|
59
|
+
* GET https://www.wixapis.com/restaurants/menus/v1/menus
|
|
60
|
+
* @param {{ onlyVisible?: boolean, limit?: number, cursor?: string }} [options]
|
|
61
|
+
* @returns {Promise<{ menus: object[], nextCursor: string|null }>}
|
|
62
|
+
*/
|
|
63
|
+
export async function listMenus({ onlyVisible = true, limit = 500, cursor } = {}) {
|
|
64
|
+
const res = await wixApiRequest("/restaurants/menus/v1/menus", {
|
|
65
|
+
method: "GET",
|
|
66
|
+
query: {
|
|
67
|
+
onlyVisible: onlyVisible ? "true" : undefined,
|
|
68
|
+
"paging.limit": String(limit),
|
|
69
|
+
"paging.cursor": cursor,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return { menus: res?.menus ?? [], nextCursor: res?.pagingMetadata?.cursors?.next ?? null };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* List sections by their GUIDs.
|
|
77
|
+
* @param {string[]} sectionIds
|
|
78
|
+
* @param {{ onlyVisible?: boolean }} [options]
|
|
79
|
+
* @returns {Promise<object[]>}
|
|
80
|
+
*/
|
|
81
|
+
export async function listSections(sectionIds, { onlyVisible = true } = {}) {
|
|
82
|
+
return fetchAllByIds("/restaurants/menus/v1/sections", "sectionIds", "sections", sectionIds, {
|
|
83
|
+
onlyVisible: onlyVisible ? "true" : undefined,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* List items by their GUIDs.
|
|
89
|
+
* @param {string[]} itemIds
|
|
90
|
+
* @param {{ onlyVisible?: boolean }} [options]
|
|
91
|
+
* @returns {Promise<object[]>}
|
|
92
|
+
*/
|
|
93
|
+
export async function listItems(itemIds, { onlyVisible = true } = {}) {
|
|
94
|
+
return fetchAllByIds("/restaurants/menus/v1/items", "itemIds", "items", itemIds, {
|
|
95
|
+
onlyVisible: onlyVisible ? "true" : undefined,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* List price variants by their GUIDs (resolves variantId → name).
|
|
101
|
+
* @param {string[]} variantIds
|
|
102
|
+
* @returns {Promise<object[]>}
|
|
103
|
+
*/
|
|
104
|
+
export async function listVariants(variantIds) {
|
|
105
|
+
return fetchAllByIds("/restaurants/menus/v1/variants", "variantIds", "variants", variantIds);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* List modifier groups by their GUIDs.
|
|
110
|
+
* @param {string[]} modifierGroupIds
|
|
111
|
+
* @returns {Promise<object[]>}
|
|
112
|
+
*/
|
|
113
|
+
export async function listModifierGroups(modifierGroupIds) {
|
|
114
|
+
return fetchAllByIds(
|
|
115
|
+
"/restaurants/menus/v1/modifier-groups",
|
|
116
|
+
"modifierGroupIds",
|
|
117
|
+
"modifierGroups",
|
|
118
|
+
modifierGroupIds,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* List modifiers by their GUIDs (resolves modifierId → name + inStock).
|
|
124
|
+
* @param {string[]} modifierIds
|
|
125
|
+
* @returns {Promise<object[]>}
|
|
126
|
+
*/
|
|
127
|
+
export async function listModifiers(modifierIds) {
|
|
128
|
+
return fetchAllByIds("/restaurants/item-modifiers/v1/modifiers", "modifierIds", "modifiers", modifierIds);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* List every item label on the site.
|
|
133
|
+
* @returns {Promise<object[]>}
|
|
134
|
+
*/
|
|
135
|
+
export async function listLabels() {
|
|
136
|
+
const res = await wixApiRequest("/restaurants/menus/v1/labels", { method: "GET" });
|
|
137
|
+
return res?.labels ?? [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Retrieve the complete assembled menu tree in one call. Walks menus → sections → items,
|
|
142
|
+
* then enriches each item with resolved price variants, modifier groups + modifiers, and labels.
|
|
143
|
+
* This is the recommended entry point for the menu screen.
|
|
144
|
+
*
|
|
145
|
+
* Returns:
|
|
146
|
+
* { menus: [ { ...menu, sections: [ { ...section, items: [ assembledItem ] } ] } ] }
|
|
147
|
+
* where assembledItem adds:
|
|
148
|
+
* price {string|null} Single price (null when variant-priced)
|
|
149
|
+
* variants {object[]} [{ variantId, name, price }]
|
|
150
|
+
* modifierGroups {object[]} [{ id, name, rule, modifiers: [{ id, name, preSelected, additionalCharge, inStock }] }]
|
|
151
|
+
* labels {object[]} [{ id, name, icon }]
|
|
152
|
+
*
|
|
153
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/retrieve-a-complete-menu-structure.md
|
|
154
|
+
* @param {{ onlyVisible?: boolean }} [options]
|
|
155
|
+
* @returns {Promise<{ menus: object[] }>}
|
|
156
|
+
*/
|
|
157
|
+
export async function getFullMenu({ onlyVisible = true } = {}) {
|
|
158
|
+
const { menus } = await listMenus({ onlyVisible });
|
|
159
|
+
if (!menus.length) return { menus: [] };
|
|
160
|
+
|
|
161
|
+
const sectionIds = menus.flatMap((m) => m.sectionIds ?? []);
|
|
162
|
+
const sections = await listSections(sectionIds, { onlyVisible });
|
|
163
|
+
|
|
164
|
+
const itemIds = sections.flatMap((s) => s.itemIds ?? []);
|
|
165
|
+
const items = await listItems(itemIds, { onlyVisible });
|
|
166
|
+
|
|
167
|
+
const variantIds = items.flatMap((i) => (i.priceVariants?.variants ?? []).map((v) => v.variantId));
|
|
168
|
+
const modifierGroupIds = items.flatMap((i) => (i.modifierGroups ?? []).map((g) => g.id));
|
|
169
|
+
|
|
170
|
+
const [variants, modifierGroups, labels] = await Promise.all([
|
|
171
|
+
listVariants(variantIds),
|
|
172
|
+
listModifierGroups(modifierGroupIds),
|
|
173
|
+
listLabels(),
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
const modifierIds = modifierGroups.flatMap((g) => (g.modifiers ?? []).map((m) => m.id));
|
|
177
|
+
const modifiers = await listModifiers(modifierIds);
|
|
178
|
+
|
|
179
|
+
const variantMap = new Map(variants.map((v) => [v.id, v]));
|
|
180
|
+
const groupMap = new Map(modifierGroups.map((g) => [g.id, g]));
|
|
181
|
+
const modifierMap = new Map(modifiers.map((m) => [m.id, m]));
|
|
182
|
+
const labelMap = new Map(labels.map((l) => [l.id, l]));
|
|
183
|
+
|
|
184
|
+
const assembleItem = (item) => ({
|
|
185
|
+
...item,
|
|
186
|
+
price: item.priceInfo?.price ?? null,
|
|
187
|
+
variants: (item.priceVariants?.variants ?? []).map((v) => ({
|
|
188
|
+
variantId: v.variantId,
|
|
189
|
+
name: variantMap.get(v.variantId)?.name ?? null,
|
|
190
|
+
price: v.priceInfo?.price ?? null,
|
|
191
|
+
})),
|
|
192
|
+
modifierGroups: (item.modifierGroups ?? [])
|
|
193
|
+
.map((ref) => groupMap.get(ref.id))
|
|
194
|
+
.filter(Boolean)
|
|
195
|
+
.map((group) => ({
|
|
196
|
+
id: group.id,
|
|
197
|
+
name: group.name,
|
|
198
|
+
rule: group.rule ?? null,
|
|
199
|
+
modifiers: (group.modifiers ?? []).map((m) => ({
|
|
200
|
+
id: m.id,
|
|
201
|
+
name: modifierMap.get(m.id)?.name ?? null,
|
|
202
|
+
preSelected: m.preSelected ?? false,
|
|
203
|
+
additionalCharge: m.additionalChargeInfo?.additionalCharge ?? "0",
|
|
204
|
+
inStock: modifierMap.get(m.id)?.inStock ?? true,
|
|
205
|
+
})),
|
|
206
|
+
})),
|
|
207
|
+
labels: (item.labels ?? []).map((ref) => labelMap.get(ref.id)).filter(Boolean),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const itemMap = new Map(items.map((i) => [i.id, assembleItem(i)]));
|
|
211
|
+
const sectionMap = new Map(
|
|
212
|
+
sections.map((s) => [
|
|
213
|
+
s.id,
|
|
214
|
+
{ ...s, items: (s.itemIds ?? []).map((id) => itemMap.get(id)).filter(Boolean) },
|
|
215
|
+
]),
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
menus: menus.map((m) => ({
|
|
220
|
+
...m,
|
|
221
|
+
sections: (m.sectionIds ?? []).map((id) => sectionMap.get(id)).filter(Boolean),
|
|
222
|
+
})),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { wixApiRequest } from "./wix-client.js";
|
|
2
|
+
|
|
3
|
+
// Data model reference: see INSTRUCTIONS.md
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Operation — online-ordering context (fulfillment + scheduling). Every cart line item must
|
|
7
|
+
* reference an operationId. Pick the default / first enabled one for a simple flow.
|
|
8
|
+
* id {string}, name {string}, default {boolean},
|
|
9
|
+
* onlineOrderingStatus {string} — "ENABLED"|"DISABLED"|"PAUSED_UNTIL"|UNDEFINED,
|
|
10
|
+
* defaultFulfillmentType {string} — "PICKUP"|"DELIVERY",
|
|
11
|
+
* fulfillmentIds {string[]}, businessLocationId {string}
|
|
12
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/operations/operation-object.md
|
|
13
|
+
*
|
|
14
|
+
* Cart (Wix eCom) — restaurant orders use the same visitor cart as the storefront.
|
|
15
|
+
* id {string}, currency {string},
|
|
16
|
+
* lineItems[].id {string} — lineItemId for update/remove (NOT the item id),
|
|
17
|
+
* lineItems[].quantity {number},
|
|
18
|
+
* lineItems[].catalogReference.catalogItemId {string} — the ordered item's GUID,
|
|
19
|
+
* lineItems[].productName.original {string},
|
|
20
|
+
* lineItems[].price.formattedAmount {string},
|
|
21
|
+
* lineItems[].availability.status {string} — "AVAILABLE"|"NOT_AVAILABLE"|"PARTIALLY_AVAILABLE"|"NOT_FOUND"
|
|
22
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/cart/cart-object.md
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Wix Restaurants Orders app id — required in catalogReference when adding menu items to the eCom cart.
|
|
26
|
+
const RESTAURANTS_ORDERS_APP_ID = "9a5d83fd-8570-482e-81ab-cfa88942ee60";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* List the restaurant's online-ordering operations.
|
|
30
|
+
* GET https://www.wixapis.com/restaurants-operations/v1/operations
|
|
31
|
+
* @returns {Promise<object[]>}
|
|
32
|
+
*/
|
|
33
|
+
export async function listOperations() {
|
|
34
|
+
const res = await wixApiRequest("/restaurants-operations/v1/operations", { method: "GET" });
|
|
35
|
+
return res?.operations ?? [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pick the operation to order through — the default, else the first ENABLED, else the first.
|
|
40
|
+
* Returns null when no operation is configured (show an "ordering unavailable" state).
|
|
41
|
+
* @returns {Promise<object|null>}
|
|
42
|
+
*/
|
|
43
|
+
export async function getDefaultOperation() {
|
|
44
|
+
const operations = await listOperations();
|
|
45
|
+
return (
|
|
46
|
+
operations.find((o) => o.default) ??
|
|
47
|
+
operations.find((o) => o.onlineOrderingStatus === "ENABLED") ??
|
|
48
|
+
operations[0] ??
|
|
49
|
+
null
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Add a restaurant menu item to the visitor's current eCom cart.
|
|
55
|
+
*
|
|
56
|
+
* Requires operationId (from listOperations/getDefaultOperation), menuId, and sectionId.
|
|
57
|
+
* Throws if any is missing, or if the added line is not AVAILABLE.
|
|
58
|
+
*
|
|
59
|
+
* Variant selection and modifier up-charges on the cart line are not covered here — the
|
|
60
|
+
* restaurants catalogReference.options shape for those is not documented for client add-to-cart.
|
|
61
|
+
* Confirm the shape before extending:
|
|
62
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/sample-flows.md
|
|
63
|
+
*
|
|
64
|
+
* POST https://www.wixapis.com/ecom/v1/carts/current/add-to-cart
|
|
65
|
+
* @param {string} itemId Menu item GUID (item.id).
|
|
66
|
+
* @param {{ operationId: string, menuId: string, sectionId: string, onlineOrderingPageUrl?: string, quantity?: number }} opts
|
|
67
|
+
* @returns {Promise<object>} Updated cart.
|
|
68
|
+
*/
|
|
69
|
+
export async function addItemToCart(itemId, { operationId, menuId, sectionId, onlineOrderingPageUrl, quantity = 1 } = {}) {
|
|
70
|
+
if (!itemId) throw new Error("addItemToCart: itemId is required.");
|
|
71
|
+
if (!operationId || !menuId || !sectionId) {
|
|
72
|
+
throw new Error("addItemToCart: operationId, menuId and sectionId are all required for a restaurant line item.");
|
|
73
|
+
}
|
|
74
|
+
const options = { operationId, menuId, sectionId };
|
|
75
|
+
if (onlineOrderingPageUrl) options.onlineOrderingPageUrl = onlineOrderingPageUrl;
|
|
76
|
+
|
|
77
|
+
const res = await wixApiRequest("/ecom/v1/carts/current/add-to-cart", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: {
|
|
80
|
+
lineItems: [{ catalogReference: { appId: RESTAURANTS_ORDERS_APP_ID, catalogItemId: itemId, options }, quantity }],
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
const line = (res?.cart?.lineItems ?? []).find((l) => l.catalogReference?.catalogItemId === itemId);
|
|
84
|
+
if (line?.availability?.status && line.availability.status !== "AVAILABLE") {
|
|
85
|
+
throw new Error(`Item not available to order (status: ${line.availability.status}).`);
|
|
86
|
+
}
|
|
87
|
+
return res?.cart;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Read the visitor's current cart. Returns null if no cart exists yet. */
|
|
91
|
+
export async function getCurrentCart() {
|
|
92
|
+
try {
|
|
93
|
+
const res = await wixApiRequest("/ecom/v1/carts/current", { method: "GET" });
|
|
94
|
+
return res?.cart ?? null;
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Update the quantity of a cart line. lineItemId is cart.lineItems[].id, not the item id.
|
|
102
|
+
* POST https://www.wixapis.com/ecom/v1/carts/current/update-line-items-quantity
|
|
103
|
+
* @returns {Promise<object>} Updated cart.
|
|
104
|
+
*/
|
|
105
|
+
export async function updateCartItemQuantity(lineItemId, quantity) {
|
|
106
|
+
const res = await wixApiRequest("/ecom/v1/carts/current/update-line-items-quantity", {
|
|
107
|
+
method: "POST",
|
|
108
|
+
body: { lineItems: [{ id: lineItemId, quantity }] },
|
|
109
|
+
});
|
|
110
|
+
return res?.cart;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove a line from the current cart by its cart.lineItems[].id.
|
|
115
|
+
* POST https://www.wixapis.com/ecom/v1/carts/current/remove-line-items
|
|
116
|
+
* @returns {Promise<object>} Updated cart.
|
|
117
|
+
*/
|
|
118
|
+
export async function removeFromCart(lineItemId) {
|
|
119
|
+
const res = await wixApiRequest("/ecom/v1/carts/current/remove-line-items", {
|
|
120
|
+
method: "POST",
|
|
121
|
+
body: { lineItemIds: [lineItemId] },
|
|
122
|
+
});
|
|
123
|
+
return res?.cart;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create a checkout from the current cart and return the Wix-hosted checkout URL.
|
|
128
|
+
* Throws on empty cart, unavailable lines, or a missing redirect URL.
|
|
129
|
+
* Redirect with: window.location.href = await checkout()
|
|
130
|
+
* @returns {Promise<string>}
|
|
131
|
+
*/
|
|
132
|
+
export async function checkout() {
|
|
133
|
+
const cart = await getCurrentCart();
|
|
134
|
+
const lines = cart?.lineItems ?? [];
|
|
135
|
+
if (!lines.length) throw new Error("Cannot check out: the cart is empty.");
|
|
136
|
+
const unavailable = lines.filter((l) => l.availability?.status && l.availability.status !== "AVAILABLE");
|
|
137
|
+
if (unavailable.length) {
|
|
138
|
+
const names = unavailable.map((l) => l.productName?.original ?? l.catalogReference?.catalogItemId).join(", ");
|
|
139
|
+
throw new Error(`Cannot check out: ${unavailable.length} item(s) not available — ${names}.`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const checkoutRes = await wixApiRequest("/ecom/v1/carts/current/create-checkout", {
|
|
143
|
+
method: "POST",
|
|
144
|
+
body: { channelType: "WEB" },
|
|
145
|
+
});
|
|
146
|
+
const checkoutId = checkoutRes?.checkoutId;
|
|
147
|
+
if (!checkoutId) throw new Error("Failed to create checkout from the current cart.");
|
|
148
|
+
|
|
149
|
+
const redirect = await wixApiRequest("/headless/v1/redirect-session", {
|
|
150
|
+
method: "POST",
|
|
151
|
+
body: { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl: window.location.href } },
|
|
152
|
+
});
|
|
153
|
+
const url = redirect?.redirectSession?.fullUrl;
|
|
154
|
+
if (!url) throw new Error("Failed to create the checkout redirect session.");
|
|
155
|
+
return url;
|
|
156
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { wixApiRequest } from "./wix-client.js";
|
|
2
|
+
|
|
3
|
+
// Data model reference: see INSTRUCTIONS.md
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ReservationLocation — a restaurant location that accepts table reservations.
|
|
7
|
+
* id {string}, default {boolean}, archived {boolean},
|
|
8
|
+
* location {object} — physical location details,
|
|
9
|
+
* configuration {object}:
|
|
10
|
+
* onlineReservations.approval.mode — "AUTOMATIC"|"MANUAL"|"MANUAL_FOR_LARGE_PARTIES"
|
|
11
|
+
* partySize.min / partySize.max — guest count limits
|
|
12
|
+
* timeSlotInterval — minutes between slots
|
|
13
|
+
* reservationForm: { lastNameRequired, emailRequired, customFieldDefinitions }
|
|
14
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/reservation-locations/reservation-location-object.md
|
|
15
|
+
*
|
|
16
|
+
* TimeSlot (from getTimeSlots):
|
|
17
|
+
* { startDate, duration, status, manualApproval }
|
|
18
|
+
* status: "AVAILABLE" | "UNAVAILABLE" | "NON_WORKING_HOURS" — offer only AVAILABLE slots.
|
|
19
|
+
*
|
|
20
|
+
* Reservation (from createHeldReservation / reserveReservation):
|
|
21
|
+
* { id, revision, status, details: { reservationLocationId, startDate, endDate, partySize }, reservee, paymentStatus }
|
|
22
|
+
* status: "HELD" → "RESERVED" (auto-approved) or "REQUESTED" (manual approval required) after reserve.
|
|
23
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/reservations/reservation-object.md
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* List the site's reservation locations (up to 100).
|
|
28
|
+
* GET https://www.wixapis.com/table-reservations/reservation-locations/v1/reservation-locations
|
|
29
|
+
* @returns {Promise<object[]>}
|
|
30
|
+
*/
|
|
31
|
+
export async function listReservationLocations() {
|
|
32
|
+
const res = await wixApiRequest(
|
|
33
|
+
"/table-reservations/reservation-locations/v1/reservation-locations",
|
|
34
|
+
{ method: "GET" },
|
|
35
|
+
);
|
|
36
|
+
return res?.reservationLocations ?? [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get reservation time slots for a location on a date, filtered to AVAILABLE only.
|
|
41
|
+
* Use slotsBefore / slotsAfter to fan out around the chosen date.
|
|
42
|
+
* POST https://www.wixapis.com/table-reservations/reservations/v1/time-slots
|
|
43
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/time-slots/get-time-slots.md
|
|
44
|
+
* @param {string} reservationLocationId
|
|
45
|
+
* @param {string} date ISO-8601 datetime e.g. "2026-07-01T19:00:00.000Z"
|
|
46
|
+
* @param {number} partySize
|
|
47
|
+
* @param {{ slotsBefore?: number, slotsAfter?: number, duration?: number }} [options]
|
|
48
|
+
* @returns {Promise<{ timeSlots: object[], availableTimeSlots: object[] }>}
|
|
49
|
+
*/
|
|
50
|
+
export async function getTimeSlots(reservationLocationId, date, partySize, { slotsBefore = 4, slotsAfter = 4, duration } = {}) {
|
|
51
|
+
if (!reservationLocationId || !date || !partySize) {
|
|
52
|
+
throw new Error("getTimeSlots: reservationLocationId, date and partySize are required.");
|
|
53
|
+
}
|
|
54
|
+
const res = await wixApiRequest("/table-reservations/reservations/v1/time-slots", {
|
|
55
|
+
method: "POST",
|
|
56
|
+
body: { reservationLocationId, date, partySize, slotsBefore, slotsAfter, ...(duration ? { duration } : {}) },
|
|
57
|
+
});
|
|
58
|
+
const timeSlots = res?.timeSlots ?? [];
|
|
59
|
+
return { timeSlots, availableTimeSlots: timeSlots.filter((s) => s.status === "AVAILABLE") };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hold a reservation for 10 minutes while the visitor fills in their details.
|
|
64
|
+
* Returns a reservation with status "HELD" — keep its id and revision for reserveReservation.
|
|
65
|
+
* POST https://www.wixapis.com/table-reservations/reservations/v1/reservations/hold
|
|
66
|
+
* @param {string} reservationLocationId
|
|
67
|
+
* @param {string} startDate ISO-8601 datetime of the chosen time slot.
|
|
68
|
+
* @param {number} partySize
|
|
69
|
+
* @returns {Promise<object>} The held reservation ({ id, revision, status: "HELD", ... }).
|
|
70
|
+
*/
|
|
71
|
+
export async function createHeldReservation(reservationLocationId, startDate, partySize) {
|
|
72
|
+
if (!reservationLocationId || !startDate || !partySize) {
|
|
73
|
+
throw new Error("createHeldReservation: reservationLocationId, startDate and partySize are required.");
|
|
74
|
+
}
|
|
75
|
+
const res = await wixApiRequest("/table-reservations/reservations/v1/reservations/hold", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: { reservationDetails: { reservationLocationId, startDate, partySize } },
|
|
78
|
+
});
|
|
79
|
+
const reservation = res?.reservation;
|
|
80
|
+
if (!reservation?.id) throw new Error("Failed to hold the reservation (the slot may no longer be available).");
|
|
81
|
+
return reservation;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Confirm a held reservation with the visitor's details. Moves status from "HELD" to
|
|
86
|
+
* "RESERVED" (auto-approval) or "REQUESTED" (manual approval required).
|
|
87
|
+
* reservee.firstName and reservee.phone (E.164, e.g. "+15551234567") are REQUIRED.
|
|
88
|
+
* Pass the revision returned by createHeldReservation. Holds expire after 10 minutes.
|
|
89
|
+
* POST https://www.wixapis.com/table-reservations/reservations/v1/reservations/{id}/reserve
|
|
90
|
+
* @param {string} reservationId
|
|
91
|
+
* @param {string} revision
|
|
92
|
+
* @param {{ firstName: string, phone: string, lastName?: string, email?: string, marketingConsent?: boolean }} reservee
|
|
93
|
+
* @returns {Promise<object>} The updated reservation.
|
|
94
|
+
*/
|
|
95
|
+
export async function reserveReservation(reservationId, revision, reservee) {
|
|
96
|
+
if (!reservationId || !revision) throw new Error("reserveReservation: reservationId and revision are required.");
|
|
97
|
+
if (!reservee?.firstName || !reservee?.phone) {
|
|
98
|
+
throw new Error("reserveReservation: reservee.firstName and reservee.phone are required.");
|
|
99
|
+
}
|
|
100
|
+
const res = await wixApiRequest(
|
|
101
|
+
`/table-reservations/reservations/v1/reservations/${encodeURIComponent(reservationId)}/reserve`,
|
|
102
|
+
{ method: "POST", body: { revision, reservee } },
|
|
103
|
+
);
|
|
104
|
+
const reservation = res?.reservation;
|
|
105
|
+
if (!reservation?.id) throw new Error("Failed to confirm the reservation (the hold may have expired — start over).");
|
|
106
|
+
return reservation;
|
|
107
|
+
}
|