@wix/himalaya-cli 0.1391.0 → 0.1393.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/stdlib/wix-sdk/bookings-v2/src/extensions.d.ts +7 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bookings.mjs +4 -4
- package/dist/cli.mjs +31 -23
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/sdk-reference.json +4 -4
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +52 -28
- package/templates/beauty-salon-owner/dev/index.ts +545 -100
- package/templates/beauty-salon-owner/himalaya.content.json +6 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +52 -28
- package/templates/branded-lite/tier5-src/himi-branded-lite-group/index.ts +24 -24
- package/templates/community-club/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/community-club/tier5-src/himi-branded-lite-group/index.ts +24 -24
- package/templates/community-club-owner/dev/index.ts +317 -100
- package/templates/community-club-owner/himalaya.content.json +6 -0
- package/templates/community-club-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/community-club-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/community-club-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/community-club-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/community-club-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/community-club-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/community-club-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/community-club-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/community-club-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/community-club-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/community-club-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/events-meetups/tier5-src/himi-branded-lite-group/index.ts +24 -24
- package/templates/events-meetups-owner/dev/index.ts +275 -100
- package/templates/events-meetups-owner/himalaya.content.json +6 -0
- package/templates/events-meetups-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/events-meetups-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +52 -28
- package/templates/gym-fitness-owner/dev/index.ts +545 -100
- package/templates/gym-fitness-owner/himalaya.content.json +6 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group/index.ts +24 -24
- package/templates/nonprofit-cause-owner/dev/index.ts +503 -100
- package/templates/nonprofit-cause-owner/himalaya.content.json +6 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/owner-lite/dev/index.ts +545 -100
- package/templates/owner-lite/himalaya.content.json +6 -0
- package/templates/owner-lite/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/owner-lite/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/owner-lite/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/owner-lite/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/owner-lite/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/owner-lite/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/owner-lite/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/owner-lite/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/owner-lite/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/owner-lite/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/owner-lite/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/owner-lite/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/owner-lite/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/podcast-creator-owner/dev/index.ts +317 -100
- package/templates/podcast-creator-owner/himalaya.content.json +6 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +52 -28
- package/templates/portfolio-creative-owner/dev/index.ts +545 -100
- package/templates/portfolio-creative-owner/himalaya.content.json +6 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/restaurant-owner/dev/index.ts +545 -100
- package/templates/restaurant-owner/himalaya.content.json +6 -0
- package/templates/restaurant-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/restaurant-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +52 -28
- package/templates/retail-store-owner/dev/index.ts +317 -100
- package/templates/retail-store-owner/himalaya.content.json +6 -0
- package/templates/retail-store-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/retail-store-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
- package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/yoga-studio-owner/dev/index.ts +503 -100
- package/templates/yoga-studio-owner/himalaya.content.json +6 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-account.ts +6 -2
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +115 -12
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
|
@@ -10,25 +10,24 @@ import { getPost, getDraftPost, publishDraftPost, revertDraftPost, deleteDraftPo
|
|
|
10
10
|
import { parseRicosJson } from "@himalaya/wix-rich-content";
|
|
11
11
|
import { openRichLink } from "../_shared/rich-content-link.js";
|
|
12
12
|
import { richBody } from "../_shared/rich-body.js";
|
|
13
|
-
import { ownerLoadError, isBridgeUnavailable, isOwnerPreviewDemo,
|
|
13
|
+
import { ownerLoadError, isBridgeUnavailable, isTransportFailure, isOwnerPreviewDemo, ownerDemoFallback, ownerWriteError, isNotFound } from "../_shared/owner-load-error.js";
|
|
14
14
|
import { DEMO_POSTS, DEMO_NOTE, DEMO_SAVE_NOTE } from "../_shared/owner-preview-demo.js";
|
|
15
15
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
16
|
-
import { get as dbGet, upsert as dbUpsert, remove as dbRemove,
|
|
16
|
+
import { get as dbGet, upsert as dbUpsert, remove as dbRemove, type DbEntity } from "../_shared/owner-local-db.js";
|
|
17
17
|
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
18
18
|
import { blankFlags } from "../_shared/detail-facts.js";
|
|
19
19
|
|
|
20
|
-
// Offline-first (data-offline):
|
|
21
|
-
// `owner_posts` entity
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
20
|
+
// Offline-first (data-offline): detail reads fall back to the last-synced local row
|
|
21
|
+
// of the encrypted `owner_posts` entity. Publish/unpublish/delete are
|
|
22
|
+
// SERVER-CONFIRMED: the local row changes only after Wix accepts the write; a failed
|
|
23
|
+
// one leaves it alone and tells the owner why. No host replays a queued write, so
|
|
24
|
+
// nothing is queued.
|
|
25
25
|
// Every local-db call is wrapped (try/catch) so a build that ships without the
|
|
26
|
-
// `local_database` grant behaves exactly as before (online-only, no cache
|
|
26
|
+
// `local_database` grant behaves exactly as before (online-only, no cache).
|
|
27
27
|
const ENTITY = "owner_posts";
|
|
28
28
|
async function cachePut(row: DbEntity): Promise<void> { try { await dbUpsert(ENTITY, row); } catch { /* capability not granted */ } }
|
|
29
29
|
async function cacheDrop(id: string): Promise<void> { try { await dbRemove(ENTITY, id); } catch { /* capability not granted */ } }
|
|
30
30
|
async function cacheGet(id: string): Promise<DbEntity | null> { try { return await dbGet(ENTITY, id); } catch { return null; } }
|
|
31
|
-
async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> { try { await dbEnqueue(actionId, params); } catch { /* capability not granted */ } }
|
|
32
31
|
/** [rico] #3370 — keep the body's plain text with the post's cached row, so the offline detail shows it. It is
|
|
33
32
|
* merged into the row the posts list wrote rather than replacing it; a later list re-sync writes its own rows
|
|
34
33
|
* and drops it again, until the detail is next opened online. */
|
|
@@ -250,16 +249,39 @@ function cachedDetail(s: PostState, row: DbEntity): PostState {
|
|
|
250
249
|
});
|
|
251
250
|
}
|
|
252
251
|
|
|
253
|
-
|
|
252
|
+
/** The re-read after a write Wix CONFIRMED: when it fails — thrown or as an error state
|
|
253
|
+
* ("post not found" for a 5xx on both reads) — the confirmed change stays on screen. */
|
|
254
|
+
async function reread(prev: PostState, actionMessage: string, confirmed: PostState): Promise<PostState> {
|
|
255
|
+
try {
|
|
256
|
+
// A reread right after a CONFIRMED write never drops the row that write just cached: a
|
|
257
|
+
// both-404 here is a lagging read, not proof the post is gone.
|
|
258
|
+
const next = await refresh(prev, prev.id, actionMessage, { dropIfGone: false });
|
|
259
|
+
return next.status === "error" ? confirmed : next;
|
|
260
|
+
} catch {
|
|
261
|
+
return confirmed;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function refresh(prev: PostState, id: string, actionMessage = "", opts: { dropIfGone?: boolean } = {}): Promise<PostState> {
|
|
254
266
|
let post: any | undefined;
|
|
255
267
|
let draft: any | undefined;
|
|
256
268
|
let lastError: unknown;
|
|
257
|
-
|
|
269
|
+
let postError: unknown;
|
|
270
|
+
try { post = (await getPost(id)).post; } catch (e) { lastError = postError = e; /* draft-only */ }
|
|
258
271
|
try { draft = (await getDraftPost(id)).draftPost; } catch (e) { lastError = e; /* published-only or missing */ }
|
|
259
272
|
if (!post && !draft) {
|
|
260
273
|
// Both arms swallowed their errors above; surface the DESIGNED bridge
|
|
261
|
-
// boundary so the callers' catches can fall
|
|
262
|
-
|
|
274
|
+
// boundary (and a device with no connection) so the callers' catches can fall
|
|
275
|
+
// back to the cached row or the demo post — never "post not found" for a post
|
|
276
|
+
// that was only unreachable.
|
|
277
|
+
// Either read counts: a published-only post's draft read is always a 404, so the
|
|
278
|
+
// published read's failure is the one that says whether the post was only unreachable.
|
|
279
|
+
for (const err of [postError, lastError]) {
|
|
280
|
+
if (isBridgeUnavailable(err) || isTransportFailure(err)) throw err;
|
|
281
|
+
}
|
|
282
|
+
// Wix says it is gone on BOTH reads (a published-only post's draft read is a 404 on its
|
|
283
|
+
// own): its cached row must not outlive it, or an offline load repaints a deleted post.
|
|
284
|
+
if (opts.dropIfGone !== false && isNotFound(postError) && isNotFound(lastError)) await cacheDrop(id);
|
|
263
285
|
return shape({ ...prev, id, status: "error", title: "", error: copyParam("ownerPost.errorNotFound", "post not found"), actionMessage });
|
|
264
286
|
}
|
|
265
287
|
const title = (draft?.title || post?.title || "Untitled post").trim();
|
|
@@ -336,9 +358,10 @@ const svc = defineService<PostState, {
|
|
|
336
358
|
return loaded;
|
|
337
359
|
} catch (e) {
|
|
338
360
|
// Offline: fall back to the last-synced local row before the demo/error paths.
|
|
339
|
-
|
|
361
|
+
// Wix says it is gone (e.g. a delete whose reply was lost): drop the row, never show it.
|
|
362
|
+
const cached = isNotFound(e) ? (await cacheDrop(id), null) : await cacheGet(id);
|
|
340
363
|
if (cached) return cachedDetail(s, cached);
|
|
341
|
-
if (
|
|
364
|
+
if (ownerDemoFallback(e)) {
|
|
342
365
|
const demo = demoDetail(s, id);
|
|
343
366
|
if (demo) return demo;
|
|
344
367
|
}
|
|
@@ -359,9 +382,10 @@ const svc = defineService<PostState, {
|
|
|
359
382
|
await cacheBodyText(loaded);
|
|
360
383
|
return loaded;
|
|
361
384
|
} catch (e) {
|
|
362
|
-
|
|
385
|
+
// Wix says it is gone (e.g. a delete whose reply was lost): drop the row, never show it.
|
|
386
|
+
const cached = isNotFound(e) ? (await cacheDrop(s.id), null) : await cacheGet(s.id);
|
|
363
387
|
if (cached) return cachedDetail(s, cached);
|
|
364
|
-
if (
|
|
388
|
+
if (ownerDemoFallback(e)) {
|
|
365
389
|
const demo = demoDetail(s, s.id);
|
|
366
390
|
if (demo) return demo;
|
|
367
391
|
}
|
|
@@ -373,19 +397,18 @@ const svc = defineService<PostState, {
|
|
|
373
397
|
if (isOwnerPreviewDemo() || s.demoNote) return shape({ ...s, actionMessage: copyParam("ownerCommon.demoSaveNote", DEMO_SAVE_NOTE) });
|
|
374
398
|
if (!s.id) return shape({ ...s, actionMessage: copyParam("ownerPost.noIdMessage", "No post id.") });
|
|
375
399
|
if (s.postStatusRaw === "PUBLISHED") return shape({ ...s, actionMessage: copyParam("ownerPost.alreadyPublished", "Post is already published.") });
|
|
376
|
-
// Optimistic local write — the detail/list repaint from cache immediately.
|
|
377
|
-
const optimistic = shape({ ...s, postStatusRaw: "PUBLISHED", postStatus: "Published", actionMessage: copyParam("ownerPost.publishedMessage", "Post published.") });
|
|
378
|
-
await cachePut(cacheRow(optimistic));
|
|
379
400
|
try {
|
|
380
401
|
await publishDraftPost(s.id);
|
|
381
|
-
return refresh(s, s.id, copyParam("ownerPost.publishedMessage", "Post published."));
|
|
382
402
|
} catch (e) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
return shape({ ...optimistic, actionMessage: copyParam("ownerCommon.demoSaveNote", DEMO_SAVE_NOTE) });
|
|
386
|
-
}
|
|
387
|
-
return shape({ ...s, actionMessage: ownerLoadError(e) });
|
|
403
|
+
// Nothing replays a queued write: the post is as it was, and the owner is told why.
|
|
404
|
+
return shape({ ...s, actionMessage: ownerWriteError(e) });
|
|
388
405
|
}
|
|
406
|
+
// Wix confirmed it: the list repaints from cache at once, and a re-read that fails
|
|
407
|
+
// afterwards still shows the confirmed change rather than undoing it on screen.
|
|
408
|
+
const published = copyParam("ownerPost.publishedMessage", "Post published.");
|
|
409
|
+
const confirmed = shape({ ...s, postStatusRaw: "PUBLISHED", postStatus: "Published", actionMessage: published });
|
|
410
|
+
await cachePut(cacheRow(confirmed));
|
|
411
|
+
return reread(s, published, confirmed);
|
|
389
412
|
},
|
|
390
413
|
unpublish: async (s0) => {
|
|
391
414
|
const s = disarm(s0);
|
|
@@ -394,19 +417,16 @@ const svc = defineService<PostState, {
|
|
|
394
417
|
if (s.postStatusRaw !== "PUBLISHED" && s.postStatusRaw !== "SCHEDULED") {
|
|
395
418
|
return shape({ ...s, actionMessage: copyParam("ownerPost.alreadyDraft", "Post is already a draft.") });
|
|
396
419
|
}
|
|
397
|
-
// Optimistic local write — the detail/list repaint from cache immediately.
|
|
398
|
-
const optimistic = shape({ ...s, postStatusRaw: "UNPUBLISHED", postStatus: "Draft", actionMessage: "Post moved to drafts." });
|
|
399
|
-
await cachePut(cacheRow(optimistic));
|
|
400
420
|
try {
|
|
401
421
|
await revertDraftPost(s.id);
|
|
402
|
-
return refresh(s, s.id, copyParam("ownerPost.unpublishedMessage", "Post moved to drafts."));
|
|
403
422
|
} catch (e) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
return shape({ ...optimistic, actionMessage: copyParam("ownerCommon.demoSaveNote", DEMO_SAVE_NOTE) });
|
|
407
|
-
}
|
|
408
|
-
return shape({ ...s, actionMessage: ownerLoadError(e) });
|
|
423
|
+
// Nothing replays a queued write: the post is as it was, and the owner is told why.
|
|
424
|
+
return shape({ ...s, actionMessage: ownerWriteError(e) });
|
|
409
425
|
}
|
|
426
|
+
const unpublished = copyParam("ownerPost.unpublishedMessage", "Post moved to drafts.");
|
|
427
|
+
const confirmed = shape({ ...s, postStatusRaw: "UNPUBLISHED", postStatus: "Draft", actionMessage: unpublished });
|
|
428
|
+
await cachePut(cacheRow(confirmed));
|
|
429
|
+
return reread(s, unpublished, confirmed);
|
|
410
430
|
},
|
|
411
431
|
// #3158 — destructive, so two steps. `delete` (the Manage card's Delete button)
|
|
412
432
|
// only ARMS the inline confirmation, which names the record and says it cannot
|
|
@@ -423,18 +443,15 @@ const svc = defineService<PostState, {
|
|
|
423
443
|
const s = disarm(s0);
|
|
424
444
|
if (isOwnerPreviewDemo() || s.demoNote) return shape({ ...s, actionMessage: copyParam("ownerCommon.demoSaveNote", DEMO_SAVE_NOTE) });
|
|
425
445
|
if (!s.id) return shape({ ...s, actionMessage: copyParam("ownerPost.noIdMessage", "No post id.") });
|
|
426
|
-
// Optimistic local delete — the list drops the row immediately.
|
|
427
|
-
await cacheDrop(s.id);
|
|
428
446
|
try {
|
|
429
447
|
await deleteDraftPost(s.id);
|
|
430
|
-
return shape({ ...s, status: "deleted", title: "", emptyText: copyParam("ownerPost.deletedEmpty", "Post deleted."), actionMessage: "" });
|
|
431
448
|
} catch (e) {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
return shape({ ...s, status: "deleted", title: "", emptyText: copyParam("ownerPost.deletedEmpty", "Post deleted."), actionMessage: copyParam("ownerCommon.demoSaveNote", DEMO_SAVE_NOTE) });
|
|
435
|
-
}
|
|
436
|
-
return shape({ ...s, actionMessage: ownerLoadError(e) });
|
|
449
|
+
// Nothing replays a queued write: the post stays, and the owner is told why.
|
|
450
|
+
return shape({ ...s, actionMessage: ownerWriteError(e) });
|
|
437
451
|
}
|
|
452
|
+
// Only a delete Wix confirmed leaves the local list.
|
|
453
|
+
await cacheDrop(s.id);
|
|
454
|
+
return shape({ ...s, status: "deleted", title: "", emptyText: copyParam("ownerPost.deletedEmpty", "Post deleted."), actionMessage: "" });
|
|
438
455
|
} finally {
|
|
439
456
|
deleteInFlight = false;
|
|
440
457
|
}
|
|
@@ -10,21 +10,20 @@ import { wixCall } from "@himalaya/wix-site-media";
|
|
|
10
10
|
import { wixMediaUrl, WIX_DETAIL_IMAGE } from "../_shared/himi-store.js";
|
|
11
11
|
import { defineService } from "@himalaya/state";
|
|
12
12
|
import { getDraftPost, createDraftPost, updateDraftPost, type WixDraftPostWrite, type WixRichContent } from "@himalaya/wix-blog";
|
|
13
|
-
import { ownerLoadError,
|
|
13
|
+
import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback, ownerWriteError } from "../_shared/owner-load-error.js";
|
|
14
14
|
import { DEMO_POSTS, DEMO_NOTE, DEMO_SAVE_NOTE, demoRefusalPatch } from "../_shared/owner-preview-demo.js";
|
|
15
15
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
16
|
-
import { get as dbGet, upsert as dbUpsert, remove as dbRemove,
|
|
16
|
+
import { get as dbGet, upsert as dbUpsert, remove as dbRemove, type DbEntity } from "../_shared/owner-local-db.js";
|
|
17
17
|
|
|
18
18
|
// Offline-first (data-offline): owner CRUD is WRITE-BEHIND against the encrypted
|
|
19
|
-
// `owner_posts` entity — cache confirmed writes
|
|
20
|
-
//
|
|
19
|
+
// `owner_posts` entity — cache confirmed writes only; a failed save says nothing was
|
|
20
|
+
// saved (no host replays a queue). Failed cover imports must not appear as saved drafts.
|
|
21
21
|
// Every local-db call is wrapped (try/catch) so a build that ships without the
|
|
22
22
|
// `local_database` grant behaves exactly as before (online-only, no cache/queue).
|
|
23
23
|
const ENTITY = "owner_posts";
|
|
24
24
|
async function cachePut(row: DbEntity): Promise<void> { try { await dbUpsert(ENTITY, row); } catch { /* capability not granted */ } }
|
|
25
25
|
async function cacheDrop(id: string): Promise<void> { try { await dbRemove(ENTITY, id); } catch { /* capability not granted */ } }
|
|
26
26
|
async function cacheGet(id: string): Promise<DbEntity | null> { try { return await dbGet(ENTITY, id); } catch { return null; } }
|
|
27
|
-
async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> { try { await dbEnqueue(actionId, params); } catch { /* capability not granted */ } }
|
|
28
27
|
|
|
29
28
|
type Mode = "create" | "edit";
|
|
30
29
|
|
|
@@ -223,7 +222,7 @@ const svc = defineService<PostFormState, {
|
|
|
223
222
|
status: "idle", error: "", savedMessage: "",
|
|
224
223
|
});
|
|
225
224
|
}
|
|
226
|
-
if (
|
|
225
|
+
if (ownerDemoFallback(e)) {
|
|
227
226
|
const d = DEMO_POSTS.find((x) => x.id === id);
|
|
228
227
|
if (d) {
|
|
229
228
|
return shape({
|
|
@@ -342,23 +341,11 @@ const svc = defineService<PostFormState, {
|
|
|
342
341
|
await cachePut(localRow(id));
|
|
343
342
|
return savedState(id, editing ? copyParam("ownerPostForm.updatedMessage", "Post updated.") : copyParam("ownerPostForm.createdMessage", "Draft created."));
|
|
344
343
|
} catch (e) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// Real device offline: cache and queue the edit for reconnect. `preserveBody` stays
|
|
351
|
-
// "true" even for a body edit, so a bundle rolled back past this change keeps the stored
|
|
352
|
-
// body rather than flattening it to text. This bundle replays `richContentJson`.
|
|
353
|
-
await cachePut(localRow(localId));
|
|
354
|
-
await queueWrite("tier5.himiOwnerLitePostForm.submit", {
|
|
355
|
-
id: targetId, title, excerpt, coverUrl, coverChanged: String(coverChanged), preserveBody: "true",
|
|
356
|
-
body: postBodyText(kept), ...(bodyEdited ? { richContentJson: bodyRaw } : {}),
|
|
357
|
-
isFeatured: String(isFeatured), mode: editing ? "edit" : "create",
|
|
358
|
-
});
|
|
359
|
-
return savedState(localId, copyParam("ownerPostForm.savedOffline", "Saved offline — will sync when you reconnect."));
|
|
360
|
-
}
|
|
361
|
-
return shape({ ...s, status: "error", error: ownerLoadError(e), savedMessage: "" });
|
|
344
|
+
// Demo / web-preview: the record came from demo sample data (marked by demoNote).
|
|
345
|
+
if (s.demoNote) return demoRefusal(s);
|
|
346
|
+
// Never "saved offline": nothing replays a queued write on any platform. The
|
|
347
|
+
// typed values stay in the form (the body in its editor), so a retry is one tap.
|
|
348
|
+
return shape({ ...s, title, excerpt, coverUrl, isFeatured: isFeatured ? "true" : "false", status: "error", error: ownerWriteError(e), savedMessage: "" });
|
|
362
349
|
}
|
|
363
350
|
})()),
|
|
364
351
|
},
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { defineService } from "../_shared/collection-service.js";
|
|
6
6
|
import { queryPosts, queryDraftPosts } from "@himalaya/wix-blog";
|
|
7
|
-
import { ownerLoadError,
|
|
7
|
+
import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_shared/owner-load-error.js";
|
|
8
8
|
import { DEMO_POSTS, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
9
9
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
10
10
|
import { getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
|
|
@@ -227,7 +227,7 @@ async function loadList(s: PostsState): Promise<PostsState> {
|
|
|
227
227
|
} catch (e) {
|
|
228
228
|
// Offline / fetch failure: keep the last-synced cache BEFORE the demo/error fallbacks.
|
|
229
229
|
if (cached.length) return base;
|
|
230
|
-
if (
|
|
230
|
+
if (ownerDemoFallback(e)) return demoList(s);
|
|
231
231
|
return shape({ ...s, status: "error", allPosts: [], posts: [], error: ownerLoadError(e) });
|
|
232
232
|
}
|
|
233
233
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { defineService } from "@himalaya/state";
|
|
10
10
|
import { querySites, type WixSite } from "@himalaya/wix-site-list";
|
|
11
|
-
import { ownerLoadError,
|
|
11
|
+
import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_shared/owner-load-error.js";
|
|
12
12
|
import { DEMO_SITES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
|
|
13
13
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
14
14
|
import { getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
|
|
@@ -165,7 +165,7 @@ async function loadList(s: SitesState): Promise<SitesState> {
|
|
|
165
165
|
} catch (e) {
|
|
166
166
|
// Offline / fetch failure: keep the last-synced cache BEFORE the demo/error fallbacks.
|
|
167
167
|
if (repairedCache.length) return base;
|
|
168
|
-
if (
|
|
168
|
+
if (ownerDemoFallback(e)) return demoList(s);
|
|
169
169
|
return shape({ ...s, status: "error", allSites: [], sites: [], error: ownerLoadError(e) });
|
|
170
170
|
}
|
|
171
171
|
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// Tier-5 bundle: __HIMI_APP_NAME__ — TODAY. The worker behind the Home Screen widget.
|
|
2
|
+
//
|
|
3
|
+
// A WidgetKit extension (and a Glance receiver) runs no JS and holds no Wix session, and the OTA
|
|
4
|
+
// widget producer has no credential either, so neither can read an owner's business. The PHONE
|
|
5
|
+
// app runs this worker headlessly with its owner Wix bridge, resolves the widget descriptors'
|
|
6
|
+
// `$service:ownerToday.*` leaves to literals (CompanionDescriptorResolver, the same pattern the
|
|
7
|
+
// watch companion uses), and writes the frozen tree to the App Group for the widget to render.
|
|
8
|
+
//
|
|
9
|
+
// One owner glance: "what's next, and what is waiting for me" — the next booking, the booking
|
|
10
|
+
// requests waiting on the owner, and the orders that need attention. Read-only: a widget never
|
|
11
|
+
// writes to the business.
|
|
12
|
+
//
|
|
13
|
+
// Each source degrades on its own. A site without Bookings answers 428/404 on the bookings
|
|
14
|
+
// query, and that must not cost the order count (or the reverse).
|
|
15
|
+
|
|
16
|
+
import { defineService } from "@himalaya/state";
|
|
17
|
+
import { queryBookings } from "@himalaya/wix-bookings";
|
|
18
|
+
import { searchOrders } from "@himalaya/wix-ecom";
|
|
19
|
+
import { ownerOrderAttentionFilter } from "../_shared/owner-order-attention.js";
|
|
20
|
+
import { readSelectedSite } from "../_shared/owner-selected-site.js";
|
|
21
|
+
|
|
22
|
+
type Rec = Record<string, unknown>;
|
|
23
|
+
|
|
24
|
+
/** One booking as the widget shows it. Client FIRST name only: a Home Screen is visible to
|
|
25
|
+
* anyone near the phone. */
|
|
26
|
+
export interface TodayBooking {
|
|
27
|
+
bookingId: string;
|
|
28
|
+
name: string;
|
|
29
|
+
service: string;
|
|
30
|
+
timeLabel: string; // "10:30"
|
|
31
|
+
dayLabel: string; // "Today" / "Tomorrow" / "Thu 16 Oct"
|
|
32
|
+
/** "Today 10:30" — the absolute moment, never a countdown: a frozen "in 21 min" is wrong a
|
|
33
|
+
* minute later, and nothing re-renders the widget between app foregrounds. */
|
|
34
|
+
whenLabel: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TodayState {
|
|
38
|
+
status: "loading" | "ready" | "error" | "signedOut";
|
|
39
|
+
siteName: string;
|
|
40
|
+
/** Header line: "Today · <site>", or "Today" when the site has no name yet. */
|
|
41
|
+
header: string;
|
|
42
|
+
next: TodayBooking;
|
|
43
|
+
hasNext: boolean;
|
|
44
|
+
/** Hide the next-booking block: nothing is booked, or Bookings cannot be read. */
|
|
45
|
+
hideNext: boolean;
|
|
46
|
+
/** "No upcoming bookings" — shown in place of the block when Bookings has nothing ahead. */
|
|
47
|
+
nextNote: string;
|
|
48
|
+
hideNextNote: boolean;
|
|
49
|
+
requestCount: number;
|
|
50
|
+
/** "2 requests" / "1 request" / "No requests". At the read cap: "50+ requests". */
|
|
51
|
+
requestLabel: string;
|
|
52
|
+
orderCount: number;
|
|
53
|
+
/** "3 orders to handle" / "1 order to handle" / "No orders waiting". */
|
|
54
|
+
orderLabel: string;
|
|
55
|
+
/** Compact counts for the small widget: "2 req · 3 orders". */
|
|
56
|
+
countsShort: string;
|
|
57
|
+
bookingsReady: boolean;
|
|
58
|
+
ordersReady: boolean;
|
|
59
|
+
hideRequests: boolean;
|
|
60
|
+
hideOrders: boolean;
|
|
61
|
+
/** One-line state copy for a degrade (signed out, read failed, nothing installed). */
|
|
62
|
+
message: string;
|
|
63
|
+
hideMessage: boolean;
|
|
64
|
+
/** Epoch SECONDS after which this frame's labels are wrong: the next local midnight ("Today" /
|
|
65
|
+
* "Tomorrow" shift) or the next booking's start (it is no longer "next"), whichever is first.
|
|
66
|
+
* The phone caps the snapshot's lifetime at it, so a frozen frame never outlives its words. */
|
|
67
|
+
validUntil: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Which verticals THIS build provisions — baked into the widget descriptors' `input`. A vertical
|
|
71
|
+
* the build does not show is never read: its count must not reach the compact line, and its
|
|
72
|
+
* transient failure must not withhold a frame about the sections the build does show. */
|
|
73
|
+
export interface Verticals {
|
|
74
|
+
bookings: boolean;
|
|
75
|
+
store: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const COPY = {
|
|
79
|
+
signedOut: "Sign in to Owner to see today",
|
|
80
|
+
error: "Open Owner to refresh",
|
|
81
|
+
nothing: "Open Owner to see your business",
|
|
82
|
+
noneUpcoming: "No upcoming bookings",
|
|
83
|
+
} as const;
|
|
84
|
+
|
|
85
|
+
const PENDING = ["PENDING", "PENDING_APPROVAL", "WAITING_LIST"];
|
|
86
|
+
/** A glance, not a list: a count at the cap reads as "50+". */
|
|
87
|
+
export const LIMIT = 50;
|
|
88
|
+
|
|
89
|
+
const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
90
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
91
|
+
|
|
92
|
+
function str(r: unknown, ...paths: string[]): string {
|
|
93
|
+
for (const path of paths) {
|
|
94
|
+
let v: unknown = r;
|
|
95
|
+
for (const k of path.split(".")) v = v && typeof v === "object" ? (v as Rec)[k] : undefined;
|
|
96
|
+
if (typeof v === "string" && v) return v;
|
|
97
|
+
if (typeof v === "number") return String(v);
|
|
98
|
+
}
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function hhmm(d: Date): string {
|
|
103
|
+
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function sameLocalDay(a: Date, b: Date): boolean {
|
|
107
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The day a booking falls on, as an owner would say it. */
|
|
111
|
+
export function dayLabel(start: Date, now: Date): string {
|
|
112
|
+
if (sameLocalDay(start, now)) return "Today";
|
|
113
|
+
const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
|
|
114
|
+
if (sameLocalDay(start, tomorrow)) return "Tomorrow";
|
|
115
|
+
return `${WEEKDAYS[start.getDay()]} ${start.getDate()} ${MONTHS[start.getMonth()]}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function startOf(b: Rec): string {
|
|
119
|
+
return str(b, "startDate", "bookedEntity.slot.startDate");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function booking(b: Rec, now: Date): TodayBooking {
|
|
123
|
+
const start = new Date(startOf(b));
|
|
124
|
+
const day = dayLabel(start, now);
|
|
125
|
+
return {
|
|
126
|
+
bookingId: str(b, "id"),
|
|
127
|
+
name: str(b, "contactDetails.firstName") || "Client",
|
|
128
|
+
service: str(b, "bookedEntity.title", "bookedEntity.slot.serviceName") || "Appointment",
|
|
129
|
+
timeLabel: hhmm(start),
|
|
130
|
+
dayLabel: day,
|
|
131
|
+
whenLabel: `${day} ${hhmm(start)}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const EMPTY_BOOKING: TodayBooking = { bookingId: "", name: "", service: "", timeLabel: "", dayLabel: "", whenLabel: "" };
|
|
136
|
+
|
|
137
|
+
function counted(n: number, capped: boolean, one: string, many: string): string {
|
|
138
|
+
return `${capped ? `${LIMIT}+` : n} ${n === 1 && !capped ? one : many}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface Sources {
|
|
142
|
+
/** Upcoming CONFIRMED bookings, or null when Bookings could not be read. */
|
|
143
|
+
bookings: Rec[] | null;
|
|
144
|
+
/** Upcoming booking REQUESTS (pending statuses), read on their own: one page of every status
|
|
145
|
+
* would fill with a busy week's confirmed bookings and hide next week's request. */
|
|
146
|
+
requests: Rec[] | null;
|
|
147
|
+
/** Orders needing attention, or null when Store could not be read. */
|
|
148
|
+
orders: Rec[] | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function upcoming(rows: Rec[] | null, statuses: string[], now: Date): Rec[] {
|
|
152
|
+
return (rows ?? [])
|
|
153
|
+
.filter((b) => str(b, "id") && statuses.includes(str(b, "status").toUpperCase()))
|
|
154
|
+
.filter((b) => Date.parse(startOf(b)) >= now.getTime())
|
|
155
|
+
.sort((a, b) => Date.parse(startOf(a)) - Date.parse(startOf(b)) || str(a, "id").localeCompare(str(b, "id")));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Pure: shape what was read into the widget state. `now` is injectable for tests. */
|
|
159
|
+
export function shape(sources: Sources, now: Date, siteName: string): TodayState {
|
|
160
|
+
const bookingsReady = sources.bookings !== null && sources.requests !== null;
|
|
161
|
+
const ordersReady = sources.orders !== null;
|
|
162
|
+
// Re-filtered even though the queries filter: a server (or a fixture) that returns a
|
|
163
|
+
// cancelled or past row must not become an appointment the owner is told to expect.
|
|
164
|
+
const confirmed = bookingsReady ? upcoming(sources.bookings, ["CONFIRMED"], now) : [];
|
|
165
|
+
// Today's next CONFIRMED booking first: a request is not an appointment yet. With none left
|
|
166
|
+
// today, the first confirmed one after today, so "what's next" still has an answer.
|
|
167
|
+
const next = confirmed.find((b) => sameLocalDay(new Date(startOf(b)), now)) ?? confirmed[0];
|
|
168
|
+
const requestCount = bookingsReady ? upcoming(sources.requests, PENDING, now).length : 0;
|
|
169
|
+
const orderCount = (sources.orders ?? []).length;
|
|
170
|
+
const requestsCapped = (sources.requests ?? []).length >= LIMIT;
|
|
171
|
+
const ordersCapped = orderCount >= LIMIT;
|
|
172
|
+
|
|
173
|
+
const shortParts = [
|
|
174
|
+
...(bookingsReady ? [`${requestsCapped ? `${LIMIT}+` : requestCount} req`] : []),
|
|
175
|
+
...(ordersReady ? [counted(orderCount, ordersCapped, "order", "orders")] : []),
|
|
176
|
+
];
|
|
177
|
+
const nothing = !bookingsReady && !ordersReady;
|
|
178
|
+
const nextNote = bookingsReady && !next ? COPY.noneUpcoming : "";
|
|
179
|
+
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).getTime();
|
|
180
|
+
const nextStart = next ? Date.parse(startOf(next)) : Infinity;
|
|
181
|
+
return {
|
|
182
|
+
validUntil: Math.floor(Math.min(midnight, nextStart) / 1000),
|
|
183
|
+
status: "ready",
|
|
184
|
+
siteName,
|
|
185
|
+
header: siteName ? `Today · ${siteName}` : "Today",
|
|
186
|
+
next: next ? booking(next, now) : EMPTY_BOOKING,
|
|
187
|
+
hasNext: !!next,
|
|
188
|
+
hideNext: !next,
|
|
189
|
+
nextNote,
|
|
190
|
+
hideNextNote: !nextNote,
|
|
191
|
+
requestCount,
|
|
192
|
+
requestLabel: requestCount ? counted(requestCount, requestsCapped, "request", "requests") : "No requests",
|
|
193
|
+
orderCount,
|
|
194
|
+
orderLabel: orderCount ? `${counted(orderCount, ordersCapped, "order", "orders")} to handle` : "No orders waiting",
|
|
195
|
+
countsShort: shortParts.join(" · "),
|
|
196
|
+
bookingsReady,
|
|
197
|
+
ordersReady,
|
|
198
|
+
hideRequests: !bookingsReady,
|
|
199
|
+
hideOrders: !ordersReady,
|
|
200
|
+
message: nothing ? COPY.nothing : "",
|
|
201
|
+
hideMessage: !nothing,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** A degrade frame: ONE line, no rows. After a sign-out or a business switch the last rows
|
|
206
|
+
* belong to someone else's clients, so none of them survive into it. */
|
|
207
|
+
export function degraded(status: "error" | "signedOut" | "loading", siteName: string): TodayState {
|
|
208
|
+
// A FIXED instant, not the clock: a degrade frame has no rows, so nothing in it depends on
|
|
209
|
+
// the time — and the initial state must be deterministic (template contract: no worker's
|
|
210
|
+
// initial state may read the clock).
|
|
211
|
+
const base = shape({ bookings: null, requests: null, orders: null }, new Date(0), siteName);
|
|
212
|
+
const message = status === "signedOut" ? COPY.signedOut : status === "error" ? COPY.error : "";
|
|
213
|
+
// validUntil pinned too: shape() derives it from LOCAL midnight, so even at a fixed instant it
|
|
214
|
+
// would vary with the build machine's timezone and change the baked services hash.
|
|
215
|
+
return { ...base, status, message, hideMessage: !message, validUntil: 0 };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** No usable owner session behind the bridge (the bridge refusing, or a 401). A transient
|
|
219
|
+
* 5xx is an ordinary error, not a sign-out — and a 403 is a missing PERMISSION for one
|
|
220
|
+
* vertical (a collaborator whose role lacks Bookings), not a sign-out either. */
|
|
221
|
+
export function isSignedOut(e: unknown): boolean {
|
|
222
|
+
const text = String((e as Error)?.message ?? e);
|
|
223
|
+
return /^HTTP 401\b/.test(text) || /wixApi not enabled|session unavailable|not signed in|webwix_bridge/i.test(text);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** This section cannot exist for this owner: the vertical is not installed on the site (its
|
|
227
|
+
* API answers 428, or 404 for the route), or the owner's role may not read it (403). Hides
|
|
228
|
+
* that one section; every other failure is an error for the whole frame.
|
|
229
|
+
*
|
|
230
|
+
* Read from the LEADING status only — the bridges format a failure as `HTTP <status>: <body>`
|
|
231
|
+
* or `HTTP <status> [<code>]: <message>` — never from anywhere in the message: a transient
|
|
232
|
+
* `HTTP 503: {"message":"upstream returned 404"}` must stay an error, not hide the section. */
|
|
233
|
+
export function isSectionUnavailable(e: unknown): boolean {
|
|
234
|
+
const text = String((e as Error)?.message ?? e);
|
|
235
|
+
return /^HTTP (?:403|404|428)\b/.test(text) || /^HTTP \d{3} \[(?:FAILED_PRECONDITION|PERMISSION_DENIED)\]/.test(text);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function siteName(): string {
|
|
239
|
+
return readSelectedSite()?.name ?? "";
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
type Read = { ok: true; value: unknown } | { ok: false; error: unknown };
|
|
243
|
+
|
|
244
|
+
async function attempt(fn: () => Promise<unknown>): Promise<Read> {
|
|
245
|
+
try {
|
|
246
|
+
return { ok: true, value: await fn() };
|
|
247
|
+
} catch (error) {
|
|
248
|
+
return { ok: false, error };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function rows(r: Read, key: string): Rec[] | null {
|
|
253
|
+
if (!r.ok) return null;
|
|
254
|
+
const list = (r.value as Rec | undefined)?.[key];
|
|
255
|
+
return Array.isArray(list) ? (list as Rec[]) : [];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** The build's verticals from the descriptor's baked `input.verticals` ("bookings,store"). A
|
|
259
|
+
* host that passes none (an older descriptor) reads both, as before. */
|
|
260
|
+
export function buildVerticals(): Verticals {
|
|
261
|
+
const raw = (globalThis as { himalaya?: { input?: Record<string, unknown> } }).himalaya?.input?.verticals;
|
|
262
|
+
if (typeof raw !== "string") return { bookings: true, store: true };
|
|
263
|
+
const set = new Set(raw.split(",").map((v) => v.trim()));
|
|
264
|
+
return { bookings: set.has("bookings"), store: set.has("store") };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** A section this build does not provision: never read, and indistinguishable from "not
|
|
268
|
+
* installed" downstream (hidden, out of the compact line, out of the error rule). */
|
|
269
|
+
const NOT_PROVISIONED: Read = { ok: false, error: new Error("HTTP 404: not provisioned in this build") };
|
|
270
|
+
|
|
271
|
+
async function read(): Promise<TodayState> {
|
|
272
|
+
const nowIso = new Date().toISOString();
|
|
273
|
+
const verticals = buildVerticals();
|
|
274
|
+
const sort = [{ fieldName: "startDate", order: "ASC" }, { fieldName: "id", order: "ASC" }];
|
|
275
|
+
const bookingsBy = (statuses: string[]) => verticals.bookings ? attempt(() => queryBookings({ query: {
|
|
276
|
+
filter: { startDate: { $gte: nowIso }, status: { $in: statuses } },
|
|
277
|
+
sort,
|
|
278
|
+
paging: { limit: LIMIT, offset: 0 },
|
|
279
|
+
} })) : Promise.resolve(NOT_PROVISIONED);
|
|
280
|
+
const reads = await Promise.all([
|
|
281
|
+
bookingsBy(["CONFIRMED"]),
|
|
282
|
+
bookingsBy(PENDING),
|
|
283
|
+
verticals.store ? attempt(() => searchOrders({ search: {
|
|
284
|
+
filter: ownerOrderAttentionFilter(),
|
|
285
|
+
sort: [{ fieldName: "createdDate", order: "DESC" }, { fieldName: "id", order: "ASC" }],
|
|
286
|
+
cursorPaging: { limit: LIMIT },
|
|
287
|
+
} })) : Promise.resolve(NOT_PROVISIONED),
|
|
288
|
+
]);
|
|
289
|
+
const failures = reads.flatMap((r) => (r.ok ? [] : [r.error]));
|
|
290
|
+
if (failures.some(isSignedOut)) return degraded("signedOut", "");
|
|
291
|
+
// A section that cannot exist (not installed, no permission) is hidden. ANY other failure —
|
|
292
|
+
// a transient 5xx on one read included — makes this an error frame, which the phone does
|
|
293
|
+
// not publish: the last good frame stays, rather than a frame that silently drops a
|
|
294
|
+
// section the owner does have and reads as "nothing waiting".
|
|
295
|
+
if (failures.some((e) => !isSectionUnavailable(e))) return degraded("error", siteName());
|
|
296
|
+
const [bookings, requests, orders] = reads;
|
|
297
|
+
return shape({
|
|
298
|
+
bookings: rows(bookings, "bookings"),
|
|
299
|
+
requests: rows(requests, "bookings"),
|
|
300
|
+
orders: rows(orders, "orders"),
|
|
301
|
+
}, new Date(), siteName());
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const svc = defineService<TodayState, {
|
|
305
|
+
load: (s: TodayState) => Promise<TodayState>;
|
|
306
|
+
refresh: (s: TodayState) => Promise<TodayState>;
|
|
307
|
+
}>("ownerToday", {
|
|
308
|
+
state: degraded("loading", ""),
|
|
309
|
+
actions: {
|
|
310
|
+
load: async () => read(),
|
|
311
|
+
refresh: async () => read(),
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
export { svc };
|