@wix/agent-skills 1.17.0 → 1.18.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/package.json +1 -1
- package/skills/wix-app/SKILL.md +115 -12
- package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
- package/skills/wix-app/references/BACKEND_API.md +18 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
- package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +74 -83
- package/skills/wix-app/references/SITE_PLUGIN.md +12 -0
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +12 -11
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +1 -0
- package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +16 -8
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +47 -14
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +3 -0
- package/skills/wix-base44-connector/SKILL.md +133 -44
- package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
- package/skills/wix-base44-connector/scripts/utils.js +216 -30
- package/skills/wix-headless/entry/skill.md +1 -1
- package/skills/wix-headless/references/CAPABILITIES.md +9 -1
- package/skills/wix-headless/references/DESIGN.md +1 -0
- package/skills/wix-headless/references/DISCOVERY.md +2 -1
- package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +4 -1
- package/skills/wix-headless/references/SEED.md +2 -1
- package/skills/wix-headless/references/SETUP.md +1 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +26 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +57 -10
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
- package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
- package/skills/wix-headless/references/non-astro.md +1 -1
- package/skills/wix-headless-fast/SKILL.md +166 -0
- package/skills/wix-headless-fast/entry/skill.md +99 -0
- package/skills/wix-headless-fast/install/deploy.mjs +433 -0
- package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
- package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
- package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
- package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
- package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
- package/skills/wix-manage/SKILL.md +113 -89
- package/skills/wix-manage/references/dashboard-navigation/routes.json +12 -52
- package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-api.md +0 -2
- package/skills/wix-manage/references/forms/create-form.md +272 -184
- package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +13 -10
- package/skills/wix-manage/references/forms/update-form.md +122 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
- package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
- package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
- package/skills/wix-manage/references/media/generate-image-with-ai.md +86 -0
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +37 -7
- package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
- package/skills/wix-vibe-headless/SKILL.md +18 -4
- package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
- package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44.md +27 -61
- package/skills/wix-vibe-headless/platforms/generic.md +6 -3
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +43 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
- package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
- package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
- package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +486 -0
- package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
- package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
- package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1836 -0
- package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +137 -84
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
- package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
- package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
- package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
|
@@ -8,45 +8,35 @@ only), safe in the frontend; use it directly for the Wix client setup.
|
|
|
8
8
|
|
|
9
9
|
> **The Wix skills installed below are the complete build and seed path for this app — the Wix connector supplies the token for admin API calls.** **Do NOT use the Base44 commerce kit (or any Base44 solution kit).**
|
|
10
10
|
|
|
11
|
-
Follow STEPs 1–5 below exactly (run STEP 4 in parallel with STEP 3).
|
|
11
|
+
Follow STEPs 1–5 below exactly (run STEP 4 in parallel with STEP 3 — **except `forms`**, see STEP 3).
|
|
12
12
|
|
|
13
13
|
## STEP 1 — Install the Wix skills locally
|
|
14
14
|
|
|
15
|
-
Install three skills
|
|
16
|
-
- **`wix-vibe-headless`** — the client build **and** seed guide (STEPs 3–4): your main source of
|
|
17
|
-
truth. Seeding lives here too, per-vertical under `references/<vertical>/seed/`.
|
|
18
|
-
- **`wix-manage`** — REST recipes for managing and configuring the site (install apps, seed
|
|
19
|
-
catalogs, business setup).
|
|
20
|
-
- **`wix-base44-connector`** — building on Wix from the Base44 sandbox: site context, API
|
|
21
|
-
contracts, and the docs **fallback** — find + read the Wix API docs for anything
|
|
22
|
-
`wix-vibe-headless` doesn't cover.
|
|
15
|
+
Install three skills under `.agents/skills/`: **`wix-vibe-headless`** (the client build + seed guide — your main source of truth), **`wix-manage`** (REST recipes to manage/configure the site), and **`wix-base44-connector`** (site context + API-doc discovery, the fallback for anything the others don't cover).
|
|
23
16
|
|
|
24
17
|
Run this through exec_tool, exactly as written — installs all three skills, deploys REST scaffolds + UI into `src/`, writes `wix-config.js`, and pins the AGENTS.md note.
|
|
25
18
|
|
|
26
|
-
**Set `VERTICALS`** to what the prompt asks for (too vague to tell? do STEP 2 first, then set it):
|
|
19
|
+
**Set `VERTICALS`** to what the prompt asks for — **list every vertical the app uses**, since several often join the main one (too vague to tell? do STEP 2 first, then set it). Adding one later: re-run with the extra name.
|
|
27
20
|
|
|
28
21
|
| vertical | pick it when the app needs to |
|
|
29
22
|
|---|---|
|
|
30
23
|
| `storefront` | sell products |
|
|
31
24
|
| `bookings` | take appointments or service bookings |
|
|
25
|
+
| `rentals` | rent out an item for a length the customer picks (by the hour or by the day) |
|
|
32
26
|
| `blog` | publish articles |
|
|
33
27
|
| `events` | publish events with RSVPs or ticket sales |
|
|
34
28
|
| `portfolio` | showcase creative work |
|
|
35
|
-
| `pricing-plans` | sell memberships or subscriptions |
|
|
29
|
+
| `pricing-plans` | sell memberships or subscriptions, incl. paid enrollment/access to an online course or program — but an "online store selling courses" is still `storefront` |
|
|
36
30
|
| `restaurants` | show a menu, take orders, book tables |
|
|
37
31
|
| `members` | let visitors sign in — this is **auth** |
|
|
38
|
-
| `
|
|
39
|
-
|
|
40
|
-
**List every vertical the app uses.** `cms` for app-stored content, `members` for visitor sign-in — these often join the main vertical. Adding one later: re-run with the extra name.
|
|
32
|
+
| `forms` | any visitor-fillable form: contact, signup, waitlist, application, survey, quote request (an event RSVP is `events`; a per-service booking form is `bookings`) |
|
|
33
|
+
| `cms` | structured content the app reads back — galleries, listings, "my submissions" (a visitor-fillable form is `forms`) |
|
|
41
34
|
|
|
42
35
|
```js
|
|
43
36
|
const { execSync } = require('child_process');
|
|
44
37
|
const { existsSync, readdirSync } = require('fs');
|
|
45
|
-
const VERTICALS = ['storefront'];
|
|
46
|
-
|
|
47
|
-
// COPY these two straight from the prompt — deploy writes them into src/rest/wix-config.js, so never
|
|
48
|
-
// retype either one into a file by hand afterwards.
|
|
49
|
-
const WIX_CLIENT_ID = '<client id from the prompt>';
|
|
38
|
+
const VERTICALS = ['storefront']; // ← set from the prompt; list every vertical the app uses (e.g. ['members','cms'])
|
|
39
|
+
const WIX_CLIENT_ID = '<client id from the prompt>'; // copy both from the prompt — deploy writes them into src/rest/wix-config.js
|
|
50
40
|
const WIX_METASITE_ID = '<site id from the prompt>';
|
|
51
41
|
const results = {};
|
|
52
42
|
for (const skill of ['wix-vibe-headless', 'wix-manage', 'wix-base44-connector']) {
|
|
@@ -93,63 +83,39 @@ truth for how the client is built.
|
|
|
93
83
|
|
|
94
84
|
**REST scaffolds + `wix-config.js` are already in `src/rest/`** (STEP 1 wrote them). Some verticals also ship a ready UI client in `src/` — theme + wire it per `INSTRUCTIONS.md`, don't rebuild. **Don't `read_file` deployed files** — every field shape is in `INSTRUCTIONS.md`; read one only on a real error or gap.
|
|
95
85
|
|
|
86
|
+
**⚠️ `forms` is the ONE vertical that does NOT run in parallel with STEP 4** — its UI is gated on a
|
|
87
|
+
file the seed writes. Read its `INSTRUCTIONS.md` **Prerequisites** before building any form UI; seed
|
|
88
|
+
it first (STEP 4) and build the rest of the app meanwhile.
|
|
89
|
+
|
|
96
90
|
**`src/App.jsx`: edit surgically, never rewrite.** It carries required platform auth scaffolding
|
|
97
91
|
(`AuthProvider`/`useAuth` from `@/lib/AuthContext`); a full rewrite drops them → the validator
|
|
98
92
|
rejects the write. Wire routes/imports in with `find_replace`, leave the rest as-is.
|
|
99
93
|
|
|
100
94
|
## STEP 4 — Manage and seed the business
|
|
101
95
|
|
|
102
|
-
**Never delete or clean up anything on the user's site — seeding is additive only.** It's a live
|
|
103
|
-
user-owned business, so never delete or overwrite existing content, even apparent sample data. If a
|
|
104
|
-
cleanup truly seems needed, ask the user first.
|
|
105
|
-
|
|
106
96
|
Seed by calling your vertical's ready-made seed module — read
|
|
107
|
-
`.agents/skills/wix-vibe-headless/references/<vertical>/seed/SEED.md` and
|
|
108
|
-
|
|
109
|
-
shape → the **`wix-base44-connector`** skill's doc discovery.
|
|
110
|
-
|
|
111
|
-
**Auth for these admin calls is the already-configured Wix connector — nothing else.** Get its
|
|
112
|
-
access token and send it as a bearer token:
|
|
97
|
+
`.agents/skills/wix-vibe-headless/references/<vertical>/seed/SEED.md` and follow it (the loader
|
|
98
|
+
snippet, admin connector token, entity images with the final `media.base44.com` url, and every field
|
|
99
|
+
shape are there). Gaps or an unexpected shape → the **`wix-base44-connector`** skill's doc discovery.
|
|
100
|
+
Seeding is **admin-only** — not part of the client, which is built solely per the `wix-vibe-headless` skill.
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// then: fetch(url, { headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" }, ... })
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Inline via exec_tool, `base44` is already declared — use it directly; do **not** import
|
|
120
|
-
`@base44/sdk`, re-declare it, or call `createClient()` (that's for standalone `.js` files only;
|
|
121
|
-
inline it throws *"Identifier 'base44' has already been declared."*).
|
|
122
|
-
|
|
123
|
-
**Entity images.** For image-bearing entities (store products, blog covers, bookings services,
|
|
124
|
-
restaurant items, portfolio projects, event heroes, CMS items), generate with **Base44's built-in
|
|
125
|
-
image generation**, then attach via the vertical seed module's image-attach step —
|
|
126
|
-
`wix-base44-connector` doc discovery if the module doesn't cover that entity.
|
|
127
|
-
|
|
128
|
-
**Seed images with the FINAL url, in one call.** Seeding writes to Wix, so use the real
|
|
129
|
-
`https://media.base44.com/...` url from the **completed** `generate_image` result and pass it straight
|
|
130
|
-
into your single `setupStore`/seed call (images included). A still-generating `/__generating__/<id>.png`
|
|
131
|
-
placeholder is not a real url — Wix can't fetch it. `generate_image` runs in the background while you
|
|
132
|
-
build the client, so the urls are ready by the time you seed.
|
|
133
|
-
|
|
134
|
-
The connector + seeding are **admin-only** (STEP 4) — **not** part of the client, which is built
|
|
135
|
-
solely per the `wix-vibe-headless` skill.
|
|
102
|
+
- **Additive only:** never delete or overwrite the user's content, even apparent sample data; ask first if a cleanup truly seems needed.
|
|
103
|
+
- Inline in exec_tool, `base44` is already declared — use it directly; do **not** `import @base44/sdk`, re-declare it, or call `createClient()` (throws *"Identifier 'base44' has already been declared."*).
|
|
136
104
|
|
|
137
105
|
## STEP 5 — Wrap up
|
|
138
106
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
1. **Mount the preview-only manage banner** (required; links the app to its Wix back office; shipped,
|
|
142
|
-
self-gates to the preview, never on the published site): render the `<WixManageBanner/>` component
|
|
143
|
-
in your Layout's fixed top region, above the header, per your vertical's INSTRUCTIONS STEP 4.
|
|
144
|
-
2. **Ask the user to open** `https://manage.wix.com/dashboard/{metaSiteId}` (substitute your
|
|
145
|
-
metasite id) to complete setup in Wix (required), and mention that the preview shows a dismissible
|
|
146
|
-
top banner linking to this same dashboard.
|
|
107
|
+
1. **Mount `<WixManageBanner/>`** (required) in your Layout's fixed top region, above the header, per your vertical's INSTRUCTIONS — it links the app to its Wix back office, self-gates to the preview, and never shows on the published site.
|
|
108
|
+
2. **Ask the user to open** `https://manage.wix.com/dashboard/{metaSiteId}` (your metasite id) to complete setup in Wix.
|
|
147
109
|
|
|
148
|
-
**
|
|
110
|
+
**Don't chase images.** A `/__generating__/…` placeholder is swapped for the final url automatically at turn end — do **not** edit, re-seed, or debug image urls.
|
|
149
111
|
|
|
150
112
|
## Later admin requests
|
|
151
113
|
|
|
152
114
|
For any later admin/management request, work as in STEP 4: your vertical's seed module first, else
|
|
153
115
|
`wix-base44-connector` doc discovery — all over the connector.
|
|
154
116
|
|
|
155
|
-
|
|
117
|
+
**A change to what the business data COLLECTS is one of these, however UI it sounds** — a new form
|
|
118
|
+
field, product option or service setting. Change it on Wix first per the vertical's `seed/SEED.md`,
|
|
119
|
+
then edit the client against the verified result.
|
|
120
|
+
|
|
121
|
+
version: v1341
|
|
@@ -27,7 +27,7 @@ Everything is under `.agents/skills/wix-vibe-headless/references/`.
|
|
|
27
27
|
- `INSTRUCTIONS.md` — the vertical's build guide + field-shape snippets; `seed/SEED.md` — how the seed
|
|
28
28
|
module is run.
|
|
29
29
|
|
|
30
|
-
**The
|
|
30
|
+
**The verticals — data layer (`app/rest/`) + seed module (`seed/`):**
|
|
31
31
|
|
|
32
32
|
| vertical | `app/rest/` data layer | seed module |
|
|
33
33
|
|---|---|---|
|
|
@@ -37,7 +37,8 @@ Everything is under `.agents/skills/wix-vibe-headless/references/`.
|
|
|
37
37
|
| events | `wix-events-browse.js`, `wix-events-registration.js` — events & categories; RSVP / ticketing + checkout | `seed-events.js` |
|
|
38
38
|
| portfolio | `wix-portfolio.js` — collections, projects, galleries | `seed-portfolio.js` |
|
|
39
39
|
| restaurants | `wix-restaurants-menu.js`, `-ordering.js`, `-reservations.js` — menu; online ordering; table reservations | `seed-restaurants.js` |
|
|
40
|
-
|
|
|
40
|
+
| forms | `wix-forms.js`, `wix-forms-submissions.js` — any visitor-fillable form: read the schema; upload attachments, create a submission (schema accessors ship alongside in `lib/wix-form-schema-utils.js`) | *(none — REST shapes in `seed/SEED.md`)* |
|
|
41
|
+
| cms | `wix-cms.js` — Wix Data collections: list / detail / filter | `seed-cms.js` |
|
|
41
42
|
| pricing-plans | `wix-pricing-plans.js` — plans list + subscribe/checkout | `seed-pricing-plans.js` |
|
|
42
43
|
| members | `wix-members-auth.js` — custom login/signup (email+password, social, SSO), session, account | *(none — members sign up at runtime; nothing to seed)* |
|
|
43
44
|
|
|
@@ -49,7 +50,9 @@ the token set) is **universal — follow it as-is**.
|
|
|
49
50
|
|
|
50
51
|
## The flow — install → build client → seed → done
|
|
51
52
|
|
|
52
|
-
Run **build the client** (step 2) and **seed** (step 3) in parallel; parallelize independent work
|
|
53
|
+
Run **build the client** (step 2) and **seed** (step 3) in parallel; parallelize independent work
|
|
54
|
+
within each. **One exception — `forms` must be seeded before its UI is built; read that gate in
|
|
55
|
+
`references/forms/INSTRUCTIONS.md` (Prerequisites) first.** Everything else still parallelizes.
|
|
53
56
|
|
|
54
57
|
### 1 · Install the skills
|
|
55
58
|
|
|
@@ -225,6 +225,49 @@ the areas they sit in:
|
|
|
225
225
|
- eCommerce checkout (paid bookings): https://dev.wix.com/docs/api-reference/business-solutions/e-commerce.md
|
|
226
226
|
- Headless redirect session (hosted checkout): https://dev.wix.com/docs/api-reference/business-management/headless/redirects.md
|
|
227
227
|
|
|
228
|
+
## Rentals — the same client, one extra step
|
|
229
|
+
|
|
230
|
+
**Wix Rentals has no APIs of its own.** A rental is a Bookings *service* with rentals-specific
|
|
231
|
+
field values, so this whole client works on it: the catalog read, the booking form, and the
|
|
232
|
+
`createBooking → cart → checkout` chain are all unchanged. `rest/wix-bookings-rentals.js` and
|
|
233
|
+
`hooks/useRentalDuration.js` carry the only differences.
|
|
234
|
+
|
|
235
|
+
**What tells a rental apart — the DATA, never the brief.** A service carries either a fixed
|
|
236
|
+
session length or a duration RANGE the customer picks within; the two are mutually exclusive:
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
import { isRental, rentalDuration, rentalRateLabel } from "@/rest/wix-bookings-rentals";
|
|
240
|
+
isRental(service) // true only when schedule.availabilityConstraints.durationRange is present
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
A 60-minute yoga class and a 60-minute massage are **not** rentals even though a massage is
|
|
244
|
+
`type: "APPOINTMENT"` exactly like a rental is. Never branch on the service's name, its
|
|
245
|
+
category, or what the brief called it.
|
|
246
|
+
|
|
247
|
+
**The extra step.** An ordinary service is one choice (a slot). A rental is two: pick a START,
|
|
248
|
+
then pick HOW LONG — and the price follows the length.
|
|
249
|
+
|
|
250
|
+
```jsx
|
|
251
|
+
const detail = useServiceDetail(serviceId); // service + start times
|
|
252
|
+
const rental = useRentalDuration(detail.service, detail.selectedSlot, detail.timeZone);
|
|
253
|
+
|
|
254
|
+
<SlotPicker … /> {/* pick a start, as ever */}
|
|
255
|
+
{rental.isRental && <RentalDurationPicker rental={rental} />} {/* then pick a length */}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Book with `rental.endDate` as the slot's `localEndDate`; everything else in the booking call is
|
|
259
|
+
identical.
|
|
260
|
+
|
|
261
|
+
**Hard rules on top of the ones below:**
|
|
262
|
+
|
|
263
|
+
- **Filter every catalog read by `appId`.** `queryRentals()` does it. On a site with both apps
|
|
264
|
+
an unfiltered `queryServices` returns haircuts next to meeting rooms.
|
|
265
|
+
- **Never compute the total yourself.** A rental is charged as a rate, hourly at per-minute
|
|
266
|
+
granularity — 90 minutes of a $10/hour room is $15. `useRentalDuration` prices the chosen
|
|
267
|
+
length on the server; multiplying the displayed rate disagrees with checkout.
|
|
268
|
+
- **Show the total before the customer commits.** A rate alone is not a price.
|
|
269
|
+
- **One unit type per service.** A room rented by the hour *and* by the day is two services.
|
|
270
|
+
|
|
228
271
|
## Hard rules
|
|
229
272
|
- Style via base44 design tokens (`index.css` / shadcn Tailwind classes), never by rewriting the shipped components or adding a parallel theme file.
|
|
230
273
|
- Header/footer live in a `Layout` around `<Outlet/>` (STEP 3) — never edit the shipped
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Rental length picker — pure UI. The options, the selection handler and the priced total all
|
|
2
|
+
// come from useRentalDuration; no data wiring lives here.
|
|
3
|
+
//
|
|
4
|
+
// Renders the step an ordinary service doesn't have: the customer has already picked a START
|
|
5
|
+
// (SlotPicker), and now picks HOW LONG. The running total sits beside the choices because a
|
|
6
|
+
// rental's cost depends on the length — showing only a rate per hour leaves the customer
|
|
7
|
+
// discovering the real number at checkout.
|
|
8
|
+
//
|
|
9
|
+
// Show this only when `rental.isRental` — an appointment or class has no length to choose.
|
|
10
|
+
// Styled with base44 design tokens (shadcn Tailwind classes).
|
|
11
|
+
const optionCls = "py-2.5 px-3 cursor-pointer text-sm font-body border rounded-sm transition-colors";
|
|
12
|
+
const idle = "border-border bg-card text-foreground hover:border-foreground/40";
|
|
13
|
+
const active = "border-primary bg-primary text-primary-foreground";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {{
|
|
17
|
+
* rental: object, // the whole return of useRentalDuration
|
|
18
|
+
* startLabel?: string, // e.g. "Fri 4 Sep, 10:00" — what the customer already picked
|
|
19
|
+
* }} props
|
|
20
|
+
*/
|
|
21
|
+
export default function RentalDurationPicker({ rental, startLabel }) {
|
|
22
|
+
const { isRental, duration, options, selected, select, price, loading, error } = rental;
|
|
23
|
+
if (!isRental) return null;
|
|
24
|
+
|
|
25
|
+
const unitWord = duration?.unit === "DAY" ? "days" : "hours";
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className="mb-6">
|
|
29
|
+
<div className="mb-2 flex items-baseline justify-between gap-3">
|
|
30
|
+
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
|
31
|
+
How long{startLabel ? ` from ${startLabel}` : ""}
|
|
32
|
+
</p>
|
|
33
|
+
{price?.total ? (
|
|
34
|
+
<p className="text-sm font-semibold text-foreground">{price.total}</p>
|
|
35
|
+
) : selected ? (
|
|
36
|
+
<p className="text-sm text-muted-foreground">Pricing…</p>
|
|
37
|
+
) : null}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{loading ? (
|
|
41
|
+
<p className="text-sm text-muted-foreground">Loading available {unitWord}…</p>
|
|
42
|
+
) : error ? (
|
|
43
|
+
<p className="text-sm text-destructive">{error}</p>
|
|
44
|
+
) : !options.length ? (
|
|
45
|
+
// An empty list is a real answer: this start has no bookable length. Say so, and leave
|
|
46
|
+
// the start picker in place so the customer can choose another one.
|
|
47
|
+
<p className="text-sm text-muted-foreground">
|
|
48
|
+
Nothing available from that start — pick another time.
|
|
49
|
+
</p>
|
|
50
|
+
) : (
|
|
51
|
+
<div className="grid grid-cols-3 gap-2 sm:grid-cols-4">
|
|
52
|
+
{options.map((option) => (
|
|
53
|
+
<button
|
|
54
|
+
key={option.localEndDate}
|
|
55
|
+
type="button"
|
|
56
|
+
aria-pressed={selected?.localEndDate === option.localEndDate}
|
|
57
|
+
className={`${optionCls} ${selected?.localEndDate === option.localEndDate ? active : idle}`}
|
|
58
|
+
onClick={() => select(option)}
|
|
59
|
+
>
|
|
60
|
+
{option.label}
|
|
61
|
+
</button>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// useRentalDuration — the extra step a rental has and an ordinary service doesn't: once the
|
|
2
|
+
// customer has picked a START, they pick how LONG, and the price follows the length.
|
|
3
|
+
//
|
|
4
|
+
// Compose it with useServiceDetail rather than replacing it. That hook already loads the
|
|
5
|
+
// service, lists start times, holds the contact fields and runs bookAndCheckout — all of which
|
|
6
|
+
// a rental uses unchanged. This adds only the second choice and its price:
|
|
7
|
+
//
|
|
8
|
+
// const detail = useServiceDetail(serviceId); // service + start slots
|
|
9
|
+
// const rental = useRentalDuration(detail.service, detail.selectedSlot, detail.timeZone);
|
|
10
|
+
// // render detail.slots → customer picks a start → render rental.options → picks a length
|
|
11
|
+
// // book with rental.endDate as the slot's localEndDate
|
|
12
|
+
//
|
|
13
|
+
// Returns empty options for a non-rental service, so a page that renders both kinds needs no
|
|
14
|
+
// branch of its own — `isRental(service)` decides whether to show the length step at all.
|
|
15
|
+
import { useCallback, useEffect, useState } from "react";
|
|
16
|
+
import {
|
|
17
|
+
dailyEndOptions,
|
|
18
|
+
isRental,
|
|
19
|
+
listEndOptions,
|
|
20
|
+
previewRentalPrice,
|
|
21
|
+
rentalDuration,
|
|
22
|
+
} from "@/rest/wix-bookings-rentals";
|
|
23
|
+
|
|
24
|
+
/** "1 hr 30 min" / "2 days" — the label for one length option. */
|
|
25
|
+
function lengthLabel(startLocal, endLocal, unit) {
|
|
26
|
+
if (unit === "DAY") {
|
|
27
|
+
const days = Math.round((new Date(`${endLocal}Z`) - new Date(`${startLocal}Z`)) / 86400000);
|
|
28
|
+
return days === 1 ? "1 day" : `${days} days`;
|
|
29
|
+
}
|
|
30
|
+
const minutes = Math.round((new Date(`${endLocal}Z`) - new Date(`${startLocal}Z`)) / 60000);
|
|
31
|
+
const h = Math.floor(minutes / 60);
|
|
32
|
+
const m = minutes % 60;
|
|
33
|
+
return [h ? `${h} hr` : "", m ? `${m} min` : ""].filter(Boolean).join(" ") || "0 min";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {object|null} service The service from useServiceDetail — may be null while loading.
|
|
38
|
+
* @param {object|null} startSlot The slot the customer picked (its localStartDate is the start).
|
|
39
|
+
* @param {string|null} timeZone The zone the slot list came back in.
|
|
40
|
+
* @returns {{
|
|
41
|
+
* isRental: boolean,
|
|
42
|
+
* duration: { unit: "HOUR"|"DAY", min: number, max: number, step: number }|null,
|
|
43
|
+
* options: { localEndDate: string, label: string }[],
|
|
44
|
+
* selected: object|null,
|
|
45
|
+
* select: (option: object) => void,
|
|
46
|
+
* endDate: string|null, // pass as the booking's localEndDate
|
|
47
|
+
* price: { total: string, currency: string|null }|null,
|
|
48
|
+
* loading: boolean,
|
|
49
|
+
* error: string|null,
|
|
50
|
+
* }}
|
|
51
|
+
*/
|
|
52
|
+
export function useRentalDuration(service, startSlot, timeZone) {
|
|
53
|
+
const [options, setOptions] = useState([]);
|
|
54
|
+
const [selected, setSelected] = useState(null);
|
|
55
|
+
const [price, setPrice] = useState(null);
|
|
56
|
+
const [loading, setLoading] = useState(false);
|
|
57
|
+
const [error, setError] = useState(null);
|
|
58
|
+
|
|
59
|
+
const rental = isRental(service);
|
|
60
|
+
const duration = rentalDuration(service);
|
|
61
|
+
const start = startSlot?.localStartDate ?? null;
|
|
62
|
+
// Forward the chosen slot's own location to end-options.
|
|
63
|
+
const location = startSlot?.location ?? null;
|
|
64
|
+
const serviceId = service?._id || service?.id || null;
|
|
65
|
+
|
|
66
|
+
// A new start invalidates the lengths that were valid for the previous one.
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
setSelected(null);
|
|
69
|
+
setPrice(null);
|
|
70
|
+
if (!rental || !start || !serviceId) {
|
|
71
|
+
setOptions([]);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let alive = true;
|
|
75
|
+
setLoading(true);
|
|
76
|
+
setError(null);
|
|
77
|
+
const load = duration.unit === "DAY"
|
|
78
|
+
? dailyEndOptions(service, { localStartDate: start, timeZone })
|
|
79
|
+
.then((list) => list.map((o) => ({ localEndDate: o.localEndDate, label: lengthLabel(start, o.localEndDate, "DAY") })))
|
|
80
|
+
: listEndOptions(serviceId, { localStartDate: start, location, timeZone })
|
|
81
|
+
.then(({ endOptions }) =>
|
|
82
|
+
endOptions.map((o) => ({ localEndDate: o.localEndDate, label: lengthLabel(start, o.localEndDate, "HOUR") })),
|
|
83
|
+
);
|
|
84
|
+
load
|
|
85
|
+
.then((list) => {
|
|
86
|
+
if (!alive) return;
|
|
87
|
+
setOptions(list);
|
|
88
|
+
setLoading(false);
|
|
89
|
+
})
|
|
90
|
+
.catch((e) => {
|
|
91
|
+
if (!alive) return;
|
|
92
|
+
// Fail loudly — an empty length list and a failed call look identical on screen
|
|
93
|
+
// otherwise, and the second one is a bug the visitor should not absorb silently.
|
|
94
|
+
setError(e?.message || "Could not load available lengths.");
|
|
95
|
+
setOptions([]);
|
|
96
|
+
setLoading(false);
|
|
97
|
+
});
|
|
98
|
+
return () => {
|
|
99
|
+
alive = false;
|
|
100
|
+
};
|
|
101
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
|
+
}, [rental, serviceId, start, timeZone, duration?.unit]);
|
|
103
|
+
|
|
104
|
+
// The price comes from the server for the chosen length — never multiply the rate locally.
|
|
105
|
+
const select = useCallback(
|
|
106
|
+
(option) => {
|
|
107
|
+
setSelected(option);
|
|
108
|
+
setPrice(null);
|
|
109
|
+
if (!option || !serviceId || !start || !timeZone) return;
|
|
110
|
+
previewRentalPrice(serviceId, { localStartDate: start, localEndDate: option.localEndDate, timeZone })
|
|
111
|
+
.then((p) => setPrice({ total: p.total, currency: p.currency }))
|
|
112
|
+
.catch((e) => setError(e?.message || "Could not price that length."));
|
|
113
|
+
},
|
|
114
|
+
[serviceId, start, timeZone],
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
isRental: rental,
|
|
119
|
+
duration,
|
|
120
|
+
options,
|
|
121
|
+
selected,
|
|
122
|
+
select,
|
|
123
|
+
endDate: selected?.localEndDate ?? null,
|
|
124
|
+
price,
|
|
125
|
+
loading,
|
|
126
|
+
error,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -31,8 +31,9 @@ export function useServiceDetail(serviceId) {
|
|
|
31
31
|
const [error, setError] = useState(null);
|
|
32
32
|
|
|
33
33
|
useEffect(() => {
|
|
34
|
-
// getService returns null on a miss — show not-found, never invent a service.
|
|
35
|
-
|
|
34
|
+
// getService returns null on a miss — show not-found, never invent a service. A rejected
|
|
35
|
+
// request (network, 4xx) must also resolve the page to not-found, never leave it loading forever.
|
|
36
|
+
getService(serviceId).then((s) => (s ? setService(s) : setNotFound(true))).catch(() => setNotFound(true));
|
|
36
37
|
}, [serviceId]);
|
|
37
38
|
|
|
38
39
|
useEffect(() => {
|
|
@@ -41,7 +42,8 @@ export function useServiceDetail(serviceId) {
|
|
|
41
42
|
// returns { slots, nextCursor }. The LIST call takes fromLocalDate / toLocalDate — a different
|
|
42
43
|
// arg naming than the single-slot re-validate call (getAvailableSlot: localStartDate/localEndDate).
|
|
43
44
|
listSlotsForService(service, { fromLocalDate: localMidnight(0), toLocalDate: localMidnight(14) })
|
|
44
|
-
.then(({ slots, nextCursor, timeZone }) => { setSlots(slots); setCursor(nextCursor); setTimeZone(timeZone); })
|
|
45
|
+
.then(({ slots, nextCursor, timeZone }) => { setSlots(slots); setCursor(nextCursor); setTimeZone(timeZone); })
|
|
46
|
+
.catch(() => setSlots([]));
|
|
45
47
|
}, [service]);
|
|
46
48
|
|
|
47
49
|
const loadMoreSlots = useCallback(() => {
|