@wix/agent-skills 1.20.1 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +71 -113
- package/skills/wix-app/references/APP_TOOLS.md +2 -1
- package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
- package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
- package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
- package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
- package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
- package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
- package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
- package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
- package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
- package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
- package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
- package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
- package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
- package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
- package/skills/wix-headless-fast/SKILL.md +144 -221
- package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
- package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +15 -15
- package/skills/wix-headless-fast/guides/existing-site.md +76 -0
- package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
- package/skills/wix-headless-fast/install/AGENTS.md +35 -0
- package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
- package/skills/wix-headless-fast/install/attach.mjs +161 -86
- package/skills/wix-headless-fast/install/deploy.mjs +21 -60
- package/skills/wix-headless-fast/install/lock.mjs +55 -0
- package/skills/wix-headless-fast/install/setup.mjs +259 -0
- package/skills/wix-headless-fast/install/templates.mjs +168 -0
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
- package/skills/wix-manage/references/events/create-wix-event.md +5 -1
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
- package/skills/wix-headless-fast/install/fast-path.mjs +0 -181
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -301
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
- package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
- package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
- package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
- package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -275
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
- package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
- package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -353
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
- package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
- package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
- package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -305
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
- package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
- package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
- package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
- package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
- package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -338
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
- package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
- package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
- package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -314
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
- package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
- package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
- package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
- package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
- package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -313
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
- package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -258
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -294
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
- package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
- package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -358
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
- package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
- package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
- package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -479
- package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
- package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
- package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
- package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
- package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
- package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -608
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -309
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -167
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
- package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
- package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -124
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -525
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// REFERENCE listing surface: category filter + events grid on the @theme tokens.
|
|
2
|
-
// Correct and complete; per the skill's model you design and build your own on useEvents.
|
|
3
|
-
import type { ComponentType, ReactNode } from "react";
|
|
4
|
-
import { useEvents } from "../../hooks/events/useEvents";
|
|
5
|
-
import { imgAttrs } from "../../wix/media";
|
|
6
|
-
import type { EventSummary } from "../../wix/events/types";
|
|
7
|
-
|
|
8
|
-
export interface LinkLikeProps {
|
|
9
|
-
href: string;
|
|
10
|
-
className?: string;
|
|
11
|
-
children?: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const PlainLink = ({ href, className, children }: LinkLikeProps) => (
|
|
15
|
-
<a href={href} className={className}>
|
|
16
|
-
{children}
|
|
17
|
-
</a>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
export interface EventCardProps {
|
|
21
|
-
event: EventSummary;
|
|
22
|
-
eventHref?: (slug: string) => string;
|
|
23
|
-
LinkComponent?: ComponentType<LinkLikeProps>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function EventCard({
|
|
27
|
-
event,
|
|
28
|
-
eventHref = (slug) => `/events/${slug}`,
|
|
29
|
-
LinkComponent = PlainLink,
|
|
30
|
-
}: EventCardProps) {
|
|
31
|
-
return (
|
|
32
|
-
<LinkComponent href={eventHref(event.slug)} className="group block no-underline">
|
|
33
|
-
<div className="relative aspect-[3/2] overflow-hidden rounded-lg bg-secondary">
|
|
34
|
-
{event.imageUrl && (
|
|
35
|
-
<img
|
|
36
|
-
{...imgAttrs(event.imageUrl, "(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw", 2 / 3)}
|
|
37
|
-
alt={event.title}
|
|
38
|
-
className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
|
|
39
|
-
/>
|
|
40
|
-
)}
|
|
41
|
-
{event.soldOut && (
|
|
42
|
-
<span className="absolute left-3 top-3 rounded-full bg-background/90 px-3 py-1 text-xs font-semibold text-foreground backdrop-blur">
|
|
43
|
-
Sold out
|
|
44
|
-
</span>
|
|
45
|
-
)}
|
|
46
|
-
</div>
|
|
47
|
-
{event.dateLabel && <p className="eyebrow mt-3">{event.dateLabel}</p>}
|
|
48
|
-
<p className="mt-1 text-sm font-medium text-foreground">{event.title}</p>
|
|
49
|
-
<p className="mt-0.5 text-xs text-muted-foreground">
|
|
50
|
-
{event.locationType === "ONLINE" ? "Online" : event.locationName}
|
|
51
|
-
{event.priceLabel ? ` · ${event.priceLabel}` : ""}
|
|
52
|
-
</p>
|
|
53
|
-
</LinkComponent>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface EventsViewProps {
|
|
58
|
-
initialEvents?: EventSummary[];
|
|
59
|
-
emptyMessage?: string;
|
|
60
|
-
eventHref?: EventCardProps["eventHref"];
|
|
61
|
-
LinkComponent?: ComponentType<LinkLikeProps>;
|
|
62
|
-
CardComponent?: ComponentType<EventCardProps>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const pill = (active: boolean) =>
|
|
66
|
-
`rounded-full border px-4 py-1.5 text-sm font-medium transition-colors ${
|
|
67
|
-
active
|
|
68
|
-
? "border-primary bg-primary text-primary-foreground"
|
|
69
|
-
: "border-border text-foreground hover:bg-secondary"
|
|
70
|
-
}`;
|
|
71
|
-
|
|
72
|
-
export default function EventsView({
|
|
73
|
-
initialEvents,
|
|
74
|
-
emptyMessage = "No upcoming events — check back soon.",
|
|
75
|
-
eventHref,
|
|
76
|
-
LinkComponent,
|
|
77
|
-
CardComponent = EventCard,
|
|
78
|
-
}: EventsViewProps) {
|
|
79
|
-
const { events, categories, activeCategoryId, setActiveCategoryId, error } = useEvents({
|
|
80
|
-
initialEvents,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<div>
|
|
85
|
-
{categories.length > 1 && (
|
|
86
|
-
<div className="mb-8 flex flex-wrap gap-2" role="group" aria-label="Categories">
|
|
87
|
-
<button type="button" className={pill(activeCategoryId === null)} onClick={() => setActiveCategoryId(null)}>
|
|
88
|
-
All
|
|
89
|
-
</button>
|
|
90
|
-
{categories.map((c) => (
|
|
91
|
-
<button key={c.id} type="button" className={pill(activeCategoryId === c.id)} onClick={() => setActiveCategoryId(c.id)}>
|
|
92
|
-
{c.name}
|
|
93
|
-
</button>
|
|
94
|
-
))}
|
|
95
|
-
</div>
|
|
96
|
-
)}
|
|
97
|
-
{error && <p className="mb-4 text-sm text-red-600">{error}</p>}
|
|
98
|
-
{events === null ? (
|
|
99
|
-
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" aria-busy="true">
|
|
100
|
-
{Array.from({ length: 6 }, (_, i) => (
|
|
101
|
-
<div key={i}>
|
|
102
|
-
<div className="aspect-[3/2] animate-pulse rounded-lg bg-secondary" />
|
|
103
|
-
<div className="mt-3 h-3.5 w-2/3 animate-pulse rounded bg-secondary" />
|
|
104
|
-
</div>
|
|
105
|
-
))}
|
|
106
|
-
</div>
|
|
107
|
-
) : events.length === 0 ? (
|
|
108
|
-
<p className="py-16 text-center text-muted-foreground">{emptyMessage}</p>
|
|
109
|
-
) : (
|
|
110
|
-
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
|
111
|
-
{events.map((e) => (
|
|
112
|
-
<CardComponent key={e.id} event={e} eventHref={eventHref} LinkComponent={LinkComponent} />
|
|
113
|
-
))}
|
|
114
|
-
</div>
|
|
115
|
-
)}
|
|
116
|
-
</div>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// React binding of the registration store (wix/events/registration-store.ts) — the whole
|
|
2
|
-
// registration state machine for one event lives there, framework-free, branched on
|
|
3
|
-
// event.registrationType: TICKETING loads the tier picker and checkout() reserves → redirects to
|
|
4
|
-
// Wix's hosted checkout; RSVP is the built-in name+email form submitted in place. All correctness
|
|
5
|
-
// (the visitor-public tier read, the reservation payload, the redirect callbacks, rsvpV2) lives
|
|
6
|
-
// in the data layer; you own how it looks. One store per event — a new event id gets a fresh one.
|
|
7
|
-
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
8
|
-
import {
|
|
9
|
-
createRegistrationStore,
|
|
10
|
-
type RegistrationState,
|
|
11
|
-
type RegistrationStore,
|
|
12
|
-
} from "../../wix/events/registration-store";
|
|
13
|
-
import type { EventDetail } from "../../wix/events/types";
|
|
14
|
-
|
|
15
|
-
export type UseEventRegistration = RegistrationState &
|
|
16
|
-
Pick<RegistrationStore, "setQuantity" | "setRsvpValue" | "checkout" | "rsvp">;
|
|
17
|
-
|
|
18
|
-
export function useEventRegistration(event: EventDetail): UseEventRegistration {
|
|
19
|
-
const key = `${event.id}:${event.registrationType}`;
|
|
20
|
-
const ref = useRef<{ key: string; store: RegistrationStore } | null>(null);
|
|
21
|
-
if (!ref.current || ref.current.key !== key) ref.current = { key, store: createRegistrationStore(event) };
|
|
22
|
-
const store = ref.current.store;
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
store.start();
|
|
25
|
-
return () => store.stop();
|
|
26
|
-
}, [store]);
|
|
27
|
-
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
28
|
-
return {
|
|
29
|
-
...state,
|
|
30
|
-
setQuantity: store.setQuantity,
|
|
31
|
-
setRsvpValue: store.setRsvpValue,
|
|
32
|
-
checkout: store.checkout,
|
|
33
|
-
rsvp: store.rsvp,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// React binding of the events store (wix/events/events-store.ts) — the listing state machine
|
|
2
|
-
// lives there, framework-free; this hook subscribes to one instance per mounted listing and
|
|
3
|
-
// exposes its state and actions under one name. SSR-friendly: pass server-fetched data as
|
|
4
|
-
// `initialEvents` (Astro frontmatter / server component) and no client fetch happens; a SPA
|
|
5
|
-
// passes nothing. Astro islands and React SPAs use this; a static page, Vue, or Svelte uses the
|
|
6
|
-
// store directly.
|
|
7
|
-
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
8
|
-
import { createEventsStore, type EventsState, type EventsStore, type EventsStoreOptions } from "../../wix/events/events-store";
|
|
9
|
-
|
|
10
|
-
export type UseEventsOptions = EventsStoreOptions;
|
|
11
|
-
|
|
12
|
-
export type UseEvents = EventsState & Pick<EventsStore, "setActiveCategoryId">;
|
|
13
|
-
|
|
14
|
-
export function useEvents(options: UseEventsOptions = {}): UseEvents {
|
|
15
|
-
const ref = useRef<EventsStore | null>(null);
|
|
16
|
-
if (!ref.current) ref.current = createEventsStore(options);
|
|
17
|
-
const store = ref.current;
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
store.start();
|
|
20
|
-
return () => store.stop();
|
|
21
|
-
}, [store]);
|
|
22
|
-
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
23
|
-
return { ...state, setActiveCategoryId: store.setActiveCategoryId };
|
|
24
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
// Event rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./events.ts (the
|
|
2
|
-
// SDK, managed Astro and React) and the REST twin in references/events/rest/events.ts (fetch, a
|
|
3
|
-
// static site or a port to another language). Every rule about statuses, fieldsets, prices,
|
|
4
|
-
// dates, images and categories lives HERE, once. A raw event may come from the SDK (`_id`,
|
|
5
|
-
// mainImage as a wix:image string) or from REST (`id`, mainImage as { id, url }); the mappers
|
|
6
|
-
// accept both. Imports are type-only so a strip to JS emits no imports.
|
|
7
|
-
import type { EventDetail, EventSummary, RegistrationType } from "./types";
|
|
8
|
-
|
|
9
|
-
/** A raw Events V3 entity as either transport returns it. */
|
|
10
|
-
export type Raw = Record<string, any>;
|
|
11
|
-
/** Media value + size → https URL. Injected: the SDK transport scales through @wix/sdk, REST through the URL form. */
|
|
12
|
-
export type ImgSrc = (value: any, width: number, height: number) => string;
|
|
13
|
-
|
|
14
|
-
/** The Wix Events app id (reference only — frontend calls need no app-id constant). */
|
|
15
|
-
export const EVENTS_APP_ID = "140603ad-af8d-84a5-2c80-a0f60cb47351";
|
|
16
|
-
|
|
17
|
-
export const rawId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
|
|
18
|
-
|
|
19
|
-
// Fieldsets are opt-in: without REGISTRATION there's no registration type to branch on;
|
|
20
|
-
// without CATEGORIES the category names never arrive; DETAILS carries the formatted date
|
|
21
|
-
// and mainImage; TEXTS carries the long description; URLS the Wix event page url.
|
|
22
|
-
export const LIST_FIELDS = ["DETAILS", "REGISTRATION", "CATEGORIES"] as const;
|
|
23
|
-
export const DETAIL_FIELDS = ["DETAILS", "TEXTS", "REGISTRATION", "URLS", "CATEGORIES"] as const;
|
|
24
|
-
|
|
25
|
-
/** Only these are listed and linked — a past or canceled event isn't registerable. */
|
|
26
|
-
export const LIVE_STATUSES = ["UPCOMING", "STARTED"] as const;
|
|
27
|
-
export const START_DATE_FIELD = "dateAndTimeSettings.startDate";
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* The Query Events body for the listing: live statuses, soonest first, a positive limit.
|
|
31
|
-
* `paging.limit` defaults to 0 — a bare query answers `total: 2, events: []` with no error — so
|
|
32
|
-
* the limit is always sent. The SDK builder spells the same three parts.
|
|
33
|
-
*/
|
|
34
|
-
export function listQuery({ limit = 100 } = {}): Raw {
|
|
35
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 1000) throw new Error("limit must be between 1 and 1000.");
|
|
36
|
-
return {
|
|
37
|
-
filter: { status: { $in: [...LIVE_STATUSES] } },
|
|
38
|
-
sort: [{ fieldName: START_DATE_FIELD, order: "ASC" }],
|
|
39
|
-
paging: { limit },
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** "From €45" (ticketed), "Free" (RSVP / free tickets), "" when nothing applies. */
|
|
44
|
-
export function lowestPriceLabel(reg: Raw): string {
|
|
45
|
-
const type = reg.type ?? reg.initialType;
|
|
46
|
-
if (type === "RSVP") return "Free";
|
|
47
|
-
if (type !== "TICKETING") return "";
|
|
48
|
-
const lowest: Raw | undefined = reg.tickets?.lowestPrice;
|
|
49
|
-
if (!lowest) return "";
|
|
50
|
-
if (Number(lowest.value ?? 0) === 0) return "Free";
|
|
51
|
-
if (lowest.formattedValue) return `From ${lowest.formattedValue}`;
|
|
52
|
-
try {
|
|
53
|
-
return `From ${new Intl.NumberFormat(undefined, { style: "currency", currency: lowest.currency || "USD" }).format(Number(lowest.value))}`;
|
|
54
|
-
} catch {
|
|
55
|
-
return `From ${lowest.value} ${lowest.currency ?? ""}`.trim();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// event.description is Ricos rich content ({ nodes: [...] }), NOT a string — calling string
|
|
60
|
-
// methods on it crashes the page. Extract plain paragraphs; detailedDescription (legacy plain
|
|
61
|
-
// text) is the fallback.
|
|
62
|
-
export function toParagraphs(rich: Raw | undefined | null, legacy: string | undefined): string[] {
|
|
63
|
-
const collect = (nodes: Raw[] | undefined): string =>
|
|
64
|
-
(nodes ?? [])
|
|
65
|
-
.map((n: Raw) => (typeof n.textData?.text === "string" ? n.textData.text : collect(n.nodes)))
|
|
66
|
-
.join("");
|
|
67
|
-
const out: string[] = [];
|
|
68
|
-
for (const node of rich?.nodes ?? []) {
|
|
69
|
-
const text = collect([node]).trim();
|
|
70
|
-
if (text) out.push(text);
|
|
71
|
-
}
|
|
72
|
-
if (!out.length && legacy) out.push(legacy);
|
|
73
|
-
return out;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The main image in the form imgSrc scales: the SDK carries it as a `wix:image://` string; REST
|
|
78
|
-
* as `{ id, url, altText }` — rebuilt into the id form so both transports resolve one URL shape.
|
|
79
|
-
*/
|
|
80
|
-
export function mainImageOf(raw: Raw): unknown {
|
|
81
|
-
const m = raw.mainImage;
|
|
82
|
-
if (m && typeof m === "object" && typeof m.id === "string" && m.id) {
|
|
83
|
-
return `wix:image://v1/${m.id}/${encodeURIComponent(String(m.altText || "image"))}`;
|
|
84
|
-
}
|
|
85
|
-
return m;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function toSummary(raw: Raw, imgSrc: ImgSrc): EventSummary {
|
|
89
|
-
const reg: Raw = raw.registration ?? {};
|
|
90
|
-
const dts: Raw = raw.dateAndTimeSettings ?? {};
|
|
91
|
-
return {
|
|
92
|
-
id: rawId(raw), // _id on the SDK, id on REST — never a bare .id on the SDK (undefined there)
|
|
93
|
-
slug: raw.slug ?? "",
|
|
94
|
-
title: raw.title ?? "",
|
|
95
|
-
shortDescription: raw.shortDescription ?? "",
|
|
96
|
-
dateLabel: dts.formatted?.dateAndTime ?? "",
|
|
97
|
-
startDateIso: dts.startDate ? new Date(dts.startDate).toISOString() : "",
|
|
98
|
-
locationName: raw.location?.name ?? "",
|
|
99
|
-
locationType: raw.location?.locationTbd
|
|
100
|
-
? "TBD"
|
|
101
|
-
: ((raw.location?.type as "VENUE" | "ONLINE") ?? "TBD"),
|
|
102
|
-
imageUrl: imgSrc(mainImageOf(raw), 1200, 800),
|
|
103
|
-
// `type` is the current flavor (can become EXTERNAL later); initialType is the immutable
|
|
104
|
-
// seeded one — read type first.
|
|
105
|
-
registrationType: (reg.type ?? reg.initialType ?? "NONE") as RegistrationType,
|
|
106
|
-
priceLabel: lowestPriceLabel(reg),
|
|
107
|
-
// The API reports tickets.soldOut true on an RSVP event too (it has no tickets at all) — sold
|
|
108
|
-
// out is a ticketing signal only.
|
|
109
|
-
soldOut: (reg.type ?? reg.initialType) === "TICKETING" && reg.tickets?.soldOut === true,
|
|
110
|
-
// `categories` is absent on the typed Event (an SDK type gap) — the Raw boundary reads
|
|
111
|
-
// the runtime field the CATEGORIES fieldset populates.
|
|
112
|
-
categories: ((raw.categories?.categories ?? []) as Raw[])
|
|
113
|
-
.map((c) => ({ id: rawId(c), name: c.name ?? "" }))
|
|
114
|
-
.filter((c) => c.id),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function toDetail(raw: Raw, imgSrc: ImgSrc): EventDetail {
|
|
119
|
-
const summary = toSummary(raw, imgSrc);
|
|
120
|
-
const reg: Raw = raw.registration ?? {};
|
|
121
|
-
return {
|
|
122
|
-
...summary,
|
|
123
|
-
aboutParagraphs: toParagraphs(raw.description, raw.detailedDescription),
|
|
124
|
-
// Only OPEN_* statuses (OPEN_RSVP, OPEN_TICKETS, OPEN_EXTERNAL, …) accept registrations.
|
|
125
|
-
registrationOpen: typeof reg.status === "string" && reg.status.startsWith("OPEN_"),
|
|
126
|
-
rsvpResponseType: reg.rsvp?.responseType === "YES_AND_NO" ? "YES_AND_NO" : "YES_ONLY",
|
|
127
|
-
externalUrl: reg.external?.url ?? "",
|
|
128
|
-
addToCalendar: { google: raw.calendarUrls?.google ?? "", ics: raw.calendarUrls?.ics ?? "" },
|
|
129
|
-
};
|
|
130
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// The events listing as a framework-free store — the logic behind useEvents, usable from React
|
|
2
|
-
// (useEvents wraps it with useSyncExternalStore), from a static page or Vue/Svelte (subscribe and
|
|
3
|
-
// render), or as the specification for a port. State, actions, subscribe/getState, emit after
|
|
4
|
-
// every change.
|
|
5
|
-
//
|
|
6
|
-
// SSR-friendly: seed with `initialEvents` and they render at once with no client fetch; a SPA
|
|
7
|
-
// passes nothing and `start()` fetches. The category menu is DERIVED from the loaded events (the
|
|
8
|
-
// categories management API is admin-scope — visitors can't query it); filtering is client-side
|
|
9
|
-
// over the live list, which is small by definition (only UPCOMING/STARTED events are listed).
|
|
10
|
-
//
|
|
11
|
-
// One store per mounted listing (a page can hold the index and a "next up" rail):
|
|
12
|
-
// createEventsStore(), not a singleton.
|
|
13
|
-
import { fetchEvents } from "./events";
|
|
14
|
-
import type { EventSummary } from "./types";
|
|
15
|
-
|
|
16
|
-
export interface EventsStoreOptions {
|
|
17
|
-
initialEvents?: EventSummary[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Everything a listing surface renders from. Read it with getState() or through a subscription. */
|
|
21
|
-
export interface EventsState {
|
|
22
|
-
/** null while the first load is in flight — render skeletons, not an empty state. */
|
|
23
|
-
events: EventSummary[] | null;
|
|
24
|
-
/** Unique assigned categories in listing order — render a filter bar only when > 1. */
|
|
25
|
-
categories: { id: string; name: string }[];
|
|
26
|
-
activeCategoryId: string | null;
|
|
27
|
-
error: string | null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface EventsStore {
|
|
31
|
-
getState(): EventsState;
|
|
32
|
-
subscribe(listener: () => void): () => void;
|
|
33
|
-
/** Fetch when no `initialEvents` were given. Call once when mounted (a browser). */
|
|
34
|
-
start(): void;
|
|
35
|
-
/** Stop reacting; drop a late response. */
|
|
36
|
-
stop(): void;
|
|
37
|
-
setActiveCategoryId(id: string | null): void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function createEventsStore({ initialEvents }: EventsStoreOptions = {}): EventsStore {
|
|
41
|
-
let all: EventSummary[] | null = initialEvents ?? null;
|
|
42
|
-
let activeCategoryId: string | null = null;
|
|
43
|
-
let error: string | null = null;
|
|
44
|
-
let started = false;
|
|
45
|
-
const listeners = new Set<() => void>();
|
|
46
|
-
let snapshot: EventsState | null = null;
|
|
47
|
-
const emit = () => {
|
|
48
|
-
snapshot = null;
|
|
49
|
-
for (const fn of listeners) fn();
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
function getState(): EventsState {
|
|
53
|
-
if (snapshot) return snapshot;
|
|
54
|
-
const seen = new Map<string, string>();
|
|
55
|
-
for (const e of all ?? []) for (const c of e.categories) if (!seen.has(c.id)) seen.set(c.id, c.name);
|
|
56
|
-
snapshot = {
|
|
57
|
-
events: all === null ? null : activeCategoryId ? all.filter((e) => e.categories.some((c) => c.id === activeCategoryId)) : all,
|
|
58
|
-
categories: [...seen.entries()].map(([id, name]) => ({ id, name })),
|
|
59
|
-
activeCategoryId,
|
|
60
|
-
error,
|
|
61
|
-
};
|
|
62
|
-
return snapshot;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
getState,
|
|
67
|
-
subscribe(fn) {
|
|
68
|
-
listeners.add(fn);
|
|
69
|
-
return () => listeners.delete(fn);
|
|
70
|
-
},
|
|
71
|
-
start() {
|
|
72
|
-
if (started) return;
|
|
73
|
-
started = true;
|
|
74
|
-
if (initialEvents) return;
|
|
75
|
-
fetchEvents()
|
|
76
|
-
.then((list) => {
|
|
77
|
-
if (!started) return;
|
|
78
|
-
all = list;
|
|
79
|
-
emit();
|
|
80
|
-
})
|
|
81
|
-
.catch((e) => {
|
|
82
|
-
if (!started) return;
|
|
83
|
-
all = [];
|
|
84
|
-
error = e instanceof Error ? e.message : String(e);
|
|
85
|
-
emit();
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
stop() {
|
|
89
|
-
started = false;
|
|
90
|
-
},
|
|
91
|
-
setActiveCategoryId(id) {
|
|
92
|
-
if (id === activeCategoryId) return;
|
|
93
|
-
activeCategoryId = id;
|
|
94
|
-
emit();
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Event reads (Wix Events V3, the `wixEventsV2` module) over the SDK — the only file that touches
|
|
2
|
-
// raw event entities on this transport. Everything it returns is a plain DTO from ./types. The
|
|
3
|
-
// rules and mappers live in ./events-core (shared with the REST twin in references/events/rest/);
|
|
4
|
-
// this file is the transport only. Copy as-is; extend by adding functions, not by editing these.
|
|
5
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/query-events.md
|
|
6
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/get-event-by-slug.md
|
|
7
|
-
import { wixEventsV2 } from "@wix/events";
|
|
8
|
-
import { wixModule } from "../sdk";
|
|
9
|
-
import { imgSrc } from "../media";
|
|
10
|
-
import { DETAIL_FIELDS, EVENTS_APP_ID, LIST_FIELDS, LIVE_STATUSES, START_DATE_FIELD, rawId, toDetail, toSummary, type Raw } from "./events-core";
|
|
11
|
-
import type { EventDetail, EventSummary } from "./types";
|
|
12
|
-
|
|
13
|
-
export { EVENTS_APP_ID };
|
|
14
|
-
|
|
15
|
-
const events = wixModule(wixEventsV2);
|
|
16
|
-
|
|
17
|
-
/** List live (UPCOMING/STARTED) events, soonest first, mapped to grid-ready DTOs. */
|
|
18
|
-
export async function fetchEvents({ limit = 100 } = {}): Promise<EventSummary[]> {
|
|
19
|
-
// The query builder, never a flat/REST `{ query: {...} }` body (the SDK silently ignores
|
|
20
|
-
// the unknown key and returns zero events). Always set a positive limit — it defaults to 0,
|
|
21
|
-
// which also returns zero events with no error.
|
|
22
|
-
const res = await events
|
|
23
|
-
.queryEvents({ fields: LIST_FIELDS as any })
|
|
24
|
-
.in("status", [...LIVE_STATUSES]) // never list or link a past event — it isn't registerable
|
|
25
|
-
.ascending(START_DATE_FIELD as any)
|
|
26
|
-
.limit(limit)
|
|
27
|
-
.find();
|
|
28
|
-
return (res.items ?? []).map((e: Raw) => toSummary(e, imgSrc));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Fetch one event by its URL slug. Null when not found. */
|
|
32
|
-
export async function fetchEventBySlug(slug: string): Promise<EventDetail | null> {
|
|
33
|
-
try {
|
|
34
|
-
// getEventBySlug returns a WRAPPED { event } — unlike getEvent below.
|
|
35
|
-
const res: Raw = await events.getEventBySlug(slug, { fields: DETAIL_FIELDS as any });
|
|
36
|
-
const raw = res?.event;
|
|
37
|
-
return raw ? toDetail(raw as Raw, imgSrc) : null;
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Fetch one event by id — the post-checkout confirmation read (the thank-you URL carries
|
|
45
|
-
* `?orderNumber=&eventId=`). getEvent returns the Event DIRECTLY (unwrapped) — the one read
|
|
46
|
-
* that isn't `{ event }`; assuming the wrapper crashes the page.
|
|
47
|
-
*/
|
|
48
|
-
export async function fetchEventById(eventId: string): Promise<EventDetail | null> {
|
|
49
|
-
try {
|
|
50
|
-
const raw: Raw = await events.getEvent(eventId, { fields: DETAIL_FIELDS as any });
|
|
51
|
-
return rawId(raw) ? toDetail(raw, imgSrc) : null;
|
|
52
|
-
} catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// Registration rules and DTO mapping — transport-agnostic, imported by both ./registration.ts
|
|
2
|
-
// (SDK) and the REST twin in references/events/rest/registration.ts (fetch). Tier mapping, the
|
|
3
|
-
// reservation line items, the payment gate, the checkout callbacks, and the RSVP body live HERE,
|
|
4
|
-
// once. Raw ticket definitions carry `_id` (SDK) or `id` (REST). Type-only imports so a strip
|
|
5
|
-
// to JS emits none.
|
|
6
|
-
import type { EventDetail, RegistrationResult, TicketTier } from "./types";
|
|
7
|
-
import type { Raw } from "./events-core";
|
|
8
|
-
|
|
9
|
-
const tierId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
|
|
10
|
-
|
|
11
|
-
export function formatTierPrice(price: Raw | undefined): string {
|
|
12
|
-
const value = price?.amount ?? price?.value;
|
|
13
|
-
if (value == null || value === "") return "";
|
|
14
|
-
try {
|
|
15
|
-
return new Intl.NumberFormat(undefined, { style: "currency", currency: price?.currency || "USD" }).format(Number(value));
|
|
16
|
-
} catch {
|
|
17
|
-
return `${value} ${price?.currency ?? ""}`.trim();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function toTier(raw: Raw): TicketTier {
|
|
22
|
-
const free = raw.free === true || Number(raw.price?.amount ?? raw.price?.value ?? 0) === 0;
|
|
23
|
-
return {
|
|
24
|
-
id: tierId(raw),
|
|
25
|
-
name: raw.name ?? "",
|
|
26
|
-
description: raw.description ?? "",
|
|
27
|
-
price: free ? "Free" : formatTierPrice(raw.price),
|
|
28
|
-
free,
|
|
29
|
-
limitPerCheckout: raw.limitPerCheckout ?? 20,
|
|
30
|
-
saleStatus: (raw.saleStatus ?? "SALE_STARTED") as TicketTier["saleStatus"],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Tiers in display order (orderIndex), skipping any without an id. */
|
|
35
|
-
export function toTiers(definitions: Raw[] | undefined): TicketTier[] {
|
|
36
|
-
return (definitions ?? [])
|
|
37
|
-
.slice()
|
|
38
|
-
.sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))
|
|
39
|
-
.map(toTier)
|
|
40
|
-
.filter((t) => t.id);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** The reservation's line items from the picker's selections; throws when nothing is picked. */
|
|
44
|
-
export function reservationTickets(selections: { tierId: string; quantity: number }[]): { ticketDefinitionId: string; quantity: number }[] {
|
|
45
|
-
const tickets = selections
|
|
46
|
-
.filter((s) => s.quantity > 0)
|
|
47
|
-
.map((s) => ({ ticketDefinitionId: s.tierId, quantity: s.quantity }));
|
|
48
|
-
if (!tickets.length) throw new Error("Pick at least one ticket first.");
|
|
49
|
-
return tickets;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* The real gate on paid tickets: until the site has a premium plan AND a configured payment
|
|
54
|
-
* method, reserving fails 403 NO_PAYMENT_METHOD_CONFIGURED. Not a permissions bug — don't
|
|
55
|
-
* elevate (that just creates an unpayable order); surface it softly.
|
|
56
|
-
*/
|
|
57
|
-
export function reservationError(e: unknown): Error {
|
|
58
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
59
|
-
if (/payment method|not configured|premium/i.test(msg)) {
|
|
60
|
-
return new Error("Ticket sales aren't switched on yet — the organizer needs to connect a payment method in the dashboard.");
|
|
61
|
-
}
|
|
62
|
-
return e instanceof Error ? e : new Error(msg);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** The reservation id out of either transport's response; throws when the hold didn't happen. */
|
|
66
|
-
export function reservationId(reservation: Raw | null | undefined): string {
|
|
67
|
-
const id = tierId(reservation);
|
|
68
|
-
if (!id) throw new Error("Those tickets couldn't be reserved — they may have just sold out.");
|
|
69
|
-
return id;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Where the hosted checkout returns to. Defaults are the Astro routes; a static site passes its file paths. */
|
|
73
|
-
export interface CheckoutPaths {
|
|
74
|
-
/** Success landing — Wix appends `?orderNumber=&eventId=`. Default `/event-confirmation`. */
|
|
75
|
-
confirmation?: string;
|
|
76
|
-
/** Back here on abandon. Default `/events/<slug>`. */
|
|
77
|
-
event?: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* The redirect session's callbacks. `origin` is the published https host (window.location.origin
|
|
82
|
-
* in a browser) — an http or server-derived origin isn't on the redirect allowlist and 403s the
|
|
83
|
-
* return; {} when unknown (SSR).
|
|
84
|
-
*/
|
|
85
|
-
export function checkoutCallbacks(origin: string, slug: string, paths: CheckoutPaths = {}): Raw {
|
|
86
|
-
if (!origin) return {};
|
|
87
|
-
return {
|
|
88
|
-
thankYouPageUrl: `${origin}${paths.confirmation ?? "/event-confirmation"}`,
|
|
89
|
-
postFlowUrl: `${origin}${paths.event ?? `/events/${slug}`}`,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** The redirect result; throws when Wix returned no URL. */
|
|
94
|
-
export function redirectResult(session: Raw | null | undefined): RegistrationResult {
|
|
95
|
-
const url = session?.redirectSession?.fullUrl;
|
|
96
|
-
if (!url) throw new Error("Checkout couldn't start — please try again.");
|
|
97
|
-
return { kind: "redirect", url };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* The RSVP body: the built-in form is exactly firstName + lastName + email — never a fetched
|
|
102
|
-
* schema, never extra fields. "NO" only when the event's rsvpResponseType is "YES_AND_NO".
|
|
103
|
-
*/
|
|
104
|
-
export function rsvpBody(eventId: string, guest: { firstName: string; lastName: string; email: string }, status: "YES" | "NO"): Raw {
|
|
105
|
-
return { eventId, firstName: guest.firstName, lastName: guest.lastName, email: guest.email, status };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** A full event with a waitlist answers status "WAITLIST" — tell the guest they're waitlisted, not confirmed. */
|
|
109
|
-
export function rsvpResult(rsvp: Raw | null | undefined, sent: "YES" | "NO"): RegistrationResult {
|
|
110
|
-
return { kind: "rsvpConfirmed", status: (rsvp?.status ?? sent) as "YES" | "NO" | "WAITLIST" };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export type CheckoutEvent = Pick<EventDetail, "id" | "slug">;
|