@wix/himalaya-cli 0.1527.0 → 0.1529.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/ecom/src/extensions.d.ts +144 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/restaurants/src/extensions.d.ts +93 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +27 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +19 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +27 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-ecom.mjs +58 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-restaurants.mjs +23 -0
- package/dist/cli.mjs +5844 -4606
- package/fixtures/wix-canned.json +83 -0
- package/guides/hhp.md +39 -0
- package/guides/himi-json-output.md +67 -1
- package/guides/himi-mcp.md +41 -0
- package/guides/iap-products.md +88 -23
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +12 -1
- package/templates/beauty-salon/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/beauty-salon/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +6 -0
- package/templates/branded-lite/config.ts +12 -1
- package/templates/branded-lite/dev/index.ts +1278 -180
- package/templates/branded-lite/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/branded-lite/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +6 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-menu-item/index.ts +144 -77
- package/templates/branded-lite/tier5-src/himi-branded-lite-menus/index.ts +16 -5
- package/templates/branded-lite/tier5-src/himi-branded-lite-reservations/index.ts +1 -1
- package/templates/branded-lite/tier5-src/wix-spaces-food-order-detail/index.ts +76 -14
- package/templates/branded-lite/tier5-src/wix-spaces-food-orders/index.ts +807 -55
- package/templates/community-club/config.ts +12 -1
- package/templates/community-club/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/events-meetups/config.ts +12 -1
- package/templates/events-meetups/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/gym-fitness/config.ts +12 -1
- package/templates/gym-fitness/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/gym-fitness/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +6 -0
- package/templates/nonprofit-cause/config.ts +12 -1
- package/templates/nonprofit-cause/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/podcast-creator/config.ts +12 -1
- package/templates/podcast-creator/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/portfolio-creative/config.ts +12 -1
- package/templates/portfolio-creative/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/portfolio-creative/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +6 -0
- package/templates/restaurant/README.md +1 -1
- package/templates/restaurant/config.ts +12 -1
- package/templates/restaurant/dev/index.ts +1373 -275
- package/templates/restaurant/himalaya.template.json +2 -1
- package/templates/restaurant/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/restaurant/tier5-src/_shared/member-orders.ts +8 -0
- package/templates/restaurant/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-menu-item/index.ts +144 -77
- package/templates/restaurant/tier5-src/himi-branded-lite-menus/index.ts +16 -5
- package/templates/restaurant/tier5-src/wix-spaces-food-order-detail/index.ts +76 -14
- package/templates/restaurant/tier5-src/wix-spaces-food-orders/index.ts +807 -55
- package/templates/retail-store/config.ts +12 -1
- package/templates/retail-store/tier5-src/_shared/himi-restaurants.ts +12 -5
- package/templates/retail-store/tier5-src/_shared/restaurant-ordering.ts +201 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +6 -0
- package/templates/yoga-studio/config.ts +12 -1
- package/templates/yoga-studio/tier5-src/_shared/himi-restaurants.ts +12 -5
|
@@ -17,6 +17,9 @@ import { copyParam, stashCopy } from "../_shared/himi-copy.js";
|
|
|
17
17
|
/** One section with its shaped dishes (the source of truth `all` keeps). */
|
|
18
18
|
interface MenuSection {
|
|
19
19
|
id: string;
|
|
20
|
+
/** The menu that lists this section ("" for the flat fallback) — the dish detail orders
|
|
21
|
+
* the dish under this menu + section, which is what Wix checkout validates. */
|
|
22
|
+
menuId: string;
|
|
20
23
|
name: string;
|
|
21
24
|
items: DishCard[];
|
|
22
25
|
}
|
|
@@ -47,6 +50,9 @@ interface MenuRow {
|
|
|
47
50
|
noLabel2: boolean;
|
|
48
51
|
noLabel3: boolean;
|
|
49
52
|
detailScreenId: string;
|
|
53
|
+
/** Where the dish is shown — passed to the detail as nav params ("" on header rows). */
|
|
54
|
+
menuId: string;
|
|
55
|
+
sectionId: string;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
interface State {
|
|
@@ -87,10 +93,12 @@ function headerRow(section: MenuSection): MenuRow {
|
|
|
87
93
|
noLabel2: true,
|
|
88
94
|
noLabel3: true,
|
|
89
95
|
detailScreenId: "",
|
|
96
|
+
menuId: "",
|
|
97
|
+
sectionId: "",
|
|
90
98
|
};
|
|
91
99
|
}
|
|
92
100
|
|
|
93
|
-
function itemRow(item: DishCard): MenuRow {
|
|
101
|
+
function itemRow(item: DishCard, section: MenuSection): MenuRow {
|
|
94
102
|
return {
|
|
95
103
|
id: item.id,
|
|
96
104
|
isHeader: false,
|
|
@@ -112,6 +120,8 @@ function itemRow(item: DishCard): MenuRow {
|
|
|
112
120
|
noLabel2: item.noLabel2,
|
|
113
121
|
noLabel3: item.noLabel3,
|
|
114
122
|
detailScreenId: item.detailScreenId,
|
|
123
|
+
menuId: section.menuId,
|
|
124
|
+
sectionId: section.id === "all" ? "" : section.id,
|
|
115
125
|
};
|
|
116
126
|
}
|
|
117
127
|
|
|
@@ -128,7 +138,7 @@ function apply(all: MenuSection[], query: string): MenuRow[] {
|
|
|
128
138
|
}))
|
|
129
139
|
.filter((section) => section.items.length > 0)
|
|
130
140
|
: all;
|
|
131
|
-
return filtered.flatMap((section) => [headerRow(section), ...section.items.map(itemRow)]);
|
|
141
|
+
return filtered.flatMap((section) => [headerRow(section), ...section.items.map((item) => itemRow(item, section))]);
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
function derive(state: State): State {
|
|
@@ -163,9 +173,10 @@ export function composeSections(menus: WixMenu[], sections: WixSection[], dishes
|
|
|
163
173
|
const sectionById = new Map(sections.filter((section) => section.id).map((section) => [section.id, section]));
|
|
164
174
|
const orderedIds: string[] = [];
|
|
165
175
|
const seen = new Set<string>();
|
|
176
|
+
const menuOf = new Map<string, string>();
|
|
166
177
|
for (const menu of menus.filter((candidate) => candidate.visible !== false)) {
|
|
167
178
|
for (const sectionId of menu.sectionIds ?? []) {
|
|
168
|
-
if (sectionId && !seen.has(sectionId)) { seen.add(sectionId); orderedIds.push(sectionId); }
|
|
179
|
+
if (sectionId && !seen.has(sectionId)) { seen.add(sectionId); orderedIds.push(sectionId); menuOf.set(sectionId, menu.id ?? ""); }
|
|
169
180
|
}
|
|
170
181
|
}
|
|
171
182
|
// Menus query failed / carried no section links → every section, in order.
|
|
@@ -182,11 +193,11 @@ export function composeSections(menus: WixMenu[], sections: WixSection[], dishes
|
|
|
182
193
|
return dish ? [dish] : [];
|
|
183
194
|
});
|
|
184
195
|
if (items.length === 0) return [];
|
|
185
|
-
return [{ id: section.id, name: cleanTitle(section.name) || copyParam("menu.sectionFallbackName", "Menu"), items }];
|
|
196
|
+
return [{ id: section.id, menuId: menuOf.get(section.id) ?? "", name: cleanTitle(section.name) || copyParam("menu.sectionFallbackName", "Menu"), items }];
|
|
186
197
|
});
|
|
187
198
|
if (composed.length > 0) return composed;
|
|
188
199
|
// Sections unavailable (or none matched a dish) → flat single-section menu.
|
|
189
|
-
return dishes.length ? [{ id: "all", name: copyParam("menu.sectionFallbackName", "Menu"), items: dishes }] : [];
|
|
200
|
+
return dishes.length ? [{ id: "all", menuId: "", name: copyParam("menu.sectionFallbackName", "Menu"), items: dishes }] : [];
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
function strOf(arg: unknown): string {
|
|
@@ -7,7 +7,7 @@ import { withOnlineWrites } from "../_shared/online-actions.js";
|
|
|
7
7
|
// INTERACTIVE: tapping an upcoming reservation cancels it — optimistic + best-effort
|
|
8
8
|
// cancelReservation (no-op on sample rows).
|
|
9
9
|
//
|
|
10
|
-
//
|
|
10
|
+
// The list is a `himalaya.Agenda` — chronological, grouped
|
|
11
11
|
// by LOCAL day under sticky headers. A reservation list is a diary, and the
|
|
12
12
|
// flat grid it replaced repeated "Fri, Aug 8 · 7:30 PM" on every card because
|
|
13
13
|
// no row knew what day the row above it was on. `Agenda` owns the day headers
|
|
@@ -1,24 +1,86 @@
|
|
|
1
|
-
// Tier-5 bundle:
|
|
2
|
-
//
|
|
1
|
+
// Tier-5 bundle: one placed restaurant order for the signed-in member.
|
|
2
|
+
// Read through the member eCom orders search (filtered to the member's email and the order id),
|
|
3
|
+
// the same path as the order list — never the owner-capable Restaurants Orders API. An order that
|
|
4
|
+
// is not this member's, or has no Restaurants line, is "not found".
|
|
3
5
|
import { defineService } from "@himalaya/state";
|
|
6
|
+
import { searchOrders, type WixOrder } from "@himalaya/wix-ecom";
|
|
4
7
|
import { presence, detailInputId, type PresenceFlags } from "../_shared/detail-presence.js";
|
|
8
|
+
import { assertOrderMember, orderAccessDenied, orderMember } from "../_shared/member-orders.js";
|
|
9
|
+
import { RESTAURANTS_ORDERS_APP_ID } from "../_shared/restaurant-ordering.js";
|
|
10
|
+
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
11
|
+
import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
|
|
5
12
|
|
|
6
13
|
interface S extends PresenceFlags { status: "loading" | "ready"; name: string; status_: string; total: string; items: string; message: string }
|
|
7
14
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const EMPTY = { name: "", status_: "", total: "", items: "", message: "" };
|
|
16
|
+
|
|
17
|
+
function statusLine(order: WixOrder): string {
|
|
18
|
+
const raw = order as WixOrder & { status?: string };
|
|
19
|
+
const status = raw.status === "CANCELED" ? copyParam("foodOrders.statusCanceled", "Canceled")
|
|
20
|
+
: order.fulfillmentStatus === "FULFILLED" ? copyParam("foodOrders.statusCompleted", "Completed")
|
|
21
|
+
: order.paymentStatus === "NOT_PAID" || order.paymentStatus === "PENDING" ? copyParam("foodOrders.statusAwaitingPayment", "Awaiting payment")
|
|
22
|
+
: copyParam("foodOrders.statusReceived", "Received");
|
|
23
|
+
const created = order.createdDate ? new Date(order.createdDate) : undefined;
|
|
24
|
+
return [status, created && !Number.isNaN(created.getTime()) ? formatDateMedium(created) : ""].filter(Boolean).join(" · ");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function fulfillmentLine(order: WixOrder): string {
|
|
28
|
+
const title = (order as WixOrder & { shippingInfo?: { title?: string } }).shippingInfo?.title ?? "";
|
|
29
|
+
return title ? copyTemplate("foodOrderDetail.fulfillment", "Fulfillment: {method}", { method: title }) : "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Bumped by every load. The module-scope load and the screen's on-appear load overlap: only the
|
|
33
|
+
* newest commits, so an older, slower answer never replaces a newer one. */
|
|
34
|
+
let loadSeq = 0;
|
|
35
|
+
/** The service's live state (set once the service exists). */
|
|
36
|
+
let latestState: () => S = () => ({ status: "loading", ...EMPTY, ...presence("loading") });
|
|
37
|
+
|
|
38
|
+
async function read(id: string): Promise<S> {
|
|
39
|
+
const member = await orderMember();
|
|
40
|
+
if (!member.email) {
|
|
41
|
+
return { status: "ready", ...EMPTY, ...presence("found"),
|
|
42
|
+
message: copyParam("foodOrderDetail.signIn", "Sign in to see this order.") };
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const response = await searchOrders({ search: {
|
|
46
|
+
filter: { "buyerInfo.email": { $eq: member.email }, id: { $eq: id } },
|
|
47
|
+
cursorPaging: { limit: 1 },
|
|
48
|
+
} });
|
|
49
|
+
await assertOrderMember(member);
|
|
50
|
+
const order = (response.orders ?? []).find((candidate) => candidate.id === id
|
|
51
|
+
&& (candidate.buyerInfo?.email ?? "").trim().toLowerCase() === member.email
|
|
52
|
+
&& (candidate.lineItems ?? []).some((line) =>
|
|
53
|
+
(line as { catalogReference?: { appId?: string } }).catalogReference?.appId === RESTAURANTS_ORDERS_APP_ID));
|
|
54
|
+
if (!order) return { status: "ready", ...EMPTY, ...presence("missing") };
|
|
55
|
+
return {
|
|
14
56
|
status: "ready",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
57
|
+
...presence("found"),
|
|
58
|
+
name: copyTemplate("foodOrders.orderTitle", "Order #{number}", { number: order.number || order.id }),
|
|
59
|
+
status_: statusLine(order),
|
|
60
|
+
total: order.priceSummary?.total?.formattedAmount ?? "",
|
|
61
|
+
items: (order.lineItems ?? [])
|
|
62
|
+
.map((line) => `${line.quantity || 1} × ${line.productName?.translated || line.productName?.original || ""}`.trim())
|
|
63
|
+
.join("\n"),
|
|
64
|
+
message: fulfillmentLine(order),
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return { status: "ready", ...EMPTY, ...presence(orderAccessDenied(error) ? "missing" : "failed") };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const svc = defineService<S, { load: (s: S, arg?: unknown) => Promise<S> }>("spacesFoodOrderDetail", {
|
|
72
|
+
state: { status: "loading", ...EMPTY, ...presence("loading") },
|
|
73
|
+
actions: {
|
|
74
|
+
load: async (_state, arg) => {
|
|
75
|
+
stashCopy(arg);
|
|
76
|
+
const id = detailInputId();
|
|
77
|
+
if (!id) return { status: "ready", ...EMPTY, ...presence("missing") };
|
|
78
|
+
const seq = ++loadSeq;
|
|
79
|
+
const next = await read(id);
|
|
80
|
+
return seq === loadSeq ? next : latestState();
|
|
81
|
+
},
|
|
21
82
|
},
|
|
22
83
|
});
|
|
84
|
+
latestState = () => svc.getState() as S;
|
|
23
85
|
svc.load();
|
|
24
86
|
export { svc };
|