@tbox.cn/app-module-member 0.2.0 → 0.8.6

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 (65) hide show
  1. package/AGENTS.md +16 -0
  2. package/README.md +99 -11
  3. package/dist/chunk-KEBILLQ5.js +771 -0
  4. package/dist/chunk-T4SYPQA5.js +1565 -0
  5. package/dist/client/index.d.ts +2 -2
  6. package/dist/client/index.js +1 -1
  7. package/dist/index.d.ts +2 -3
  8. package/dist/index.js +12 -2
  9. package/dist/login-mascot-5D4X6YZ7.jpg +0 -0
  10. package/dist/member-QFCIYILN.css +1734 -0
  11. package/dist/server/index.d.ts +617 -246
  12. package/dist/server/index.js +11 -1
  13. package/package.json +25 -16
  14. package/skills/member/SKILL.md +141 -0
  15. package/skills/member/references/enrollment.md +34 -0
  16. package/skills/member/references/points-and-card.md +24 -0
  17. package/src/client/assets/login-mascot.jpg +0 -0
  18. package/src/client/assets.d.ts +5 -0
  19. package/src/client/cards/index.ts +10 -0
  20. package/src/client/cards/member-card-summary/index.tsx +375 -0
  21. package/src/client/cards/member-enrollment-cta/index.tsx +61 -0
  22. package/src/client/cards/member-enrollment-form/index.tsx +181 -0
  23. package/src/client/cards/member-enrollment-status/index.tsx +65 -0
  24. package/src/client/cards/member-info/index.tsx +60 -0
  25. package/src/client/cards/member-login-cta/index.tsx +81 -0
  26. package/src/client/cards/member-point-usage-list/index.tsx +53 -0
  27. package/src/client/cards/view.ts +39 -0
  28. package/src/client/components/ImageWithFallback.tsx +38 -0
  29. package/src/client/index.ts +6 -4
  30. package/src/client/styles/member.css +1734 -0
  31. package/src/client/types/css.d.ts +2 -0
  32. package/src/server/action.ts +348 -0
  33. package/src/server/cards/index.ts +7 -7
  34. package/src/server/cards/member-card-summary/meta.ts +26 -5
  35. package/src/server/cards/member-card-summary/samples.ts +272 -0
  36. package/src/server/cards/member-enrollment-cta/meta.ts +19 -0
  37. package/src/server/cards/member-enrollment-form/meta.ts +10 -6
  38. package/src/server/cards/member-enrollment-status/meta.ts +5 -6
  39. package/src/server/cards/member-info/meta.ts +1 -1
  40. package/src/server/cards/member-login-cta/meta.ts +16 -0
  41. package/src/server/cards/member-point-usage-list/meta.ts +2 -3
  42. package/src/server/handler.ts +159 -119
  43. package/src/server/index.ts +109 -50
  44. package/src/server/ports.ts +66 -0
  45. package/src/server/service.ts +94 -80
  46. package/src/server/status.ts +87 -0
  47. package/src/server/subject-binding.ts +19 -0
  48. package/src/server/tool.ts +469 -99
  49. package/tbox.module.json +124 -0
  50. package/tests/cards-render.test.tsx +526 -0
  51. package/tests/enrollment.test.ts +121 -0
  52. package/tests/ports-resolve.test.ts +95 -0
  53. package/tests/preference-memory.test.ts +86 -0
  54. package/tests/samples.test.ts +61 -0
  55. package/tests/service.test.ts +593 -35
  56. package/tests/skills.test.ts +65 -0
  57. package/tests/status.test.ts +127 -0
  58. package/tests/view.test.ts +33 -0
  59. package/tsup.config.ts +9 -1
  60. package/dist/chunk-JGZGLFO6.js +0 -111
  61. package/dist/chunk-ZV6B36AO.js +0 -613
  62. package/src/client/cards/index.tsx +0 -135
  63. package/src/server/cards/member-coupon-detail/meta.ts +0 -19
  64. package/src/server/cards/member-coupon-list/meta.ts +0 -18
  65. package/tbox.component.json +0 -28
@@ -0,0 +1,771 @@
1
+ // src/client/index.ts
2
+ import "./member-QFCIYILN.css";
3
+
4
+ // src/client/cards/member-info/index.tsx
5
+ import { CalendarBlank, Phone, Tag, UserCircle } from "@phosphor-icons/react";
6
+
7
+ // src/client/components/ImageWithFallback.tsx
8
+ import { useState } from "react";
9
+ import { ImageSquare } from "@phosphor-icons/react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ function ImageWithFallback(props) {
12
+ const { src, alt, className, size = 40, loading = "lazy", fallback } = props;
13
+ const [failed, setFailed] = useState(false);
14
+ if (!src || failed) {
15
+ return /* @__PURE__ */ jsx("div", { className: `img-fallback ${className ?? ""}`.trim(), "aria-label": alt, role: "img", children: fallback ?? /* @__PURE__ */ jsx(ImageSquare, { weight: "duotone", size: Math.round(size * 0.45) }) });
16
+ }
17
+ return /* @__PURE__ */ jsx(
18
+ "img",
19
+ {
20
+ className,
21
+ src,
22
+ alt,
23
+ loading,
24
+ referrerPolicy: "no-referrer",
25
+ onError: () => setFailed(true)
26
+ }
27
+ );
28
+ }
29
+
30
+ // src/client/cards/view.ts
31
+ function pointAmountClass(amount) {
32
+ return amount.startsWith("-") ? "member-pu__amount--spend" : "member-pu__amount--income";
33
+ }
34
+ function formatMemberDate(value) {
35
+ if (!value) return "";
36
+ const match = /^(\d{4})-(\d{2})-(\d{2})/u.exec(value);
37
+ return match ? `${match[1]}.${match[2]}.${match[3]}` : value;
38
+ }
39
+ function enrollmentStateText(state) {
40
+ switch (state) {
41
+ case "active":
42
+ return "\u5165\u4F1A\u6210\u529F";
43
+ case "pending_confirmation":
44
+ return "\u5382\u5546\u786E\u8BA4\u4E2D";
45
+ case "confirmation_timeout":
46
+ return "\u786E\u8BA4\u8D85\u65F6";
47
+ default:
48
+ return "\u672A\u5B8C\u6210";
49
+ }
50
+ }
51
+ function enrollmentTone(state) {
52
+ if (state === "active") return "success";
53
+ if (state === "pending_confirmation") return "warning";
54
+ return "neutral";
55
+ }
56
+ function memberStateText(state, authState) {
57
+ if (state === "active") return "\u5DF2\u5165\u4F1A";
58
+ if (state === "closed") return "\u5DF2\u6CE8\u9500";
59
+ if (state === "unknown") return authState === "unauthenticated" ? "\u672A\u767B\u5F55" : "\u72B6\u6001\u5F85\u786E\u8BA4";
60
+ return "\u672A\u5165\u4F1A";
61
+ }
62
+
63
+ // src/client/cards/member-info/index.tsx
64
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
65
+ function MemberInfoCard(props) {
66
+ const { data } = props;
67
+ return /* @__PURE__ */ jsxs("section", { className: "member-card member-info", children: [
68
+ /* @__PURE__ */ jsxs("div", { className: "member-info__head", children: [
69
+ data.avatarUrl ? /* @__PURE__ */ jsx2(ImageWithFallback, { src: data.avatarUrl, alt: data.displayName ?? "\u4F1A\u5458\u5934\u50CF", className: "member-info__avatar", size: 48 }) : /* @__PURE__ */ jsx2("div", { className: "member-info__avatar member-info__avatar--fallback", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(UserCircle, { size: 34, weight: "duotone" }) }),
70
+ /* @__PURE__ */ jsxs("div", { className: "member-info__body", children: [
71
+ /* @__PURE__ */ jsx2("span", { className: "member-info__eyebrow", children: "\u4F1A\u5458\u8D44\u6599" }),
72
+ /* @__PURE__ */ jsxs("div", { className: "member-info__name-row", children: [
73
+ /* @__PURE__ */ jsx2("strong", { children: data.displayName ?? "\u4F1A\u5458" }),
74
+ /* @__PURE__ */ jsx2("span", { className: `member-status member-status--${data.state === "active" ? "active" : "inactive"}`, children: memberStateText(data.state, data.authState) })
75
+ ] })
76
+ ] })
77
+ ] }),
78
+ (data.contactDisplay || data.registeredAt) && /* @__PURE__ */ jsxs("dl", { className: "member-info__details", children: [
79
+ data.contactDisplay && /* @__PURE__ */ jsxs("div", { children: [
80
+ /* @__PURE__ */ jsxs("dt", { children: [
81
+ /* @__PURE__ */ jsx2(Phone, { size: 16, weight: "duotone" }),
82
+ "\u8054\u7CFB\u65B9\u5F0F"
83
+ ] }),
84
+ /* @__PURE__ */ jsx2("dd", { children: data.contactDisplay })
85
+ ] }),
86
+ data.registeredAt && /* @__PURE__ */ jsxs("div", { children: [
87
+ /* @__PURE__ */ jsxs("dt", { children: [
88
+ /* @__PURE__ */ jsx2(CalendarBlank, { size: 16, weight: "duotone" }),
89
+ "\u5165\u4F1A\u65F6\u95F4"
90
+ ] }),
91
+ /* @__PURE__ */ jsx2("dd", { children: formatMemberDate(data.registeredAt) })
92
+ ] })
93
+ ] }),
94
+ data.labels.length > 0 && /* @__PURE__ */ jsxs("div", { className: "member-info__labels", children: [
95
+ /* @__PURE__ */ jsxs("div", { className: "member-info__section-title", children: [
96
+ /* @__PURE__ */ jsx2(Tag, { size: 16, weight: "duotone" }),
97
+ "\u4F1A\u5458\u6807\u7B7E"
98
+ ] }),
99
+ /* @__PURE__ */ jsx2("div", { className: "member-tags", children: data.labels.map((l) => /* @__PURE__ */ jsx2("span", { children: l.name }, l.labelRef)) })
100
+ ] })
101
+ ] });
102
+ }
103
+ var member_info_default = MemberInfoCard;
104
+
105
+ // src/client/cards/member-card-summary/index.tsx
106
+ import { useEffect, useMemo, useRef, useState as useState2 } from "react";
107
+ import { createPortal } from "react-dom";
108
+ import { X } from "@phosphor-icons/react";
109
+ import { markSelfRendering, sendCardAction } from "@tbox.cn/app-sdk/client";
110
+ import { Car, Confetti, Coins, Gift, Sparkle } from "@phosphor-icons/react";
111
+ import { MEMBER_PREFERENCE_PROMPTS } from "@tbox.cn/app-contracts-mall";
112
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
113
+ function isProviderMiniappUrl(value) {
114
+ return /^(alipays|alipayrisk):\/\/[^/?#]/u.test(value);
115
+ }
116
+ function renderBenefitText(text) {
117
+ const parts = text.split(/(\d{3,4}-\d{7,8}|\d{7,12})/u);
118
+ return parts.map((part, index) => /^\d{3,4}-\d{7,8}$|^\d{7,12}$/u.test(part) ? /* @__PURE__ */ jsx3("a", { href: `tel:${part.replace(/-/gu, "")}`, children: part }, `${part}-${String(index)}`) : /* @__PURE__ */ jsx3("span", { children: part }, `${String(index)}-${part}`));
119
+ }
120
+ function BenefitFallbackIcon({ name }) {
121
+ const props = {
122
+ "aria-hidden": true,
123
+ className: "member-card-summary__benefit-icon-fallback",
124
+ size: 28,
125
+ weight: "duotone"
126
+ };
127
+ if (/停车|泊车/.test(name)) return /* @__PURE__ */ jsx3(Car, { ...props });
128
+ if (/积分|消费/.test(name)) return /* @__PURE__ */ jsx3(Coins, { ...props });
129
+ if (/活动|派对/.test(name)) return /* @__PURE__ */ jsx3(Confetti, { ...props });
130
+ return /* @__PURE__ */ jsx3(Gift, { ...props });
131
+ }
132
+ var BENEFITS_PER_PAGE = 8;
133
+ function MemberCardSummaryCard(props) {
134
+ const { data, cardId = "", isHistory = false } = props;
135
+ const dynamicFace = data.presentation !== void 0;
136
+ const labelsEmbedded = data.presentation?.labelsEmbedded === true;
137
+ const benefitPages = useMemo(() => {
138
+ const items = data.benefits;
139
+ if (!items?.length) return [];
140
+ const pages = [];
141
+ for (let i = 0; i < items.length; i += BENEFITS_PER_PAGE) {
142
+ pages.push(items.slice(i, i + BENEFITS_PER_PAGE));
143
+ }
144
+ return pages;
145
+ }, [data.benefits]);
146
+ const [benefitPage, setBenefitPage] = useState2(0);
147
+ const onBenefitsScroll = (event) => {
148
+ const el = event.currentTarget;
149
+ if (el.clientWidth === 0) return;
150
+ const next = Math.round(el.scrollLeft / el.clientWidth);
151
+ setBenefitPage((prev) => prev === next ? prev : next);
152
+ };
153
+ const preferencePrompts = data.preferencePrompts ?? MEMBER_PREFERENCE_PROMPTS;
154
+ const [pointsRuleOpen, setPointsRuleOpen] = useState2(false);
155
+ const [pointsRuleClosing, setPointsRuleClosing] = useState2(false);
156
+ const [benefitAction, setBenefitAction] = useState2();
157
+ const benefitActionCloseTimerRef = useRef();
158
+ const pointsRuleTriggerRef = useRef(null);
159
+ const pointsRuleCloseRef = useRef(null);
160
+ const pointsRuleCloseTimerRef = useRef();
161
+ useEffect(() => {
162
+ if (!pointsRuleOpen) return;
163
+ const previousOverflow = document.body.style.overflow;
164
+ document.body.style.overflow = "hidden";
165
+ pointsRuleCloseRef.current?.focus();
166
+ const onKeyDown = (event) => {
167
+ if (event.key !== "Escape") return;
168
+ closePointsRule();
169
+ };
170
+ window.addEventListener("keydown", onKeyDown);
171
+ return () => {
172
+ document.body.style.overflow = previousOverflow;
173
+ window.removeEventListener("keydown", onKeyDown);
174
+ };
175
+ }, [pointsRuleOpen]);
176
+ useEffect(() => () => {
177
+ window.clearTimeout(pointsRuleCloseTimerRef.current);
178
+ window.clearTimeout(benefitActionCloseTimerRef.current);
179
+ }, []);
180
+ const closeBenefitAction = () => {
181
+ if (!benefitAction || benefitAction.closing) return;
182
+ setBenefitAction({ ...benefitAction, closing: true });
183
+ benefitActionCloseTimerRef.current = window.setTimeout(() => setBenefitAction(void 0), 180);
184
+ };
185
+ const finishClosePointsRule = () => {
186
+ window.clearTimeout(pointsRuleCloseTimerRef.current);
187
+ setPointsRuleOpen(false);
188
+ setPointsRuleClosing(false);
189
+ pointsRuleTriggerRef.current?.focus();
190
+ };
191
+ const closePointsRule = () => {
192
+ if (pointsRuleClosing) return;
193
+ setPointsRuleClosing(true);
194
+ pointsRuleCloseTimerRef.current = window.setTimeout(finishClosePointsRule, 220);
195
+ };
196
+ const openPointsRule = (event) => {
197
+ event.preventDefault();
198
+ event.stopPropagation();
199
+ setPointsRuleClosing(false);
200
+ setPointsRuleOpen(true);
201
+ };
202
+ const pointsRuleTrigger = data.pointsRuleImageUrl || data.pointsRuleContent ? /* @__PURE__ */ jsx3(
203
+ "button",
204
+ {
205
+ ref: pointsRuleTriggerRef,
206
+ type: "button",
207
+ className: labelsEmbedded ? "member-card-summary__rule-hotspot" : "member-card-summary__rule-trigger",
208
+ "aria-label": "\u79EF\u5206\u89C4\u5219",
209
+ "aria-haspopup": "dialog",
210
+ onClick: openPointsRule,
211
+ children: labelsEmbedded ? null : /* @__PURE__ */ jsx3("span", { children: "\u79EF\u5206\u89C4\u5219" })
212
+ }
213
+ ) : null;
214
+ return /* @__PURE__ */ jsxs2("section", { className: `member-card member-card-summary${dynamicFace ? ` member-card-summary--dynamic member-card-summary--${data.presentation.variant}` : ""}`, children: [
215
+ dynamicFace ? /* @__PURE__ */ jsxs2(
216
+ "div",
217
+ {
218
+ className: `member-card-summary__face member-card-summary__face--dynamic member-card-summary__face--${data.presentation.variant}${labelsEmbedded ? " member-card-summary__face--embedded" : ""}`,
219
+ "aria-label": `${data.cardDisplay}\uFF0C\u53EF\u7528\u79EF\u5206 ${String(data.availablePoints)}`,
220
+ children: [
221
+ data.cardImageUrl ? /* @__PURE__ */ jsx3(
222
+ ImageWithFallback,
223
+ {
224
+ src: data.cardImageUrl,
225
+ alt: "",
226
+ className: "member-card-summary__background",
227
+ size: 96,
228
+ loading: "eager"
229
+ }
230
+ ) : /* @__PURE__ */ jsx3("span", { className: "member-card-summary__background member-card-summary__background--fallback" }),
231
+ /* @__PURE__ */ jsxs2("div", { className: "member-card-summary__overlay", children: [
232
+ !labelsEmbedded && /* @__PURE__ */ jsxs2(Fragment, { children: [
233
+ /* @__PURE__ */ jsx3("strong", { className: "member-card-summary__level", children: data.cardDisplay }),
234
+ data.pointsUrl ? /* @__PURE__ */ jsxs2("button", { type: "button", className: "member-card-summary__points-label", onClick: () => sendCardAction(cardId, { type: "openLink", url: data.pointsUrl }), children: [
235
+ "\u6211\u7684\u79EF\u5206 ",
236
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: ">" })
237
+ ] }) : /* @__PURE__ */ jsxs2("span", { className: "member-card-summary__points-label", children: [
238
+ "\u6211\u7684\u79EF\u5206 ",
239
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: ">" })
240
+ ] })
241
+ ] }),
242
+ /* @__PURE__ */ jsx3("b", { className: `member-card-summary__balance${labelsEmbedded ? " member-card-summary__balance--embedded" : ""}`, children: String(data.availablePoints) }),
243
+ data.progress && /* @__PURE__ */ jsxs2("div", { className: "member-card-summary__progress", children: [
244
+ /* @__PURE__ */ jsx3("div", { className: `member-card-summary__progress-text${data.progress.message.length > 24 ? " member-card-summary__progress-text--scroll" : ""}`, children: /* @__PURE__ */ jsx3("span", { children: data.progress.message }) }),
245
+ /* @__PURE__ */ jsx3(
246
+ "div",
247
+ {
248
+ className: "member-card-summary__progress-track",
249
+ role: "progressbar",
250
+ "aria-label": "\u4F1A\u5458\u7B49\u7EA7\u6D88\u8D39\u8FDB\u5EA6",
251
+ "aria-valuemin": 0,
252
+ "aria-valuemax": 100,
253
+ "aria-valuenow": Math.round(data.progress.percent),
254
+ children: /* @__PURE__ */ jsx3("span", { style: { width: `${data.progress.percent}%` } })
255
+ }
256
+ )
257
+ ] }),
258
+ labelsEmbedded && data.pointsUrl && /* @__PURE__ */ jsx3(
259
+ "button",
260
+ {
261
+ type: "button",
262
+ className: "member-card-summary__points-hotspot",
263
+ "aria-label": "\u6253\u5F00\u6211\u7684\u79EF\u5206",
264
+ onClick: () => sendCardAction(cardId, { type: "openLink", url: data.pointsUrl })
265
+ }
266
+ ),
267
+ pointsRuleTrigger
268
+ ] })
269
+ ]
270
+ }
271
+ ) : data.cardImageUrl ? /* @__PURE__ */ jsx3(
272
+ ImageWithFallback,
273
+ {
274
+ src: data.cardImageUrl,
275
+ alt: data.cardDisplay,
276
+ className: "member-card-summary__face",
277
+ size: 96,
278
+ loading: "eager"
279
+ }
280
+ ) : /* @__PURE__ */ jsx3("div", { className: "member-card-summary__face member-card-summary__face--gradient", children: /* @__PURE__ */ jsx3("strong", { children: data.cardDisplay }) }),
281
+ !dynamicFace && /* @__PURE__ */ jsxs2("div", { className: "member-card-summary__metric", children: [
282
+ /* @__PURE__ */ jsx3("b", { className: "member-card-summary__points-value", children: String(data.availablePoints) }),
283
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__metric-label", children: "\u79EF\u5206" }),
284
+ data.status !== "active" && /* @__PURE__ */ jsx3("em", { className: "member-card-summary__status", children: data.status }),
285
+ pointsRuleTrigger
286
+ ] }),
287
+ benefitPages.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
288
+ /* @__PURE__ */ jsx3(
289
+ "div",
290
+ {
291
+ className: "member-card-summary__benefit-pager",
292
+ role: "group",
293
+ "aria-label": "\u5F53\u524D\u4F1A\u5458\u6743\u76CA",
294
+ onScroll: benefitPages.length > 1 ? onBenefitsScroll : void 0,
295
+ children: benefitPages.map((page) => /* @__PURE__ */ jsx3("ul", { className: "member-card-summary__benefits", children: page.map((benefit) => /* @__PURE__ */ jsx3("li", { children: benefit.action?.kind === "miniapp" && benefit.action.url && isProviderMiniappUrl(benefit.action.url) ? /* @__PURE__ */ jsxs2(
296
+ "button",
297
+ {
298
+ type: "button",
299
+ className: "member-card-summary__benefit-button",
300
+ "aria-label": `\u6253\u5F00${benefit.name}`,
301
+ onClick: () => sendCardAction(cardId, { type: "openLink", url: benefit.action.url }),
302
+ children: [
303
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-icon", children: /* @__PURE__ */ jsx3(
304
+ ImageWithFallback,
305
+ {
306
+ src: benefit.iconUrl,
307
+ alt: `${benefit.name}\u6743\u76CA\u56FE\u6807`,
308
+ size: 48,
309
+ loading: "eager",
310
+ fallback: /* @__PURE__ */ jsx3(BenefitFallbackIcon, { name: benefit.name })
311
+ }
312
+ ) }),
313
+ /* @__PURE__ */ jsxs2("span", { className: "member-card-summary__benefit-copy", children: [
314
+ /* @__PURE__ */ jsx3("span", { children: benefit.name }),
315
+ benefit.description && /* @__PURE__ */ jsx3("small", { className: "member-card-summary__benefit-description", children: benefit.description })
316
+ ] })
317
+ ]
318
+ }
319
+ ) : benefit.action?.kind === "toast" ? /* @__PURE__ */ jsxs2("button", { type: "button", className: "member-card-summary__benefit-button", onClick: () => sendCardAction(cardId, { type: "toast", content: benefit.action?.text ?? "\u656C\u8BF7\u671F\u5F85~" }), children: [
320
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-icon", children: /* @__PURE__ */ jsx3(ImageWithFallback, { src: benefit.iconUrl, alt: `${benefit.name}\u6743\u76CA\u56FE\u6807`, size: 48, loading: "eager", fallback: /* @__PURE__ */ jsx3(BenefitFallbackIcon, { name: benefit.name }) }) }),
321
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-copy", children: /* @__PURE__ */ jsx3("span", { children: benefit.name }) })
322
+ ] }) : benefit.action?.kind === "dialog" ? /* @__PURE__ */ jsxs2("button", { type: "button", className: "member-card-summary__benefit-button", onClick: () => setBenefitAction({ name: benefit.action?.title ?? benefit.name, url: "", title: benefit.action?.title, text: benefit.action?.text }), children: [
323
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-icon", children: /* @__PURE__ */ jsx3(ImageWithFallback, { src: benefit.iconUrl, alt: `${benefit.name}\u6743\u76CA\u56FE\u6807`, size: 48, loading: "eager", fallback: /* @__PURE__ */ jsx3(BenefitFallbackIcon, { name: benefit.name }) }) }),
324
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-copy", children: /* @__PURE__ */ jsx3("span", { children: benefit.name }) })
325
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
326
+ /* @__PURE__ */ jsx3("span", { className: "member-card-summary__benefit-icon", children: /* @__PURE__ */ jsx3(ImageWithFallback, { src: benefit.iconUrl, alt: `${benefit.name}\u6743\u76CA\u56FE\u6807`, size: 48, loading: "eager", fallback: /* @__PURE__ */ jsx3(BenefitFallbackIcon, { name: benefit.name }) }) }),
327
+ /* @__PURE__ */ jsxs2("span", { className: "member-card-summary__benefit-copy", children: [
328
+ /* @__PURE__ */ jsx3("span", { children: benefit.name }),
329
+ benefit.description && /* @__PURE__ */ jsx3("small", { className: "member-card-summary__benefit-description", children: benefit.description })
330
+ ] })
331
+ ] }) }, benefit.benefitRef)) }, page[0].benefitRef))
332
+ }
333
+ ),
334
+ benefitPages.length > 1 && /* @__PURE__ */ jsx3("div", { className: "member-card-summary__benefit-dots", "aria-hidden": "true", children: benefitPages.map((page, index) => /* @__PURE__ */ jsx3("span", { "data-active": index === benefitPage }, page[0].benefitRef)) })
335
+ ] }),
336
+ /* @__PURE__ */ jsxs2("div", { className: "member-card-summary__preferences", children: [
337
+ /* @__PURE__ */ jsxs2("strong", { children: [
338
+ /* @__PURE__ */ jsx3(Sparkle, { size: 15, weight: "fill", "aria-hidden": "true" }),
339
+ /* @__PURE__ */ jsx3("span", { children: "\u8BF4\u8BF4\u4F60\u7684\u504F\u597D" })
340
+ ] }),
341
+ /* @__PURE__ */ jsx3("p", { className: "member-card-summary__preference-hint", children: "\u8BF7\u9009\u62E9\u4F60\u7684\u504F\u597D\uFF0C\u6216\u76F4\u63A5\u544A\u8BC9\u6211" }),
342
+ /* @__PURE__ */ jsx3("div", { className: "member-card-summary__preference-list", children: preferencePrompts.map((prompt) => /* @__PURE__ */ jsx3(
343
+ "button",
344
+ {
345
+ type: "button",
346
+ disabled: isHistory || !cardId,
347
+ onClick: () => sendCardAction(cardId, {
348
+ type: "sendMessage",
349
+ value: prompt.query,
350
+ displayText: prompt.value,
351
+ visible: true
352
+ }),
353
+ children: /* @__PURE__ */ jsx3("span", { children: prompt.value })
354
+ },
355
+ prompt.value
356
+ )) })
357
+ ] }),
358
+ pointsRuleOpen && (data.pointsRuleImageUrl || data.pointsRuleContent) && createPortal(
359
+ /* @__PURE__ */ jsx3(
360
+ "div",
361
+ {
362
+ className: `member-points-rule${pointsRuleClosing ? " member-points-rule--closing" : ""}`,
363
+ role: "dialog",
364
+ "aria-modal": "true",
365
+ "aria-labelledby": "member-points-rule-title",
366
+ onAnimationEnd: (event) => {
367
+ if (pointsRuleClosing && event.target === event.currentTarget) finishClosePointsRule();
368
+ },
369
+ onMouseDown: (event) => {
370
+ if (event.target === event.currentTarget) closePointsRule();
371
+ },
372
+ children: /* @__PURE__ */ jsxs2("div", { className: "member-points-rule__panel", children: [
373
+ /* @__PURE__ */ jsxs2("header", { className: "member-points-rule__header", children: [
374
+ /* @__PURE__ */ jsx3("strong", { id: "member-points-rule-title", children: "\u79EF\u5206\u89C4\u5219" }),
375
+ /* @__PURE__ */ jsx3(
376
+ "button",
377
+ {
378
+ ref: pointsRuleCloseRef,
379
+ type: "button",
380
+ className: "member-points-rule__close",
381
+ "aria-label": "\u5173\u95ED\u79EF\u5206\u89C4\u5219",
382
+ onClick: closePointsRule,
383
+ children: /* @__PURE__ */ jsx3(X, { size: 20, weight: "bold", "aria-hidden": "true" })
384
+ }
385
+ )
386
+ ] }),
387
+ /* @__PURE__ */ jsx3("div", { className: "member-points-rule__body", children: data.pointsRuleImageUrl ? /* @__PURE__ */ jsx3(ImageWithFallback, { src: data.pointsRuleImageUrl, alt: "\u79EF\u5206\u89C4\u5219\u8BE6\u60C5", className: "member-points-rule__image", size: 96, loading: "eager" }) : /* @__PURE__ */ jsx3("div", { className: "member-points-rule__content", children: renderBenefitText(data.pointsRuleContent ?? "") }) })
388
+ ] })
389
+ }
390
+ ),
391
+ document.body
392
+ ),
393
+ benefitAction && createPortal(
394
+ /* @__PURE__ */ jsx3("div", { className: "member-miniapp-dialog", role: "dialog", "aria-modal": "true", "aria-label": benefitAction.title ?? benefitAction.name, onMouseDown: (event) => {
395
+ if (event.target === event.currentTarget) closeBenefitAction();
396
+ }, children: /* @__PURE__ */ jsxs2("div", { className: `member-miniapp-dialog__panel${benefitAction.url ? " member-miniapp-dialog__panel--miniapp" : " member-miniapp-dialog__panel--text"}${benefitAction.closing ? " member-miniapp-dialog__panel--closing" : ""}`, children: [
397
+ /* @__PURE__ */ jsxs2("header", { className: "member-miniapp-dialog__header", children: [
398
+ /* @__PURE__ */ jsx3("strong", { children: benefitAction.title ?? benefitAction.name }),
399
+ /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": "\u5173\u95ED", onClick: closeBenefitAction, children: /* @__PURE__ */ jsx3(X, { size: 20, weight: "bold", "aria-hidden": "true" }) })
400
+ ] }),
401
+ benefitAction.url ? /* @__PURE__ */ jsx3("iframe", { className: "member-miniapp-dialog__frame", src: benefitAction.url, title: benefitAction.title ?? benefitAction.name }) : /* @__PURE__ */ jsx3("div", { className: "member-miniapp-dialog__text", children: renderBenefitText(benefitAction.text ?? "") }),
402
+ !benefitAction.url && /* @__PURE__ */ jsx3("button", { type: "button", className: "member-miniapp-dialog__confirm", onClick: closeBenefitAction, children: "\u6211\u77E5\u9053\u4E86" })
403
+ ] }) }),
404
+ document.body
405
+ )
406
+ ] });
407
+ }
408
+ var member_card_summary_default = markSelfRendering(MemberCardSummaryCard);
409
+
410
+ // src/client/cards/member-point-usage-list/index.tsx
411
+ import { ArrowDownRight, ArrowUpRight, Coins as Coins2 } from "@phosphor-icons/react";
412
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
413
+ function MemberPointUsageListCard(props) {
414
+ const { data } = props;
415
+ return /* @__PURE__ */ jsxs3("section", { className: "member-card member-point-usage", children: [
416
+ /* @__PURE__ */ jsxs3("header", { className: "member-pu__head", children: [
417
+ /* @__PURE__ */ jsx4("div", { className: "member-pu__head-icon", children: /* @__PURE__ */ jsx4(Coins2, { size: 22, weight: "duotone" }) }),
418
+ /* @__PURE__ */ jsxs3("div", { children: [
419
+ /* @__PURE__ */ jsx4("span", { children: "\u79EF\u5206\u8D26\u6237" }),
420
+ /* @__PURE__ */ jsx4("strong", { children: "\u6211\u7684\u79EF\u5206" })
421
+ ] }),
422
+ data.membershipLabel && /* @__PURE__ */ jsx4("em", { children: data.membershipLabel })
423
+ ] }),
424
+ /* @__PURE__ */ jsxs3("div", { className: "member-pu__metric", children: [
425
+ /* @__PURE__ */ jsx4("b", { children: String(data.balance) }),
426
+ /* @__PURE__ */ jsx4("span", { children: "\u79EF\u5206" })
427
+ ] }),
428
+ /* @__PURE__ */ jsxs3("div", { className: "member-pu__section-title", children: [
429
+ /* @__PURE__ */ jsx4("strong", { children: "\u6700\u8FD1\u79EF\u5206\u8BB0\u5F55" }),
430
+ /* @__PURE__ */ jsxs3("span", { children: [
431
+ "\u5171 ",
432
+ data.total ?? data.items.length,
433
+ " \u6761"
434
+ ] })
435
+ ] }),
436
+ data.items.length > 0 ? /* @__PURE__ */ jsx4("ul", { className: "member-pu__list", children: data.items.map((u) => {
437
+ const isSpend = u.amount.startsWith("-");
438
+ const Icon = isSpend ? ArrowUpRight : ArrowDownRight;
439
+ return /* @__PURE__ */ jsxs3("li", { className: "member-pu__row", children: [
440
+ /* @__PURE__ */ jsx4("span", { className: `member-pu__flow-icon member-pu__flow-icon--${isSpend ? "spend" : "income"}`, children: /* @__PURE__ */ jsx4(Icon, { size: 16, weight: "bold" }) }),
441
+ /* @__PURE__ */ jsxs3("span", { className: "member-pu__copy", children: [
442
+ /* @__PURE__ */ jsx4("strong", { children: u.title }),
443
+ u.usedAt && /* @__PURE__ */ jsx4("small", { children: formatMemberDate(u.usedAt) })
444
+ ] }),
445
+ /* @__PURE__ */ jsx4("b", { className: pointAmountClass(u.amount), children: u.amount })
446
+ ] }, u.usageRecordRef);
447
+ }) }) : /* @__PURE__ */ jsx4("p", { className: "member-pu__empty", children: "\u6682\u65E0\u79EF\u5206\u8BB0\u5F55" })
448
+ ] });
449
+ }
450
+ var member_point_usage_list_default = MemberPointUsageListCard;
451
+
452
+ // src/client/cards/member-enrollment-form/index.tsx
453
+ import { useRef as useRef2, useState as useState3 } from "react";
454
+ import { Lock, ShieldCheck, UserPlus } from "@phosphor-icons/react";
455
+ import { sendCardAction as sendCardAction2, markSelfRendering as markSelfRendering2 } from "@tbox.cn/app-sdk/client";
456
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
457
+ var AUTO_AUTH_ACTION = "member.request-alipay-authorization";
458
+ function MemberEnrollmentFormCard(props) {
459
+ const { data, cardId, isHistory, actionTokens } = props;
460
+ const [values, setValues] = useState3(
461
+ () => Object.fromEntries(data.fields.map((f) => [f.fieldId, f.prefill ?? ""]))
462
+ );
463
+ const [consented, setConsented] = useState3({});
464
+ const [authRequesting, setAuthRequesting] = useState3(false);
465
+ const [submitAttempted, setSubmitAttempted] = useState3(false);
466
+ const [submitting, setSubmitting] = useState3(false);
467
+ const authRequestingRef = useRef2(false);
468
+ const submittingRef = useRef2(false);
469
+ const authToken = actionTokens?.[AUTO_AUTH_ACTION];
470
+ const enrollToken = actionTokens?.["member.enroll"];
471
+ const fireAuth = () => {
472
+ if (!authToken || isHistory || authRequestingRef.current) return;
473
+ authRequestingRef.current = true;
474
+ setAuthRequesting(true);
475
+ sendCardAction2(cardId, { type: "moduleAction", actionId: AUTO_AUTH_ACTION, contextToken: authToken });
476
+ };
477
+ if (data.state === "active") {
478
+ return /* @__PURE__ */ jsx5("section", { className: "member-card member-enrollment-form", children: /* @__PURE__ */ jsxs4("div", { className: "member-enrollment-form__done", children: [
479
+ /* @__PURE__ */ jsx5("span", { className: "member-enrollment-form__done-icon", children: /* @__PURE__ */ jsx5(ShieldCheck, { size: 30, weight: "duotone" }) }),
480
+ /* @__PURE__ */ jsxs4("span", { children: [
481
+ /* @__PURE__ */ jsx5("small", { children: "\u4F1A\u5458\u72B6\u6001" }),
482
+ /* @__PURE__ */ jsx5("strong", { children: "\u60A8\u5DF2\u662F\u4F1A\u5458" })
483
+ ] })
484
+ ] }) });
485
+ }
486
+ const missingFields = data.fields.filter((field) => field.required && !(values[field.fieldId] ?? "").trim());
487
+ const missingConsents = data.consents.filter((consent) => consent.required && !consented[consent.consentId]);
488
+ const submit = () => {
489
+ if (!enrollToken || isHistory || submittingRef.current) return;
490
+ setSubmitAttempted(true);
491
+ if (missingFields.length > 0 || missingConsents.length > 0) return;
492
+ submittingRef.current = true;
493
+ setSubmitting(true);
494
+ sendCardAction2(
495
+ cardId,
496
+ { type: "moduleAction", actionId: "member.enroll", contextToken: enrollToken },
497
+ {
498
+ fieldValues: values,
499
+ acceptedConsentIds: data.consents.filter((c) => consented[c.consentId]).map((c) => c.consentId),
500
+ formVersion: data.formVersion
501
+ }
502
+ );
503
+ };
504
+ const authStatus = data.authorization.status;
505
+ return /* @__PURE__ */ jsxs4("section", { className: "member-card member-enrollment-form", children: [
506
+ /* @__PURE__ */ jsxs4("header", { className: "member-enrollment-form__head", children: [
507
+ /* @__PURE__ */ jsx5("span", { className: "member-enrollment-form__head-icon", children: /* @__PURE__ */ jsx5(UserPlus, { size: 22, weight: "duotone" }) }),
508
+ /* @__PURE__ */ jsxs4("div", { children: [
509
+ /* @__PURE__ */ jsx5("span", { children: "\u4F1A\u5458" }),
510
+ /* @__PURE__ */ jsx5("strong", { children: "\u5F00\u5361\u5165\u4F1A" })
511
+ ] })
512
+ ] }),
513
+ /* @__PURE__ */ jsx5("p", { className: "member-enrollment-form__subtitle", children: "\u5B8C\u5584\u57FA\u7840\u8D44\u6599\uFF0C\u5F00\u542F\u4F1A\u5458\u670D\u52A1" }),
514
+ /* @__PURE__ */ jsx5("div", { className: `member-enrollment-form__auth member-enrollment-form__auth--${authStatus}`, children: authStatus === "authorized" ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
515
+ /* @__PURE__ */ jsx5(ShieldCheck, { size: 16 }),
516
+ /* @__PURE__ */ jsxs4("span", { children: [
517
+ "\u5DF2\u901A\u8FC7\u652F\u4ED8\u5B9D\u6388\u6743\u9884\u586B\u624B\u673A\u53F7",
518
+ data.authorization.mobileMasked ? `\uFF08${data.authorization.mobileMasked}\uFF09` : ""
519
+ ] })
520
+ ] }) : authStatus === "required" ? /* @__PURE__ */ jsxs4(
521
+ "button",
522
+ {
523
+ type: "button",
524
+ className: "member-enrollment-form__auth-btn",
525
+ disabled: isHistory || !authToken || authRequesting,
526
+ onClick: fireAuth,
527
+ children: [
528
+ /* @__PURE__ */ jsx5(ShieldCheck, { size: 16 }),
529
+ authRequesting ? "\u6B63\u5728\u8BF7\u6C42\u652F\u4ED8\u5B9D\u6388\u6743\u2026" : "\u652F\u4ED8\u5B9D\u6388\u6743\u5E76\u586B\u5145"
530
+ ]
531
+ }
532
+ ) : /* @__PURE__ */ jsx5("span", { children: "\u652F\u4ED8\u5B9D\u6388\u6743\u4E0D\u53EF\u7528\uFF0C\u8BF7\u624B\u52A8\u586B\u5199" }) }),
533
+ data.manualNotice && /* @__PURE__ */ jsx5("p", { className: "member-enrollment-form__notice", children: data.manualNotice }),
534
+ data.fields.map((f) => /* @__PURE__ */ jsxs4("div", { className: "member-ef-field", children: [
535
+ /* @__PURE__ */ jsxs4("label", { className: "member-ef-field__label", children: [
536
+ f.label,
537
+ f.required && /* @__PURE__ */ jsx5("em", { children: "*" })
538
+ ] }),
539
+ f.type === "select" ? /* @__PURE__ */ jsxs4(
540
+ "select",
541
+ {
542
+ className: "member-ef-field__control",
543
+ value: values[f.fieldId] ?? "",
544
+ disabled: f.readOnly || isHistory,
545
+ onChange: (e) => setValues((v) => ({ ...v, [f.fieldId]: e.target.value })),
546
+ children: [
547
+ /* @__PURE__ */ jsx5("option", { value: "", children: "\u8BF7\u9009\u62E9" }),
548
+ (f.options ?? []).map((opt) => /* @__PURE__ */ jsx5("option", { value: opt, children: opt }, opt))
549
+ ]
550
+ }
551
+ ) : /* @__PURE__ */ jsx5(
552
+ "input",
553
+ {
554
+ className: "member-ef-field__control",
555
+ type: f.type === "tel" ? "tel" : f.type === "date" ? "date" : "text",
556
+ value: values[f.fieldId] ?? "",
557
+ readOnly: f.readOnly || isHistory,
558
+ placeholder: f.placeholder ?? "",
559
+ onChange: (e) => setValues((v) => ({ ...v, [f.fieldId]: e.target.value }))
560
+ }
561
+ ),
562
+ f.readOnly && /* @__PURE__ */ jsx5(Lock, { className: "member-ef-field__lock", size: 13, weight: "fill" }),
563
+ submitAttempted && f.required && !(values[f.fieldId] ?? "").trim() && /* @__PURE__ */ jsxs4("p", { className: "member-ef-field__error", role: "alert", children: [
564
+ "\u8BF7\u586B\u5199",
565
+ f.label
566
+ ] })
567
+ ] }, f.fieldId)),
568
+ /* @__PURE__ */ jsx5("div", { className: "member-ef-consents", children: data.consents.map((c) => /* @__PURE__ */ jsxs4("label", { className: "member-ef-consents__item", children: [
569
+ /* @__PURE__ */ jsx5(
570
+ "input",
571
+ {
572
+ type: "checkbox",
573
+ checked: !!consented[c.consentId],
574
+ disabled: isHistory,
575
+ onChange: (e) => setConsented((s) => ({ ...s, [c.consentId]: e.target.checked }))
576
+ }
577
+ ),
578
+ /* @__PURE__ */ jsxs4("span", { children: [
579
+ c.title,
580
+ c.required && /* @__PURE__ */ jsx5("em", { children: "\uFF08\u5FC5\u9009\uFF09" })
581
+ ] })
582
+ ] }, c.consentId)) }),
583
+ submitAttempted && missingConsents.length > 0 && /* @__PURE__ */ jsxs4("p", { className: "member-ef-validation", role: "alert", children: [
584
+ "\u8BF7\u5148\u540C\u610F\uFF1A",
585
+ missingConsents.map((consent) => consent.title).join("\u3001")
586
+ ] }),
587
+ /* @__PURE__ */ jsx5(
588
+ "button",
589
+ {
590
+ type: "button",
591
+ className: "member-ef-submit",
592
+ disabled: isHistory || !enrollToken || submitting,
593
+ onClick: submit,
594
+ children: submitting ? "\u6B63\u5728\u63D0\u4EA4\u2026" : "\u63D0\u4EA4\u5165\u4F1A"
595
+ }
596
+ )
597
+ ] });
598
+ }
599
+ var member_enrollment_form_default = markSelfRendering2(MemberEnrollmentFormCard);
600
+
601
+ // src/client/cards/member-enrollment-status/index.tsx
602
+ import { useRef as useRef3, useState as useState4 } from "react";
603
+ import { ArrowClockwise, CheckCircle, Clock, WarningCircle } from "@phosphor-icons/react";
604
+ import { sendCardAction as sendCardAction3, markSelfRendering as markSelfRendering3 } from "@tbox.cn/app-sdk/client";
605
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
606
+ var ICONS = { success: CheckCircle, warning: Clock, neutral: WarningCircle };
607
+ function MemberEnrollmentStatusCard(props) {
608
+ const { data, cardId, isHistory, actionTokens } = props;
609
+ const tone = enrollmentTone(data.state);
610
+ const Icon = ICONS[tone];
611
+ const refreshToken = actionTokens?.["member.query-enrollment-status"];
612
+ const [refreshing, setRefreshing] = useState4(false);
613
+ const refreshingRef = useRef3(false);
614
+ return /* @__PURE__ */ jsxs5("section", { className: `member-card member-es member-es--${data.state}`, children: [
615
+ /* @__PURE__ */ jsx6("span", { className: "member-es__eyebrow", children: "\u5165\u4F1A\u7533\u8BF7" }),
616
+ /* @__PURE__ */ jsx6("div", { className: `member-es__icon member-es__icon--${tone}`, children: /* @__PURE__ */ jsx6(Icon, { size: 30, weight: "duotone" }) }),
617
+ /* @__PURE__ */ jsx6("h4", { children: enrollmentStateText(data.state) }),
618
+ data.message && /* @__PURE__ */ jsx6("p", { className: "member-es__message", children: data.message }),
619
+ data.state === "active" && /* @__PURE__ */ jsx6("p", { className: "member-es__support", children: "\u4F1A\u5458\u72B6\u6001\u5DF2\u66F4\u65B0\uFF0C\u53EF\u7EE7\u7EED\u67E5\u8BE2\u4F1A\u5458\u5361\u6216\u79EF\u5206" }),
620
+ (data.state === "failed" || data.state === "confirmation_timeout") && /* @__PURE__ */ jsx6("p", { className: "member-es__support", children: "\u672C\u6B21\u672A\u786E\u8BA4\u6210\u529F\uFF0C\u8BF7\u6839\u636E\u63D0\u793A\u91CD\u65B0\u53D1\u8D77\u6216\u7A0D\u540E\u518D\u8BD5" }),
621
+ data.state === "pending_confirmation" && data.attemptRef && /* @__PURE__ */ jsxs5(
622
+ "button",
623
+ {
624
+ type: "button",
625
+ className: "member-es__refresh",
626
+ disabled: isHistory || !refreshToken || refreshing,
627
+ onClick: () => {
628
+ if (!refreshToken || isHistory || refreshingRef.current) return;
629
+ refreshingRef.current = true;
630
+ setRefreshing(true);
631
+ sendCardAction3(
632
+ cardId,
633
+ { type: "moduleAction", actionId: "member.query-enrollment-status", contextToken: refreshToken },
634
+ { attemptRef: data.attemptRef }
635
+ );
636
+ },
637
+ children: [
638
+ /* @__PURE__ */ jsx6(ArrowClockwise, { size: 16, weight: "bold" }),
639
+ refreshing ? "\u6B63\u5728\u5237\u65B0\u2026" : "\u5237\u65B0\u72B6\u6001"
640
+ ]
641
+ }
642
+ ),
643
+ isHistory && data.state === "pending_confirmation" && /* @__PURE__ */ jsx6("p", { className: "member-es__support", children: "\u5386\u53F2\u7533\u8BF7\u4E0D\u53EF\u5237\u65B0\uFF0C\u8BF7\u91CD\u65B0\u67E5\u8BE2\u5F53\u524D\u4F1A\u5458\u72B6\u6001" })
644
+ ] });
645
+ }
646
+ var member_enrollment_status_default = markSelfRendering3(MemberEnrollmentStatusCard);
647
+
648
+ // src/client/cards/member-enrollment-cta/index.tsx
649
+ import { useRef as useRef4, useState as useState5 } from "react";
650
+ import { ArrowSquareOut, IdentificationCard, ShieldCheck as ShieldCheck2, WarningCircle as WarningCircle2 } from "@phosphor-icons/react";
651
+ import { sendCardAction as sendCardAction4 } from "@tbox.cn/app-sdk/client";
652
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
653
+ function MemberEnrollmentCtaCard(props) {
654
+ const { data, cardId, isHistory } = props;
655
+ const [opening, setOpening] = useState5(false);
656
+ const openingRef = useRef4(false);
657
+ function handleEnroll() {
658
+ if (isHistory || openingRef.current || !data.enrollUrl) return;
659
+ openingRef.current = true;
660
+ setOpening(true);
661
+ sendCardAction4(cardId, { type: "openLink", url: data.enrollUrl });
662
+ }
663
+ return /* @__PURE__ */ jsxs6("section", { className: "member-card member-enroll-cta", children: [
664
+ /* @__PURE__ */ jsxs6("div", { className: "member-enroll-cta__hero", children: [
665
+ /* @__PURE__ */ jsx7("span", { className: "member-enroll-cta__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx7(IdentificationCard, { size: 28, weight: "duotone" }) }),
666
+ /* @__PURE__ */ jsx7("span", { className: "member-enroll-cta__eyebrow", children: "\u4F1A\u5458\u670D\u52A1" }),
667
+ /* @__PURE__ */ jsx7("h4", { children: data.title ?? "\u5F00\u5361\u5165\u4F1A" }),
668
+ /* @__PURE__ */ jsx7("p", { children: "\u524D\u5F80\u652F\u4ED8\u5B9D\u4F1A\u5458\u9875\u9762\u5B8C\u6210\u5F00\u5361\uFF0C\u7ED3\u679C\u4EE5\u9875\u9762\u4E3A\u51C6" })
669
+ ] }),
670
+ /* @__PURE__ */ jsxs6("div", { className: "member-enroll-cta__footer", children: [
671
+ /* @__PURE__ */ jsxs6("p", { className: "member-enroll-cta__hint", children: [
672
+ /* @__PURE__ */ jsx7(ShieldCheck2, { size: 16, weight: "fill", "aria-hidden": "true" }),
673
+ "\u767B\u5F55\u72B6\u6001\u4E0D\u53D7\u5165\u4F1A\u7ED3\u679C\u5F71\u54CD\uFF0C\u5F00\u5361\u7ED3\u679C\u4EE5\u652F\u4ED8\u5B9D\u4F1A\u5458\u9875\u9762\u4E3A\u51C6"
674
+ ] }),
675
+ /* @__PURE__ */ jsxs6(
676
+ "button",
677
+ {
678
+ type: "button",
679
+ className: "member-enroll-cta__btn",
680
+ disabled: isHistory || opening || !data.enrollUrl,
681
+ onClick: handleEnroll,
682
+ "aria-label": data.enrollUrl ? "\u7ACB\u5373\u5F00\u5361\u5165\u4F1A" : "\u5165\u4F1A\u6682\u4E0D\u53EF\u7528\uFF08\u8BF7\u8054\u7CFB\u5546\u573A\u5BA2\u670D\uFF09",
683
+ children: [
684
+ opening ? "\u6B63\u5728\u6253\u5F00\u652F\u4ED8\u5B9D\u2026" : data.enrollUrl ? "\u7ACB\u5373\u5F00\u5361\u5165\u4F1A" : "\u6682\u4E0D\u53EF\u7528\uFF08\u8BF7\u8054\u7CFB\u5546\u573A\u5BA2\u670D\uFF09",
685
+ data.enrollUrl ? /* @__PURE__ */ jsx7(ArrowSquareOut, { size: 18, weight: "bold", "aria-hidden": "true" }) : /* @__PURE__ */ jsx7(WarningCircle2, { size: 18, weight: "fill", "aria-hidden": "true" })
686
+ ]
687
+ }
688
+ ),
689
+ isHistory && /* @__PURE__ */ jsx7("p", { className: "member-enroll-cta__history", children: "\u5386\u53F2\u5361\u7247\u4E0D\u53EF\u91CD\u590D\u64CD\u4F5C" })
690
+ ] })
691
+ ] });
692
+ }
693
+ var member_enrollment_cta_default = MemberEnrollmentCtaCard;
694
+
695
+ // src/client/cards/member-login-cta/index.tsx
696
+ import { useRef as useRef5, useState as useState6 } from "react";
697
+ import { ArrowSquareOut as ArrowSquareOut2, WarningCircle as WarningCircle3 } from "@phosphor-icons/react";
698
+ import { sendCardAction as sendCardAction5 } from "@tbox.cn/app-sdk/client";
699
+
700
+ // src/client/assets/login-mascot.jpg
701
+ var login_mascot_default = "./login-mascot-5D4X6YZ7.jpg";
702
+
703
+ // src/client/cards/member-login-cta/index.tsx
704
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
705
+ function MemberLoginCtaCard(props) {
706
+ const { data, cardId, isHistory } = props;
707
+ const [opening, setOpening] = useState6(false);
708
+ const openingRef = useRef5(false);
709
+ function handleLogin() {
710
+ if (isHistory || openingRef.current || !data.loginUrl) return;
711
+ openingRef.current = true;
712
+ setOpening(true);
713
+ sendCardAction5(cardId, { type: "openLink", url: data.loginUrl });
714
+ }
715
+ return /* @__PURE__ */ jsxs7("section", { className: "member-card member-login-cta", children: [
716
+ /* @__PURE__ */ jsxs7("div", { className: "member-login-cta__stage", children: [
717
+ /* @__PURE__ */ jsx8("span", { className: "member-login-cta__sky", "aria-hidden": "true" }),
718
+ /* @__PURE__ */ jsxs7("svg", { className: "member-login-cta__doodle", viewBox: "0 0 390 170", "aria-hidden": "true", children: [
719
+ /* @__PURE__ */ jsx8("path", { d: "M50 40 l5,11 12,2 -9,9 3,12 -11,-6 -11,6 3,-12 -9,-9 12,-2 Z" }),
720
+ /* @__PURE__ */ jsx8("path", { d: "M318 56 c10,-12 23,-11 29,-1 c6,10 -3,20 -12,17" }),
721
+ /* @__PURE__ */ jsx8("path", { d: "M40 122 c12,-8 20,2 11,9" })
722
+ ] }),
723
+ /* @__PURE__ */ jsx8("span", { className: "member-login-cta__ground", "aria-hidden": "true" }),
724
+ /* @__PURE__ */ jsx8("img", { className: "member-login-cta__mascot", src: login_mascot_default, alt: "" }),
725
+ /* @__PURE__ */ jsx8("span", { className: "member-login-cta__grain", "aria-hidden": "true" })
726
+ ] }),
727
+ /* @__PURE__ */ jsx8("svg", { className: "member-login-cta__tear", viewBox: "0 0 390 16", preserveAspectRatio: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M0,16 L390,16 L390,6 L358,10 L330,4 L298,11 L266,5 L236,12 L204,6 L174,12 L144,6 L112,13 L82,7 L52,14 L24,8 L0,12 Z" }) }),
728
+ /* @__PURE__ */ jsxs7("div", { className: "member-login-cta__body", children: [
729
+ /* @__PURE__ */ jsx8("h4", { children: data.title ?? "\u767B\u5F55\u540E\u7EE7\u7EED" }),
730
+ /* @__PURE__ */ jsx8("p", { className: "member-login-cta__reason", children: "\u767B\u5F55\u540E\u53EF\u89E3\u9501\u5168\u90E8\u529F\u80FD" }),
731
+ /* @__PURE__ */ jsxs7(
732
+ "button",
733
+ {
734
+ type: "button",
735
+ className: "member-login-cta__btn",
736
+ disabled: isHistory || opening || !data.loginUrl,
737
+ onClick: handleLogin,
738
+ "aria-label": data.loginUrl ? "\u524D\u5F80\u767B\u5F55" : "\u767B\u5F55\u6682\u4E0D\u53EF\u7528\uFF08\u8BF7\u8054\u7CFB\u5546\u573A\u5BA2\u670D\uFF09",
739
+ children: [
740
+ opening ? "\u6B63\u5728\u6253\u5F00\u5546\u573A\u5C0F\u7A0B\u5E8F\u2026" : data.loginUrl ? "\u7ACB\u5373\u767B\u5F55" : "\u6682\u4E0D\u53EF\u7528\uFF08\u8BF7\u8054\u7CFB\u5546\u573A\u5BA2\u670D\uFF09",
741
+ data.loginUrl ? /* @__PURE__ */ jsx8(ArrowSquareOut2, { size: 18, weight: "bold", "aria-hidden": "true" }) : /* @__PURE__ */ jsx8(WarningCircle3, { size: 18, weight: "fill", "aria-hidden": "true" })
742
+ ]
743
+ }
744
+ ),
745
+ /* @__PURE__ */ jsx8("p", { className: "member-login-cta__hint", children: "\u767B\u5F55\u5728\u5546\u573A\u5C0F\u7A0B\u5E8F\u5185\u5B8C\u6210\uFF0C\u5B8C\u6210\u540E\u56DE\u5230\u8FD9\u91CC\u7EE7\u7EED" }),
746
+ isHistory && /* @__PURE__ */ jsx8("p", { className: "member-login-cta__history", children: "\u5386\u53F2\u5361\u7247\u4E0D\u53EF\u91CD\u590D\u64CD\u4F5C" })
747
+ ] })
748
+ ] });
749
+ }
750
+ var member_login_cta_default = MemberLoginCtaCard;
751
+
752
+ // src/client/index.ts
753
+ var cards = {
754
+ "member-info": member_info_default,
755
+ "member-card-summary": member_card_summary_default,
756
+ "member-point-usage-list": member_point_usage_list_default,
757
+ "member-enrollment-form": member_enrollment_form_default,
758
+ "member-enrollment-status": member_enrollment_status_default,
759
+ "member-enrollment-cta": member_enrollment_cta_default,
760
+ "member-login-cta": member_login_cta_default
761
+ };
762
+ var clientModule = {
763
+ cards,
764
+ register(ctx) {
765
+ ctx.cards.registerMap(cards);
766
+ }
767
+ };
768
+
769
+ export {
770
+ clientModule
771
+ };