@wix/himalaya-cli 0.1467.0 → 0.1468.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/cli.mjs +0 -1
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/_shared/host-events.ts +27 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +13 -0
- package/templates/branded-lite/tier5-src/_shared/host-events.ts +27 -0
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +13 -0
- package/templates/gym-fitness/tier5-src/_shared/host-events.ts +27 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +13 -0
- package/templates/yoga-studio/tier5-src/_shared/host-events.ts +27 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +13 -0
package/dist/cli.mjs
CHANGED
|
@@ -8127,7 +8127,6 @@ function resolveTranslation(value, catalog3, sourceCatalog) {
|
|
|
8127
8127
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
8128
8128
|
var init_bindings = __esm({
|
|
8129
8129
|
"../../core/ts/src/bindings.ts"() {
|
|
8130
|
-
"use strict";
|
|
8131
8130
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
8132
8131
|
BINDING_SIGIL_RE = new RegExp(
|
|
8133
8132
|
`^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1468.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "dd16fbdf6eef44d6e5c3095a1d25fc071a62d7eb1df54f9bdb1444a6"
|
|
75
75
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Host events — what a member screen tells the app hosting it about something the member did
|
|
2
|
+
// (a booking confirmed), so a host such as Symphony can say so in its chat and refresh what it shows.
|
|
3
|
+
//
|
|
4
|
+
// A worker dispatches `host.event` with `{ type, ...fields }` (string values only: a dispatch carries
|
|
5
|
+
// one string params map). An embed (`HimalayaEmbed`) hands it to the host's `onAction` as an action
|
|
6
|
+
// with that id; anywhere else nothing handles it and it is dropped. It is a notice, never a request:
|
|
7
|
+
// the host owns what happens next, and the worker never waits on it or depends on its answer.
|
|
8
|
+
|
|
9
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
10
|
+
|
|
11
|
+
export const HOST_EVENT_ACTION_ID = "host.event";
|
|
12
|
+
|
|
13
|
+
/** The events a member screen reports. */
|
|
14
|
+
export type HostEventType = "booking.created";
|
|
15
|
+
|
|
16
|
+
/** Tell the host about [type]. Never throws: a host that does not listen must not break the screen. */
|
|
17
|
+
export async function emitHostEvent(type: HostEventType, fields: Record<string, string | undefined> = {}): Promise<void> {
|
|
18
|
+
const params: Record<string, string> = { type };
|
|
19
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
20
|
+
if (typeof value === "string" && value !== "") params[key] = value;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await dispatch(HOST_EVENT_ACTION_ID, params);
|
|
24
|
+
} catch {
|
|
25
|
+
// Not embedded, or the host has no handler: nothing to tell.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@ import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-
|
|
|
16
16
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
17
17
|
import { upsert as dbUpsert, remove as dbRemove, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
|
|
18
18
|
import { isBridgeUnavailable } from "../_shared/owner-load-error.js";
|
|
19
|
+
import { emitHostEvent } from "../_shared/host-events.js";
|
|
19
20
|
import { wixMediaUrl, WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
20
21
|
|
|
21
22
|
// Offline-first (data-offline): booking a slot is WRITE-BEHIND against the
|
|
@@ -635,6 +636,15 @@ const svc = defineService<S, {
|
|
|
635
636
|
if (!s.selectedSlotId) return derive({ ...s, message: copyParam("time.bookNeedsSlot", "Choose one time first.") });
|
|
636
637
|
const slot = slotsById.get(s.selectedSlotId);
|
|
637
638
|
if (!slot) return derive({ ...s, message: copyParam("time.bookSlotGone", "That time is no longer available. Try again.") });
|
|
639
|
+
// A confirmed booking is reported to the app hosting this screen (an embed's `onAction`), so a
|
|
640
|
+
// host chat can say so and refresh what it shows. Dropped where nothing hosts the screen.
|
|
641
|
+
const reportBooked = (bookingId: string | undefined) => emitHostEvent("booking.created", {
|
|
642
|
+
bookingId,
|
|
643
|
+
serviceId: s.id,
|
|
644
|
+
serviceName: s.serviceName,
|
|
645
|
+
start: slot.startDate,
|
|
646
|
+
end: slot.endDate,
|
|
647
|
+
});
|
|
638
648
|
// PAID service — FULLY NATIVE in-app payment (mirrors Wix's RN apps): NO
|
|
639
649
|
// hosted-checkout WebView / browser redirect. The chain is
|
|
640
650
|
// createBooking → ecom.createCheckout(booking line item) → ecom.createOrder
|
|
@@ -669,6 +679,7 @@ const svc = defineService<S, {
|
|
|
669
679
|
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
680
|
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
681
|
if (!snapshotId && !hosted) {
|
|
682
|
+
await reportBooked(bookingId);
|
|
672
683
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
673
684
|
}
|
|
674
685
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -690,6 +701,7 @@ const svc = defineService<S, {
|
|
|
690
701
|
},
|
|
691
702
|
});
|
|
692
703
|
if (pay.kind === "paid") {
|
|
704
|
+
await reportBooked(bookingId);
|
|
693
705
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
694
706
|
}
|
|
695
707
|
if (pay.kind === "handoff") {
|
|
@@ -728,6 +740,7 @@ const svc = defineService<S, {
|
|
|
728
740
|
// Reconcile the optimistic local id with the server-assigned booking id.
|
|
729
741
|
const realId = created.booking?.id;
|
|
730
742
|
if (realId && realId !== localId) { await cacheDrop(localId); await cachePut(localRow(realId)); }
|
|
743
|
+
await reportBooked(realId);
|
|
731
744
|
return derive({
|
|
732
745
|
...pending,
|
|
733
746
|
bookingInFlight: false,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Host events — what a member screen tells the app hosting it about something the member did
|
|
2
|
+
// (a booking confirmed), so a host such as Symphony can say so in its chat and refresh what it shows.
|
|
3
|
+
//
|
|
4
|
+
// A worker dispatches `host.event` with `{ type, ...fields }` (string values only: a dispatch carries
|
|
5
|
+
// one string params map). An embed (`HimalayaEmbed`) hands it to the host's `onAction` as an action
|
|
6
|
+
// with that id; anywhere else nothing handles it and it is dropped. It is a notice, never a request:
|
|
7
|
+
// the host owns what happens next, and the worker never waits on it or depends on its answer.
|
|
8
|
+
|
|
9
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
10
|
+
|
|
11
|
+
export const HOST_EVENT_ACTION_ID = "host.event";
|
|
12
|
+
|
|
13
|
+
/** The events a member screen reports. */
|
|
14
|
+
export type HostEventType = "booking.created";
|
|
15
|
+
|
|
16
|
+
/** Tell the host about [type]. Never throws: a host that does not listen must not break the screen. */
|
|
17
|
+
export async function emitHostEvent(type: HostEventType, fields: Record<string, string | undefined> = {}): Promise<void> {
|
|
18
|
+
const params: Record<string, string> = { type };
|
|
19
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
20
|
+
if (typeof value === "string" && value !== "") params[key] = value;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await dispatch(HOST_EVENT_ACTION_ID, params);
|
|
24
|
+
} catch {
|
|
25
|
+
// Not embedded, or the host has no handler: nothing to tell.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@ import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-
|
|
|
16
16
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
17
17
|
import { upsert as dbUpsert, remove as dbRemove, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
|
|
18
18
|
import { isBridgeUnavailable } from "../_shared/owner-load-error.js";
|
|
19
|
+
import { emitHostEvent } from "../_shared/host-events.js";
|
|
19
20
|
import { wixMediaUrl, WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
20
21
|
|
|
21
22
|
// Offline-first (data-offline): booking a slot is WRITE-BEHIND against the
|
|
@@ -635,6 +636,15 @@ const svc = defineService<S, {
|
|
|
635
636
|
if (!s.selectedSlotId) return derive({ ...s, message: copyParam("time.bookNeedsSlot", "Choose one time first.") });
|
|
636
637
|
const slot = slotsById.get(s.selectedSlotId);
|
|
637
638
|
if (!slot) return derive({ ...s, message: copyParam("time.bookSlotGone", "That time is no longer available. Try again.") });
|
|
639
|
+
// A confirmed booking is reported to the app hosting this screen (an embed's `onAction`), so a
|
|
640
|
+
// host chat can say so and refresh what it shows. Dropped where nothing hosts the screen.
|
|
641
|
+
const reportBooked = (bookingId: string | undefined) => emitHostEvent("booking.created", {
|
|
642
|
+
bookingId,
|
|
643
|
+
serviceId: s.id,
|
|
644
|
+
serviceName: s.serviceName,
|
|
645
|
+
start: slot.startDate,
|
|
646
|
+
end: slot.endDate,
|
|
647
|
+
});
|
|
638
648
|
// PAID service — FULLY NATIVE in-app payment (mirrors Wix's RN apps): NO
|
|
639
649
|
// hosted-checkout WebView / browser redirect. The chain is
|
|
640
650
|
// createBooking → ecom.createCheckout(booking line item) → ecom.createOrder
|
|
@@ -669,6 +679,7 @@ const svc = defineService<S, {
|
|
|
669
679
|
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
680
|
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
681
|
if (!snapshotId && !hosted) {
|
|
682
|
+
await reportBooked(bookingId);
|
|
672
683
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
673
684
|
}
|
|
674
685
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -690,6 +701,7 @@ const svc = defineService<S, {
|
|
|
690
701
|
},
|
|
691
702
|
});
|
|
692
703
|
if (pay.kind === "paid") {
|
|
704
|
+
await reportBooked(bookingId);
|
|
693
705
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
694
706
|
}
|
|
695
707
|
if (pay.kind === "handoff") {
|
|
@@ -728,6 +740,7 @@ const svc = defineService<S, {
|
|
|
728
740
|
// Reconcile the optimistic local id with the server-assigned booking id.
|
|
729
741
|
const realId = created.booking?.id;
|
|
730
742
|
if (realId && realId !== localId) { await cacheDrop(localId); await cachePut(localRow(realId)); }
|
|
743
|
+
await reportBooked(realId);
|
|
731
744
|
return derive({
|
|
732
745
|
...pending,
|
|
733
746
|
bookingInFlight: false,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Host events — what a member screen tells the app hosting it about something the member did
|
|
2
|
+
// (a booking confirmed), so a host such as Symphony can say so in its chat and refresh what it shows.
|
|
3
|
+
//
|
|
4
|
+
// A worker dispatches `host.event` with `{ type, ...fields }` (string values only: a dispatch carries
|
|
5
|
+
// one string params map). An embed (`HimalayaEmbed`) hands it to the host's `onAction` as an action
|
|
6
|
+
// with that id; anywhere else nothing handles it and it is dropped. It is a notice, never a request:
|
|
7
|
+
// the host owns what happens next, and the worker never waits on it or depends on its answer.
|
|
8
|
+
|
|
9
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
10
|
+
|
|
11
|
+
export const HOST_EVENT_ACTION_ID = "host.event";
|
|
12
|
+
|
|
13
|
+
/** The events a member screen reports. */
|
|
14
|
+
export type HostEventType = "booking.created";
|
|
15
|
+
|
|
16
|
+
/** Tell the host about [type]. Never throws: a host that does not listen must not break the screen. */
|
|
17
|
+
export async function emitHostEvent(type: HostEventType, fields: Record<string, string | undefined> = {}): Promise<void> {
|
|
18
|
+
const params: Record<string, string> = { type };
|
|
19
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
20
|
+
if (typeof value === "string" && value !== "") params[key] = value;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await dispatch(HOST_EVENT_ACTION_ID, params);
|
|
24
|
+
} catch {
|
|
25
|
+
// Not embedded, or the host has no handler: nothing to tell.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@ import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-
|
|
|
16
16
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
17
17
|
import { upsert as dbUpsert, remove as dbRemove, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
|
|
18
18
|
import { isBridgeUnavailable } from "../_shared/owner-load-error.js";
|
|
19
|
+
import { emitHostEvent } from "../_shared/host-events.js";
|
|
19
20
|
import { wixMediaUrl, WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
20
21
|
|
|
21
22
|
// Offline-first (data-offline): booking a slot is WRITE-BEHIND against the
|
|
@@ -635,6 +636,15 @@ const svc = defineService<S, {
|
|
|
635
636
|
if (!s.selectedSlotId) return derive({ ...s, message: copyParam("time.bookNeedsSlot", "Choose one time first.") });
|
|
636
637
|
const slot = slotsById.get(s.selectedSlotId);
|
|
637
638
|
if (!slot) return derive({ ...s, message: copyParam("time.bookSlotGone", "That time is no longer available. Try again.") });
|
|
639
|
+
// A confirmed booking is reported to the app hosting this screen (an embed's `onAction`), so a
|
|
640
|
+
// host chat can say so and refresh what it shows. Dropped where nothing hosts the screen.
|
|
641
|
+
const reportBooked = (bookingId: string | undefined) => emitHostEvent("booking.created", {
|
|
642
|
+
bookingId,
|
|
643
|
+
serviceId: s.id,
|
|
644
|
+
serviceName: s.serviceName,
|
|
645
|
+
start: slot.startDate,
|
|
646
|
+
end: slot.endDate,
|
|
647
|
+
});
|
|
638
648
|
// PAID service — FULLY NATIVE in-app payment (mirrors Wix's RN apps): NO
|
|
639
649
|
// hosted-checkout WebView / browser redirect. The chain is
|
|
640
650
|
// createBooking → ecom.createCheckout(booking line item) → ecom.createOrder
|
|
@@ -669,6 +679,7 @@ const svc = defineService<S, {
|
|
|
669
679
|
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
680
|
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
681
|
if (!snapshotId && !hosted) {
|
|
682
|
+
await reportBooked(bookingId);
|
|
672
683
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
673
684
|
}
|
|
674
685
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -690,6 +701,7 @@ const svc = defineService<S, {
|
|
|
690
701
|
},
|
|
691
702
|
});
|
|
692
703
|
if (pay.kind === "paid") {
|
|
704
|
+
await reportBooked(bookingId);
|
|
693
705
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
694
706
|
}
|
|
695
707
|
if (pay.kind === "handoff") {
|
|
@@ -728,6 +740,7 @@ const svc = defineService<S, {
|
|
|
728
740
|
// Reconcile the optimistic local id with the server-assigned booking id.
|
|
729
741
|
const realId = created.booking?.id;
|
|
730
742
|
if (realId && realId !== localId) { await cacheDrop(localId); await cachePut(localRow(realId)); }
|
|
743
|
+
await reportBooked(realId);
|
|
731
744
|
return derive({
|
|
732
745
|
...pending,
|
|
733
746
|
bookingInFlight: false,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Host events — what a member screen tells the app hosting it about something the member did
|
|
2
|
+
// (a booking confirmed), so a host such as Symphony can say so in its chat and refresh what it shows.
|
|
3
|
+
//
|
|
4
|
+
// A worker dispatches `host.event` with `{ type, ...fields }` (string values only: a dispatch carries
|
|
5
|
+
// one string params map). An embed (`HimalayaEmbed`) hands it to the host's `onAction` as an action
|
|
6
|
+
// with that id; anywhere else nothing handles it and it is dropped. It is a notice, never a request:
|
|
7
|
+
// the host owns what happens next, and the worker never waits on it or depends on its answer.
|
|
8
|
+
|
|
9
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
10
|
+
|
|
11
|
+
export const HOST_EVENT_ACTION_ID = "host.event";
|
|
12
|
+
|
|
13
|
+
/** The events a member screen reports. */
|
|
14
|
+
export type HostEventType = "booking.created";
|
|
15
|
+
|
|
16
|
+
/** Tell the host about [type]. Never throws: a host that does not listen must not break the screen. */
|
|
17
|
+
export async function emitHostEvent(type: HostEventType, fields: Record<string, string | undefined> = {}): Promise<void> {
|
|
18
|
+
const params: Record<string, string> = { type };
|
|
19
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
20
|
+
if (typeof value === "string" && value !== "") params[key] = value;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await dispatch(HOST_EVENT_ACTION_ID, params);
|
|
24
|
+
} catch {
|
|
25
|
+
// Not embedded, or the host has no handler: nothing to tell.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@ import { formatServicePrice, serviceIsChargeable } from "../_shared/wix-service-
|
|
|
16
16
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
17
17
|
import { upsert as dbUpsert, remove as dbRemove, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
|
|
18
18
|
import { isBridgeUnavailable } from "../_shared/owner-load-error.js";
|
|
19
|
+
import { emitHostEvent } from "../_shared/host-events.js";
|
|
19
20
|
import { wixMediaUrl, WIX_DETAIL_IMAGE } from "@himalaya/wix-media";
|
|
20
21
|
|
|
21
22
|
// Offline-first (data-offline): booking a slot is WRITE-BEHIND against the
|
|
@@ -635,6 +636,15 @@ const svc = defineService<S, {
|
|
|
635
636
|
if (!s.selectedSlotId) return derive({ ...s, message: copyParam("time.bookNeedsSlot", "Choose one time first.") });
|
|
636
637
|
const slot = slotsById.get(s.selectedSlotId);
|
|
637
638
|
if (!slot) return derive({ ...s, message: copyParam("time.bookSlotGone", "That time is no longer available. Try again.") });
|
|
639
|
+
// A confirmed booking is reported to the app hosting this screen (an embed's `onAction`), so a
|
|
640
|
+
// host chat can say so and refresh what it shows. Dropped where nothing hosts the screen.
|
|
641
|
+
const reportBooked = (bookingId: string | undefined) => emitHostEvent("booking.created", {
|
|
642
|
+
bookingId,
|
|
643
|
+
serviceId: s.id,
|
|
644
|
+
serviceName: s.serviceName,
|
|
645
|
+
start: slot.startDate,
|
|
646
|
+
end: slot.endDate,
|
|
647
|
+
});
|
|
638
648
|
// PAID service — FULLY NATIVE in-app payment (mirrors Wix's RN apps): NO
|
|
639
649
|
// hosted-checkout WebView / browser redirect. The chain is
|
|
640
650
|
// createBooking → ecom.createCheckout(booking line item) → ecom.createOrder
|
|
@@ -669,6 +679,7 @@ const svc = defineService<S, {
|
|
|
669
679
|
const orderRes = hosted ? { paymentGatewayOrderId: "" } : await createOrder(checkoutId);
|
|
670
680
|
const snapshotId = orderRes.paymentGatewayOrderId ?? "";
|
|
671
681
|
if (!snapshotId && !hosted) {
|
|
682
|
+
await reportBooked(bookingId);
|
|
672
683
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
673
684
|
}
|
|
674
685
|
// 4. Collect payment IN-APP — wallet when this app has one wired, otherwise
|
|
@@ -690,6 +701,7 @@ const svc = defineService<S, {
|
|
|
690
701
|
},
|
|
691
702
|
});
|
|
692
703
|
if (pay.kind === "paid") {
|
|
704
|
+
await reportBooked(bookingId);
|
|
693
705
|
return derive({ ...pending, bookingInFlight: false, successMessage: copyParam("time.successMessage", "Booked. Your confirmation is ready in My Bookings."), message: "" });
|
|
694
706
|
}
|
|
695
707
|
if (pay.kind === "handoff") {
|
|
@@ -728,6 +740,7 @@ const svc = defineService<S, {
|
|
|
728
740
|
// Reconcile the optimistic local id with the server-assigned booking id.
|
|
729
741
|
const realId = created.booking?.id;
|
|
730
742
|
if (realId && realId !== localId) { await cacheDrop(localId); await cachePut(localRow(realId)); }
|
|
743
|
+
await reportBooked(realId);
|
|
731
744
|
return derive({
|
|
732
745
|
...pending,
|
|
733
746
|
bookingInFlight: false,
|