@wix/agent-skills 1.14.0 → 1.15.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.
- package/README.md +12 -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/DATA_COLLECTION.md +5 -3
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +25 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
- 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/backend-event/COMMON-EVENTS.md +5 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +151 -0
- 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/COMPONENT-PREVIEW.md +57 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +23 -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 +18 -16
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
- package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
- package/skills/wix-app/references/stores/INVENTORY.md +37 -0
- package/skills/wix-app/references/stores/QUERY.md +87 -0
- package/skills/wix-app/references/stores/WRITE.md +55 -0
- 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 +89 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +76 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +86 -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 +129 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +99 -0
- package/skills/wix-headless/references/SEED.md +45 -187
- 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 +213 -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 +232 -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 +192 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +155 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +197 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +136 -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 +79 -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 +15 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +71 -0
- package/skills/wix-manage/SKILL.md +29 -3
- package/skills/wix-manage/references/analytics/query-site-analytics.md +298 -0
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
- package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +299 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +6 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +517 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +218 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/sites/site-import.md +270 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +57 -0
- package/skills/wix-vibe-headless/SKILL.md +142 -0
- package/skills/wix-vibe-headless/platforms/README.md +22 -0
- package/skills/wix-vibe-headless/platforms/base44.md +142 -0
- package/skills/wix-vibe-headless/platforms/generic.md +87 -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 +157 -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 +217 -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 +136 -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 +223 -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 +164 -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 +146 -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,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
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST version of the Wix headless integration — the direct analog of
|
|
3
|
+
* `storefrontApiRequest` in src/lib/shopify.ts. Plain fetch, JSON in / JSON out.
|
|
4
|
+
* No SDK, no query builder, no Velo.
|
|
5
|
+
*
|
|
6
|
+
* WIX_CLIENT_ID is the one thing to set. The client exchanges it for a visitor
|
|
7
|
+
* access token via the OAuth2 token endpoint, then sends that token on every API call.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The public headless OAuth client id. It is a buyer-facing credential (it only mints
|
|
12
|
+
* anonymous visitor tokens), NOT a secret — so it is safe to hardcode here. Paste the
|
|
13
|
+
* value from the Wix Business Manager prompt in place of the placeholder.
|
|
14
|
+
*/
|
|
15
|
+
export const WIX_CLIENT_ID = "<YOUR-CLIENT-ID>";
|
|
16
|
+
|
|
17
|
+
export const WIX_API_BASE = "https://www.wixapis.com";
|
|
18
|
+
const OAUTH_TOKEN_URL = `${WIX_API_BASE}/oauth2/token`;
|
|
19
|
+
|
|
20
|
+
// Scope the storage key by client id so two headless sites served from the same
|
|
21
|
+
// origin (e.g. localhost:4321 across projects) don't share one visitor token —
|
|
22
|
+
// which would load site A's token for site B and mix up carts/identity.
|
|
23
|
+
const TOKEN_STORAGE_KEY = `wix-visitor-token-${WIX_CLIENT_ID}`;
|
|
24
|
+
let tokenCache = null;
|
|
25
|
+
|
|
26
|
+
function loadToken() {
|
|
27
|
+
if (tokenCache) return tokenCache;
|
|
28
|
+
if (typeof window === "undefined") return null;
|
|
29
|
+
try {
|
|
30
|
+
const raw = window.localStorage.getItem(TOKEN_STORAGE_KEY);
|
|
31
|
+
if (raw) tokenCache = JSON.parse(raw);
|
|
32
|
+
} catch {
|
|
33
|
+
/* ignore disabled/full storage */
|
|
34
|
+
}
|
|
35
|
+
return tokenCache;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function saveToken(t) {
|
|
39
|
+
tokenCache = t;
|
|
40
|
+
if (typeof window === "undefined") return;
|
|
41
|
+
try {
|
|
42
|
+
window.localStorage.setItem(TOKEN_STORAGE_KEY, JSON.stringify(t));
|
|
43
|
+
} catch {
|
|
44
|
+
/* ignore */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function mintToken(body) {
|
|
49
|
+
const res = await fetch(OAUTH_TOKEN_URL, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
body: JSON.stringify(body),
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) throw new Error(`Wix OAuth failed: ${res.status}`);
|
|
55
|
+
const data = await res.json();
|
|
56
|
+
return {
|
|
57
|
+
accessToken: data.access_token,
|
|
58
|
+
refreshToken: data.refresh_token,
|
|
59
|
+
expiresAt: Date.now() + data.expires_in * 1000,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Log a member in on THIS client by swapping the persisted token set for the
|
|
65
|
+
* member's tokens (see references/members/). Member tokens are the SAME shape as
|
|
66
|
+
* visitor tokens and refresh via the same `refresh_token` grant — logging in just
|
|
67
|
+
* replaces the set the client already carries, so EVERY subsequent `wixApiRequest`
|
|
68
|
+
* (cart, orders, bookings, "my …" reads) now runs as the member. Called by the
|
|
69
|
+
* members helper after a successful credential / social / SSO login.
|
|
70
|
+
*
|
|
71
|
+
* @param {{ accessToken: string, refreshToken: string, expiresIn: number }} tokens
|
|
72
|
+
*/
|
|
73
|
+
export function setSessionTokens({ accessToken, refreshToken, expiresIn }) {
|
|
74
|
+
saveToken({
|
|
75
|
+
accessToken,
|
|
76
|
+
refreshToken,
|
|
77
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
78
|
+
role: "member",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Drop the persisted session so the next call mints a FRESH anonymous visitor.
|
|
84
|
+
* Call on logout — otherwise the dead member token lingers and reads fail.
|
|
85
|
+
*/
|
|
86
|
+
export function clearSession() {
|
|
87
|
+
tokenCache = null;
|
|
88
|
+
if (typeof window === "undefined") return;
|
|
89
|
+
try {
|
|
90
|
+
window.localStorage.removeItem(TOKEN_STORAGE_KEY);
|
|
91
|
+
} catch {
|
|
92
|
+
/* ignore */
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* True once a member is logged in on this client (vs. an anonymous visitor).
|
|
98
|
+
* Gate account UI on this, or on the members helper's `isLoggedIn()`.
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
export function isMember() {
|
|
102
|
+
return loadToken()?.role === "member";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get a visitor access token from the client id.
|
|
107
|
+
*
|
|
108
|
+
* The visitor token IS the identity of the Wix "current cart", so we persist the
|
|
109
|
+
* refresh token to localStorage and REFRESH it on expiry — re-minting a fresh
|
|
110
|
+
* `anonymous` token would create a NEW visitor and silently empty the cart on
|
|
111
|
+
* every reload / after the 4h token lifetime. Anonymous mint happens only once
|
|
112
|
+
* (or when no refresh token is stored).
|
|
113
|
+
*/
|
|
114
|
+
async function getAccessToken() {
|
|
115
|
+
const cached = loadToken();
|
|
116
|
+
if (cached && cached.expiresAt > Date.now() + 60_000) return cached.accessToken;
|
|
117
|
+
|
|
118
|
+
if (cached?.refreshToken) {
|
|
119
|
+
try {
|
|
120
|
+
const refreshed = await mintToken({ clientId: WIX_CLIENT_ID, grantType: "refresh_token", refreshToken: cached.refreshToken });
|
|
121
|
+
// Refreshing preserves identity: a member refresh token yields member tokens.
|
|
122
|
+
refreshed.role = cached.role || "visitor";
|
|
123
|
+
saveToken(refreshed);
|
|
124
|
+
return refreshed.accessToken;
|
|
125
|
+
} catch {
|
|
126
|
+
/* refresh failed — fall through to a fresh anonymous visitor */
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const fresh = await mintToken({ clientId: WIX_CLIENT_ID, grantType: "anonymous" });
|
|
130
|
+
fresh.role = "visitor";
|
|
131
|
+
saveToken(fresh);
|
|
132
|
+
return fresh.accessToken;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Core transport — mirrors storefrontApiRequest. Adds the Authorization header,
|
|
137
|
+
* resolves the path against the Wix API base, parses JSON, surfaces errors.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} path
|
|
140
|
+
* @param {{ method?: "GET"|"POST"|"PUT"|"DELETE", body?: unknown, query?: Record<string, string | undefined> }} [options]
|
|
141
|
+
*/
|
|
142
|
+
export async function wixApiRequest(path, options = {}) {
|
|
143
|
+
const { method = "POST", body, query } = options;
|
|
144
|
+
const token = await getAccessToken();
|
|
145
|
+
|
|
146
|
+
const url = new URL(path.startsWith("http") ? path : `${WIX_API_BASE}${path}`);
|
|
147
|
+
if (query) {
|
|
148
|
+
for (const [k, v] of Object.entries(query)) {
|
|
149
|
+
if (v === undefined) continue;
|
|
150
|
+
if (Array.isArray(v)) {
|
|
151
|
+
for (const item of v) url.searchParams.append(k, item);
|
|
152
|
+
} else {
|
|
153
|
+
url.searchParams.set(k, v);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const res = await fetch(url.toString(), {
|
|
159
|
+
method,
|
|
160
|
+
headers: {
|
|
161
|
+
"Content-Type": "application/json",
|
|
162
|
+
Authorization: token, // Wix expects the raw access token (no "Bearer " prefix)
|
|
163
|
+
},
|
|
164
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (res.status === 402) {
|
|
168
|
+
// This API requires an active plan / premium feature on the site.
|
|
169
|
+
console.warn("Wix: Payment required (402) — this API needs an active plan/premium feature.");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!res.ok) {
|
|
173
|
+
const text = await res.text().catch(() => "");
|
|
174
|
+
let parsed;
|
|
175
|
+
try { parsed = JSON.parse(text); } catch { parsed = text; }
|
|
176
|
+
// Attach status + parsed body so callers (e.g. the members helper) can map a
|
|
177
|
+
// meaningful auth outcome (404 = bad credentials, 409 = email exists) to a
|
|
178
|
+
// friendly message instead of parsing the message string.
|
|
179
|
+
const err = new Error(`Wix API error ${res.status}: ${text}`);
|
|
180
|
+
err.status = res.status;
|
|
181
|
+
err.body = parsed;
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
if (res.status === 204) return undefined;
|
|
185
|
+
return await res.json();
|
|
186
|
+
}
|