@wix/agent-skills 1.17.0 → 1.18.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 +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 +14 -3
- 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 +19 -1
- 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-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 +18 -2
- 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/stores/create-product-catalog-v3.md +21 -6
- 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 +23 -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 +470 -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 +1762 -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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rentals
|
|
3
|
+
description: Rentals — renting out an item for a length the customer picks. Runs on the Bookings vertical.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rentals
|
|
7
|
+
|
|
8
|
+
Rentals is **the Bookings vertical** — Wix Rentals runs on the Bookings APIs. There is nothing
|
|
9
|
+
separate to build here.
|
|
10
|
+
|
|
11
|
+
Read and follow `.agents/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md` (its
|
|
12
|
+
**Rentals** section), and use the bookings scaffolds under `references/bookings/app/`. The install
|
|
13
|
+
already deploys those for you when `rentals` is selected.
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Wix Storefront — ready-made client
|
|
2
2
|
|
|
3
|
-
The storefront
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
The storefront **commerce engine ships as real files** — the hooks, the server cart, the REST
|
|
4
|
+
transport, the image helpers, and the `Shop` listing page, all correct (variant resolution,
|
|
5
|
+
modifiers, stock gating, checkout). It reads from your app's design tokens (base44's `src/index.css`
|
|
6
|
+
— the shadcn palette the design phase already set).
|
|
7
|
+
|
|
8
|
+
**The presentation doesn't ship — you build it** (STEP 3): the product **card**, **grid**, **variant
|
|
9
|
+
controls**, and the whole **product (PDP) page**, plus **Home** and the **header/footer**. Each is
|
|
10
|
+
built on a shipped hook whose return type + field shapes are documented in the outline right next to
|
|
11
|
+
it — the data is handed to you done, the layout and look are yours. `Shop` renders once your
|
|
12
|
+
`ProductGrid` exists; the PDP renders once you build its page — that's the point.
|
|
8
13
|
|
|
9
14
|
Talks to Wix directly over the public `WIX_CLIENT_ID` (anonymous visitor tokens). Never mock
|
|
10
15
|
products; never hand-build a `/checkout` URL — the shipped cart goes through the eCom
|
|
@@ -22,40 +27,38 @@ so you don't need to open them:**
|
|
|
22
27
|
| file | what it is |
|
|
23
28
|
|---|---|
|
|
24
29
|
| `context/CartContext.jsx` | `useCart()` provider: server cart, add/update/remove, checkout |
|
|
25
|
-
| `hooks/useProductDetail.js` | PDP data — product + variant resolution for a slug, plus load/add state |
|
|
30
|
+
| `hooks/useProductDetail.js` | PDP data — product + variant resolution for a slug, plus load/add state; **your product page (STEP 3) is built on it** |
|
|
26
31
|
| `hooks/useShop.js` | catalog listing — category menu, cursor paging, sort, failure state |
|
|
27
|
-
| `hooks/useProductCard.js` | headless data layer for a grid tile — returns `leftBadges`, `promoBadge`, `priceDisplay`, `compareAtDisplay`, `colors`, `optionLabel`, `isQuickAddable`, `image`, `hoverImage`; **
|
|
28
|
-
| `
|
|
29
|
-
| `components/ProductGrid.jsx` | reference grid layout (2-col mobile → auto-fill desktop) with skeleton + empty state — read it for the skeleton/empty-state patterns, build your own layout rather than using it directly |
|
|
30
|
-
| `components/ProductGallery.jsx` | PDP main image + thumbnails |
|
|
31
|
-
| `lib/storeImage.js` | `productImage()` / `productGallery()` / `storeImage()` — normalise Wix image urls |
|
|
32
|
+
| `hooks/useProductCard.js` | headless data layer for a grid tile — returns `leftBadges`, `promoBadge`, `priceDisplay`, `compareAtDisplay`, `colors`, `optionLabel`, `isQuickAddable`, `image`, `hoverImage`; **your `ProductCard` (STEP 3) is built on it** |
|
|
33
|
+
| `lib/storeImage.js` | `productImage()` / `productGallery()` / `storeImage()` / `choiceImage()` — normalise Wix image urls; `productGallery(product)` → `[{ url, altText }]` (your PDP gallery); `choiceImage(choice)` resolves an option choice's photo (V3 read shape: `media.items[].mediaId`, not `linkedMedia`) |
|
|
32
34
|
| `components/CartButton.jsx` | header cart **icon** button with a live-count badge |
|
|
33
35
|
| `components/CartDrawer.jsx` | slide-over cart (mount once; opens from `useCart`) |
|
|
34
|
-
| `hooks/useVariantOptions.js` | headless data layer for options/modifiers — returns `optionGroups` + `modifierGroups` (normalised, render-agnostic); **
|
|
35
|
-
| `components/VariantPicker.jsx` | reference implementation of a variant selector built on `useVariantOptions` (pills + colour swatches) — read it for inspiration, but build your own component rather than using it directly |
|
|
36
|
+
| `hooks/useVariantOptions.js` | headless data layer for options/modifiers — returns `optionGroups` + `modifierGroups` (normalised, render-agnostic); **your PDP's variant controls (STEP 3) render from it** |
|
|
36
37
|
| `components/WixManageBanner.jsx` | preview-only manage banner — drop it into your Layout (STEP 3) |
|
|
37
|
-
| `pages/Shop.jsx
|
|
38
|
+
| `pages/Shop.jsx` | the shipped `/shop` listing page — renders your `ProductGrid` (you build `/product/:slug` and `/`) |
|
|
38
39
|
| `rest/wix-config.js` | the two ids, written by the install step |
|
|
39
40
|
| `rest/wix-client.js` + `rest/wix-store-*.js` | REST transport + catalog/cart helpers |
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
Everything in the table is already in place — go **straight to wiring + building your presentation**
|
|
43
|
+
(card, grid, variant controls, the product page, Home — STEP 3), nothing to verify first.
|
|
44
|
+
**Don't `read_file` the shipped page/hook source to inspect it** — the table says what each is and
|
|
45
|
+
every field shape you need is in the outlines below. Read a shipped file's source **only** on a real
|
|
46
|
+
fallback — a runtime error, or a field the outlines don't cover (see "Fallback only" at the end).
|
|
47
|
+
(Shipped files missing? the install's `deploy` result lists what it wrote; re-run install, or copy
|
|
46
48
|
`references/storefront/app/` → `src/`.)
|
|
47
49
|
|
|
48
50
|
|
|
49
|
-
## STEP 2 — Theme
|
|
50
|
-
The shipped
|
|
51
|
+
## STEP 2 — Theme
|
|
52
|
+
The shipped pages carry **no palette of their own** — they render from base44's design tokens
|
|
51
53
|
in `src/index.css` (`:root`/`.dark`: `--background`, `--foreground`, `--card`, `--primary`,
|
|
52
54
|
`--muted`, `--border`, `--radius`, `--font-*`) via shadcn Tailwind classes (`bg-card`,
|
|
53
55
|
`text-foreground`, `bg-primary`, `text-muted-foreground`, `border-border`, `rounded-lg`,
|
|
54
56
|
`font-display`). Those tokens are **already set to the brand by the design phase**, so the shipped
|
|
55
57
|
pages are themed with zero work here. To adjust the palette, edit `index.css` (`:root` **and**
|
|
56
58
|
`.dark`) — the base44 way; **never add a parallel theme file (e.g. a `theme.css`) or restyle the
|
|
57
|
-
shipped
|
|
58
|
-
matches automatically. A dark brand is just base44's
|
|
59
|
+
shipped pages.** Style the components you build (STEP 3) and the Home/Header you add from the
|
|
60
|
+
**same** base44 tokens/classes so everything matches automatically. A dark brand is just base44's
|
|
61
|
+
dark palette in `index.css` — no per-component work.
|
|
59
62
|
|
|
60
63
|
## STEP 3 — Wire routes + provider (surgical `find_replace` on `src/App.jsx`, never a rewrite)
|
|
61
64
|
**No file reads needed to wire this.** Every shipped page and `WixManageBanner` is a default export that takes **no props** — wire them exactly as the snippet shows; nothing in those files needs looking up.
|
|
@@ -64,77 +67,126 @@ replace it.
|
|
|
64
67
|
- Wrap the routed tree in `<CartProvider>` (from `@/context/CartContext`).
|
|
65
68
|
- Put your **header + footer in a `Layout`** that renders `<Outlet/>` between them, and nest every
|
|
66
69
|
route under one pathless `<Route element={<Layout/>}>`. Your brand chrome then wraps **every** page
|
|
67
|
-
— including the shipped `Shop`
|
|
68
|
-
header/footer** (
|
|
70
|
+
— including the shipped `Shop` and your own pages — so you **never edit the shipped `Shop` to add a
|
|
71
|
+
header/footer** (it renders inside `<Outlet/>` as-is). Mount `<CartDrawer/>` once in the Layout.
|
|
69
72
|
- **Pin the top chrome as one fixed block.** Put `<WixManageBanner/>` (shipped, preview-only) **above**
|
|
70
73
|
your `<Header/>` inside a single `position:fixed` top region — the header itself is plain in-flow
|
|
71
74
|
markup, the region owns the fixing — so banner + header ride together (no scroll drift/gap). Pad
|
|
72
75
|
the content by the region's measured height so it clears the chrome and self-corrects when the
|
|
73
76
|
banner is dismissed.
|
|
74
|
-
- Routes under the Layout: `/shop` → `Shop
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
- Routes under the Layout: `/shop` → `Shop` (shipped, renders your grid); `/product/:slug` → **your
|
|
78
|
+
`ProductDetail`**; `/` → **your `Home`**.
|
|
79
|
+
|
|
80
|
+
**Build the presentation — it's all yours.** Each piece below is built on a shipped hook whose return
|
|
81
|
+
type + field shapes are in the outline right after this list — the data is done, the render is yours.
|
|
82
|
+
`Shop` won't show products until `ProductGrid` exists, and `/product/:slug` won't render until you
|
|
83
|
+
build the product page, so these aren't optional:
|
|
84
|
+
|
|
85
|
+
- **`components/ProductGrid.jsx`** — `Shop` and your Home render it. It receives `products`, `loading`,
|
|
86
|
+
`empty`, `emptyHint` and owns three states (loading, empty, list) plus the layout. A boutique might
|
|
87
|
+
want a 3-col editorial layout; a high-volume store a dense 4-col grid; a home strip a horizontal scroll.
|
|
88
|
+
- **`components/ProductCard.jsx`** — your grid maps each product to it. Built on `useProductCard`
|
|
89
|
+
(badges, price display, colour dots, quick-add flag, images) — you decide layout, shape, hover, CTA.
|
|
90
|
+
A lifestyle brand might want full-bleed images with an overlay gradient; a tech store a compact item.
|
|
91
|
+
- **`pages/ProductDetail.jsx`** — the **whole product page**, built on `useProductDetail`; route
|
|
92
|
+
`/product/:slug` to it. Gallery, price, description, the variant controls (options/modifiers via
|
|
93
|
+
`useVariantOptions`), the buy box — you arrange and style all of it (nothing PDP ships). This is the
|
|
94
|
+
surface that usually looks most generic, so make the layout the brand's: an editorial split, a sticky
|
|
95
|
+
buy column, a full-bleed gallery, large swatches vs a compact dropdown — your call.
|
|
79
96
|
|
|
80
97
|
```jsx
|
|
98
|
+
// components/ProductCard.jsx — your grid maps each product to it.
|
|
81
99
|
import { Link } from "react-router-dom";
|
|
82
|
-
import { useCart } from "@/context/CartContext";
|
|
100
|
+
import { useCart } from "@/context/CartContext"; // addToCart(product.id) for quick-add
|
|
83
101
|
import { useProductCard } from "@/hooks/useProductCard";
|
|
84
102
|
|
|
85
|
-
export default function
|
|
103
|
+
export default function ProductCard({ product }) {
|
|
86
104
|
const { addToCart } = useCart();
|
|
87
105
|
const {
|
|
88
106
|
isSoldOut, isPreorder,
|
|
89
|
-
leftBadges, // [{ type: 'pre-order'|'sold-out'|'limited-stock', label }] —
|
|
90
|
-
promoBadge, // { type: 'discount'|'ribbon', label } | null —
|
|
91
|
-
priceDisplay, // "€10"
|
|
92
|
-
compareAtDisplay, // original price string | null
|
|
93
|
-
colors, // hex strings →
|
|
94
|
-
optionLabel, // "3 sizes · 2 materials"
|
|
95
|
-
isQuickAddable, // true
|
|
96
|
-
image,
|
|
97
|
-
hoverImage, // second image URL | null
|
|
107
|
+
leftBadges, // [{ type: 'pre-order'|'sold-out'|'limited-stock', label }] — image top-left
|
|
108
|
+
promoBadge, // { type: 'discount'|'ribbon', label } | null — image top-right
|
|
109
|
+
priceDisplay, // "€10" | "€10 – €20" (range when variants differ)
|
|
110
|
+
compareAtDisplay, // original price string | null — strike-through
|
|
111
|
+
colors, // hex strings → colour dots
|
|
112
|
+
optionLabel, // "3 sizes · 2 materials" | ""
|
|
113
|
+
isQuickAddable, // true → addToCart(product.id); else <Link to={`/product/${product.slug}`}>
|
|
114
|
+
image, hoverImage,// URLs | null
|
|
98
115
|
} = useProductCard(product);
|
|
99
|
-
|
|
100
|
-
// Then render however you want:
|
|
101
|
-
return (
|
|
102
|
-
<div>
|
|
103
|
-
{/* image, badges, price, colour dots, quick-add or "Choose options" CTA */}
|
|
104
|
-
{isQuickAddable && <button onClick={() => addToCart(product.id)}>Quick add</button>}
|
|
105
|
-
{!isQuickAddable && !isSoldOut && <Link to={`/product/${product.slug}`}>Choose options</Link>}
|
|
106
|
-
{isSoldOut && isPreorder && <Link to={`/product/${product.slug}`}>Pre-order</Link>}
|
|
107
|
-
</div>
|
|
108
|
-
);
|
|
116
|
+
// …you implement the tile.
|
|
109
117
|
}
|
|
110
118
|
```
|
|
111
119
|
|
|
112
120
|
```jsx
|
|
121
|
+
// Variant controls — render the product's options/modifiers from useVariantOptions.
|
|
122
|
+
// The inputs (options, modifiers, selectedOptions, modifierValues) come from useProductDetail (below).
|
|
113
123
|
import { useVariantOptions } from "@/hooks/useVariantOptions";
|
|
114
124
|
|
|
115
|
-
// options/modifiers/selectedOptions/modifierValues come from useProductDetail:
|
|
116
125
|
const { optionGroups, modifierGroups } = useVariantOptions(options, modifiers, selectedOptions, modifierValues);
|
|
117
|
-
|
|
118
|
-
// optionGroups: [{ id, name, isColor, choices: [{ choiceId, name, colorCode, isColorSwatch, inStock, selected }] }]
|
|
126
|
+
// optionGroups: [{ id, name, isColor, choices: [{ choiceId, name, colorCode, isColorSwatch, inStock, selected }] }]
|
|
119
127
|
// modifierGroups: [{ key, name, mandatory, type: 'choices'|'text', choices?: [{ key, name, selected }], value?: string }]
|
|
128
|
+
// pick a choice: selectOption(group.id, choice.choiceId)
|
|
129
|
+
// set a modifier: setModifier(m.key, choice.key) · text type: setModifier(m.key, e.target.value)
|
|
130
|
+
```
|
|
120
131
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
```jsx
|
|
133
|
+
// components/ProductGrid.jsx — Shop and your Home render it.
|
|
134
|
+
import ProductCard from "./ProductCard"; // your card, above
|
|
135
|
+
|
|
136
|
+
export default function ProductGrid({ products, loading, empty, emptyHint }) {
|
|
137
|
+
// products — array | null (null while loading)
|
|
138
|
+
// loading — boolean
|
|
139
|
+
// empty — heading string for the no-products state
|
|
140
|
+
// emptyHint — sub-text string for the no-products state
|
|
141
|
+
// …you implement: the loading state, the empty state (empty + emptyHint), and the layout
|
|
142
|
+
// mapping products → <ProductCard product={p} />.
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```jsx
|
|
147
|
+
// pages/ProductDetail.jsx — YOU build the whole product page. Route `/product/:slug` to it.
|
|
148
|
+
// A thin view over useProductDetail: keep the data logic in the hook, render however fits the brand.
|
|
149
|
+
import { useMemo } from "react";
|
|
150
|
+
import { useParams, Link } from "react-router-dom";
|
|
151
|
+
import { useProductDetail } from "@/hooks/useProductDetail";
|
|
152
|
+
import { productGallery } from "@/lib/storeImage";
|
|
153
|
+
|
|
154
|
+
export default function ProductDetail() {
|
|
155
|
+
const { slug } = useParams();
|
|
156
|
+
const d = useProductDetail(slug);
|
|
157
|
+
// useProductDetail(slug) returns:
|
|
158
|
+
// product Wix product | null (loading) — has .name, .plainDescription (HTML), .slug
|
|
159
|
+
// notFound bool — dead link (distinct from error)
|
|
160
|
+
// error string | null — failed load; call retry() to reload
|
|
161
|
+
// retry () => void
|
|
162
|
+
// price formatted string, follows the selection ("€24.00")
|
|
163
|
+
// compareAtPrice formatted string — a "was" price; strike it only when it differs from price
|
|
164
|
+
// options, modifiers → feed useVariantOptions for the variant controls (block above)
|
|
165
|
+
// selectedOptions, selectOption, modifierValues, setModifier → also for the variant controls
|
|
166
|
+
// variant resolved variant | null (null until every option is picked)
|
|
167
|
+
// focusMediaUrl image url for the selected choice — make the gallery show it
|
|
168
|
+
// quantity, setQuantity(n) number (may be "" mid-edit) — keep min 1
|
|
169
|
+
// inStock, canAdd, adding booleans that gate the buy button
|
|
170
|
+
// submit async () => adds the resolved variant + quantity + modifiers to the cart
|
|
171
|
+
const images = useMemo(() => productGallery(d.product), [d.product]); // [{ url, altText }], main first, de-duped
|
|
172
|
+
|
|
173
|
+
// …you implement the page. Handle in order:
|
|
174
|
+
// error → show d.error + a retry button (onClick={d.retry})
|
|
175
|
+
// notFound → a "not found" message + a <Link to="/shop">
|
|
176
|
+
// !product → a loading placeholder
|
|
177
|
+
// else the product view, laid out to fit the brand:
|
|
178
|
+
// • gallery from `images` — main + thumbnails, a carousel, a full-bleed hero (your call);
|
|
179
|
+
// make the shown image follow d.focusMediaUrl when a choice is selected
|
|
180
|
+
// • d.product.name · d.price (strike d.compareAtPrice when it differs) ·
|
|
181
|
+
// d.product.plainDescription (HTML → dangerouslySetInnerHTML)
|
|
182
|
+
// • variant controls — render d.options/d.modifiers via useVariantOptions (block above);
|
|
183
|
+
// d.selectOption / d.setModifier update the selection
|
|
184
|
+
// • a "pick an option to continue" hint when d.options.length && !d.variant
|
|
185
|
+
// • a quantity control (d.quantity / d.setQuantity, min 1 — a −/+ stepper reads better than a
|
|
186
|
+
// native number input) + the buy button:
|
|
187
|
+
// <button disabled={!d.canAdd || d.adding} onClick={d.submit}>
|
|
188
|
+
// {d.adding ? "Adding…" : d.inStock ? "Add to cart" : "Out of stock"}</button>
|
|
189
|
+
}
|
|
138
190
|
```
|
|
139
191
|
|
|
140
192
|
```jsx
|
|
@@ -144,7 +196,7 @@ import { CartProvider } from "@/context/CartContext";
|
|
|
144
196
|
import CartDrawer from "@/components/CartDrawer";
|
|
145
197
|
import WixManageBanner from "@/components/WixManageBanner"; // shipped, preview-only · default export, no props
|
|
146
198
|
import Shop from "@/pages/Shop"; // shipped · default export, no props
|
|
147
|
-
import ProductDetail from "@/pages/ProductDetail"; //
|
|
199
|
+
import ProductDetail from "@/pages/ProductDetail"; // YOU build
|
|
148
200
|
import Home from "@/pages/Home"; // YOU build
|
|
149
201
|
import Header from "@/components/Header"; // YOU build — plain in-flow markup, NOT position:fixed
|
|
150
202
|
import Footer from "@/components/Footer"; // YOU build
|
|
@@ -163,7 +215,7 @@ function Layout() {
|
|
|
163
215
|
<Header /> {/* your brand header, in-flow inside this fixed block */}
|
|
164
216
|
</div>
|
|
165
217
|
<div style={{ paddingTop: offset }}> {/* clears the chrome; shrinks when the banner is dismissed */}
|
|
166
|
-
<Outlet /> {/* shipped Shop
|
|
218
|
+
<Outlet /> {/* shipped Shop + your pages render here */}
|
|
167
219
|
<Footer />
|
|
168
220
|
</div>
|
|
169
221
|
<CartDrawer /> {/* overlays every page */}
|
|
@@ -175,7 +227,7 @@ function Layout() {
|
|
|
175
227
|
<Route element={<Layout />}> {/* chrome wraps all */}
|
|
176
228
|
<Route path="/" element={<Home />} /> {/* yours */}
|
|
177
229
|
<Route path="/shop" element={<Shop />} /> {/* shipped, as-is */}
|
|
178
|
-
<Route path="/product/:slug" element={<ProductDetail />} /> {/*
|
|
230
|
+
<Route path="/product/:slug" element={<ProductDetail />} /> {/* yours */}
|
|
179
231
|
</Route>
|
|
180
232
|
</Routes>
|
|
181
233
|
</CartProvider>
|
|
@@ -184,8 +236,8 @@ function Layout() {
|
|
|
184
236
|
## What you build (not shipped)
|
|
185
237
|
The **home / landing page**, the **`Header`** (mount `<CartButton/>` in it) and a **`Footer`** — the
|
|
186
238
|
two you drop into the `Layout` (STEP 3) so they wrap every route — plus the overall brand story,
|
|
187
|
-
styled from the same base44 tokens/classes. **
|
|
188
|
-
featured strip is just `queryProducts` +
|
|
239
|
+
styled from the same base44 tokens/classes. **Reuse your own `ProductGrid`** (STEP 3) and the shipped
|
|
240
|
+
cart pieces — a featured strip is just `queryProducts` + your `ProductGrid`; the nav is a `<CartButton/>`
|
|
189
241
|
(a clean cart-**icon** button with a live-count badge — render it as-is, don't wrap it in your own
|
|
190
242
|
text button) + a link to `/shop`:
|
|
191
243
|
|
|
@@ -193,8 +245,8 @@ text button) + a link to `/shop`:
|
|
|
193
245
|
import { useState, useEffect } from "react";
|
|
194
246
|
import { Link } from "react-router-dom";
|
|
195
247
|
import { queryProducts } from "@/rest/wix-store-catalog";
|
|
196
|
-
import ProductGrid from "@/components/ProductGrid";
|
|
197
|
-
import CartButton from "@/components/CartButton";
|
|
248
|
+
import ProductGrid from "@/components/ProductGrid"; // yours (STEP 3)
|
|
249
|
+
import CartButton from "@/components/CartButton"; // shipped
|
|
198
250
|
|
|
199
251
|
// Responsive header: choose ONE branch with a state flag, so <CartButton/> mounts once.
|
|
200
252
|
// Do NOT render a desktop nav AND a mobile nav toggled by `hidden md:flex` / `md:hidden`:
|
|
@@ -268,7 +320,7 @@ function CartCount() { // header badge
|
|
|
268
320
|
return <button onClick={() => setIsOpen(true)}>Cart ({itemCount})</button>;
|
|
269
321
|
}
|
|
270
322
|
|
|
271
|
-
// Buy from a card → link to the PDP;
|
|
323
|
+
// Buy from a card → link to the PDP; your ProductDetail (on useProductDetail) owns options/variants + add-to-cart.
|
|
272
324
|
// (Listing helpers return no variants — only getProductBySlug does — so buying happens on the PDP.)
|
|
273
325
|
const CardBuy = ({ product }) => <Link to={`/product/${product.slug}`}>View</Link>;
|
|
274
326
|
|
|
@@ -313,8 +365,8 @@ reference page inline; these are the areas they sit in:
|
|
|
313
365
|
- Headless redirect session (hosted checkout): https://dev.wix.com/docs/api-reference/business-management/headless/redirects.md
|
|
314
366
|
|
|
315
367
|
## Hard rules
|
|
316
|
-
- Style via base44 design tokens (`index.css` / shadcn Tailwind classes), never by rewriting the shipped
|
|
317
|
-
- Header/footer live in a `Layout` around `<Outlet/>` (STEP 3) — never edit the shipped `Shop
|
|
368
|
+
- Style via base44 design tokens (`index.css` / shadcn Tailwind classes), never by rewriting the shipped pages or adding a parallel theme file. Everything you build (card, grid, PDP, variant controls, Home) draws from the same tokens.
|
|
369
|
+
- Header/footer live in a `Layout` around `<Outlet/>` (STEP 3) — never edit the shipped `Shop` to add chrome.
|
|
318
370
|
- The Layout's fixed top region owns positioning: `<WixManageBanner/>` above `<Header/>`; your `Header` is plain in-flow markup (not `position:fixed`).
|
|
319
371
|
- Checkout goes through the shipped cart (redirect-session) — never a hand-built `/checkout` URL.
|
|
320
372
|
- Render live Wix data or the shipped empty state — never mock products.
|
|
@@ -330,9 +382,10 @@ client build; run in parallel.
|
|
|
330
382
|
|
|
331
383
|
## Verify (before declaring done)
|
|
332
384
|
- [ ] Client files copied into `src/`; `WIX_CLIENT_ID` set (not the placeholder).
|
|
333
|
-
- [ ]
|
|
334
|
-
- [ ]
|
|
335
|
-
- [ ] `
|
|
385
|
+
- [ ] **The pieces you own exist and are wired:** `components/ProductCard.jsx`, `components/ProductGrid.jsx` (imported by `Shop` + your Home), and `pages/ProductDetail.jsx` (routed at `/product/:slug`, with working variant controls). `/shop` and a PDP compile and render (they won't until these exist).
|
|
386
|
+
- [ ] Brand palette lives in `index.css` (`:root`/`.dark`); no parallel theme file; the shipped `Shop` page not restyled or rewritten.
|
|
387
|
+
- [ ] **Opened `/shop` and a product detail page** (not just the home page) and confirmed your cards render themed (surface, text, brand color) with images; the grid shows its loading + empty states; the PDP shows the gallery, price, variant controls, and add-to-cart, and its error/not-found/loading states hold.
|
|
388
|
+
- [ ] `Layout` (fixed `<WixManageBanner/>` + `<Header/>` region, then `<Outlet/>` + Footer) wraps all routes; the shipped `Shop` untouched; content clears the fixed chrome; `<CartProvider>` wraps the tree; `<CartDrawer/>` mounted; `<CartButton/>` in the header.
|
|
336
389
|
- [ ] Cart survives reload (same visitor); add / update-qty / remove work; checkout redirects; the drawer shows a **subtotal**.
|
|
337
390
|
- [ ] Empty catalog shows the shipped empty state; no mock products anywhere.
|
|
338
391
|
- [ ] A product with several images shows **thumbnails** on the PDP, and one with per-variant prices shows a **range** on its card.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// renders what this returns.
|
|
6
6
|
import { useState, useEffect, useMemo } from "react";
|
|
7
7
|
import { getProductBySlug } from "@/rest/wix-store-catalog";
|
|
8
|
-
import {
|
|
8
|
+
import { choiceImage, variantImage } from "@/lib/storeImage";
|
|
9
9
|
import { useCart } from "@/context/CartContext";
|
|
10
10
|
|
|
11
11
|
export function useProductDetail(slug) {
|
|
@@ -61,19 +61,26 @@ export function useProductDetail(slug) {
|
|
|
61
61
|
m.modifierRenderType === "FREE_TEXT" ? !!modifierValues[m.freeTextSettings?.key] : !!modifierValues[m.key]);
|
|
62
62
|
}, [options, variant, inStock, modifiers, modifierValues]);
|
|
63
63
|
|
|
64
|
+
// Everything the buyer sees follows the resolved `variant` (also returned below, so an agent can
|
|
65
|
+
// surface more from it — sku, barcode, subscriptionPricesInfo — without new plumbing). Price and
|
|
66
|
+
// its struck-through "was" price come off the variant, falling back to the product's range before
|
|
67
|
+
// every option is picked.
|
|
64
68
|
const price = variant?.price?.actualPrice?.formattedAmount || product?.actualPriceRange?.minValue?.formattedAmount || "";
|
|
69
|
+
const compareAtPrice = variant?.price?.compareAtPrice?.formattedAmount || product?.compareAtPriceRange?.minValue?.formattedAmount || "";
|
|
65
70
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
71
|
+
// The gallery follows the selection. Prefer the selected choice's own image (the per-swatch photo,
|
|
72
|
+
// choice.media.items[].mediaId) — Wix's per-variant media is often NOT differentiated (it defaults to
|
|
73
|
+
// the product's main image), so preferring the variant would override the correct choice image for
|
|
74
|
+
// every colour. Fall back to the resolved variant's image only when no chosen option carries one.
|
|
75
|
+
// See lib/storeImage: choiceImage() / variantImage().
|
|
69
76
|
const focusMediaUrl = useMemo(() => {
|
|
70
77
|
for (const o of options) {
|
|
71
78
|
const choice = (o.choicesSettings?.choices || []).find((c) => c.choiceId === selectedOptions[o.id]);
|
|
72
|
-
const url =
|
|
79
|
+
const url = choiceImage(choice);
|
|
73
80
|
if (url) return url;
|
|
74
81
|
}
|
|
75
|
-
return
|
|
76
|
-
}, [options, selectedOptions]);
|
|
82
|
+
return variantImage(variant);
|
|
83
|
+
}, [variant, options, selectedOptions]);
|
|
77
84
|
|
|
78
85
|
const selectOption = (optionId, choiceId) => setSelectedOptions((s) => ({ ...s, [optionId]: choiceId }));
|
|
79
86
|
const setModifier = (key, value) => setModifierValues((s) => ({ ...s, [key]: value }));
|
|
@@ -104,6 +111,6 @@ export function useProductDetail(slug) {
|
|
|
104
111
|
product, notFound, error, retry: () => setReloadKey((k) => k + 1),
|
|
105
112
|
options, modifiers,
|
|
106
113
|
selectedOptions, selectOption, modifierValues, setModifier,
|
|
107
|
-
quantity, setQuantity, variant, inStock, canAdd, adding, price, submit, focusMediaUrl,
|
|
114
|
+
quantity, setQuantity, variant, inStock, canAdd, adding, price, compareAtPrice, submit, focusMediaUrl,
|
|
108
115
|
};
|
|
109
116
|
}
|
|
@@ -10,6 +10,43 @@ export function storeImage(value) {
|
|
|
10
10
|
return url;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// A Wix media id (e.g. "abc123~mv2.jpg") is NOT a URL — build the static CDN url for it.
|
|
14
|
+
export function wixMediaUrl(mediaId) {
|
|
15
|
+
if (!mediaId || typeof mediaId !== "string") return null;
|
|
16
|
+
if (mediaId.startsWith("http") || mediaId.startsWith("//")) return storeImage(mediaId);
|
|
17
|
+
return `https://static.wixstatic.com/media/${mediaId}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The media id inside a Wix image url (…/media/<id>/v1/… or a bare …/media/<id>). Compare two urls of
|
|
21
|
+
// the SAME image that differ only in sizing/format params by their id, not full-string equality.
|
|
22
|
+
export function wixMediaId(url) {
|
|
23
|
+
const m = typeof url === "string" && url.match(/\/media\/([^/?]+)/);
|
|
24
|
+
return m ? m[1] : url;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The image assigned to a product OPTION CHOICE (e.g. a colour swatch). The storefront fetches with the
|
|
28
|
+
// PRODUCT_CHOICES_MEDIA_REFERENCES field, so Wix returns the choice image at choice.media.items[].mediaId
|
|
29
|
+
// and returns choice.linkedMedia EMPTY. Read media.items — do NOT switch this to choice.linkedMedia even
|
|
30
|
+
// if a direct admin/API probe shows linkedMedia populated: a probe made WITHOUT that field mask returns
|
|
31
|
+
// linkedMedia, but the storefront requests the mask, which blanks linkedMedia and returns media.items.
|
|
32
|
+
export function choiceImage(choice) {
|
|
33
|
+
const mediaId = choice?.media?.items?.[0]?.mediaId;
|
|
34
|
+
return mediaId ? wixMediaUrl(mediaId) : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The image for a resolved VARIANT (a full choice combination). Wix computes variant.media from the
|
|
38
|
+
// picked choices' media, so this is the exact image for the current selection — prefer it over a
|
|
39
|
+
// single choice's image once all options are chosen.
|
|
40
|
+
// ⚠️ Read `media.image.url` (the URL the API already returns), or build from `media.id` — the
|
|
41
|
+
// `~mv2` file id. NOT `media.uploadId`: that's a dashed GUID (the id the file was uploaded with),
|
|
42
|
+
// and https://static.wixstatic.com/media/<uploadId> is a 403. Variants without media (a fresh
|
|
43
|
+
// template's demo products) return null, and the caller falls back to the choice's own image.
|
|
44
|
+
export function variantImage(variant) {
|
|
45
|
+
const m = variant?.media;
|
|
46
|
+
if (!m) return null;
|
|
47
|
+
return storeImage(m.image?.url) || wixMediaUrl(m.id) || storeImage(m.thumbnail?.url);
|
|
48
|
+
}
|
|
49
|
+
|
|
13
50
|
// The main catalog image for a product (grid tiles, cart fallbacks).
|
|
14
51
|
export function productImage(product) {
|
|
15
52
|
return storeImage(product?.media?.main?.image?.url);
|
|
@@ -30,12 +30,13 @@ import { wixApiRequest } from "./wix-client.js";
|
|
|
30
30
|
* options {array} — product options e.g. Size, Color:
|
|
31
31
|
* [{ id, name, optionRenderType "TEXT_CHOICES"|"COLOR_CHOICES"|"SWATCH_CHOICES",
|
|
32
32
|
* choicesSettings.choices [{ choiceId, key, name, inStock, visible, choiceType, colorCode,
|
|
33
|
-
*
|
|
33
|
+
* media }] }],
|
|
34
34
|
* A COLOR/SWATCH option's choices carry choiceType "ONE_COLOR" and colorCode "#395E55" — render
|
|
35
|
-
* those as real colour swatches, not text pills.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* those as real colour swatches, not text pills. A choice's photo is at media.items[].mediaId (a
|
|
36
|
+
* bare Wix media id — build https://static.wixstatic.com/media/<id>); use choiceImage() from
|
|
37
|
+
* lib/storeImage to resolve it. Needs the PRODUCT_CHOICES_MEDIA_REFERENCES field (requested by
|
|
38
|
+
* getProductBySlug below). visible false is a retired choice the merchant no longer sells: filter
|
|
39
|
+
* it out. (TEXT_CHOICES choices are choiceType "CHOICE_TEXT" with no colorCode.)
|
|
39
40
|
* modifiers {array} — non-variant customizations (engraving, gift wrap):
|
|
40
41
|
* [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
|
|
41
42
|
* key, choicesSettings.choices, freeTextSettings.key }],
|
|
@@ -85,7 +86,18 @@ export async function queryProducts({ limit = 100, cursor } = {}) {
|
|
|
85
86
|
export async function getProductBySlug(slug) {
|
|
86
87
|
const res = await wixApiRequest(`/stores/v3/products/slug/${encodeURIComponent(slug)}`, {
|
|
87
88
|
method: "GET",
|
|
88
|
-
|
|
89
|
+
// PRODUCT_CHOICES_MEDIA_REFERENCES → choice.media.items[].mediaId (the per-colour photos, needed
|
|
90
|
+
// for the swatch→gallery swap); VARIANT_OPTION_CHOICE_NAMES → variant choice names. Without these
|
|
91
|
+
// the choice media / variant data come back null.
|
|
92
|
+
query: {
|
|
93
|
+
fields: [
|
|
94
|
+
"CURRENCY",
|
|
95
|
+
"PLAIN_DESCRIPTION",
|
|
96
|
+
"MEDIA_ITEMS_INFO",
|
|
97
|
+
"PRODUCT_CHOICES_MEDIA_REFERENCES",
|
|
98
|
+
"VARIANT_OPTION_CHOICE_NAMES",
|
|
99
|
+
],
|
|
100
|
+
},
|
|
89
101
|
});
|
|
90
102
|
return res?.product ?? null;
|
|
91
103
|
}
|
|
@@ -4,6 +4,10 @@ Seed a Wix Stores catalog by **calling `seed-store.js`** — don't hand-write th
|
|
|
4
4
|
a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Stores
|
|
5
5
|
seed operation. Load it and call **`setupStore` — the one-call path** — with plain data.
|
|
6
6
|
|
|
7
|
+
**Match each product's type to what the buyer receives** (the example shows both). *Access* — a
|
|
8
|
+
membership, or an online course/program the buyer enrolls in — isn't a store product at all; that's
|
|
9
|
+
the `pricing-plans` vertical, not here.
|
|
10
|
+
|
|
7
11
|
```js
|
|
8
12
|
// build-time exec_tool
|
|
9
13
|
const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix");
|
|
@@ -22,12 +26,15 @@ const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
|
|
|
22
26
|
// generate_image runs in the background while you build, so the urls are ready by seed time.
|
|
23
27
|
const result = await seed.setupStore(ctx, {
|
|
24
28
|
products: [
|
|
29
|
+
// physical — a shipped item: carries `quantity` (the default type)
|
|
25
30
|
{ name: "The Glam Rocker", description: "Sequin-studded velvet legend…", price: 49.99, quantity: 12, imageUrl: imageUrls[0] },
|
|
26
31
|
// a product with buyer choices — see "Options, variants and sale prices" below
|
|
27
32
|
{ name: "The Understudy", description: "…", price: 245, quantity: 8, imageUrl: imageUrls[1],
|
|
28
33
|
options: [{ name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] }] },
|
|
29
34
|
// a product on sale — compareAtPrice drives the strikethrough + the tile's percent-off badge
|
|
30
35
|
{ name: "Encore Jacket", description: "…", price: 68, compareAtPrice: 129, quantity: 5, imageUrl: imageUrls[2] },
|
|
36
|
+
// digital — a file the buyer downloads & keeps (ebook, PDF, video): `digitalFileUrl`, NO `quantity`
|
|
37
|
+
{ name: "Backstage Guide", description: "…", price: 12, digitalFileUrl: "https://…/guide.pdf" },
|
|
31
38
|
],
|
|
32
39
|
categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
|
|
33
40
|
});
|
|
@@ -37,13 +44,15 @@ const result = await seed.setupStore(ctx, {
|
|
|
37
44
|
**Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
|
|
38
45
|
"sample" data, don't reset. Just add.
|
|
39
46
|
|
|
40
|
-
##
|
|
47
|
+
## How many, and exercising the UI
|
|
48
|
+
|
|
49
|
+
**Default to 3 products** unless the brief asks for a specific catalog — the seed shows the shape,
|
|
50
|
+
not a full inventory; the owner adds the rest later, from the Wix dashboard or by asking you for more.
|
|
41
51
|
|
|
42
52
|
The shipped storefront renders colour options as real swatches, shows a size/colour summary on each
|
|
43
53
|
tile, and puts a percent-off badge on a discounted product. A catalog of plain single-price products
|
|
44
|
-
leaves all of that invisible, so **
|
|
45
|
-
|
|
46
|
-
to the business — a ceramics studio has glaze colours, a bakery does not.
|
|
54
|
+
leaves all of that invisible, so **make those 3 exercise it**: unless the brief says otherwise, give
|
|
55
|
+
at least one product a colour option and put one product on sale. Keep it truthful to the business.
|
|
47
56
|
|
|
48
57
|
```js
|
|
49
58
|
options: [
|
|
@@ -60,13 +69,27 @@ options: [
|
|
|
60
69
|
- `compareAtPrice` (> `price`) is the "was" price: strikethrough on the PDP and a `−N%` badge on the
|
|
61
70
|
tile, computed from the two amounts. It works with or without options.
|
|
62
71
|
|
|
72
|
+
## Digital downloads
|
|
73
|
+
|
|
74
|
+
**Pick the product type from what the buyer receives.** A shipped physical item is the default. A
|
|
75
|
+
**downloadable file the buyer keeps** — ebook, PDF guide, template, preset pack, printable, music
|
|
76
|
+
track, downloadable video — is a **digital** product: pass its file as `digitalFileUrl`. Selling
|
|
77
|
+
*access* rather than a file — a membership, subscription, or an online course/program the buyer
|
|
78
|
+
enrolls in — is **Pricing Plans**, not a Stores product, so it isn't seeded here.
|
|
79
|
+
|
|
80
|
+
`digitalFileUrl` (plus `digitalFileName` when the url carries no filename) makes a product a digital
|
|
81
|
+
download — uploaded and created with both the file and stock, which is what the cart requires
|
|
82
|
+
(`quantity` is ignored). It's also the only way in: a file-less digital product is created
|
|
83
|
+
successfully, reads back healthy, and is then rejected at add-to-cart as `ITEM_NOT_FOUND_IN_CATALOG`.
|
|
84
|
+
|
|
63
85
|
Two things this module does **not** seed, so don't try:
|
|
64
86
|
|
|
65
87
|
- **Ribbons** ("New", "Best Seller"). The tile renders `product.ribbon` when it's there, but ribbons
|
|
66
88
|
are set in the Wix dashboard — tell the merchant that's where to add them.
|
|
67
|
-
- **Per-choice
|
|
68
|
-
|
|
69
|
-
the
|
|
89
|
+
- **Per-choice media** — the photo that makes picking a choice swap the gallery image. Seeded swatches
|
|
90
|
+
select and price correctly; the gallery follows a choice once photos are linked to it (Wix dashboard,
|
|
91
|
+
or the wix-manage "Update Product with Options" recipe → Choice & variant fields). The shipped PDP then
|
|
92
|
+
follows automatically — `choiceImage()` reads it back at `media.items[].mediaId`.
|
|
70
93
|
|
|
71
94
|
## Escape hatch — individual functions
|
|
72
95
|
Reach for the functions below only when the one-call `setupStore` doesn't fit (partial re-seed, custom
|