@wix/himalaya-cli 0.1582.0 → 0.1584.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/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +8 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +26 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +18 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/blog-v3/src/extensions.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/comments-v1/src/extensions.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/index.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/groups/src/extensions.d.ts +15 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/extensions.d.ts +13 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-v1/src/index.d.ts +19 -4
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +5 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +5 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-comments.mjs +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +4 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-groups.mjs +5 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members.mjs +10 -3
- package/dist/cli.mjs +1098 -702
- package/dist/preview-assets.generated.bin +0 -0
- package/fixtures/wix-canned.json +25 -0
- package/guides/component-reference.json +4 -3
- package/guides/component-reference.md +24 -2
- package/guides/one-app-to-himi-app.md +52 -1
- package/guides/sdk-reference.json +37 -9
- package/guides/wix-api-usage.md +9 -0
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +27 -1
- package/templates/beauty-salon/dev/index.ts +2285 -757
- package/templates/beauty-salon/himalaya.content.json +3 -0
- package/templates/beauty-salon/tier5-src/_shared/booking-location.ts +147 -0
- package/templates/beauty-salon/tier5-src/_shared/booking-session.ts +222 -0
- package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/beauty-salon/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/beauty-salon/tier5-src/_shared/owner-editor-value.ts +164 -0
- package/templates/beauty-salon/tier5-src/_shared/store-product-info.ts +50 -0
- package/templates/beauty-salon/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +277 -14
- package/templates/beauty-salon/tier5-src/himi-booking-services/index.ts +351 -92
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +25 -5
- package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
- package/templates/beauty-salon/tier5-src/himi-branded-lite-category/index.ts +3 -2
- package/templates/beauty-salon/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +14 -3
- package/templates/beauty-salon/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/beauty-salon/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/beauty-salon-owner/dev/index.ts +129 -66
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/branded-lite/config.ts +29 -1
- package/templates/branded-lite/dev/index.ts +8371 -5565
- package/templates/branded-lite/himalaya.content.json +3 -0
- package/templates/branded-lite/l10n/en.json +2 -2
- package/templates/branded-lite/tier5-src/_shared/booking-location.ts +147 -0
- package/templates/branded-lite/tier5-src/_shared/booking-session.ts +222 -0
- package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/branded-lite/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/branded-lite/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/branded-lite/tier5-src/_shared/owner-editor-value.ts +164 -0
- package/templates/branded-lite/tier5-src/_shared/store-product-info.ts +50 -0
- package/templates/branded-lite/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +277 -14
- package/templates/branded-lite/tier5-src/himi-booking-services/index.ts +351 -92
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +25 -5
- package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
- package/templates/branded-lite/tier5-src/himi-branded-lite-badges/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-category/index.ts +3 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-feed/index.ts +4 -3
- package/templates/branded-lite/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +115 -49
- package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-podcasts/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/facts.ts +52 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +21 -11
- package/templates/branded-lite/tier5-src/himi-branded-lite-video/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/branded-lite/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +13 -3
- package/templates/branded-lite/tier5-src/wix-spaces-forum-post/index.ts +3 -2
- package/templates/branded-lite/tier5-src/wix-spaces-member-detail/index.ts +53 -37
- package/templates/branded-lite/tier5-src/wix-spaces-members/index.ts +100 -34
- package/templates/branded-lite/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/branded-lite/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/community-club/config.ts +36 -1
- package/templates/community-club/dev/index.ts +1930 -401
- package/templates/community-club/himalaya.content.json +6 -0
- package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/community-club/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/community-club/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/community-club/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/community-club/tier5-src/himi-branded-lite-feed/index.ts +4 -3
- package/templates/community-club/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
- package/templates/community-club/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/community-club/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/community-club/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/community-club/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/community-club-owner/dev/index.ts +53 -1
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/community-club-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/community-club-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/community-club-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/community-club-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/events-meetups/config.ts +36 -1
- package/templates/events-meetups/dev/index.ts +1930 -401
- package/templates/events-meetups/himalaya.content.json +6 -0
- package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/events-meetups/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/events-meetups/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/events-meetups/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/events-meetups/tier5-src/himi-branded-lite-feed/index.ts +4 -3
- package/templates/events-meetups/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/events-meetups/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/events-meetups/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/events-meetups-owner/dev/index.ts +6 -0
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/gym-fitness/config.ts +27 -1
- package/templates/gym-fitness/dev/index.ts +2803 -844
- package/templates/gym-fitness/himalaya.content.json +3 -0
- package/templates/gym-fitness/tier5-src/_shared/booking-location.ts +147 -0
- package/templates/gym-fitness/tier5-src/_shared/booking-session.ts +222 -0
- package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/gym-fitness/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/gym-fitness/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/gym-fitness/tier5-src/_shared/owner-editor-value.ts +164 -0
- package/templates/gym-fitness/tier5-src/_shared/store-product-info.ts +50 -0
- package/templates/gym-fitness/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +277 -14
- package/templates/gym-fitness/tier5-src/himi-booking-services/index.ts +351 -92
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +25 -5
- package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
- package/templates/gym-fitness/tier5-src/himi-branded-lite-category/index.ts +3 -2
- package/templates/gym-fitness/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/gym-fitness/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +14 -3
- package/templates/gym-fitness/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/gym-fitness/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/gym-fitness-owner/dev/index.ts +132 -66
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/nonprofit-cause/config.ts +36 -1
- package/templates/nonprofit-cause/dev/index.ts +1925 -396
- package/templates/nonprofit-cause/himalaya.content.json +6 -0
- package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/nonprofit-cause/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/nonprofit-cause/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/nonprofit-cause/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-feed/index.ts +4 -3
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/nonprofit-cause/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/nonprofit-cause/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/nonprofit-cause/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/nonprofit-cause-owner/dev/index.ts +85 -65
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-rich-guard.ts +27 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/owner-lite/dev/index.ts +132 -66
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/owner-lite/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/owner-lite/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/owner-lite/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/owner-lite/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/owner-lite/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/owner-lite/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/owner-lite/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/podcast-creator/config.ts +27 -1
- package/templates/podcast-creator/dev/index.ts +1051 -158
- package/templates/podcast-creator/himalaya.content.json +3 -0
- package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/podcast-creator/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/podcast-creator/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/podcast-creator/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/podcast-creator/tier5-src/himi-branded-lite-feed/index.ts +4 -3
- package/templates/podcast-creator/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-podcasts/index.ts +2 -1
- package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/podcast-creator/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/podcast-creator/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/podcast-creator/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/podcast-creator-owner/dev/index.ts +53 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/portfolio-creative/config.ts +27 -1
- package/templates/portfolio-creative/dev/index.ts +1305 -468
- package/templates/portfolio-creative/himalaya.content.json +3 -0
- package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/portfolio-creative/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/portfolio-creative/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/portfolio-creative/tier5-src/_shared/owner-editor-value.ts +164 -0
- package/templates/portfolio-creative/tier5-src/_shared/store-product-info.ts +50 -0
- package/templates/portfolio-creative/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-category/index.ts +3 -2
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio/index.ts +2 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -2
- package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/portfolio-creative/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +14 -3
- package/templates/portfolio-creative/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/portfolio-creative-owner/dev/index.ts +129 -66
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/restaurant/config.ts +27 -1
- package/templates/restaurant/dev/index.ts +1051 -158
- package/templates/restaurant/himalaya.content.json +3 -0
- package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/restaurant/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/restaurant/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/restaurant/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/restaurant/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/restaurant/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/restaurant/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/restaurant/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/restaurant-owner/dev/index.ts +132 -66
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
- package/templates/retail-store/config.ts +27 -1
- package/templates/retail-store/dev/index.ts +597 -191
- package/templates/retail-store/himalaya.content.json +3 -0
- package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/retail-store/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/retail-store/tier5-src/_shared/owner-editor-value.ts +164 -0
- package/templates/retail-store/tier5-src/_shared/store-product-info.ts +50 -0
- package/templates/retail-store/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/retail-store/tier5-src/himi-branded-lite-category/index.ts +3 -2
- package/templates/retail-store/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +13 -3
- package/templates/retail-store/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/retail-store-owner/dev/index.ts +50 -1
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
- package/templates/yoga-studio/config.ts +27 -1
- package/templates/yoga-studio/dev/index.ts +2996 -877
- package/templates/yoga-studio/himalaya.content.json +3 -0
- package/templates/yoga-studio/tier5-src/_shared/booking-location.ts +147 -0
- package/templates/yoga-studio/tier5-src/_shared/booking-session.ts +222 -0
- package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +1 -1
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/yoga-studio/tier5-src/_shared/event-registration.ts +86 -0
- package/templates/yoga-studio/tier5-src/_shared/himi-restaurants.ts +2 -1
- package/templates/yoga-studio/tier5-src/himi-blog-post/index.ts +21 -8
- package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +277 -14
- package/templates/yoga-studio/tier5-src/himi-booking-services/index.ts +351 -92
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +25 -5
- package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
- package/templates/yoga-studio/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
- package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +2 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/facts.ts +52 -0
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +21 -11
- package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +12 -86
- package/templates/yoga-studio/tier5-src/himi-events-list/index.ts +47 -6
- package/templates/yoga-studio/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
- package/templates/yoga-studio/tier5-src/wix-spaces-whats-new/index.ts +2 -1
- package/templates/yoga-studio-owner/dev/index.ts +85 -65
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +19 -3
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-rich-guard.ts +27 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
|
@@ -25,7 +25,7 @@ import { initials } from "../_shared/himi-text.js";
|
|
|
25
25
|
import { copyParam, stashCopy } from "../_shared/himi-copy.js";
|
|
26
26
|
import { formatMonthDay } from "../_shared/engine-intl.js";
|
|
27
27
|
import { openRichLink } from "../_shared/rich-content-link.js";
|
|
28
|
-
import {
|
|
28
|
+
import { descriptionBody, ROW_IMAGE_WIDTH } from "../_shared/rich-body.js";
|
|
29
29
|
|
|
30
30
|
interface FeedRow {
|
|
31
31
|
id: string;
|
|
@@ -104,7 +104,7 @@ function feedText(item: WixFeedItem): string {
|
|
|
104
104
|
if (joined) return joined;
|
|
105
105
|
}
|
|
106
106
|
const lean = item.entity?.body?.content;
|
|
107
|
-
return
|
|
107
|
+
return descriptionBody(lean, copyParam("feed.sharedUpdateFallback", "Shared an update.")).bodyText;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
function authorName(item: WixFeedItem, profiles: WixFeedProfile[]): string {
|
|
@@ -172,7 +172,8 @@ function feedRow(item: WixFeedItem, profiles: WixFeedProfile[]): FeedRow {
|
|
|
172
172
|
const count = Array.isArray(item.reactionsList) ? item.reactionsList.length : 0;
|
|
173
173
|
const avatar = authorAvatar(item, profiles);
|
|
174
174
|
// A Ricos post's plain text is the whole document's (every node level), not feedText's one-level read.
|
|
175
|
-
const
|
|
175
|
+
const fallback = item.content == null ? copyParam("feed.sharedUpdateFallback", "Shared an update.") : feedText(item);
|
|
176
|
+
const { bodyJson, bodyText: text } = descriptionBody(item.content || item.entity?.body?.content, fallback, ROW_IMAGE_WIDTH);
|
|
176
177
|
// A Ricos post draws its own images in RichContent, so the separate row image would repeat the first one.
|
|
177
178
|
const image = bodyJson ? "" : contentImage(item);
|
|
178
179
|
return {
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { defineService } from "@himalaya/state";
|
|
2
|
+
import { getGroup, listRules, type WixGroup, type WixGroupRule } from "@himalaya/wix-groups";
|
|
3
|
+
import { WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
4
|
+
import { copyParam, stashCopy } from "../_shared/himi-copy.js";
|
|
5
|
+
import { groupImage } from "../_shared/himi-media.js";
|
|
6
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
7
|
+
import { openRichLink } from "../_shared/rich-content-link.js";
|
|
8
|
+
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
9
|
+
|
|
10
|
+
// The About & rules page of ONE group. The group is `input.id`, never a fallback: a missing
|
|
11
|
+
// id is an error, not "the first group". The group read and the rules read are independent —
|
|
12
|
+
// the page renders the group's own facts when only the rules read failed, and says so in the
|
|
13
|
+
// rules region, so a rules outage is never shown as "this group has no rules".
|
|
14
|
+
//
|
|
15
|
+
// Read-only and online-only: no write exists on this page, so there is nothing to queue.
|
|
16
|
+
|
|
17
|
+
interface RuleRow {
|
|
18
|
+
id: string;
|
|
19
|
+
number: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type Failure = "forbidden" | "missing" | "failed";
|
|
25
|
+
|
|
26
|
+
interface State {
|
|
27
|
+
status: "loading" | "ready" | "error";
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
descriptionJson: string;
|
|
32
|
+
hasDescriptionJson: boolean;
|
|
33
|
+
privacy: string;
|
|
34
|
+
createdDate: string;
|
|
35
|
+
memberCount: string;
|
|
36
|
+
image: string;
|
|
37
|
+
initial: string;
|
|
38
|
+
rules: RuleRow[];
|
|
39
|
+
/** The group read failed: the whole page says why. */
|
|
40
|
+
errorText: string;
|
|
41
|
+
/** The rules read alone failed: only the rules region says why. */
|
|
42
|
+
rulesErrorText: string;
|
|
43
|
+
hideLoading: boolean;
|
|
44
|
+
hideError: boolean;
|
|
45
|
+
hideContent: boolean;
|
|
46
|
+
hideImage: boolean;
|
|
47
|
+
hidePrivacy: boolean;
|
|
48
|
+
hideCreated: boolean;
|
|
49
|
+
hideMemberCount: boolean;
|
|
50
|
+
hideRules: boolean;
|
|
51
|
+
hideRulesEmpty: boolean;
|
|
52
|
+
hideRulesError: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const initial: State = {
|
|
56
|
+
status: "loading",
|
|
57
|
+
id: "",
|
|
58
|
+
name: "",
|
|
59
|
+
description: "",
|
|
60
|
+
descriptionJson: "",
|
|
61
|
+
hasDescriptionJson: false,
|
|
62
|
+
privacy: "",
|
|
63
|
+
createdDate: "",
|
|
64
|
+
memberCount: "",
|
|
65
|
+
image: "",
|
|
66
|
+
initial: "G",
|
|
67
|
+
rules: [],
|
|
68
|
+
errorText: "",
|
|
69
|
+
rulesErrorText: "",
|
|
70
|
+
hideLoading: false,
|
|
71
|
+
hideError: true,
|
|
72
|
+
hideContent: true,
|
|
73
|
+
hideImage: true,
|
|
74
|
+
hidePrivacy: true,
|
|
75
|
+
hideCreated: true,
|
|
76
|
+
hideMemberCount: true,
|
|
77
|
+
hideRules: true,
|
|
78
|
+
hideRulesEmpty: true,
|
|
79
|
+
hideRulesError: true,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Bumped by every group load, so a response that arrives after a newer load began is dropped. */
|
|
83
|
+
let loadSeq = 0;
|
|
84
|
+
|
|
85
|
+
function inputId(): string {
|
|
86
|
+
// `himalaya.input.id` is the contract: hosts thread the opener's `id` nav param
|
|
87
|
+
// (himi.open { screenId: "himi_group_about", id }) into worker input.
|
|
88
|
+
const input = (globalThis as { himalaya?: { input?: { id?: string } } }).himalaya?.input;
|
|
89
|
+
return typeof input?.id === "string" ? input.id : "";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function failureOf(e: unknown): Failure {
|
|
93
|
+
const message = String((e as Error)?.message ?? e);
|
|
94
|
+
if (/HTTP (401|403)\b/.test(message)) return "forbidden";
|
|
95
|
+
if (/HTTP 404\b/.test(message)) return "missing";
|
|
96
|
+
return "failed";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function groupFailureText(failure: Failure): string {
|
|
100
|
+
if (failure === "forbidden") return copyParam("groupAbout.forbiddenTitle", "You can’t view this group’s details.");
|
|
101
|
+
if (failure === "missing") return copyParam("groupAbout.missingTitle", "This group no longer exists.");
|
|
102
|
+
return copyParam("groupAbout.errorTitle", "This group’s details could not be loaded.");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function rulesFailureText(failure: Failure): string {
|
|
106
|
+
if (failure === "forbidden") return copyParam("groupAbout.rulesForbidden", "You can’t view this group’s rules.");
|
|
107
|
+
return copyParam("groupAbout.rulesError", "The rules could not be loaded.");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The rules the server sent, numbered from 1. `undefined` when the answer is not a rules list
|
|
111
|
+
* at all — a missing or non-array `rules` is a malformed answer, not an empty group. */
|
|
112
|
+
function ruleRowsOf(response: unknown): RuleRow[] | undefined {
|
|
113
|
+
const rules = (response as { rules?: unknown } | null | undefined)?.rules;
|
|
114
|
+
if (!Array.isArray(rules)) return undefined;
|
|
115
|
+
const rows: RuleRow[] = [];
|
|
116
|
+
for (const entry of rules as WixGroupRule[]) {
|
|
117
|
+
const title = typeof entry?.title === "string" ? entry.title.trim() : "";
|
|
118
|
+
const description = typeof entry?.description === "string" ? entry.description.trim() : "";
|
|
119
|
+
if (!title && !description) continue;
|
|
120
|
+
rows.push({ id: `rule_${rows.length + 1}`, number: String(rows.length + 1), title, description });
|
|
121
|
+
}
|
|
122
|
+
return rows;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function withRules(state: State, rules: RuleRow[] | undefined, failure: Failure | undefined): State {
|
|
126
|
+
if (failure || !rules) {
|
|
127
|
+
return {
|
|
128
|
+
...state,
|
|
129
|
+
rules: [],
|
|
130
|
+
rulesErrorText: rulesFailureText(failure ?? "failed"),
|
|
131
|
+
hideRules: true,
|
|
132
|
+
hideRulesEmpty: true,
|
|
133
|
+
hideRulesError: false,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
...state,
|
|
138
|
+
rules,
|
|
139
|
+
rulesErrorText: "",
|
|
140
|
+
hideRules: rules.length === 0,
|
|
141
|
+
hideRulesEmpty: rules.length > 0,
|
|
142
|
+
hideRulesError: true,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function capitalized(value: string): string {
|
|
147
|
+
const lower = value.trim().toLowerCase();
|
|
148
|
+
return lower ? lower[0].toUpperCase() + lower.slice(1) : "";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function createdLabel(value: unknown): string {
|
|
152
|
+
if (typeof value !== "string" || !value) return "";
|
|
153
|
+
const date = new Date(value);
|
|
154
|
+
return Number.isNaN(date.getTime()) ? "" : formatDateMedium(date);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function groupState(state: State, id: string, group: WixGroup): State {
|
|
158
|
+
const name = (group.name || (group as { title?: string }).title || copyParam("group.groupFallbackName", "Group")).trim();
|
|
159
|
+
const body = descriptionBody(group.description, descriptionBody(group.teaser, "").bodyText);
|
|
160
|
+
const privacy = capitalized(group.privacyStatus ?? "");
|
|
161
|
+
const created = createdLabel(group.createdDate);
|
|
162
|
+
const count = group.membersCount ?? group.memberCount;
|
|
163
|
+
const image = groupImage(group, WIX_DETAIL_IMAGE);
|
|
164
|
+
return {
|
|
165
|
+
...state,
|
|
166
|
+
status: "ready",
|
|
167
|
+
id,
|
|
168
|
+
name,
|
|
169
|
+
description: body.bodyText,
|
|
170
|
+
descriptionJson: body.bodyJson,
|
|
171
|
+
hasDescriptionJson: body.bodyJson !== "",
|
|
172
|
+
privacy,
|
|
173
|
+
createdDate: created,
|
|
174
|
+
memberCount: typeof count === "number" ? `${count} ${count === 1 ? "member" : "members"}` : "",
|
|
175
|
+
image,
|
|
176
|
+
initial: (name[0] || "G").toUpperCase(),
|
|
177
|
+
errorText: "",
|
|
178
|
+
hideLoading: true,
|
|
179
|
+
hideError: true,
|
|
180
|
+
hideContent: false,
|
|
181
|
+
hideImage: !image,
|
|
182
|
+
hidePrivacy: !privacy,
|
|
183
|
+
hideCreated: !created,
|
|
184
|
+
hideMemberCount: typeof count !== "number",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function groupErrorState(id: string, failure: Failure): State {
|
|
189
|
+
return {
|
|
190
|
+
...initial,
|
|
191
|
+
id,
|
|
192
|
+
status: "error",
|
|
193
|
+
errorText: groupFailureText(failure),
|
|
194
|
+
hideLoading: true,
|
|
195
|
+
hideError: false,
|
|
196
|
+
hideContent: true,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const svc = defineService<State, {
|
|
201
|
+
load: (state: State, arg?: unknown) => Promise<State | undefined>;
|
|
202
|
+
reloadRules: (state: State, arg?: unknown) => Promise<State | undefined>;
|
|
203
|
+
openLink: (state: State, arg?: unknown) => Promise<undefined>;
|
|
204
|
+
}>("himiBrandedGroupAbout", {
|
|
205
|
+
state: initial,
|
|
206
|
+
actions: {
|
|
207
|
+
load: async (state, arg) => {
|
|
208
|
+
stashCopy(arg);
|
|
209
|
+
const seq = ++loadSeq;
|
|
210
|
+
const id = inputId();
|
|
211
|
+
if (!id) return groupErrorState("", "missing");
|
|
212
|
+
const [groupResult, rulesResult] = await Promise.allSettled([getGroup(id), listRules(id)]);
|
|
213
|
+
// A newer load began while these reads were in flight: its answer owns the state.
|
|
214
|
+
if (seq !== loadSeq) return undefined;
|
|
215
|
+
if (groupResult.status === "rejected") return groupErrorState(id, failureOf(groupResult.reason));
|
|
216
|
+
// Social Groups wraps the entity as `{ group }`; the typed signature claims a bare group.
|
|
217
|
+
const group = ((groupResult.value as unknown as { group?: WixGroup }).group ?? groupResult.value) as WixGroup;
|
|
218
|
+
if (!group || typeof group !== "object" || (group.id && group.id !== id)) return groupErrorState(id, "failed");
|
|
219
|
+
const ready = groupState(state, id, group);
|
|
220
|
+
return rulesResult.status === "rejected"
|
|
221
|
+
? withRules(ready, undefined, failureOf(rulesResult.reason))
|
|
222
|
+
: withRules(ready, ruleRowsOf(rulesResult.value), undefined);
|
|
223
|
+
},
|
|
224
|
+
// Retry for the rules region alone: the group's own facts stay on screen.
|
|
225
|
+
reloadRules: async (state, arg) => {
|
|
226
|
+
stashCopy(arg);
|
|
227
|
+
const id = state.id;
|
|
228
|
+
if (!id) return undefined;
|
|
229
|
+
const seq = loadSeq;
|
|
230
|
+
try {
|
|
231
|
+
const rules = ruleRowsOf(await listRules(id));
|
|
232
|
+
if (seq !== loadSeq || inputId() !== id) return undefined;
|
|
233
|
+
return withRules(state, rules, undefined);
|
|
234
|
+
} catch (e) {
|
|
235
|
+
if (seq !== loadSeq || inputId() !== id) return undefined;
|
|
236
|
+
return withRules(state, undefined, failureOf(e));
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
openLink: async (_state, arg) => { await openRichLink(arg); return undefined; },
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
export { svc };
|
|
@@ -1,69 +1,135 @@
|
|
|
1
|
-
//
|
|
2
|
-
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
-
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
-
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
-
// (_shared/branded-load-state.ts).
|
|
1
|
+
// Public Loyalty offering plus the current member's separately verified balance.
|
|
6
2
|
import { defineService } from "../_shared/collection-service.js";
|
|
7
3
|
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
8
|
-
import {
|
|
4
|
+
import { copyParam, copyTemplate } from "../_shared/himi-copy.js";
|
|
5
|
+
import { formatCurrency, formatNumber } from "../_shared/engine-intl.js";
|
|
6
|
+
import { memberAccess, assertMemberAccess } from "../_shared/member-access.js";
|
|
7
|
+
import { getLoyaltyProgram, listLoyaltyRewards, listLoyaltyEarningRules, getCurrentMemberLoyaltyAccount, type WixLoyaltyReward, type WixLoyaltyEarningRule } from "@himalaya/wix-loyalty";
|
|
9
8
|
|
|
10
9
|
interface Row { id: string; name: string; subtitle: string }
|
|
11
10
|
interface S extends LoadFlags {
|
|
12
|
-
programName: string; unit: string;
|
|
13
|
-
rewards: Row[]; emptyText: string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
notMockEmpty: boolean; notMockUnavailable: boolean;
|
|
11
|
+
programName: string; unit: string; currency: string;
|
|
12
|
+
rewards: Row[]; earningRules: Row[]; emptyText: string; earningEmptyText: string;
|
|
13
|
+
hideCatalog: boolean; hideEarningHeading: boolean; inactiveText: string;
|
|
14
|
+
rewardError: string; earningError: string; hideRewardError: boolean; hideEarningError: boolean; hideRewardRows: boolean;
|
|
15
|
+
memberPoints: string; memberMessage: string;
|
|
16
|
+
hideMemberCard: boolean; hideMemberSignIn: boolean; hideMemberRetry: boolean;
|
|
19
17
|
}
|
|
18
|
+
const PRIVATE_EMPTY = { memberPoints: "", memberMessage: "", hideMemberCard: true, hideMemberSignIn: true, hideMemberRetry: true };
|
|
19
|
+
const INITIAL: S = { ...LOADING, ...PRIVATE_EMPTY, programName: "", unit: "", currency: "", rewards: [], earningRules: [], emptyText: "", earningEmptyText: "", hideCatalog: false, hideEarningHeading: true, inactiveText: "", rewardError: "", earningError: "", hideRewardError: true, hideEarningError: true, hideRewardRows: false };
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
function
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
if (pts <= 0) return "Free";
|
|
26
|
-
return `${pts.toLocaleString()} ${unit}`;
|
|
21
|
+
function amount(value: unknown): value is number { return typeof value === "number" && Number.isFinite(value) && value >= 0; }
|
|
22
|
+
function baseConfig<T extends { tierId?: string }>(configs: T[] | undefined): T | undefined {
|
|
23
|
+
const base = configs?.filter(config => !config.tierId);
|
|
24
|
+
return base?.length === 1 ? base[0] : undefined;
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return
|
|
26
|
+
function points(value: number, customUnit: string): string {
|
|
27
|
+
const unit = customUnit || copyParam(value === 1 ? "loyalty.pointOne" : "loyalty.pointMany", value === 1 ? "point" : "points");
|
|
28
|
+
return copyTemplate("loyalty.pointsLabel", "{points} {unit}", { points: formatNumber(value), unit });
|
|
29
|
+
}
|
|
30
|
+
function rewardLabel(reward: WixLoyaltyReward, customUnit: string): string {
|
|
31
|
+
const configs = reward.discountAmount?.configsByTier ?? reward.couponReward?.fixedAmount?.configsByTier
|
|
32
|
+
?? reward.couponReward?.percentage?.configsByTier ?? reward.couponReward?.freeShipping?.configsByTier;
|
|
33
|
+
const cost = configs?.length ? baseConfig<{ tierId?: string; costInPoints?: number }>(configs)?.costInPoints : reward.requiredPoints;
|
|
34
|
+
if (!amount(cost)) return copyParam("loyalty.costUnavailable", "Points details unavailable");
|
|
35
|
+
return cost === 0 ? copyParam("loyalty.free", "Free") : points(cost, customUnit);
|
|
36
|
+
}
|
|
37
|
+
function earningLabel(rule: WixLoyaltyEarningRule, customUnit: string, currency: string): string {
|
|
38
|
+
if (rule.fixedAmount) {
|
|
39
|
+
const value = baseConfig(rule.fixedAmount.configs)?.points;
|
|
40
|
+
return amount(value) ? points(value, customUnit) : copyParam("loyalty.earningUnavailable", "Points details unavailable");
|
|
41
|
+
}
|
|
42
|
+
const rate = baseConfig(rule.conversionRate?.configs);
|
|
43
|
+
if (!rate || !amount(rate.points) || !amount(rate.moneyAmount) || rate.moneyAmount === 0 || !currency) {
|
|
44
|
+
return copyParam("loyalty.earningUnavailable", "Points details unavailable");
|
|
45
|
+
}
|
|
46
|
+
return copyTemplate("loyalty.pointsPerSpend", "{points} per {amount}", {
|
|
47
|
+
points: points(rate.points, customUnit), amount: formatCurrency(rate.moneyAmount, currency, "en", Number.isInteger(rate.moneyAmount) ? 0 : undefined),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function businessStamp(): unknown {
|
|
51
|
+
return (globalThis as { himalaya?: { input?: Record<string, unknown> } }).himalaya?.input?.__himiPreferenceBusiness;
|
|
52
|
+
}
|
|
53
|
+
function currencyFrom(s: S, arg: unknown): string {
|
|
54
|
+
if (!arg || typeof arg !== "object" || !("currency" in arg)) return s.currency;
|
|
55
|
+
const raw = (arg as { currency?: unknown }).currency;
|
|
56
|
+
return typeof raw === "string" && /^[A-Z]{3}$/.test(raw) ? raw : "";
|
|
31
57
|
}
|
|
32
|
-
|
|
33
|
-
const MOCK: Row[] = [
|
|
34
|
-
{ id: "sample-5off", name: "5% off your next order", subtitle: "500 points" },
|
|
35
|
-
{ id: "sample-ship", name: "Free shipping", subtitle: "300 points" },
|
|
36
|
-
{ id: "sample-15", name: "15% off any purchase", subtitle: "750 points" },
|
|
37
|
-
{ id: "sample-gift", name: "Free welcome gift", subtitle: "1,000 points" },
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
41
|
-
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
42
58
|
const COPY: LoadCopy<Row> = {
|
|
43
|
-
prefix: "loyalty",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
signIn: "Sign in to see your points and rewards.",
|
|
47
|
-
sample: () => MOCK.map((r) => ({ ...r })),
|
|
59
|
+
prefix: "loyalty", empty: "No rewards to redeem yet.",
|
|
60
|
+
error: "The rewards program couldn't be loaded.", signIn: "The rewards program couldn't be loaded.",
|
|
61
|
+
sample: () => [{ id: "sample-reward", name: copyParam("loyalty.sampleReward", "5% off your next order"), subtitle: points(500, "") }],
|
|
48
62
|
};
|
|
49
63
|
|
|
50
|
-
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedLoyalty", {
|
|
51
|
-
state:
|
|
64
|
+
const svc = defineService<S, { prepare: (s: S) => S; load: (s: S, arg?: unknown) => Promise<S> }>("himiBrandedLoyalty", {
|
|
65
|
+
state: INITIAL,
|
|
66
|
+
notHydrated: ["memberPoints", "memberMessage", "hideMemberCard", "hideMemberSignIn", "hideMemberRetry"],
|
|
67
|
+
notPersisted: ["memberPoints", "memberMessage", "hideMemberCard", "hideMemberSignIn", "hideMemberRetry"],
|
|
52
68
|
actions: {
|
|
53
|
-
|
|
69
|
+
prepare: s => ({ ...s, ...PRIVATE_EMPTY }),
|
|
70
|
+
load: async (s, arg) => {
|
|
71
|
+
const currency = currencyFrom(s, arg);
|
|
72
|
+
const business = businessStamp();
|
|
54
73
|
try {
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
const [response, member] = await Promise.all([getLoyaltyProgram(), memberAccess()]);
|
|
75
|
+
const program = response.loyaltyProgram ?? response.program;
|
|
76
|
+
if (!program || !["ACTIVE", "DRAFT", "PAUSED"].includes(program.status ?? "")) throw new Error("Loyalty program response is unavailable");
|
|
77
|
+
const customUnit = (program.pointDefinition?.customName ?? "").trim();
|
|
78
|
+
const common = { ...s, ...PRIVATE_EMPTY, currency, programName: program.name || copyParam("loyalty.programFallback", "Rewards"), unit: customUnit || copyParam("loyalty.pointMany", "points"), inactiveText: "", rewardError: "", earningError: "", hideRewardError: true, hideEarningError: true, hideRewardRows: true, hideEarningHeading: true };
|
|
79
|
+
if (program.status !== "ACTIVE") {
|
|
80
|
+
return { ...common, ...loaded("rewards", [], COPY), earningRules: [], earningEmptyText: "", hideCatalog: true,
|
|
81
|
+
inactiveText: copyParam("loyalty.inactive", "The rewards program isn't available right now.") };
|
|
82
|
+
}
|
|
83
|
+
// Balance failures cannot discard a public offering that loaded correctly.
|
|
84
|
+
const privateStateSupported = !!member.scope && ((globalThis as { himalaya?: { readLifecycleVersion?: number } }).himalaya?.readLifecycleVersion ?? 0) >= 1;
|
|
85
|
+
const accountRead = member.email && privateStateSupported
|
|
86
|
+
? getCurrentMemberLoyaltyAccount().then(value => ({ value, failed: false })).catch(() => ({ value: undefined, failed: true }))
|
|
87
|
+
: Promise.resolve({ value: undefined, failed: false });
|
|
88
|
+
const [[rewardResult, earningResult], account] = await Promise.all([
|
|
89
|
+
Promise.allSettled([listLoyaltyRewards(), listLoyaltyEarningRules()]), accountRead,
|
|
90
|
+
]);
|
|
91
|
+
const rewardResponse = rewardResult.status === "fulfilled" ? rewardResult.value : undefined;
|
|
92
|
+
const earningResponse = earningResult.status === "fulfilled" ? earningResult.value : undefined;
|
|
93
|
+
if (businessStamp() !== business) throw new Error("Business changed while Loyalty loaded");
|
|
94
|
+
if (rewardResult.status === "rejected" && earningResult.status === "rejected") throw new Error("Loyalty catalog is unavailable");
|
|
95
|
+
const rewards = (rewardResponse?.rewards ?? []).filter(reward => reward.active === true).map((reward, i) => ({
|
|
96
|
+
id: reward.id || `reward-${i}`, name: reward.name || copyParam("loyalty.rewardFallback", "Reward"), subtitle: rewardLabel(reward, customUnit),
|
|
97
|
+
}));
|
|
98
|
+
const earningRules = (earningResponse?.earningRules ?? []).filter(rule => rule.status === "ACTIVE").map((rule, i) => ({
|
|
99
|
+
id: rule.id || `earning-${i}`, name: rule.title || copyParam("loyalty.earnFallback", "Earn points"), subtitle: earningLabel(rule, customUnit, currency),
|
|
100
|
+
}));
|
|
101
|
+
let privateState = { ...PRIVATE_EMPTY };
|
|
102
|
+
if (member.email) {
|
|
103
|
+
try {
|
|
104
|
+
await assertMemberAccess(member);
|
|
105
|
+
const balance = account.value?.account?.points?.balance;
|
|
106
|
+
privateState = { ...PRIVATE_EMPTY, hideMemberCard: false,
|
|
107
|
+
memberPoints: typeof balance === "number" && Number.isFinite(balance) ? points(balance, customUnit) : "",
|
|
108
|
+
memberMessage: !privateStateSupported ? copyParam("loyalty.updateApp", "Update the app to see your points securely.") : account.failed ? copyParam("loyalty.pointsError", "Your points couldn't be loaded.")
|
|
109
|
+
: typeof balance !== "number" || !Number.isFinite(balance) ? copyParam("loyalty.pointsUnavailable", "Your points aren't available yet.") : "",
|
|
110
|
+
hideMemberRetry: !account.failed };
|
|
111
|
+
} catch {
|
|
112
|
+
const current = await memberAccess();
|
|
113
|
+
privateState = { ...PRIVATE_EMPTY, hideMemberCard: !current.email, hideMemberSignIn: !!current.email,
|
|
114
|
+
memberMessage: current.email ? copyParam("loyalty.pointsError", "Your points couldn't be loaded.") : "", hideMemberRetry: !current.email };
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
privateState.hideMemberSignIn = false;
|
|
118
|
+
}
|
|
119
|
+
return { ...common, ...loaded("rewards", rewards, COPY), ...privateState, earningRules, hideCatalog: false, hideEarningHeading: false,
|
|
120
|
+
rewardError: rewardResult.status === "rejected" ? copyParam("loyalty.rewardsError", "Rewards couldn't be loaded.") : "",
|
|
121
|
+
earningError: earningResult.status === "rejected" ? copyParam("loyalty.earningError", "Ways to earn points couldn't be loaded.") : "",
|
|
122
|
+
hideRewardError: rewardResult.status === "fulfilled", hideEarningError: earningResult.status === "fulfilled", hideRewardRows: rewardResult.status === "rejected",
|
|
123
|
+
emptyText: rewardResult.status === "rejected" ? "" : rewards.length ? "" : copyParam("loyalty.emptyText", COPY.empty),
|
|
124
|
+
earningEmptyText: earningResult.status === "rejected" || earningRules.length ? "" : copyParam("loyalty.earningEmpty", "No ways to earn points yet.") };
|
|
125
|
+
} catch (error) {
|
|
126
|
+
const failure = loadFailed("rewards", error, COPY);
|
|
127
|
+
return { ...s, ...PRIVATE_EMPTY, currency, earningRules: [], earningEmptyText: "", inactiveText: "", hideCatalog: !failure.isMock, hideEarningHeading: true, rewardError: "", earningError: "", hideRewardError: true, hideEarningError: true, hideRewardRows: !failure.isMock,
|
|
128
|
+
...failure, signInRequired: false, noSignIn: true };
|
|
64
129
|
}
|
|
65
130
|
},
|
|
66
131
|
},
|
|
67
132
|
});
|
|
133
|
+
svc.prepare();
|
|
68
134
|
svc.load();
|
|
69
135
|
export { svc };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
1
2
|
import { paymentSetupMessage } from "../_shared/payment-setup.js";
|
|
2
3
|
import { offlineWriteMessage, offlineWritesEnabled, withOnlineWrites } from "../_shared/online-actions.js";
|
|
3
4
|
import { connectivity } from "@himalaya/state";
|
|
@@ -140,7 +141,7 @@ function planRow(plan: WixPlan): PlanRow {
|
|
|
140
141
|
return {
|
|
141
142
|
id: plan.id || "",
|
|
142
143
|
name,
|
|
143
|
-
description: (plan.description
|
|
144
|
+
description: descriptionBody(plan.description).bodyText,
|
|
144
145
|
trialBadge,
|
|
145
146
|
noTrialBadge: !trialBadge,
|
|
146
147
|
priceLine: money(plan),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
1
2
|
// himi-branded-lite-podcasts — live RSS episodes with a persistent queue and
|
|
2
3
|
// the shared native/web media playback transport.
|
|
3
4
|
import { defineService } from "../_shared/collection-service.js";
|
|
@@ -99,7 +100,7 @@ function norm(episode: Episode): Row | null {
|
|
|
99
100
|
title: (episode.title || "Episode").trim() || "Episode",
|
|
100
101
|
subtitle: [dateLabel(episode.date), duration ? clock(duration) : ""].filter(Boolean).join(" · "),
|
|
101
102
|
image: (episode.image || "").trim(),
|
|
102
|
-
description: (episode.descriptionExcerpt
|
|
103
|
+
description: descriptionBody(episode.descriptionExcerpt).bodyText,
|
|
103
104
|
audioUrl,
|
|
104
105
|
durationMs: duration,
|
|
105
106
|
progressLabel: "",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
1
2
|
// himi-branded-lite-portfolio — real, public Wix Portfolio projects.
|
|
2
3
|
// Empty and error states stay explicit; media IDs are normalized for every host.
|
|
3
4
|
import { defineService } from "../_shared/collection-service.js";
|
|
@@ -28,7 +29,7 @@ function norm(project: WixPortfolioProject): Row {
|
|
|
28
29
|
return {
|
|
29
30
|
id: project.id || project.slug || title,
|
|
30
31
|
title,
|
|
31
|
-
subtitle: (project.description
|
|
32
|
+
subtitle: descriptionBody(project.description).bodyText,
|
|
32
33
|
image,
|
|
33
34
|
initial: (title[0] || "#").toUpperCase(),
|
|
34
35
|
hasImage: Boolean(image),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { descriptionBody } from "../_shared/rich-body.js";
|
|
1
2
|
// himi-branded-lite-portfolio-project — real Wix Portfolio project detail.
|
|
2
3
|
// The public project row is resolved again from Wix, then its ordered project
|
|
3
4
|
// items supply the actual image/video/text story. No sample project is invented.
|
|
@@ -59,7 +60,7 @@ function row(item: WixPortfolioProjectItem, index: number): MediaRow {
|
|
|
59
60
|
return {
|
|
60
61
|
id: item.id || `portfolio-item-${index}`,
|
|
61
62
|
title: (item.title ?? "").trim(),
|
|
62
|
-
description: (item.description
|
|
63
|
+
description: descriptionBody(item.description).bodyText,
|
|
63
64
|
image,
|
|
64
65
|
videoUrl: hasVideo ? videoUrl : "",
|
|
65
66
|
hasImage,
|
|
@@ -132,7 +133,7 @@ const svc = defineService<State, { load: (state: State, arg?: unknown) => Promis
|
|
|
132
133
|
id,
|
|
133
134
|
title: (project.title || copyParam("portfolioProject.projectFallbackName", "Project")).trim(),
|
|
134
135
|
initial: ((project.title || "P").trim()[0] || "P").toUpperCase(),
|
|
135
|
-
description: (project.description
|
|
136
|
+
description: descriptionBody(project.description).bodyText,
|
|
136
137
|
coverImage: wixMediaUrl(portfolioCoverRef(project.coverImage), WIX_DETAIL_IMAGE),
|
|
137
138
|
items,
|
|
138
139
|
emptyText: items.length ? "" : copyParam("portfolioProject.noMediaText", "This project has no published media yet."),
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { WixProgramFull } from "@himalaya/wix-online-programs";
|
|
2
|
+
import { copyParam } from "../_shared/himi-copy.js";
|
|
3
|
+
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
4
|
+
|
|
5
|
+
export interface ProgramFact { id: string; icon: string; title: string; body: string }
|
|
6
|
+
|
|
7
|
+
/** Only explicit Program fields establish a fact. Missing access is never public. */
|
|
8
|
+
export function programFacts(program: WixProgramFull, locale: string): ProgramFact[] {
|
|
9
|
+
const facts: ProgramFact[] = [];
|
|
10
|
+
const timeline = program.timeline;
|
|
11
|
+
if (timeline?.selfPaced === true) facts.push({
|
|
12
|
+
id: "pace", icon: "clock",
|
|
13
|
+
title: copyParam("program.facts.selfPacedTitle", "Self-paced"),
|
|
14
|
+
body: copyParam("program.facts.selfPacedBody", "Complete steps at your own pace."),
|
|
15
|
+
});
|
|
16
|
+
else if (timeline?.selfPaced === false) facts.push({
|
|
17
|
+
id: "pace", icon: "clock",
|
|
18
|
+
title: copyParam("program.facts.scheduledTitle", "Scheduled"),
|
|
19
|
+
body: copyParam("program.facts.scheduledBody", "Follow the program schedule."),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const rawStart = timeline?.startDate;
|
|
23
|
+
// A date-only field is a calendar day, not midnight in the viewer's time zone. Build it at LOCAL noon and
|
|
24
|
+
// format it in the local zone: that reads the same day with ECMA-402 and on engines without it (watch/Wear),
|
|
25
|
+
// whose fallback ignores a timeZone argument and reads local getters.
|
|
26
|
+
const dateOnly = typeof rawStart === "string" ? /^(\d{4})-(\d{2})-(\d{2})$/.exec(rawStart.trim()) : null;
|
|
27
|
+
const date = dateOnly ? new Date(Number(dateOnly[1]), Number(dateOnly[2]) - 1, Number(dateOnly[3]), 12)
|
|
28
|
+
: typeof rawStart === "string" && rawStart.trim() ? new Date(rawStart) : undefined;
|
|
29
|
+
if (date && Number.isFinite(date.getTime())) {
|
|
30
|
+
let body: string;
|
|
31
|
+
try { body = formatDateMedium(date, locale); }
|
|
32
|
+
catch { body = formatDateMedium(date, "en"); }
|
|
33
|
+
facts.push({ id: "start", icon: "calendar", title: copyParam("program.facts.fixedStartTitle", "Fixed start date"), body });
|
|
34
|
+
} else if (timeline?.selfPaced === true && (rawStart === undefined || rawStart === "")) facts.push({
|
|
35
|
+
id: "start", icon: "calendar",
|
|
36
|
+
title: copyParam("program.facts.flexibleStartTitle", "Flexible start date"),
|
|
37
|
+
body: copyParam("program.facts.flexibleStartBody", "Start whenever you're ready."),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const access = program.restrictions?.accessType?.toUpperCase();
|
|
41
|
+
if (access === "PUBLIC") facts.push({
|
|
42
|
+
id: "access", icon: "globe",
|
|
43
|
+
title: copyParam("program.facts.publicTitle", "Public"),
|
|
44
|
+
body: copyParam("program.facts.publicBody", "Anyone can join."),
|
|
45
|
+
});
|
|
46
|
+
else if (access === "PRIVATE") facts.push({
|
|
47
|
+
id: "access", icon: "lock",
|
|
48
|
+
title: copyParam("program.facts.privateTitle", "Private"),
|
|
49
|
+
body: copyParam("program.facts.privateBody", "Approval is required to join."),
|
|
50
|
+
});
|
|
51
|
+
return facts;
|
|
52
|
+
}
|