@tbox.cn/app-module-promotion 0.1.0 → 0.9.3

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.
Files changed (67) hide show
  1. package/AGENTS.md +16 -0
  2. package/README.md +90 -11
  3. package/dist/chunk-P7IEEV37.js +1347 -0
  4. package/dist/chunk-QOTX4XDS.js +1745 -0
  5. package/dist/client/index.d.ts +21 -3
  6. package/dist/client/index.js +4 -2
  7. package/dist/index.d.ts +4 -3
  8. package/dist/index.js +16 -4
  9. package/dist/promotion-CMKJ4DB3.css +2135 -0
  10. package/dist/promotion-activity-header-pea-v2-4CCHFCCM.jpg +0 -0
  11. package/dist/promotion-coupon-header-pea-v1-4CCHFCCM.jpg +0 -0
  12. package/dist/server/index.d.ts +2481 -41
  13. package/dist/server/index.js +13 -3
  14. package/package.json +28 -15
  15. package/skills/promotion/SKILL.md +137 -0
  16. package/skills/promotion/references/claim-loop.md +18 -0
  17. package/src/client/assets/promotion-activity-header-pea-v2.jpg +0 -0
  18. package/src/client/assets/promotion-coupon-header-pea-v1.jpg +0 -0
  19. package/src/client/assets.d.ts +5 -0
  20. package/src/client/cards/index.ts +10 -0
  21. package/src/client/cards/promotion-activity-category-list/index.tsx +34 -0
  22. package/src/client/cards/promotion-activity-detail/index.tsx +84 -0
  23. package/src/client/cards/promotion-activity-list/index.tsx +58 -0
  24. package/src/client/cards/promotion-best-deal/index.tsx +18 -0
  25. package/src/client/cards/promotion-entitlement-list/index.tsx +163 -0
  26. package/src/client/cards/promotion-offer-detail/index.tsx +116 -0
  27. package/src/client/cards/promotion-offer-list/index.tsx +285 -0
  28. package/src/client/cards/view.ts +72 -0
  29. package/src/client/components/CouponQrCode.tsx +48 -0
  30. package/src/client/components/CouponSheet.tsx +124 -0
  31. package/src/client/components/ImageWithFallback.tsx +39 -0
  32. package/src/client/index.ts +23 -4
  33. package/src/client/styles/promotion.css +2135 -0
  34. package/src/client/types/css.d.ts +2 -0
  35. package/src/client/utils/sanitize-activity-html.ts +48 -0
  36. package/src/client/utils/scroll-card-bottom.ts +40 -0
  37. package/src/server/actions.ts +217 -0
  38. package/src/server/cards/index.ts +19 -0
  39. package/src/server/cards/promotion-activity-category-list/meta.ts +13 -0
  40. package/src/server/cards/promotion-activity-detail/meta.ts +29 -0
  41. package/src/server/cards/promotion-activity-list/meta.ts +13 -0
  42. package/src/server/cards/promotion-best-deal/meta.ts +20 -0
  43. package/src/server/cards/promotion-entitlement-list/meta.ts +17 -0
  44. package/src/server/cards/promotion-entitlement-list/samples.ts +51 -0
  45. package/src/server/cards/promotion-offer-detail/meta.ts +25 -0
  46. package/src/server/cards/promotion-offer-list/meta.ts +20 -0
  47. package/src/server/cards/promotion-offer-list/samples.ts +154 -0
  48. package/src/server/handler.ts +378 -16
  49. package/src/server/index.ts +117 -22
  50. package/src/server/navigation.ts +23 -0
  51. package/src/server/ports.ts +56 -0
  52. package/src/server/service.ts +243 -24
  53. package/src/server/tools.ts +789 -0
  54. package/tbox.module.json +126 -0
  55. package/tests/cards-render.test.tsx +656 -0
  56. package/tests/ports-resolve.test.ts +96 -0
  57. package/tests/pretool-coupons.test.ts +63 -0
  58. package/tests/promotion.test.ts +976 -0
  59. package/tests/samples.test.ts +42 -0
  60. package/tests/view.test.ts +61 -0
  61. package/tsup.config.ts +9 -1
  62. package/dist/chunk-AD6OLHSM.js +0 -86
  63. package/dist/chunk-LQGF6337.js +0 -32
  64. package/src/client/cards/coupon/index.tsx +0 -12
  65. package/src/server/cards/coupon/meta.ts +0 -23
  66. package/tbox.component.json +0 -20
  67. package/tests/service.test.ts +0 -31
@@ -0,0 +1,1347 @@
1
+ // src/client/index.ts
2
+ import "./promotion-CMKJ4DB3.css";
3
+
4
+ // src/client/cards/promotion-offer-list/index.tsx
5
+ import { CalendarBlank, CalendarDots, CaretDown, Lightbulb, MapPin, Sparkle, Ticket } from "@phosphor-icons/react";
6
+ import { useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
7
+ import { ItemActionsRow, markSelfRendering, navigateToAlipayPage, sendCardAction } from "@tbox.cn/app-sdk/client";
8
+
9
+ // src/client/components/CouponSheet.tsx
10
+ import { X } from "@phosphor-icons/react";
11
+ import { useCallback, useEffect, useRef, useState as useState2 } from "react";
12
+ import { createPortal } from "react-dom";
13
+
14
+ // src/client/components/ImageWithFallback.tsx
15
+ import { useState } from "react";
16
+ import { ImageSquare } from "@phosphor-icons/react";
17
+ import { jsx } from "react/jsx-runtime";
18
+ function ImageWithFallback(props) {
19
+ const { src, alt, className, size = 40 } = props;
20
+ const [failed, setFailed] = useState(false);
21
+ if (!src || failed) {
22
+ return /* @__PURE__ */ jsx(
23
+ "div",
24
+ {
25
+ className: `img-fallback promotion-image--fallback ${className ?? ""}`.trim(),
26
+ "aria-label": alt,
27
+ role: "img",
28
+ children: /* @__PURE__ */ jsx(ImageSquare, { weight: "duotone", size: Math.round(size * 0.45) })
29
+ }
30
+ );
31
+ }
32
+ return /* @__PURE__ */ jsx(
33
+ "img",
34
+ {
35
+ className,
36
+ src,
37
+ alt,
38
+ loading: "eager",
39
+ decoding: "async",
40
+ referrerPolicy: "no-referrer",
41
+ onError: () => setFailed(true)
42
+ }
43
+ );
44
+ }
45
+
46
+ // src/client/utils/sanitize-activity-html.ts
47
+ var DROP_TAGS = /* @__PURE__ */ new Set([
48
+ "script",
49
+ "iframe",
50
+ "object",
51
+ "embed",
52
+ "style",
53
+ "link",
54
+ "meta",
55
+ "base",
56
+ "form",
57
+ "input",
58
+ "svg",
59
+ "math"
60
+ ]);
61
+ var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "xlink:href", "formaction", "action", "poster", "background"]);
62
+ function sanitizeActivityHtml(html) {
63
+ if (typeof DOMParser === "undefined") return "";
64
+ const doc = new DOMParser().parseFromString(html, "text/html");
65
+ const walk = (node) => {
66
+ for (const child of [...node.children]) {
67
+ if (DROP_TAGS.has(child.tagName.toLowerCase())) {
68
+ child.remove();
69
+ continue;
70
+ }
71
+ for (const attr of [...child.attributes]) {
72
+ const name = attr.name.toLowerCase();
73
+ if (name.startsWith("on")) {
74
+ child.removeAttribute(attr.name);
75
+ continue;
76
+ }
77
+ if (URL_ATTRS.has(name)) {
78
+ const value = attr.value.trim().toLowerCase();
79
+ const isJs = value.startsWith("javascript:");
80
+ const isData = value.startsWith("data:") && !value.startsWith("data:image/");
81
+ if (isJs || isData) child.removeAttribute(attr.name);
82
+ }
83
+ }
84
+ walk(child);
85
+ }
86
+ };
87
+ walk(doc.body);
88
+ return doc.body.innerHTML;
89
+ }
90
+
91
+ // src/client/components/CouponSheet.tsx
92
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
93
+ function CouponSheet(props) {
94
+ const { title, imageUrl, subtitle, noticeText, guaranteeText, priceMain, priceOriginal, aside, facts = [], beforeFacts, extra, foot, onClose } = props;
95
+ const [closing, setClosing] = useState2(false);
96
+ const closingRef = useRef(false);
97
+ const closeTimerRef = useRef();
98
+ const onCloseRef = useRef(onClose);
99
+ onCloseRef.current = onClose;
100
+ const finishClose = useCallback(() => {
101
+ if (!closingRef.current) return;
102
+ window.clearTimeout(closeTimerRef.current);
103
+ closingRef.current = false;
104
+ setClosing(false);
105
+ onCloseRef.current();
106
+ }, []);
107
+ const requestClose = useCallback(() => {
108
+ if (closingRef.current) return;
109
+ closingRef.current = true;
110
+ setClosing(true);
111
+ const reducedMotion = window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches ?? false;
112
+ closeTimerRef.current = window.setTimeout(finishClose, reducedMotion ? 1 : 200);
113
+ }, [finishClose]);
114
+ useEffect(() => {
115
+ const onKey = (e) => {
116
+ if (e.key === "Escape") requestClose();
117
+ };
118
+ document.addEventListener("keydown", onKey);
119
+ return () => document.removeEventListener("keydown", onKey);
120
+ }, [requestClose]);
121
+ useEffect(() => () => window.clearTimeout(closeTimerRef.current), []);
122
+ return createPortal(
123
+ /* @__PURE__ */ jsx2(
124
+ "div",
125
+ {
126
+ className: `promotion-sheet${closing ? " promotion-sheet--closing" : ""}`,
127
+ role: "dialog",
128
+ "aria-modal": "true",
129
+ "aria-label": `${title} \u8BE6\u60C5`,
130
+ onAnimationEnd: (event) => {
131
+ if (closing && event.target === event.currentTarget) finishClose();
132
+ },
133
+ onMouseDown: (e) => {
134
+ if (e.target === e.currentTarget) requestClose();
135
+ },
136
+ children: /* @__PURE__ */ jsxs("div", { className: "promotion-sheet__panel", children: [
137
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "promotion-sheet__close", "aria-label": "\u5173\u95ED\u8BE6\u60C5", onClick: requestClose, children: /* @__PURE__ */ jsx2(X, { size: 18, weight: "bold", "aria-hidden": "true" }) }),
138
+ /* @__PURE__ */ jsxs("div", { className: "promotion-sheet__scroll", children: [
139
+ /* @__PURE__ */ jsx2(ImageWithFallback, { src: imageUrl, alt: title, className: "promotion-sheet__image" }),
140
+ (priceMain || aside) && /* @__PURE__ */ jsxs("div", { className: "promotion-sheet__price", children: [
141
+ priceMain && /* @__PURE__ */ jsx2("b", { children: priceMain }),
142
+ priceMain && priceOriginal && /* @__PURE__ */ jsx2("s", { children: priceOriginal }),
143
+ aside && /* @__PURE__ */ jsx2("span", { className: "promotion-sheet__stock", children: aside })
144
+ ] }),
145
+ /* @__PURE__ */ jsx2("h4", { className: "promotion-sheet__title", children: title }),
146
+ (noticeText || guaranteeText) && /* @__PURE__ */ jsxs("div", { className: "promotion-sheet__notice-strip", children: [
147
+ noticeText && /* @__PURE__ */ jsxs("span", { children: [
148
+ /* @__PURE__ */ jsx2("b", { children: "\u987B\u77E5" }),
149
+ noticeText
150
+ ] }),
151
+ guaranteeText && /* @__PURE__ */ jsxs("span", { children: [
152
+ /* @__PURE__ */ jsx2("b", { children: "\u4FDD\u969C" }),
153
+ guaranteeText
154
+ ] })
155
+ ] }),
156
+ subtitle && /* @__PURE__ */ jsx2("p", { className: "promotion-sheet__sub", dangerouslySetInnerHTML: { __html: subtitle } }),
157
+ beforeFacts,
158
+ facts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
159
+ /* @__PURE__ */ jsx2("div", { className: "promotion-sheet__section", children: "\u4F7F\u7528\u987B\u77E5" }),
160
+ /* @__PURE__ */ jsx2("dl", { className: "promotion-sheet__facts", children: facts.map((f) => /* @__PURE__ */ jsxs("div", { children: [
161
+ /* @__PURE__ */ jsxs("dt", { children: [
162
+ f.icon,
163
+ f.label
164
+ ] }),
165
+ /* @__PURE__ */ jsx2("dd", { dangerouslySetInnerHTML: { __html: sanitizeActivityHtml(f.value) } })
166
+ ] }, f.label)) })
167
+ ] }),
168
+ extra
169
+ ] }),
170
+ foot && /* @__PURE__ */ jsx2("div", { className: "promotion-sheet__foot", children: foot })
171
+ ] })
172
+ }
173
+ ),
174
+ document.body
175
+ );
176
+ }
177
+
178
+ // src/client/assets/promotion-coupon-header-pea-v1.jpg
179
+ var promotion_coupon_header_pea_v1_default = "./promotion-coupon-header-pea-v1-4CCHFCCM.jpg";
180
+
181
+ // src/client/cards/view.ts
182
+ function offerTypeLabel(offerType) {
183
+ switch (offerType) {
184
+ case "COUPON":
185
+ return "\u4F18\u60E0\u5238";
186
+ case "BUNDLE":
187
+ return "\u7EC4\u5408\u5238";
188
+ case "PROMOTION":
189
+ return "\u4FC3\u9500";
190
+ case "ACTIVITY":
191
+ return "\u6D3B\u52A8";
192
+ case "GROUPON":
193
+ return "\u56E2\u8D2D";
194
+ default:
195
+ return "\u4F18\u60E0";
196
+ }
197
+ }
198
+ function entitlementStatusLabel(status) {
199
+ switch (status) {
200
+ case "EFFECTIVE":
201
+ return "\u53EF\u7528";
202
+ case "USED":
203
+ return "\u5DF2\u4F7F\u7528";
204
+ case "EXPIRED":
205
+ return "\u5DF2\u8FC7\u671F";
206
+ case "INVALID":
207
+ return "\u5DF2\u5931\u6548";
208
+ default:
209
+ return "\u672A\u77E5";
210
+ }
211
+ }
212
+
213
+ // src/client/utils/scroll-card-bottom.ts
214
+ var MIN_BOTTOM_GAP = 96;
215
+ function scrollCardBottom(anchor) {
216
+ const rootStyle = typeof document !== "undefined" ? getComputedStyle(document.documentElement) : void 0;
217
+ const reservedHeight = Number.parseFloat(rootStyle?.getPropertyValue("--tbox-chat-bottom-height") ?? "") || 0;
218
+ const bottomGap = Math.max(MIN_BOTTOM_GAP, reservedHeight + 24);
219
+ let scroller = anchor.parentElement;
220
+ while (scroller && scroller !== document.body) {
221
+ const style = getComputedStyle(scroller);
222
+ if (/(auto|scroll|overlay)/.test(style.overflowY) && scroller.scrollHeight > scroller.clientHeight) break;
223
+ scroller = scroller.parentElement;
224
+ }
225
+ if (!scroller || scroller === document.body) {
226
+ anchor.scrollIntoView?.({ behavior: "smooth", block: "end" });
227
+ return;
228
+ }
229
+ const anchorRect = anchor.getBoundingClientRect();
230
+ const scrollerRect = scroller.getBoundingClientRect();
231
+ scroller.scrollTo?.({
232
+ top: scroller.scrollTop + anchorRect.bottom - scrollerRect.bottom + bottomGap,
233
+ behavior: "smooth"
234
+ });
235
+ }
236
+
237
+ // src/client/cards/promotion-offer-list/index.tsx
238
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
239
+ var statusText = (status, claimable) => {
240
+ if (status === "REQUIRES_ACTION") return "\u9700\u64CD\u4F5C";
241
+ if (status === "UNKNOWN") return "\u5F85\u786E\u8BA4";
242
+ return claimable ? "\u53EF\u9886\u53D6" : "\u4E0D\u53EF\u9886";
243
+ };
244
+ var statusTone = (status, claimable) => status?.toLowerCase() ?? (claimable ? "available" : "unavailable");
245
+ var couponSubtitleIsTime = (subtitle) => {
246
+ const plainText = subtitle.replace(/<[^>]+>/g, " ").replace(/&nbsp;/gi, " ");
247
+ return /\d{4}\s*[-/.年]\s*\d{1,2}\s*[-/.月]\s*\d{1,2}|\d{1,2}:\d{2}/.test(plainText);
248
+ };
249
+ function PromotionOfferListCard(props) {
250
+ const { data, cardId = "", isHistory = false, actionTokens } = props;
251
+ const [openRef, setOpenRef] = useState3(null);
252
+ const [claimingRef, setClaimingRef] = useState3(null);
253
+ const [claimedRefs, setClaimedRefs] = useState3(() => /* @__PURE__ */ new Set());
254
+ const [expanded, setExpanded] = useState3(false);
255
+ const [listHeights, setListHeights] = useState3({ collapsed: 0, expanded: 0 });
256
+ const listRef = useRef2(null);
257
+ const bottomRef = useRef2(null);
258
+ const initialRenderRef = useRef2(true);
259
+ useEffect2(() => {
260
+ if (initialRenderRef.current) {
261
+ initialRenderRef.current = false;
262
+ return;
263
+ }
264
+ if (bottomRef.current) scrollCardBottom(bottomRef.current);
265
+ }, [expanded]);
266
+ useLayoutEffect(() => {
267
+ const list = listRef.current;
268
+ if (!list) return;
269
+ const rows = [...list.children];
270
+ const boundary = rows[Math.min(maxItems, rows.length) - 1];
271
+ const listTop = list.getBoundingClientRect().top;
272
+ const collapsed = boundary ? boundary.getBoundingClientRect().bottom - listTop : list.scrollHeight;
273
+ setListHeights({ collapsed, expanded: list.scrollHeight });
274
+ }, [data.items.length, data.maxItems]);
275
+ const toggleExpanded = () => {
276
+ setExpanded((value) => !value);
277
+ };
278
+ useEffect2(() => {
279
+ if (!cardId || typeof window === "undefined") return void 0;
280
+ const onNotice = (event) => {
281
+ const detail = event.detail;
282
+ if (!detail?.text || detail.surfaceId && detail.surfaceId !== cardId) return;
283
+ const ref = claimingRef;
284
+ if (!ref) return;
285
+ setClaimingRef(null);
286
+ if (detail.level === "success" || /领取成功|已存入卡包|已领取/.test(detail.text)) {
287
+ setClaimedRefs((current) => new Set(current).add(ref));
288
+ }
289
+ };
290
+ window.addEventListener("tbox:notice", onNotice);
291
+ return () => window.removeEventListener("tbox:notice", onNotice);
292
+ }, [cardId, claimingRef]);
293
+ if (data.presentation === "recommendation") {
294
+ const [offer, ...alternatives] = data.items;
295
+ if (!offer) return /* @__PURE__ */ jsx3(Empty, { text: data.noResultsReason ?? "\u6682\u672A\u627E\u5230\u5339\u914D\u5F53\u524D\u573A\u666F\u7684\u4F18\u60E0" });
296
+ return /* @__PURE__ */ jsxs2("section", { className: "promotion-card promotion-recommendation", "aria-label": "\u66F4\u9002\u5408\u4F60\u7684\u4F18\u60E0", children: [
297
+ /* @__PURE__ */ jsxs2("header", { className: "promotion-card__header", children: [
298
+ /* @__PURE__ */ jsx3("span", { className: "promotion-card__mark promotion-card__mark--violet", children: /* @__PURE__ */ jsx3(Sparkle, { weight: "fill" }) }),
299
+ /* @__PURE__ */ jsxs2("div", { children: [
300
+ /* @__PURE__ */ jsx3("span", { className: "promotion-card__eyebrow", children: "\u667A\u80FD\u5339\u914D" }),
301
+ /* @__PURE__ */ jsx3("h3", { children: "\u66F4\u9002\u5408\u4F60\u7684\u4F18\u60E0" }),
302
+ /* @__PURE__ */ jsx3("p", { children: "\u6839\u636E\u5F53\u524D\u53EF\u7528\u6027\u4E0E\u9884\u8BA1\u8282\u7701\u6392\u5E8F" })
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-recommendation__main", children: [
306
+ /* @__PURE__ */ jsx3(ImageWithFallback, { src: offer.imageUrl, alt: offer.title, className: "promotion-recommendation__image" }),
307
+ /* @__PURE__ */ jsxs2("div", { children: [
308
+ /* @__PURE__ */ jsx3("span", { className: `promotion-status promotion-status--${statusTone(offer.availabilityStatus, offer.claimable)}`, children: statusText(offer.availabilityStatus, offer.claimable) }),
309
+ /* @__PURE__ */ jsx3("strong", { children: offer.title }),
310
+ /* @__PURE__ */ jsx3("small", { children: offer.subtitle ?? offer.validityText ?? "\u5F53\u524D\u5546\u573A\u53EF\u7528" })
311
+ ] }),
312
+ /* @__PURE__ */ jsx3("em", { children: offer.benefitText ?? offerTypeLabel(offer.offerType) })
313
+ ] }),
314
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-recommendation__reason", children: [
315
+ /* @__PURE__ */ jsx3(Lightbulb, { weight: "duotone" }),
316
+ /* @__PURE__ */ jsxs2("span", { children: [
317
+ /* @__PURE__ */ jsx3("b", { children: "\u63A8\u8350\u4F9D\u636E" }),
318
+ data.summary ?? "\u7EFC\u5408\u8D44\u683C\u3001\u53EF\u7528\u6027\u548C\u4F18\u60E0\u529B\u5EA6"
319
+ ] })
320
+ ] }),
321
+ alternatives.length > 0 && /* @__PURE__ */ jsxs2("div", { className: "promotion-recommendation__alternatives", children: [
322
+ "\u53E6\u6709 ",
323
+ alternatives.length,
324
+ " \u4E2A\u5019\u9009\u4F18\u60E0"
325
+ ] }),
326
+ /* @__PURE__ */ jsx3(ItemActionsRow, { actions: offer.itemActions ?? [], cardId, isHistory, className: "promotion-recommendation__actions", chipClassName: "promotion-button promotion-button--primary" })
327
+ ] });
328
+ }
329
+ const promotion = data.presentation === "promotion";
330
+ const hero = data.items[0];
331
+ const coupon = data.presentation === "coupon" || data.mode === "claimable";
332
+ const title = promotion ? "\u672C\u5468\u8425\u9500\u6D3B\u52A8" : coupon ? "\u5546\u573A\u795E\u5238" : "\u6D3B\u52A8\u4E0E\u4F18\u60E0";
333
+ const eyebrow = promotion ? "\u6D3B\u52A8\u53D1\u73B0" : coupon ? "\u5F53\u524D\u5546\u573A \xB7 \u4F18\u60E0\u7CBE\u9009" : "\u4F18\u60E0\u7CBE\u9009";
334
+ const summary = data.summary && data.summary !== eyebrow ? data.summary : void 0;
335
+ const items = data.mode === "claimable" ? data.items.filter((item) => item.claimable) : data.items;
336
+ const maxItems = data.maxItems ?? 4;
337
+ return /* @__PURE__ */ jsxs2("section", { className: `promotion-card promotion-list${promotion ? " promotion-list--promotion" : ""}${coupon ? " promotion-list--coupon promotion-list--offers" : ""}`, "aria-label": title, children: [
338
+ promotion && hero && /* @__PURE__ */ jsxs2("div", { className: "promotion-list__hero", children: [
339
+ /* @__PURE__ */ jsx3(ImageWithFallback, { src: hero.imageUrl, alt: title, className: "promotion-list__hero-image" }),
340
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-list__glass", children: [
341
+ /* @__PURE__ */ jsx3("span", { children: "\u521A\u521A\u66F4\u65B0" }),
342
+ /* @__PURE__ */ jsxs2("strong", { children: [
343
+ data.items.length,
344
+ " \u4E2A\u6D3B\u52A8\u6B63\u5728\u8FDB\u884C"
345
+ ] })
346
+ ] })
347
+ ] }),
348
+ coupon ? /* @__PURE__ */ jsxs2("header", { className: "promotion-activity__header promotion-activity__header--pea promotion-coupon__header", children: [
349
+ /* @__PURE__ */ jsx3("img", { src: promotion_coupon_header_pea_v1_default, alt: "", "aria-hidden": "true", className: "promotion-activity__header-art" }),
350
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-activity__header-copy", children: [
351
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-activity__header-title-row", children: [
352
+ /* @__PURE__ */ jsx3(Ticket, { weight: "fill" }),
353
+ /* @__PURE__ */ jsx3("h3", { children: title })
354
+ ] }),
355
+ /* @__PURE__ */ jsx3("p", { children: eyebrow })
356
+ ] })
357
+ ] }) : /* @__PURE__ */ jsxs2("header", { className: "promotion-card__header", children: [
358
+ /* @__PURE__ */ jsx3("span", { className: "promotion-card__mark", children: promotion ? /* @__PURE__ */ jsx3(CalendarDots, { weight: "duotone" }) : /* @__PURE__ */ jsx3(Sparkle, { weight: "fill" }) }),
359
+ /* @__PURE__ */ jsxs2("div", { children: [
360
+ /* @__PURE__ */ jsx3("span", { className: "promotion-card__eyebrow", children: eyebrow }),
361
+ /* @__PURE__ */ jsx3("h3", { children: title }),
362
+ /* @__PURE__ */ jsx3("p", { children: summary ?? "\u6839\u636E\u5F53\u524D\u573A\u666F\u5B9E\u65F6\u7B5B\u9009" })
363
+ ] }),
364
+ /* @__PURE__ */ jsxs2("b", { className: "promotion-card__count", children: [
365
+ data.items.length,
366
+ " \u4E2A"
367
+ ] })
368
+ ] }),
369
+ !items.length ? /* @__PURE__ */ jsx3(Empty, { text: data.noResultsReason ?? "\u6682\u672A\u627E\u5230\u7B26\u5408\u6761\u4EF6\u7684\u4F18\u60E0" }) : /* @__PURE__ */ jsx3("div", { ref: listRef, className: `promotion-list__items${expanded ? " promotion-list__items--expanded" : ""}`, style: { maxHeight: expanded ? listHeights.expanded || void 0 : listHeights.collapsed || void 0 }, onTransitionEnd: () => {
370
+ if (bottomRef.current) scrollCardBottom(bottomRef.current);
371
+ }, children: items.map((item) => coupon ? /* @__PURE__ */ jsxs2(
372
+ "article",
373
+ {
374
+ className: "promotion-coupon-row",
375
+ role: "button",
376
+ tabIndex: 0,
377
+ "aria-label": `${item.claimActionLabel ?? "\u9886\u53D6"}\u300C${item.title}\u300D`,
378
+ onClick: () => setOpenRef(item.offerRef),
379
+ onKeyDown: (e) => {
380
+ if (e.key === "Enter" || e.key === " ") {
381
+ e.preventDefault();
382
+ setOpenRef(item.offerRef);
383
+ }
384
+ },
385
+ children: [
386
+ /* @__PURE__ */ jsx3(ImageWithFallback, { src: item.imageUrl, alt: item.title, className: "promotion-coupon-row__thumb" }),
387
+ /* @__PURE__ */ jsxs2("div", { className: "promotion-coupon-row__main", children: [
388
+ /* @__PURE__ */ jsx3("strong", { className: "promotion-coupon-row__title", children: item.title }),
389
+ item.tags.some((tag) => !/^TOP[1-5]$/i.test(tag)) && /* @__PURE__ */ jsx3("span", { className: "promotion-coupon-row__tags", children: item.tags.filter((tag) => !/^TOP[1-5]$/i.test(tag)).slice(0, 3).map((tag) => /* @__PURE__ */ jsx3("em", { className: /^(精选|餐饮|购物|生活)$/.test(tag) ? "promotion-coupon-row__tag--category" : "promotion-coupon-row__tag--meta", children: tag }, tag)) }),
390
+ item.subtitle && !couponSubtitleIsTime(item.subtitle) && /* @__PURE__ */ jsx3("span", { className: "promotion-coupon-row__sub", dangerouslySetInnerHTML: { __html: item.subtitle } }),
391
+ /* @__PURE__ */ jsxs2("span", { className: "promotion-coupon-row__price", children: [
392
+ /* @__PURE__ */ jsx3("b", { children: item.priceText ?? item.benefitText ?? offerTypeLabel(item.offerType) }),
393
+ item.discountLabel && /* @__PURE__ */ jsx3("em", { className: "promotion-coupon-row__discount", children: item.discountLabel }),
394
+ item.priceText && item.originalPriceText && /* @__PURE__ */ jsx3("s", { children: item.originalPriceText })
395
+ ] })
396
+ ] }),
397
+ /* @__PURE__ */ jsx3("span", { className: "promotion-item-actions promotion-item-actions--coupon", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("span", { className: "promotion-chip promotion-chip--coupon", children: item.claimActionLabel ?? "\u9886\u53D6" }) })
398
+ ]
399
+ },
400
+ item.offerRef
401
+ ) : /* @__PURE__ */ jsxs2("article", { children: [
402
+ /* @__PURE__ */ jsxs2("span", { className: "promotion-list__visual", children: [
403
+ /* @__PURE__ */ jsx3(ImageWithFallback, { src: item.imageUrl, alt: item.title, className: "promotion-list__thumb" }),
404
+ /* @__PURE__ */ jsx3("em", { children: item.benefitText ?? offerTypeLabel(item.offerType) })
405
+ ] }),
406
+ /* @__PURE__ */ jsxs2("span", { className: "promotion-list__copy", children: [
407
+ /* @__PURE__ */ jsx3("small", { children: promotion ? "\u672C\u5468\u6D3B\u52A8" : offerTypeLabel(item.offerType) }),
408
+ /* @__PURE__ */ jsx3("strong", { children: item.title }),
409
+ /* @__PURE__ */ jsx3("span", { children: item.subtitle ?? item.validityText ?? "\u5F53\u524D\u5546\u573A\u53EF\u7528" })
410
+ ] }),
411
+ /* @__PURE__ */ jsx3("span", { className: `promotion-status promotion-status--${statusTone(item.availabilityStatus, item.claimable)}`, children: statusText(item.availabilityStatus, item.claimable) }),
412
+ /* @__PURE__ */ jsx3(ItemActionsRow, { actions: item.itemActions ?? [], cardId, isHistory, className: "promotion-item-actions", chipClassName: "promotion-chip" })
413
+ ] }, item.offerRef)) }),
414
+ items.length > maxItems && /* @__PURE__ */ jsxs2(
415
+ "button",
416
+ {
417
+ type: "button",
418
+ className: "promotion-list__toggle",
419
+ "aria-expanded": expanded,
420
+ onClick: toggleExpanded,
421
+ children: [
422
+ !coupon && /* @__PURE__ */ jsx3(CaretDown, { size: 16, "data-rotated": expanded || void 0 }),
423
+ expanded ? "\u6536\u8D77" : `\u67E5\u770B\u66F4\u591A\uFF08${items.length - maxItems} \u6761\uFF09`,
424
+ coupon && /* @__PURE__ */ jsx3(CaretDown, { size: 17, "aria-hidden": "true", "data-rotated": expanded || void 0 })
425
+ ]
426
+ }
427
+ ),
428
+ items.length > maxItems && /* @__PURE__ */ jsx3("div", { ref: bottomRef, className: "promotion-list__bottom-anchor", "aria-hidden": "true" }),
429
+ data.nextCursor && /* @__PURE__ */ jsx3("p", { className: "promotion-list__more", children: "\u8FD8\u6709\u66F4\u591A\u5185\u5BB9\uFF0C\u53EF\u7EE7\u7EED\u67E5\u8BE2" }),
430
+ openRef && (() => {
431
+ const target = items.find((i) => i.offerRef === openRef);
432
+ if (!target) return null;
433
+ const token = actionTokens?.["promotion.acquire-from-list"];
434
+ const label = target.claimActionLabel ?? "\u9886\u53D6";
435
+ const purchaseOnly = label === "\u62A2\u8D2D";
436
+ const redirectOnly = purchaseOnly || target.freeCouponClaimMode === "REDIRECT";
437
+ const redirectLabel = purchaseOnly ? "\u53BB\u5C0F\u7A0B\u5E8F\u62A2\u8D2D" : "\u53BB\u5C0F\u7A0B\u5E8F\u9886\u53D6";
438
+ const facts = [
439
+ target.usageSceneText ? { icon: /* @__PURE__ */ jsx3(MapPin, { weight: "duotone" }), label: "\u4F7F\u7528\u573A\u666F", value: target.usageSceneText } : null,
440
+ target.usageTimeText ? { icon: /* @__PURE__ */ jsx3(CalendarBlank, { weight: "duotone" }), label: "\u4F7F\u7528\u65F6\u95F4", value: target.usageTimeText } : null,
441
+ target.thresholdText ? { icon: /* @__PURE__ */ jsx3(Ticket, { weight: "duotone" }), label: "\u4F7F\u7528\u9650\u5236", value: target.thresholdText } : null,
442
+ target.claimTimeText ? { icon: /* @__PURE__ */ jsx3(CalendarBlank, { weight: "duotone" }), label: "\u53EF\u9886\u53D6\u65F6\u95F4", value: target.claimTimeText } : null,
443
+ target.validityText ? { icon: /* @__PURE__ */ jsx3(CalendarBlank, { weight: "duotone" }), label: "\u6709\u6548\u671F", value: target.validityText } : null,
444
+ target.usageRuleText ? { icon: /* @__PURE__ */ jsx3(Ticket, { weight: "duotone" }), label: "\u4F7F\u7528\u89C4\u5219", value: target.usageRuleText } : null
445
+ ].filter(Boolean);
446
+ const priceMain = target.priceText ?? target.benefitText ?? offerTypeLabel(target.offerType);
447
+ return /* @__PURE__ */ jsx3(
448
+ CouponSheet,
449
+ {
450
+ title: target.title,
451
+ imageUrl: target.imageUrl,
452
+ noticeText: target.usageNoticeText,
453
+ guaranteeText: target.guaranteeText,
454
+ subtitle: redirectOnly ? [target.subtitle, target.purchaseUrl ? `\u8BE5\u4F18\u60E0\u9700\u524D\u5F80\u5C0F\u7A0B\u5E8F\u5B8C\u6210${purchaseOnly ? "\u8D2D\u4E70" : "\u9886\u53D6"}` : `\u8BE5\u4F18\u60E0\u7684${purchaseOnly ? "\u62A2\u8D2D" : "\u9886\u53D6"}\u94FE\u63A5\u6682\u4E0D\u53EF\u7528`].filter(Boolean).join(" \xB7 ") : target.subtitle,
455
+ priceMain,
456
+ priceOriginal: target.priceText ? target.originalPriceText : void 0,
457
+ aside: target.stockText,
458
+ facts,
459
+ onClose: () => {
460
+ setOpenRef(null);
461
+ setClaimingRef((current) => current === target.offerRef ? null : current);
462
+ setClaimedRefs((current) => {
463
+ if (!current.has(target.offerRef)) return current;
464
+ const next = new Set(current);
465
+ next.delete(target.offerRef);
466
+ return next;
467
+ });
468
+ },
469
+ foot: /* @__PURE__ */ jsxs2(Fragment2, { children: [
470
+ /* @__PURE__ */ jsxs2("span", { className: "promotion-sheet__foot-price", children: [
471
+ /* @__PURE__ */ jsx3("b", { children: target.priceText ?? target.benefitText ?? "" }),
472
+ target.priceText && target.originalPriceText && /* @__PURE__ */ jsx3("s", { children: target.originalPriceText })
473
+ ] }),
474
+ redirectOnly ? /* @__PURE__ */ jsx3(
475
+ "button",
476
+ {
477
+ type: "button",
478
+ disabled: !target.purchaseUrl,
479
+ className: "promotion-chip promotion-chip--coupon promotion-chip--coupon-lg",
480
+ onClick: () => {
481
+ if (!target.purchaseUrl) return;
482
+ void navigateToAlipayPage(target.purchaseUrl).catch((err) => {
483
+ console.warn("[PromotionOfferListCard] navigateTo failed", err);
484
+ });
485
+ },
486
+ children: target.purchaseUrl ? redirectLabel : `${purchaseOnly ? "\u62A2\u8D2D" : "\u9886\u53D6"}\u94FE\u63A5\u6682\u4E0D\u53EF\u7528`
487
+ }
488
+ ) : token && !isHistory ? (
489
+ // 直接走写动作,不再绕发消息:结果以新卡片回到对话流,当前浮层保持已领取态
490
+ /* @__PURE__ */ jsx3(
491
+ "button",
492
+ {
493
+ type: "button",
494
+ className: "promotion-chip promotion-chip--coupon promotion-chip--coupon-lg",
495
+ onClick: () => {
496
+ setClaimingRef(target.offerRef);
497
+ sendCardAction(cardId, { type: "moduleAction", actionId: "promotion.acquire-from-list", contextToken: token }, { offerRef: target.offerRef });
498
+ },
499
+ disabled: claimingRef === target.offerRef || claimedRefs.has(target.offerRef),
500
+ children: claimedRefs.has(target.offerRef) ? "\u5DF2\u9886\u53D6" : claimingRef === target.offerRef ? "\u9886\u53D6\u4E2D\uFF0C\u8BF7\u7A0D\u5019\u2026" : label
501
+ }
502
+ )
503
+ ) : (
504
+ // 无令牌(历史卡、旧服务端)时退回发消息,保住可用性
505
+ /* @__PURE__ */ jsx3(
506
+ ItemActionsRow,
507
+ {
508
+ actions: target.itemActions ?? [],
509
+ cardId,
510
+ isHistory,
511
+ className: "promotion-item-actions",
512
+ chipClassName: "promotion-chip promotion-chip--coupon promotion-chip--coupon-lg"
513
+ }
514
+ )
515
+ )
516
+ ] })
517
+ }
518
+ );
519
+ })()
520
+ ] });
521
+ }
522
+ markSelfRendering(PromotionOfferListCard);
523
+ function Empty({ text }) {
524
+ return /* @__PURE__ */ jsxs2("div", { className: "promotion-card__empty", children: [
525
+ /* @__PURE__ */ jsx3(Ticket, { size: 28, weight: "duotone" }),
526
+ /* @__PURE__ */ jsx3("span", { children: text })
527
+ ] });
528
+ }
529
+ var promotion_offer_list_default = PromotionOfferListCard;
530
+
531
+ // src/client/cards/promotion-offer-detail/index.tsx
532
+ import { CalendarBlank as CalendarBlank2, CheckCircle, Clock, Gift, Info, ListChecks, MapPin as MapPin2, SealCheck, Ticket as Ticket2 } from "@phosphor-icons/react";
533
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
534
+ import { markSelfRendering as markSelfRendering2, navigateToAlipayPage as navigateToAlipayPage2, sendCardAction as sendCardAction2 } from "@tbox.cn/app-sdk/client";
535
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
536
+ var modeText = {
537
+ AUTOMATIC_DISCOUNT: "\u7ED3\u7B97\u65F6\u81EA\u52A8\u4F18\u60E0",
538
+ CLAIM_THEN_PURCHASE: "\u5148\u9886\u5238\uFF0C\u518D\u8D2D\u4E70",
539
+ REGISTER_THEN_ATTEND: "\u5148\u62A5\u540D\uFF0C\u518D\u5230\u573A",
540
+ GROUP_PURCHASE: "\u53D1\u8D77\u6216\u53C2\u4E0E\u62FC\u56E2",
541
+ UNKNOWN: "\u4EE5\u6D3B\u52A8\u9875\u8BF4\u660E\u4E3A\u51C6"
542
+ };
543
+ function isClaimSuccess(text, level) {
544
+ return level === "success" || /领取成功|已存入卡包|已领取/.test(text);
545
+ }
546
+ function PromotionOfferDetailCard({ data, cardId = "", isHistory = false, actionTokens }) {
547
+ const [acquiring, setAcquiring] = useState4(false);
548
+ const [claimed, setClaimed] = useState4(false);
549
+ const [claimMessage, setClaimMessage] = useState4(null);
550
+ const pendingClaimRef = useRef3(false);
551
+ useEffect3(() => {
552
+ if (!cardId || typeof window === "undefined") return void 0;
553
+ const onNotice = (event) => {
554
+ const detail = event.detail;
555
+ if (!detail?.text || detail.surfaceId && detail.surfaceId !== cardId) return;
556
+ setAcquiring(false);
557
+ pendingClaimRef.current = false;
558
+ if (isClaimSuccess(detail.text, detail.level)) {
559
+ setClaimed(true);
560
+ }
561
+ setClaimMessage(detail.text);
562
+ };
563
+ const onCard = (event) => {
564
+ const card = event.detail;
565
+ if (card?.cardType !== "promotion-entitlement-list" || !pendingClaimRef.current) return;
566
+ pendingClaimRef.current = false;
567
+ setAcquiring(false);
568
+ setClaimed(true);
569
+ setClaimMessage("\u9886\u53D6\u6210\u529F\uFF01\u5DF2\u5B58\u5165\u5361\u5305");
570
+ };
571
+ window.addEventListener("tbox:notice", onNotice);
572
+ window.addEventListener("tbox:card", onCard);
573
+ return () => {
574
+ window.removeEventListener("tbox:notice", onNotice);
575
+ window.removeEventListener("tbox:card", onCard);
576
+ };
577
+ }, [cardId]);
578
+ if (data.presentation === "promotion-guide") return /* @__PURE__ */ jsx4(PromotionGuide, { data });
579
+ const coupon = data.offerType === "COUPON" || data.presentation === "coupon";
580
+ const purchaseOnly = coupon && data.claimActionLabel === "\u62A2\u8D2D";
581
+ const label = data.presentation === "promotion" ? "\u672C\u5468\u6D3B\u52A8" : data.presentation === "package" ? "\u7EC4\u5408\u793C\u5305" : "\u4F1A\u5458\u4E13\u4EAB";
582
+ return /* @__PURE__ */ jsxs3("section", { className: `promotion-card promotion-detail${coupon ? " promotion-detail--coupon" : ""}`, "aria-label": data.title, children: [
583
+ /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__hero", children: [
584
+ /* @__PURE__ */ jsx4(ImageWithFallback, { src: data.imageUrl, alt: data.title, className: "promotion-detail__image" }),
585
+ /* @__PURE__ */ jsx4("span", { className: "promotion-detail__hero-label", children: label }),
586
+ /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__glass", children: [
587
+ /* @__PURE__ */ jsx4("small", { children: data.claimable ? "\u53EF\u9886\u53D6" : "\u8BE6\u60C5" }),
588
+ /* @__PURE__ */ jsx4("strong", { children: data.benefitText ?? offerTypeLabel(data.offerType) }),
589
+ /* @__PURE__ */ jsx4("em", { children: data.subtitle ?? "\u5F53\u524D\u5546\u573A\u53EF\u7528" })
590
+ ] })
591
+ ] }),
592
+ /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__body", children: [
593
+ /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__status", children: [
594
+ /* @__PURE__ */ jsxs3("span", { className: `promotion-status promotion-status--${data.claimable ? "available" : "unavailable"}`, children: [
595
+ /* @__PURE__ */ jsx4(SealCheck, { weight: "fill" }),
596
+ data.claimable ? "\u53EF\u9886\u53D6" : "\u6682\u4E0D\u53EF\u9886"
597
+ ] }),
598
+ data.validityText && /* @__PURE__ */ jsxs3("small", { children: [
599
+ /* @__PURE__ */ jsx4(Clock, {}),
600
+ data.validityText
601
+ ] })
602
+ ] }),
603
+ /* @__PURE__ */ jsx4("h3", { children: data.title }),
604
+ (data.usageNoticeText || data.guaranteeText) && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__notice-strip", children: [
605
+ data.usageNoticeText && /* @__PURE__ */ jsxs3("span", { children: [
606
+ /* @__PURE__ */ jsx4("b", { children: "\u987B\u77E5" }),
607
+ data.usageNoticeText
608
+ ] }),
609
+ data.guaranteeText && /* @__PURE__ */ jsxs3("span", { children: [
610
+ /* @__PURE__ */ jsx4("b", { children: "\u4FDD\u969C" }),
611
+ data.guaranteeText
612
+ ] })
613
+ ] }),
614
+ (data.usageSceneText || data.validityText || data.usageTimeText || data.thresholdText || data.claimTimeText) && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__facts", children: [
615
+ data.usageSceneText && /* @__PURE__ */ jsxs3("div", { children: [
616
+ /* @__PURE__ */ jsxs3("dt", { children: [
617
+ /* @__PURE__ */ jsx4(MapPin2, { weight: "duotone" }),
618
+ "\u4F7F\u7528\u573A\u666F"
619
+ ] }),
620
+ /* @__PURE__ */ jsx4("dd", { children: data.usageSceneText })
621
+ ] }),
622
+ data.validityText && /* @__PURE__ */ jsxs3("div", { children: [
623
+ /* @__PURE__ */ jsxs3("dt", { children: [
624
+ /* @__PURE__ */ jsx4(CalendarBlank2, { weight: "duotone" }),
625
+ "\u6709\u6548\u671F"
626
+ ] }),
627
+ /* @__PURE__ */ jsx4("dd", { children: data.validityText })
628
+ ] }),
629
+ data.usageTimeText && /* @__PURE__ */ jsxs3("div", { children: [
630
+ /* @__PURE__ */ jsxs3("dt", { children: [
631
+ /* @__PURE__ */ jsx4(Clock, { weight: "duotone" }),
632
+ "\u4F7F\u7528\u65F6\u95F4"
633
+ ] }),
634
+ /* @__PURE__ */ jsx4("dd", { children: data.usageTimeText })
635
+ ] }),
636
+ data.thresholdText && /* @__PURE__ */ jsxs3("div", { children: [
637
+ /* @__PURE__ */ jsxs3("dt", { children: [
638
+ /* @__PURE__ */ jsx4(Ticket2, { weight: "duotone" }),
639
+ "\u4F7F\u7528\u9650\u5236"
640
+ ] }),
641
+ /* @__PURE__ */ jsx4("dd", { children: data.thresholdText })
642
+ ] }),
643
+ data.claimTimeText && /* @__PURE__ */ jsxs3("div", { children: [
644
+ /* @__PURE__ */ jsxs3("dt", { children: [
645
+ /* @__PURE__ */ jsx4(CalendarBlank2, { weight: "duotone" }),
646
+ "\u53EF\u9886\u53D6\u65F6\u95F4"
647
+ ] }),
648
+ /* @__PURE__ */ jsx4("dd", { children: data.claimTimeText })
649
+ ] })
650
+ ] }),
651
+ (data.steps?.length ?? 0) > 0 && /* @__PURE__ */ jsx4("div", { className: "promotion-detail__rules", children: data.steps?.slice(0, 3).map((step, index) => /* @__PURE__ */ jsxs3("span", { children: [
652
+ /* @__PURE__ */ jsx4(CheckCircle, { weight: "fill" }),
653
+ /* @__PURE__ */ jsx4("b", { children: step.title }),
654
+ /* @__PURE__ */ jsx4("small", { children: step.description ?? "" })
655
+ ] }, index)) }),
656
+ (data.usageRuleText || data.description) && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__usage-rule", children: [
657
+ /* @__PURE__ */ jsx4("strong", { children: "\u4F7F\u7528\u89C4\u5219" }),
658
+ /* @__PURE__ */ jsx4("div", { dangerouslySetInnerHTML: { __html: sanitizeActivityHtml(data.usageRuleText ?? data.description ?? "") } })
659
+ ] }),
660
+ purchaseOnly ? /* @__PURE__ */ jsx4("button", { className: "promotion-coupon-main-action", type: "button", disabled: !data.purchaseUrl || isHistory, onClick: () => {
661
+ if (!data.purchaseUrl) return;
662
+ void navigateToAlipayPage2(data.purchaseUrl).catch((err) => console.warn("[PromotionOfferDetailCard] navigateTo failed", err));
663
+ }, children: data.purchaseUrl ? "\u53BB\u5C0F\u7A0B\u5E8F\u62A2\u8D2D" : "\u62A2\u8D2D\u94FE\u63A5\u6682\u4E0D\u53EF\u7528" }) : data.claimable && actionTokens?.["promotion.acquire"] && /* @__PURE__ */ jsx4("button", { className: `promotion-coupon-main-action${acquiring ? " promotion-coupon-main-action--pending" : ""}`, type: "button", disabled: acquiring || claimed, onClick: () => {
664
+ pendingClaimRef.current = true;
665
+ setAcquiring(true);
666
+ setClaimMessage("\u9886\u53D6\u4E2D\uFF0C\u8BF7\u7A0D\u5019\uFF1B\u9886\u53D6\u6210\u529F\u540E\u5C06\u81EA\u52A8\u5C55\u793A\u6211\u7684\u5238\u5305");
667
+ sendCardAction2(cardId, { type: "moduleAction", actionId: "promotion.acquire", contextToken: actionTokens["promotion.acquire"] }, { offerRef: data.offerRef });
668
+ }, children: claimed ? "\u5DF2\u9886\u53D6" : acquiring ? "\u9886\u53D6\u4E2D\u2026" : "\u7ACB\u5373\u9886\u53D6" }),
669
+ claimMessage && /* @__PURE__ */ jsx4("p", { className: "promotion-detail__claim-status", role: "status", children: claimMessage }),
670
+ (data.bundleItems?.length ?? 0) > 0 && /* @__PURE__ */ jsx4("div", { className: "promotion-detail__bundle", children: data.bundleItems?.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
671
+ /* @__PURE__ */ jsx4(Gift, { weight: "duotone" }),
672
+ /* @__PURE__ */ jsx4("b", { children: item.name }),
673
+ /* @__PURE__ */ jsxs3("small", { children: [
674
+ "x",
675
+ item.quantity
676
+ ] })
677
+ ] }, index)) }),
678
+ data.notice && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__notice", children: [
679
+ /* @__PURE__ */ jsx4(Info, {}),
680
+ data.notice
681
+ ] }),
682
+ (data.stores?.length ?? 0) > 0 && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__stores", children: [
683
+ /* @__PURE__ */ jsx4("strong", { children: "\u9002\u7528\u95E8\u5E97" }),
684
+ data.stores?.slice(0, 8).map((store) => /* @__PURE__ */ jsxs3("span", { children: [
685
+ /* @__PURE__ */ jsx4(MapPin2, { weight: "fill" }),
686
+ store.storeName,
687
+ store.floor ? ` \xB7 ${store.floor}` : "",
688
+ store.address ? ` \xB7 ${store.address}` : ""
689
+ ] }, store.storeId))
690
+ ] }),
691
+ !data.claimable && data.unavailableReason && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__notice", children: [
692
+ /* @__PURE__ */ jsx4(Info, {}),
693
+ data.unavailableReason
694
+ ] }),
695
+ data.caveats.length > 0 && /* @__PURE__ */ jsx4("footer", { className: "promotion-card__footer", children: data.caveats.join("\uFF1B") })
696
+ ] })
697
+ ] });
698
+ }
699
+ function PromotionGuide({ data }) {
700
+ const steps = data.steps ?? data.rules.map((rule) => ({ title: rule }));
701
+ return /* @__PURE__ */ jsxs3("section", { className: "promotion-card promotion-guide", "aria-label": "\u6D3B\u52A8\u53C2\u4E0E\u65B9\u5F0F", children: [
702
+ /* @__PURE__ */ jsxs3("header", { className: "promotion-card__header promotion-card__header--compact", children: [
703
+ /* @__PURE__ */ jsx4("span", { className: "promotion-card__mark promotion-card__mark--cyan", children: /* @__PURE__ */ jsx4(ListChecks, { weight: "duotone" }) }),
704
+ /* @__PURE__ */ jsxs3("div", { children: [
705
+ /* @__PURE__ */ jsx4("span", { className: "promotion-card__eyebrow", children: "\u6D3B\u52A8\u53C2\u4E0E\u65B9\u5F0F" }),
706
+ /* @__PURE__ */ jsx4("h3", { children: data.title }),
707
+ /* @__PURE__ */ jsx4("p", { children: data.validityText ?? "\u5F53\u524D\u6D3B\u52A8\u6709\u6548\u671F\u4EE5\u73B0\u573A\u4E3A\u51C6" })
708
+ ] }),
709
+ /* @__PURE__ */ jsx4("b", { className: `promotion-status promotion-status--${data.claimable ? "available" : "unavailable"}`, children: data.claimable ? "\u53EF\u53C2\u4E0E" : "\u67E5\u770B\u89C4\u5219" })
710
+ ] }),
711
+ /* @__PURE__ */ jsxs3("div", { className: "promotion-guide__summary", children: [
712
+ /* @__PURE__ */ jsxs3("span", { children: [
713
+ /* @__PURE__ */ jsx4(MapPin2, { weight: "fill" }),
714
+ "\u5F53\u524D\u5546\u573A"
715
+ ] }),
716
+ /* @__PURE__ */ jsx4("strong", { children: modeText[data.participationMode ?? "UNKNOWN"] })
717
+ ] }),
718
+ /* @__PURE__ */ jsx4("ol", { children: steps.map((step, index) => /* @__PURE__ */ jsxs3("li", { children: [
719
+ /* @__PURE__ */ jsx4("b", { children: index + 1 }),
720
+ /* @__PURE__ */ jsxs3("span", { children: [
721
+ /* @__PURE__ */ jsx4("strong", { children: step.title }),
722
+ /* @__PURE__ */ jsx4("small", { children: step.description ?? "" })
723
+ ] })
724
+ ] }, index)) }),
725
+ (data.requirements?.length ?? 0) > 0 && /* @__PURE__ */ jsx4("div", { className: "promotion-guide__requirements", children: data.requirements?.map((item) => /* @__PURE__ */ jsxs3("span", { children: [
726
+ /* @__PURE__ */ jsx4(CheckCircle, { weight: "fill" }),
727
+ item
728
+ ] }, item)) }),
729
+ data.notice && /* @__PURE__ */ jsxs3("div", { className: "promotion-detail__notice", children: [
730
+ /* @__PURE__ */ jsx4(Info, { weight: "duotone" }),
731
+ data.notice
732
+ ] }),
733
+ /* @__PURE__ */ jsx4("footer", { className: "promotion-card__footer", children: "\u53C2\u4E0E\u8D44\u683C\u548C\u573A\u6B21\u4EE5\u6D3B\u52A8\u73B0\u573A\u5B9E\u65F6\u4FE1\u606F\u4E3A\u51C6" })
734
+ ] });
735
+ }
736
+ var promotion_offer_detail_default = PromotionOfferDetailCard;
737
+ markSelfRendering2(PromotionOfferDetailCard);
738
+
739
+ // src/client/cards/promotion-entitlement-list/index.tsx
740
+ import { CalendarBlank as CalendarBlank3, CaretDown as CaretDown2, Copy, MapPinLine, NavigationArrow, ShieldCheck, Ticket as Ticket3 } from "@phosphor-icons/react";
741
+ import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState6 } from "react";
742
+ import { callJsapi, httpGet } from "@tbox.cn/app-sdk/client";
743
+
744
+ // src/client/components/CouponQrCode.tsx
745
+ import QRCode from "qrcode";
746
+ import JsBarcode from "jsbarcode";
747
+ import { useEffect as useEffect4, useState as useState5 } from "react";
748
+ import { useRef as useRef4 } from "react";
749
+ import { jsx as jsx5 } from "react/jsx-runtime";
750
+ function CouponQrCode(props) {
751
+ const { value, disabled = false } = props;
752
+ const [src, setSrc] = useState5();
753
+ useEffect4(() => {
754
+ let active = true;
755
+ setSrc(void 0);
756
+ void QRCode.toDataURL(value, {
757
+ width: 200,
758
+ margin: 1,
759
+ errorCorrectionLevel: "M",
760
+ color: { dark: disabled ? "#999999" : "#000000", light: "#ffffff" }
761
+ }).then((dataUrl) => {
762
+ if (active) setSrc(dataUrl);
763
+ }).catch(() => {
764
+ if (active) setSrc(void 0);
765
+ });
766
+ return () => {
767
+ active = false;
768
+ };
769
+ }, [disabled, value]);
770
+ return src ? /* @__PURE__ */ jsx5("img", { className: `promotion-sheet__qrcode${disabled ? " promotion-sheet__qrcode--disabled" : ""}`, src, alt: "\u5238\u7801\u4E8C\u7EF4\u7801" }) : null;
771
+ }
772
+ function CouponBarcode(props) {
773
+ const { value, disabled = false } = props;
774
+ const ref = useRef4(null);
775
+ useEffect4(() => {
776
+ if (!ref.current) return;
777
+ try {
778
+ JsBarcode(ref.current, value, {
779
+ format: "CODE128",
780
+ width: 2,
781
+ height: 52,
782
+ margin: 0,
783
+ displayValue: false,
784
+ lineColor: disabled ? "#999999" : "#000000"
785
+ });
786
+ } catch {
787
+ ref.current.replaceChildren();
788
+ }
789
+ }, [disabled, value]);
790
+ return /* @__PURE__ */ jsx5("svg", { ref, className: `promotion-sheet__barcode${disabled ? " promotion-sheet__barcode--disabled" : ""}`, "aria-label": "\u5238\u7801\u6761\u5F62\u7801", role: "img" });
791
+ }
792
+
793
+ // src/client/cards/promotion-entitlement-list/index.tsx
794
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
795
+ function PromotionEntitlementListCard(props) {
796
+ const { data } = props;
797
+ const [openRef, setOpenRef] = useState6(null);
798
+ const [expanded, setExpanded] = useState6(false);
799
+ const [listHeights, setListHeights] = useState6({ collapsed: 0, expanded: 0 });
800
+ const listRef = useRef5(null);
801
+ const bottomRef = useRef5(null);
802
+ const initialRenderRef = useRef5(true);
803
+ useEffect5(() => {
804
+ if (initialRenderRef.current) {
805
+ initialRenderRef.current = false;
806
+ return;
807
+ }
808
+ if (bottomRef.current) scrollCardBottom(bottomRef.current);
809
+ }, [expanded]);
810
+ useLayoutEffect2(() => {
811
+ const list = listRef.current;
812
+ if (!list) return;
813
+ const rows = [...list.children];
814
+ const boundary = rows[Math.min(maxItems, rows.length) - 1];
815
+ const listTop = list.getBoundingClientRect().top;
816
+ const collapsed = boundary ? boundary.getBoundingClientRect().bottom - listTop : list.scrollHeight;
817
+ setListHeights({ collapsed, expanded: list.scrollHeight });
818
+ }, [data.items.length, data.maxItems]);
819
+ const toggleExpanded = () => {
820
+ setExpanded((value) => !value);
821
+ };
822
+ const target = openRef ? data.items.find((item) => item.entitlementRef === openRef) : void 0;
823
+ const [detailTarget, setDetailTarget] = useState6();
824
+ const [detailLoading, setDetailLoading] = useState6(false);
825
+ const detailController = useRef5(null);
826
+ const [copied, setCopied] = useState6(false);
827
+ useEffect5(() => {
828
+ detailController.current?.abort();
829
+ if (!openRef || !target) {
830
+ setDetailTarget(void 0);
831
+ setDetailLoading(false);
832
+ return void 0;
833
+ }
834
+ const controller = new AbortController();
835
+ detailController.current = controller;
836
+ setDetailTarget(void 0);
837
+ setDetailLoading(true);
838
+ const params = new URLSearchParams({ entitlementRef: openRef });
839
+ if (data.mallId) params.set("mallId", data.mallId);
840
+ if (data.miniAppId) params.set("miniAppId", data.miniAppId);
841
+ httpGet(`/api/m/promotion/entitlement-detail?${params.toString()}`, { signal: controller.signal }).then(({ data: payload }) => {
842
+ if (!controller.signal.aborted) setDetailTarget(payload.data);
843
+ }).catch(() => void 0).finally(() => {
844
+ if (!controller.signal.aborted) setDetailLoading(false);
845
+ });
846
+ return () => controller.abort();
847
+ }, [openRef, target]);
848
+ const sheetTarget = detailTarget ?? target;
849
+ const maxItems = data.maxItems ?? 4;
850
+ const copyCode = async (code) => {
851
+ try {
852
+ await navigator.clipboard?.writeText(code);
853
+ setCopied(true);
854
+ window.setTimeout(() => setCopied(false), 1600);
855
+ } catch {
856
+ setCopied(false);
857
+ }
858
+ };
859
+ return /* @__PURE__ */ jsxs4("section", { className: "promotion-card promotion-list--coupon promotion-entitlements", "aria-label": "\u6211\u7684\u4F18\u60E0\u6743\u76CA", children: [
860
+ /* @__PURE__ */ jsxs4("header", { className: "promotion-activity__header promotion-activity__header--pea promotion-coupon__header", children: [
861
+ /* @__PURE__ */ jsx6("img", { src: promotion_coupon_header_pea_v1_default, alt: "", "aria-hidden": "true", className: "promotion-activity__header-art" }),
862
+ /* @__PURE__ */ jsxs4("div", { className: "promotion-activity__header-copy", children: [
863
+ /* @__PURE__ */ jsxs4("div", { className: "promotion-activity__header-title-row", children: [
864
+ /* @__PURE__ */ jsx6(Ticket3, { weight: "fill" }),
865
+ /* @__PURE__ */ jsx6("h3", { children: "\u6211\u7684\u4F18\u60E0\u5238" })
866
+ ] }),
867
+ /* @__PURE__ */ jsx6("p", { children: "\u5F53\u524D\u8D26\u6237 \xB7 \u5238\u5305\u6743\u76CA" })
868
+ ] })
869
+ ] }),
870
+ !data.items.length ? /* @__PURE__ */ jsxs4("div", { className: "promotion-card__empty", children: [
871
+ /* @__PURE__ */ jsx6(Ticket3, { size: 28, weight: "duotone" }),
872
+ /* @__PURE__ */ jsx6("span", { children: data.noResultsReason ?? "\u5F53\u524D\u8D26\u6237\u6682\u65E0\u53EF\u7528\u6743\u76CA" })
873
+ ] }) : /* @__PURE__ */ jsx6("div", { ref: listRef, className: `promotion-list__items${expanded ? " promotion-list__items--expanded" : ""}`, style: { maxHeight: expanded ? listHeights.expanded || void 0 : listHeights.collapsed || void 0 }, onTransitionEnd: () => {
874
+ if (bottomRef.current) scrollCardBottom(bottomRef.current);
875
+ }, children: data.items.map((item) => /* @__PURE__ */ jsxs4(
876
+ "article",
877
+ {
878
+ className: `promotion-coupon-row${item.status === "EFFECTIVE" ? "" : " promotion-coupon-row--disabled"}`,
879
+ role: "button",
880
+ tabIndex: 0,
881
+ "aria-label": `\u67E5\u770B\u300C${item.title}\u300D`,
882
+ onClick: () => setOpenRef(item.entitlementRef),
883
+ onKeyDown: (e) => {
884
+ if (e.key === "Enter" || e.key === " ") {
885
+ e.preventDefault();
886
+ setOpenRef(item.entitlementRef);
887
+ }
888
+ },
889
+ children: [
890
+ /* @__PURE__ */ jsx6(ImageWithFallback, { src: item.imageUrl, alt: item.title, className: "promotion-coupon-row__thumb" }),
891
+ /* @__PURE__ */ jsxs4("div", { className: "promotion-coupon-row__main", children: [
892
+ /* @__PURE__ */ jsx6("strong", { className: "promotion-coupon-row__title", children: item.title }),
893
+ item.usageNotice && /* @__PURE__ */ jsx6("span", { className: "promotion-coupon-row__sub", dangerouslySetInnerHTML: { __html: sanitizeActivityHtml(item.usageNotice) } }),
894
+ /* @__PURE__ */ jsxs4("span", { className: "promotion-coupon-row__price", children: [
895
+ /* @__PURE__ */ jsx6("b", { children: item.benefitText ?? entitlementStatusLabel(item.status) }),
896
+ item.thresholdText && /* @__PURE__ */ jsx6("em", { className: "promotion-coupon-row__discount", children: item.thresholdText })
897
+ ] })
898
+ ] }),
899
+ /* @__PURE__ */ jsx6(
900
+ "span",
901
+ {
902
+ className: `promotion-owned-action promotion-chip promotion-chip--coupon promotion-coupon-row__state--${item.status.toLowerCase()}${item.status === "EFFECTIVE" ? "" : " promotion-chip--coupon-off"}`,
903
+ "aria-hidden": "true",
904
+ children: item.status === "EFFECTIVE" ? "\u53BB\u4F7F\u7528" : entitlementStatusLabel(item.status)
905
+ }
906
+ )
907
+ ]
908
+ },
909
+ item.entitlementRef
910
+ )) }),
911
+ data.items.length > maxItems && /* @__PURE__ */ jsxs4(
912
+ "button",
913
+ {
914
+ type: "button",
915
+ className: "promotion-list__toggle",
916
+ "aria-expanded": expanded,
917
+ onClick: toggleExpanded,
918
+ children: [
919
+ /* @__PURE__ */ jsx6(CaretDown2, { size: 16, "data-rotated": expanded || void 0 }),
920
+ expanded ? "\u6536\u8D77" : `\u67E5\u770B\u66F4\u591A\uFF08${data.items.length - maxItems} \u6761\uFF09`
921
+ ]
922
+ }
923
+ ),
924
+ data.items.length > maxItems && /* @__PURE__ */ jsx6("div", { ref: bottomRef, className: "promotion-list__bottom-anchor", "aria-hidden": "true" }),
925
+ sheetTarget && (() => {
926
+ const facts = [
927
+ sheetFact(/* @__PURE__ */ jsx6(MapPinLine, { weight: "duotone" }), "\u4F7F\u7528\u573A\u666F", sheetTarget.usageSceneText),
928
+ sheetFact(/* @__PURE__ */ jsx6(CalendarBlank3, { weight: "duotone" }), "\u6709\u6548\u671F", sheetTarget.validityText ?? sheetTarget.validUntilText),
929
+ sheetFact(/* @__PURE__ */ jsx6(CalendarBlank3, { weight: "duotone" }), "\u4F7F\u7528\u65F6\u95F4", sheetTarget.usageTimeText),
930
+ sheetFact(/* @__PURE__ */ jsx6(ShieldCheck, { weight: "duotone" }), "\u4F7F\u7528\u9650\u5236", sheetTarget.thresholdText),
931
+ sheetFact(/* @__PURE__ */ jsx6(CalendarBlank3, { weight: "duotone" }), "\u53EF\u9886\u53D6\u65F6\u95F4", sheetTarget.claimTimeText),
932
+ sheetFact(/* @__PURE__ */ jsx6(Ticket3, { weight: "duotone" }), "\u4F7F\u7528\u89C4\u5219", sheetTarget.usageRuleText)
933
+ ].filter(Boolean);
934
+ return /* @__PURE__ */ jsx6(
935
+ CouponSheet,
936
+ {
937
+ title: sheetTarget.title,
938
+ imageUrl: sheetTarget.imageUrl,
939
+ priceMain: sheetTarget.benefitText,
940
+ aside: detailLoading ? "\u52A0\u8F7D\u8BE6\u60C5\u4E2D" : entitlementStatusLabel(sheetTarget.status),
941
+ noticeText: sheetTarget.usageNotice,
942
+ guaranteeText: sheetTarget.guaranteeText,
943
+ facts,
944
+ onClose: () => setOpenRef(null),
945
+ beforeFacts: /* @__PURE__ */ jsxs4(Fragment3, { children: [
946
+ sheetTarget.qrCodeEnabled && sheetTarget.code && /* @__PURE__ */ jsxs4(Fragment3, { children: [
947
+ /* @__PURE__ */ jsx6(CouponBarcode, { value: sheetTarget.code, disabled: sheetTarget.status !== "EFFECTIVE" }),
948
+ /* @__PURE__ */ jsx6(CouponQrCode, { value: sheetTarget.code, disabled: sheetTarget.status !== "EFFECTIVE" })
949
+ ] }),
950
+ (sheetTarget.code || sheetTarget.codeMasked) && /* @__PURE__ */ jsxs4("div", { className: `promotion-sheet__code${sheetTarget.status === "EFFECTIVE" ? "" : " promotion-sheet__code--disabled"}`, children: [
951
+ /* @__PURE__ */ jsx6("span", { children: "\u5238\u7801" }),
952
+ /* @__PURE__ */ jsx6("strong", { children: sheetTarget.code || sheetTarget.codeMasked }),
953
+ /* @__PURE__ */ jsxs4("button", { type: "button", className: "promotion-sheet__copy", onClick: () => copyCode(sheetTarget.code || sheetTarget.codeMasked), children: [
954
+ /* @__PURE__ */ jsx6(Copy, { size: 16 }),
955
+ copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236"
956
+ ] })
957
+ ] }),
958
+ sheetTarget.stores?.length ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
959
+ /* @__PURE__ */ jsx6("div", { className: "promotion-sheet__section", children: "\u9002\u7528\u5546\u5BB6" }),
960
+ /* @__PURE__ */ jsx6("div", { className: "promotion-sheet__stores", children: sheetTarget.stores.map((store) => /* @__PURE__ */ jsxs4("div", { className: "promotion-sheet__store", children: [
961
+ store.imageUrl && /* @__PURE__ */ jsx6(ImageWithFallback, { src: store.imageUrl, alt: store.storeName, className: "promotion-sheet__store-image" }),
962
+ /* @__PURE__ */ jsxs4("span", { children: [
963
+ /* @__PURE__ */ jsx6("strong", { children: store.storeName }),
964
+ store.businessName && store.businessName !== store.storeName && /* @__PURE__ */ jsx6("small", { children: store.businessName }),
965
+ store.floor && /* @__PURE__ */ jsx6("small", { children: store.floor }),
966
+ store.address && /* @__PURE__ */ jsx6("small", { children: store.address })
967
+ ] }),
968
+ store.latitude !== void 0 && store.longitude !== void 0 && /* @__PURE__ */ jsxs4("button", { type: "button", className: "promotion-sheet__navigate", "aria-label": `\u5BFC\u822A\u5230${store.storeName}`, onClick: (event) => {
969
+ event.stopPropagation();
970
+ void callJsapi("openLocation", { latitude: store.latitude, longitude: store.longitude, name: store.storeName, address: store.address ?? "" }).catch(() => void 0);
971
+ }, children: [
972
+ /* @__PURE__ */ jsx6(NavigationArrow, { size: 18 }),
973
+ "\u5BFC\u822A"
974
+ ] })
975
+ ] }, store.storeId)) })
976
+ ] }) : null
977
+ ] })
978
+ }
979
+ );
980
+ })()
981
+ ] });
982
+ }
983
+ function sheetFact(icon, label, value) {
984
+ return value ? { icon, label, value } : null;
985
+ }
986
+ var promotion_entitlement_list_default = PromotionEntitlementListCard;
987
+
988
+ // src/client/cards/promotion-activity-list/index.tsx
989
+ import { CalendarDots as CalendarDots2, Sparkle as Sparkle2, Ticket as Ticket4 } from "@phosphor-icons/react";
990
+ import { sendCardAction as sendCardAction3 } from "@tbox.cn/app-sdk/client";
991
+
992
+ // src/client/assets/promotion-activity-header-pea-v2.jpg
993
+ var promotion_activity_header_pea_v2_default = "./promotion-activity-header-pea-v2-4CCHFCCM.jpg";
994
+
995
+ // src/client/cards/promotion-activity-list/index.tsx
996
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
997
+ var statusText2 = { AVAILABLE: "\u53EF\u62A5\u540D", FULL: "\u5DF2\u6EE1", ENDED: "\u5DF2\u7ED3\u675F", UPCOMING: "\u5373\u5C06\u5F00\u59CB", UNKNOWN: "\u5F85\u786E\u8BA4" };
998
+ function PromotionActivityListCard(props) {
999
+ const { data, cardId = "", isHistory = false } = props;
1000
+ return /* @__PURE__ */ jsxs5("section", { className: "promotion-card promotion-activity promotion-activity--list", children: [
1001
+ /* @__PURE__ */ jsxs5("header", { className: "promotion-activity__header promotion-activity__header--pea", children: [
1002
+ /* @__PURE__ */ jsx7("img", { src: promotion_activity_header_pea_v2_default, alt: "", "aria-hidden": "true", className: "promotion-activity__header-art" }),
1003
+ /* @__PURE__ */ jsxs5("div", { className: "promotion-activity__header-copy", children: [
1004
+ /* @__PURE__ */ jsxs5("div", { className: "promotion-activity__header-title-row", children: [
1005
+ /* @__PURE__ */ jsx7(Sparkle2, { weight: "fill" }),
1006
+ /* @__PURE__ */ jsx7("h3", { children: "\u6D3B\u52A8\u4E2D\u5FC3" })
1007
+ ] }),
1008
+ /* @__PURE__ */ jsx7("p", { children: "\u53D1\u73B0\u5546\u573A\u8FD1\u671F\u7CBE\u5F69\u6D3B\u52A8" })
1009
+ ] })
1010
+ ] }),
1011
+ /* @__PURE__ */ jsx7("div", { className: "promotion-activity__list", children: data.items.map((item) => {
1012
+ const status = item.availabilityStatus ?? (item.remainingQuota === 0 ? "FULL" : "UNKNOWN");
1013
+ const action = item.itemActions?.find((candidate) => candidate.kind === "send" || candidate.kind === "link");
1014
+ const jumpOnly = item.jumpOnly === true;
1015
+ return /* @__PURE__ */ jsxs5(
1016
+ "button",
1017
+ {
1018
+ type: "button",
1019
+ disabled: isHistory || !action,
1020
+ "aria-label": action?.label ?? (jumpOnly ? `\u6253\u5F00${item.title}` : `\u67E5\u770B${item.title}\u8BE6\u60C5`),
1021
+ className: status === "FULL" || status === "ENDED" ? "is-muted" : "",
1022
+ onClick: () => {
1023
+ if (!action || isHistory) return;
1024
+ if (action.kind === "link") {
1025
+ sendCardAction3(cardId, { type: "openLink", url: action.url });
1026
+ } else {
1027
+ sendCardAction3(cardId, { type: "sendMessage", value: action.value ?? action.label, visible: true });
1028
+ }
1029
+ },
1030
+ children: [
1031
+ /* @__PURE__ */ jsxs5("span", { className: "promotion-activity__visual", children: [
1032
+ /* @__PURE__ */ jsx7(ImageWithFallback, { src: item.coverUrl, alt: item.title, className: "promotion-activity__thumb" }),
1033
+ /* @__PURE__ */ jsx7("span", { className: `promotion-activity__status promotion-activity__status--${status.toLowerCase()}`, children: statusText2[status] })
1034
+ ] }),
1035
+ /* @__PURE__ */ jsxs5("span", { className: "promotion-activity__copy", children: [
1036
+ /* @__PURE__ */ jsxs5("small", { children: [
1037
+ /* @__PURE__ */ jsx7(Sparkle2, { weight: "fill" }),
1038
+ item.categoryName ?? (jumpOnly ? "\u9996\u9875\u7CBE\u9009" : "\u4F1A\u5458\u6D3B\u52A8")
1039
+ ] }),
1040
+ /* @__PURE__ */ jsx7("strong", { children: item.title }),
1041
+ /* @__PURE__ */ jsxs5("span", { children: [
1042
+ /* @__PURE__ */ jsx7(CalendarDots2, { weight: "duotone" }),
1043
+ item.periodText ?? (jumpOnly ? "\u70B9\u51FB\u6253\u5F00\u67E5\u770B\u5185\u5BB9" : "\u65F6\u95F4\u4EE5\u6D3B\u52A8\u9875\u4E3A\u51C6")
1044
+ ] }),
1045
+ /* @__PURE__ */ jsx7("em", { children: item.remainingQuota !== void 0 ? item.remainingQuota > 0 ? `\u4EC5\u4F59 ${item.remainingQuota} \u5E2D` : "\u540D\u989D\u5DF2\u6EE1" : jumpOnly ? item.jumpLabel ?? "\u6253\u5F00\u67E5\u770B" : item.registrationRequired ? "\u9700\u63D0\u524D\u62A5\u540D" : "\u65E0\u9700\u62A5\u540D" })
1046
+ ] })
1047
+ ]
1048
+ },
1049
+ item.activityRef
1050
+ );
1051
+ }) }),
1052
+ !data.items.length && /* @__PURE__ */ jsxs5("div", { className: "promotion-card__empty", children: [
1053
+ /* @__PURE__ */ jsx7(CalendarDots2, { size: 28 }),
1054
+ /* @__PURE__ */ jsx7("span", { children: data.noResultsReason ?? "\u8FD1\u671F\u6682\u65E0\u6D3B\u52A8" })
1055
+ ] }),
1056
+ /* @__PURE__ */ jsxs5("footer", { className: "promotion-activity__footer", children: [
1057
+ /* @__PURE__ */ jsx7(Ticket4, { weight: "duotone" }),
1058
+ "\u4F1A\u5458\u6D3B\u52A8\u540D\u989D\u5B9E\u65F6\u53D8\u5316\uFF0C\u4EE5\u6D3B\u52A8\u8BE6\u60C5\u4E3A\u51C6"
1059
+ ] })
1060
+ ] });
1061
+ }
1062
+ var promotion_activity_list_default = PromotionActivityListCard;
1063
+
1064
+ // src/client/cards/promotion-activity-detail/index.tsx
1065
+ import { ArrowSquareOut, CalendarDots as CalendarDots3, CheckCircle as CheckCircle2, Clock as Clock2, Crown, ListChecks as ListChecks2, MapPin as MapPin3, Sparkle as Sparkle3, Users } from "@phosphor-icons/react";
1066
+ import { sendCardAction as sendCardAction4 } from "@tbox.cn/app-sdk/client";
1067
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1068
+ var sessionText = { OPEN: "\u53EF\u9009", FULL: "\u5DF2\u6EE1", CLOSED: "\u5DF2\u7ED3\u675F", UNKNOWN: "\u5F85\u786E\u8BA4" };
1069
+ function PromotionActivityDetailCard({ data, cardId = "", isHistory = false }) {
1070
+ if (data.presentation === "schedule") return /* @__PURE__ */ jsx8(ActivitySchedule, { data });
1071
+ if (data.presentation === "guide") return /* @__PURE__ */ jsx8(ActivityGuide, { data });
1072
+ return /* @__PURE__ */ jsx8(ActivityDetail, { data, cardId, isHistory });
1073
+ }
1074
+ function ActivityDetail({ data, cardId, isHistory }) {
1075
+ const status = data.remainingQuota === 0 ? "FULL" : "AVAILABLE";
1076
+ return /* @__PURE__ */ jsxs6("section", { className: "promotion-card promotion-activity promotion-activity--detail", children: [
1077
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__cover", children: [
1078
+ /* @__PURE__ */ jsx8(ImageWithFallback, { src: data.coverUrl, alt: data.title, className: "promotion-activity__cover-image" }),
1079
+ /* @__PURE__ */ jsx8("span", { className: "promotion-activity__cover-shade" }),
1080
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__cover-meta", children: [
1081
+ /* @__PURE__ */ jsxs6("span", { children: [
1082
+ /* @__PURE__ */ jsx8(Crown, { weight: "fill" }),
1083
+ "\u4F1A\u5458\u4E13\u4EAB\u4F53\u9A8C"
1084
+ ] }),
1085
+ /* @__PURE__ */ jsx8("span", { className: `promotion-activity__status promotion-activity__status--${status.toLowerCase()}`, children: status === "FULL" ? "\u5DF2\u6EE1" : "\u53EF\u62A5\u540D" })
1086
+ ] })
1087
+ ] }),
1088
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__detail-body", children: [
1089
+ /* @__PURE__ */ jsx8("small", { children: data.jumpOnly ? "\u9996\u9875\u7CBE\u9009 \xB7 \u53EF\u8DF3\u8F6C\u5185\u5BB9" : `\u6D3B\u52A8\u8BE6\u60C5 \xB7 ${data.categoryName ?? "\u4F1A\u5458\u6D3B\u52A8"}` }),
1090
+ /* @__PURE__ */ jsx8("h3", { children: data.title }),
1091
+ (data.subtitle ?? data.description) && /* @__PURE__ */ jsx8("p", { children: data.subtitle ?? data.description }),
1092
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__spotlight", children: [
1093
+ /* @__PURE__ */ jsxs6("span", { children: [
1094
+ /* @__PURE__ */ jsx8(CalendarDots3, { weight: "duotone" }),
1095
+ /* @__PURE__ */ jsx8("small", { children: data.jumpOnly ? "\u5185\u5BB9\u8BF4\u660E" : "\u6D3B\u52A8\u65F6\u95F4" }),
1096
+ /* @__PURE__ */ jsx8("strong", { children: data.periodText ?? (data.jumpOnly ? "\u8BE6\u60C5\u4EE5\u8DF3\u8F6C\u9875\u9762\u4E3A\u51C6" : "\u4EE5\u6D3B\u52A8\u9875\u4E3A\u51C6") })
1097
+ ] }),
1098
+ /* @__PURE__ */ jsxs6("span", { children: [
1099
+ /* @__PURE__ */ jsx8(Users, { weight: "duotone" }),
1100
+ /* @__PURE__ */ jsx8("small", { children: "\u6D3B\u52A8\u540D\u989D" }),
1101
+ /* @__PURE__ */ jsx8("strong", { children: data.remainingQuota !== void 0 ? `\u5269\u4F59 ${data.remainingQuota} \u5E2D` : data.registrationRequired ? "\u9700\u63D0\u524D\u62A5\u540D" : "\u65E0\u9700\u62A5\u540D" })
1102
+ ] })
1103
+ ] }),
1104
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__venue", children: [
1105
+ /* @__PURE__ */ jsx8(MapPin3, { weight: "fill" }),
1106
+ /* @__PURE__ */ jsxs6("span", { children: [
1107
+ /* @__PURE__ */ jsx8("small", { children: "\u6D3B\u52A8\u5730\u70B9" }),
1108
+ /* @__PURE__ */ jsx8("strong", { children: data.location ?? "\u5F53\u524D\u5546\u573A" })
1109
+ ] })
1110
+ ] }),
1111
+ data.registrationRequired && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__benefit", children: [
1112
+ /* @__PURE__ */ jsx8(Crown, { weight: "fill" }),
1113
+ /* @__PURE__ */ jsxs6("span", { children: [
1114
+ /* @__PURE__ */ jsx8("b", { children: "\u4F1A\u5458\u4E13\u4EAB\u793C\u9047" }),
1115
+ "\u5B8C\u6210\u4F1A\u5458\u8EAB\u4EFD\u6821\u9A8C\u540E\u53EF\u53C2\u4E0E"
1116
+ ] })
1117
+ ] }),
1118
+ data.notice && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__detail-notice", children: [
1119
+ /* @__PURE__ */ jsx8(Clock2, { weight: "duotone" }),
1120
+ /* @__PURE__ */ jsx8("span", { children: data.notice })
1121
+ ] }),
1122
+ (data.sessions.length > 0 || data.guideSteps.length > 0) && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__readonly", children: [
1123
+ /* @__PURE__ */ jsx8(ListChecks2, { weight: "fill" }),
1124
+ "\u53EF\u7EE7\u7EED\u8BE2\u95EE\u53C2\u4E0E\u6307\u5357\u548C\u53EF\u9009\u573A\u6B21"
1125
+ ] }),
1126
+ (data.registrationRequired || data.jumpOnly) && data.registrationUrl && /* @__PURE__ */ jsxs6(
1127
+ "button",
1128
+ {
1129
+ type: "button",
1130
+ className: "promotion-activity__register",
1131
+ disabled: isHistory,
1132
+ onClick: () => sendCardAction4(cardId, { type: "openLink", url: data.registrationUrl }),
1133
+ children: [
1134
+ /* @__PURE__ */ jsx8(ArrowSquareOut, { weight: "bold" }),
1135
+ data.jumpOnly ? data.jumpLabel ?? "\u6253\u5F00\u5C0F\u7A0B\u5E8F" : "\u53BB\u652F\u4ED8\u5B9D\u62A5\u540D"
1136
+ ]
1137
+ }
1138
+ ),
1139
+ data.jumpOnly && !data.registrationUrl && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__detail-notice", children: [
1140
+ /* @__PURE__ */ jsx8(Clock2, { weight: "duotone" }),
1141
+ /* @__PURE__ */ jsx8("span", { children: "\u8BE5\u9996\u9875\u8D44\u6E90\u6682\u65E0\u53EF\u7528\u8DF3\u8F6C\u94FE\u63A5" })
1142
+ ] })
1143
+ ] })
1144
+ ] });
1145
+ }
1146
+ function ActivitySchedule({ data }) {
1147
+ return /* @__PURE__ */ jsxs6("section", { className: "promotion-card promotion-activity promotion-activity--schedule", children: [
1148
+ /* @__PURE__ */ jsx8(ActivityHeader, { title: "\u9009\u62E9\u5FC3\u4EEA\u573A\u6B21", subtitle: data.title, icon: "calendar" }),
1149
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__session-summary", children: [
1150
+ /* @__PURE__ */ jsx8(CalendarDots3, { weight: "duotone" }),
1151
+ /* @__PURE__ */ jsxs6("span", { children: [
1152
+ /* @__PURE__ */ jsx8("small", { children: "\u53EF\u9009\u573A\u6B21" }),
1153
+ /* @__PURE__ */ jsxs6("strong", { children: [
1154
+ data.sessions.length,
1155
+ " \u573A"
1156
+ ] })
1157
+ ] }),
1158
+ /* @__PURE__ */ jsx8("em", { children: "\u5B9E\u65F6\u540D\u989D" })
1159
+ ] }),
1160
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__sessions", children: [
1161
+ data.sessions.map((session, index) => /* @__PURE__ */ jsxs6("article", { className: session.status === "OPEN" ? "is-available" : "is-full", children: [
1162
+ /* @__PURE__ */ jsx8("b", { children: String(index + 1).padStart(2, "0") }),
1163
+ /* @__PURE__ */ jsxs6("span", { children: [
1164
+ /* @__PURE__ */ jsx8("strong", { children: session.title }),
1165
+ /* @__PURE__ */ jsxs6("small", { children: [
1166
+ session.startText,
1167
+ session.endText ? ` - ${session.endText}` : ""
1168
+ ] })
1169
+ ] }),
1170
+ /* @__PURE__ */ jsxs6("span", { children: [
1171
+ /* @__PURE__ */ jsx8(Users, { weight: "duotone" }),
1172
+ session.remainingQuota !== void 0 ? `\u4F59 ${session.remainingQuota} \u5E2D` : session.location ?? "\u540D\u989D\u5B9E\u65F6"
1173
+ ] }),
1174
+ /* @__PURE__ */ jsx8("em", { children: sessionText[session.status] })
1175
+ ] }, session.sessionRef)),
1176
+ !data.sessions.length && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__empty-state", children: [
1177
+ /* @__PURE__ */ jsx8(Clock2, { weight: "duotone" }),
1178
+ /* @__PURE__ */ jsxs6("span", { children: [
1179
+ /* @__PURE__ */ jsx8("strong", { children: "\u573A\u6B21\u6B63\u5728\u786E\u8BA4" }),
1180
+ /* @__PURE__ */ jsx8("small", { children: "\u7A0D\u540E\u518D\u6765\u67E5\u770B\u6700\u65B0\u5B89\u6392" })
1181
+ ] })
1182
+ ] })
1183
+ ] }),
1184
+ /* @__PURE__ */ jsxs6("p", { className: "promotion-activity__readonly", children: [
1185
+ /* @__PURE__ */ jsx8(CheckCircle2, { weight: "fill" }),
1186
+ "\u5F53\u524D\u4EC5\u5C55\u793A\u573A\u6B21\u4E0E\u540D\u989D\uFF0C\u4E0D\u4F1A\u76F4\u63A5\u63D0\u4EA4\u62A5\u540D"
1187
+ ] })
1188
+ ] });
1189
+ }
1190
+ function ActivityGuide({ data }) {
1191
+ const steps = data.guideItems ?? data.guideSteps.map((title) => ({ title }));
1192
+ return /* @__PURE__ */ jsxs6("section", { className: "promotion-card promotion-activity promotion-activity--guide", children: [
1193
+ /* @__PURE__ */ jsx8(ActivityHeader, { title: "\u53C2\u4E0E\u6307\u5357", subtitle: data.title, icon: "guide" }),
1194
+ /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__guide-banner", children: [
1195
+ /* @__PURE__ */ jsx8(Sparkle3, { weight: "fill" }),
1196
+ /* @__PURE__ */ jsxs6("span", { children: [
1197
+ /* @__PURE__ */ jsx8("small", { children: "HOW TO JOIN" }),
1198
+ /* @__PURE__ */ jsx8("strong", { children: "\u63D0\u524D\u51C6\u5907\uFF0C\u5230\u573A\u66F4\u4ECE\u5BB9" })
1199
+ ] })
1200
+ ] }),
1201
+ /* @__PURE__ */ jsx8("ol", { className: "promotion-activity__steps", children: steps.map((step, index) => /* @__PURE__ */ jsxs6("li", { children: [
1202
+ /* @__PURE__ */ jsx8("b", { children: index + 1 }),
1203
+ /* @__PURE__ */ jsxs6("span", { children: [
1204
+ /* @__PURE__ */ jsx8("strong", { children: step.title }),
1205
+ /* @__PURE__ */ jsx8("small", { children: step.description ?? "" })
1206
+ ] })
1207
+ ] }, index)) }),
1208
+ data.conditions.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "promotion-activity__requirements", children: [
1209
+ /* @__PURE__ */ jsx8("b", { children: "\u53C2\u4E0E\u6761\u4EF6" }),
1210
+ /* @__PURE__ */ jsx8("div", { children: data.conditions.map((item) => /* @__PURE__ */ jsxs6("span", { children: [
1211
+ /* @__PURE__ */ jsx8(CheckCircle2, { weight: "fill" }),
1212
+ item
1213
+ ] }, item)) })
1214
+ ] }),
1215
+ /* @__PURE__ */ jsxs6("p", { className: "promotion-activity__readonly", children: [
1216
+ /* @__PURE__ */ jsx8(CheckCircle2, { weight: "fill" }),
1217
+ data.notice ?? "\u5F53\u524D\u4EC5\u63D0\u4F9B\u53C2\u4E0E\u8BF4\u660E\uFF0C\u4E0D\u4F1A\u76F4\u63A5\u63D0\u4EA4\u62A5\u540D"
1218
+ ] })
1219
+ ] });
1220
+ }
1221
+ function ActivityHeader({ title, subtitle, icon }) {
1222
+ return /* @__PURE__ */ jsxs6("header", { className: "promotion-card__header promotion-card__header--compact", children: [
1223
+ /* @__PURE__ */ jsx8("span", { className: "promotion-card__mark", children: icon === "calendar" ? /* @__PURE__ */ jsx8(CalendarDots3, { weight: "duotone" }) : /* @__PURE__ */ jsx8(ListChecks2, { weight: "duotone" }) }),
1224
+ /* @__PURE__ */ jsxs6("div", { children: [
1225
+ /* @__PURE__ */ jsx8("span", { className: "promotion-card__eyebrow", children: "\u4F1A\u5458\u6D3B\u52A8" }),
1226
+ /* @__PURE__ */ jsx8("h3", { children: title }),
1227
+ /* @__PURE__ */ jsx8("p", { children: subtitle })
1228
+ ] })
1229
+ ] });
1230
+ }
1231
+ var promotion_activity_detail_default = PromotionActivityDetailCard;
1232
+
1233
+ // src/client/cards/promotion-activity-category-list/index.tsx
1234
+ import { GameController, Palette, Sparkle as Sparkle4, Storefront } from "@phosphor-icons/react";
1235
+ import { ItemActionsRow as ItemActionsRow2 } from "@tbox.cn/app-sdk/client";
1236
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1237
+ var icons = [GameController, Storefront, Palette, Sparkle4];
1238
+ function PromotionActivityCategoryListCard(props) {
1239
+ const { data, cardId = "", isHistory = false } = props;
1240
+ return /* @__PURE__ */ jsxs7("section", { className: "promotion-card promotion-activity promotion-activity--categories", children: [
1241
+ /* @__PURE__ */ jsxs7("header", { className: "promotion-card__header promotion-card__header--compact", children: [
1242
+ /* @__PURE__ */ jsx9("span", { className: "promotion-card__mark", children: /* @__PURE__ */ jsx9(Sparkle4, { weight: "fill" }) }),
1243
+ /* @__PURE__ */ jsxs7("div", { children: [
1244
+ /* @__PURE__ */ jsx9("span", { className: "promotion-card__eyebrow", children: "\u4F1A\u5458\u6D3B\u52A8" }),
1245
+ /* @__PURE__ */ jsx9("h3", { children: "\u63A2\u7D22\u4F1A\u5458\u6D3B\u52A8" }),
1246
+ /* @__PURE__ */ jsx9("p", { children: "\u6309\u5174\u8DA3\u627E\u5230\u4F60\u7684\u4E13\u5C5E\u5468\u672B" })
1247
+ ] })
1248
+ ] }),
1249
+ /* @__PURE__ */ jsx9("div", { className: "promotion-activity__categories", children: data.items.map((item, index) => {
1250
+ const Icon = icons[index % icons.length];
1251
+ return /* @__PURE__ */ jsxs7("article", { children: [
1252
+ /* @__PURE__ */ jsx9("span", { className: `promotion-activity__category-icon promotion-activity__category-icon--${index % 4}`, children: /* @__PURE__ */ jsx9(Icon, { weight: "duotone" }) }),
1253
+ /* @__PURE__ */ jsxs7("span", { children: [
1254
+ /* @__PURE__ */ jsx9("strong", { children: item.name }),
1255
+ /* @__PURE__ */ jsx9("small", { children: "\u53D1\u73B0\u7CBE\u5F69\u6D3B\u52A8" })
1256
+ ] }),
1257
+ /* @__PURE__ */ jsx9(ItemActionsRow2, { actions: item.itemActions ?? [], cardId, isHistory, className: "promotion-item-actions", chipClassName: "promotion-chip" })
1258
+ ] }, item.categoryId);
1259
+ }) }),
1260
+ !data.items.length && /* @__PURE__ */ jsxs7("div", { className: "promotion-card__empty", children: [
1261
+ /* @__PURE__ */ jsx9(Sparkle4, { size: 28 }),
1262
+ /* @__PURE__ */ jsx9("span", { children: data.noResultsReason ?? "\u6682\u65E0\u6D3B\u52A8\u5206\u7C7B" })
1263
+ ] })
1264
+ ] });
1265
+ }
1266
+ var promotion_activity_category_list_default = PromotionActivityCategoryListCard;
1267
+
1268
+ // src/client/cards/promotion-best-deal/index.tsx
1269
+ import { Calculator, TrendUp } from "@phosphor-icons/react";
1270
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1271
+ var money = (cents) => (cents / 100).toFixed(2);
1272
+ function PromotionBestDealCard({ data }) {
1273
+ const savings = data.savingsCents ?? 0;
1274
+ const payable = data.expectedPayCents ?? Math.max(0, data.originalAmountCents - savings);
1275
+ return /* @__PURE__ */ jsxs8("section", { className: "promotion-card promotion-deal", "aria-label": "\u4F18\u60E0\u6D4B\u7B97", children: [
1276
+ /* @__PURE__ */ jsxs8("header", { className: "promotion-card__header", children: [
1277
+ /* @__PURE__ */ jsx10("span", { className: "promotion-card__mark promotion-card__mark--cyan", children: /* @__PURE__ */ jsx10(Calculator, { weight: "duotone" }) }),
1278
+ /* @__PURE__ */ jsxs8("div", { children: [
1279
+ /* @__PURE__ */ jsx10("span", { className: "promotion-card__eyebrow", children: "\u4F18\u60E0\u65B9\u6848" }),
1280
+ /* @__PURE__ */ jsx10("h3", { children: "\u4F18\u60E0\u6D4B\u7B97" }),
1281
+ /* @__PURE__ */ jsx10("p", { children: data.authoritative ? "\u5B9E\u65F6\u4F18\u60E0\u6D4B\u7B97" : "\u7ED3\u7B97\u524D\u4F18\u60E0\u5EFA\u8BAE" })
1282
+ ] })
1283
+ ] }),
1284
+ data.authoritative ? /* @__PURE__ */ jsxs8("div", { className: "promotion-deal__hero", children: [
1285
+ /* @__PURE__ */ jsxs8("span", { children: [
1286
+ /* @__PURE__ */ jsx10("small", { children: "\u9884\u8BA1\u5B9E\u4ED8" }),
1287
+ /* @__PURE__ */ jsxs8("strong", { children: [
1288
+ "\xA5",
1289
+ money(payable)
1290
+ ] })
1291
+ ] }),
1292
+ /* @__PURE__ */ jsxs8("em", { children: [
1293
+ "\u9884\u8BA1\u8282\u7701 \xA5",
1294
+ money(savings)
1295
+ ] })
1296
+ ] }) : /* @__PURE__ */ jsxs8("div", { className: "promotion-deal__notice", children: [
1297
+ /* @__PURE__ */ jsx10(TrendUp, { weight: "duotone" }),
1298
+ /* @__PURE__ */ jsxs8("span", { children: [
1299
+ /* @__PURE__ */ jsx10("b", { children: "\u5F53\u524D\u4E3A\u5EFA\u8BAE\u7ED3\u679C" }),
1300
+ data.message ?? "\u6700\u7EC8\u91D1\u989D\u8BF7\u5728\u7ED3\u7B97\u9875\u786E\u8BA4"
1301
+ ] })
1302
+ ] }),
1303
+ /* @__PURE__ */ jsxs8("div", { className: "promotion-deal__metrics", children: [
1304
+ /* @__PURE__ */ jsxs8("span", { children: [
1305
+ /* @__PURE__ */ jsx10("small", { children: "\u6D88\u8D39\u91D1\u989D" }),
1306
+ /* @__PURE__ */ jsxs8("strong", { children: [
1307
+ "\xA5",
1308
+ money(data.originalAmountCents)
1309
+ ] })
1310
+ ] }),
1311
+ /* @__PURE__ */ jsxs8("span", { children: [
1312
+ /* @__PURE__ */ jsx10("small", { children: "\u9884\u8BA1\u8282\u7701" }),
1313
+ /* @__PURE__ */ jsxs8("strong", { children: [
1314
+ "\xA5",
1315
+ money(savings)
1316
+ ] })
1317
+ ] }),
1318
+ /* @__PURE__ */ jsxs8("span", { children: [
1319
+ /* @__PURE__ */ jsx10("small", { children: "\u5019\u9009\u4F18\u60E0" }),
1320
+ /* @__PURE__ */ jsx10("strong", { children: data.candidates?.length ?? data.appliedOfferRefs.length })
1321
+ ] })
1322
+ ] })
1323
+ ] });
1324
+ }
1325
+ var promotion_best_deal_default = PromotionBestDealCard;
1326
+
1327
+ // src/client/index.ts
1328
+ var cards = {
1329
+ "promotion-offer-list": promotion_offer_list_default,
1330
+ "promotion-offer-detail": promotion_offer_detail_default,
1331
+ "promotion-entitlement-list": promotion_entitlement_list_default,
1332
+ "promotion-activity-list": promotion_activity_list_default,
1333
+ "promotion-activity-detail": promotion_activity_detail_default,
1334
+ "promotion-activity-category-list": promotion_activity_category_list_default,
1335
+ "promotion-best-deal": promotion_best_deal_default
1336
+ };
1337
+ var clientModule = {
1338
+ cards,
1339
+ register(ctx) {
1340
+ ctx.cards.registerMap(cards);
1341
+ }
1342
+ };
1343
+
1344
+ export {
1345
+ cards,
1346
+ clientModule
1347
+ };