@tbox.cn/app-module-promotion 0.2.0 → 0.9.4

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