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