@shopbb/helium 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/analytics/index.d.ts +18 -0
  2. package/dist/analytics/index.d.ts.map +1 -0
  3. package/dist/analytics/index.js +16 -0
  4. package/dist/analytics/index.js.map +1 -0
  5. package/dist/analytics/queue.d.ts +31 -0
  6. package/dist/analytics/queue.d.ts.map +1 -0
  7. package/dist/analytics/queue.js +203 -0
  8. package/dist/analytics/queue.js.map +1 -0
  9. package/dist/analytics/react.d.ts +44 -0
  10. package/dist/analytics/react.d.ts.map +1 -0
  11. package/dist/analytics/react.js +114 -0
  12. package/dist/analytics/react.js.map +1 -0
  13. package/dist/analytics/types.d.ts +68 -0
  14. package/dist/analytics/types.d.ts.map +1 -0
  15. package/dist/analytics/types.js +7 -0
  16. package/dist/analytics/types.js.map +1 -0
  17. package/dist/components/AddToCartButton.d.ts +7 -0
  18. package/dist/components/AddToCartButton.d.ts.map +1 -1
  19. package/dist/components/AddToCartButton.js +13 -2
  20. package/dist/components/AddToCartButton.js.map +1 -1
  21. package/dist/components/DiscountComponents.d.ts +3 -0
  22. package/dist/components/DiscountComponents.d.ts.map +1 -1
  23. package/dist/components/DiscountComponents.js +4 -4
  24. package/dist/components/DiscountComponents.js.map +1 -1
  25. package/dist/react.d.ts +5 -0
  26. package/dist/react.d.ts.map +1 -1
  27. package/dist/react.js +10 -0
  28. package/dist/react.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/analytics/index.ts +27 -0
  31. package/src/analytics/queue.ts +224 -0
  32. package/src/analytics/react.tsx +146 -0
  33. package/src/analytics/types.ts +81 -0
  34. package/src/components/AddToCartButton.tsx +18 -0
  35. package/src/components/DiscountComponents.tsx +15 -3
  36. package/src/react.tsx +26 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @shopbb/helium/analytics — 埋点 SDK 公开 API
3
+ *
4
+ * 浏览器侧用法:
5
+ * - <TrackingProvider>:包在 root,初始化 session、起 flush 定时器、自动 page_view
6
+ * - useTracking():在组件内拿到 track() 函数
7
+ *
8
+ * 服务端不要用本模块——服务端事件(checkout_paid)由 platform-api 直接 INSERT。
9
+ *
10
+ * 注意:本模块与 components/AnalyticsProvider 是两个独立产品:
11
+ * - AnalyticsProvider(components):客户端事件总线,挂 GA / 自定义 reporter
12
+ * - TrackingProvider(本模块):把 5 个核心事件批量发到 /api/events,给 agent 用
13
+ */
14
+ export { TrackingProvider, useTracking } from './react';
15
+ export type { TrackingProviderProps } from './react';
16
+ export { AnalyticsQueue } from './queue';
17
+ export type { AnalyticsEvent, AnalyticsConfig, EventType, PageViewProps, ProductViewProps, AddToCartProps, CheckoutStartProps, TrackFn, } from './types';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,YAAY,EACV,cAAc,EACd,eAAe,EACf,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,OAAO,GACR,MAAM,SAAS,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @shopbb/helium/analytics — 埋点 SDK 公开 API
3
+ *
4
+ * 浏览器侧用法:
5
+ * - <TrackingProvider>:包在 root,初始化 session、起 flush 定时器、自动 page_view
6
+ * - useTracking():在组件内拿到 track() 函数
7
+ *
8
+ * 服务端不要用本模块——服务端事件(checkout_paid)由 platform-api 直接 INSERT。
9
+ *
10
+ * 注意:本模块与 components/AnalyticsProvider 是两个独立产品:
11
+ * - AnalyticsProvider(components):客户端事件总线,挂 GA / 自定义 reporter
12
+ * - TrackingProvider(本模块):把 5 个核心事件批量发到 /api/events,给 agent 用
13
+ */
14
+ export { TrackingProvider, useTracking } from './react';
15
+ export { AnalyticsQueue } from './queue';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * AnalyticsQueue — 浏览器侧事件缓冲队列
3
+ *
4
+ * 职责:
5
+ * 1. 把 track() 调用收集到内存队列
6
+ * 2. 定时(3s)或满批(20)触发 flush
7
+ * 3. flush 调 POST /api/events,失败重试 1 次
8
+ * 4. beforeunload 时用 navigator.sendBeacon 兜底刷出
9
+ *
10
+ * 注意:这是浏览器侧逻辑。SSR 阶段调 track() 会被丢弃(typeof window === 'undefined' 检查)。
11
+ */
12
+ import type { AnalyticsConfig, AnalyticsEvent } from './types';
13
+ export declare class AnalyticsQueue {
14
+ private readonly config;
15
+ private queue;
16
+ private timer;
17
+ private sessionId;
18
+ private flushing;
19
+ constructor(config: AnalyticsConfig);
20
+ start(): void;
21
+ stop(): void;
22
+ setBuyerId(id: string | null): void;
23
+ track(event: AnalyticsEvent): void;
24
+ /** 主动 flush。返回是否实际发送了请求 */
25
+ flush(): Promise<boolean>;
26
+ /** 用 sendBeacon 兜底,页面卸载场景 */
27
+ private flushBeacon;
28
+ private headers;
29
+ private log;
30
+ }
31
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/analytics/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAe,MAAM,SAAS,CAAC;AAgC5E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGrB;IACF,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,eAAe;IAWnC,KAAK,IAAI,IAAI;IAqBb,IAAI,IAAI,IAAI;IAOZ,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAInC,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAoClC,2BAA2B;IACrB,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IA0C/B,6BAA6B;IAC7B,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,GAAG;CAMZ"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * AnalyticsQueue — 浏览器侧事件缓冲队列
3
+ *
4
+ * 职责:
5
+ * 1. 把 track() 调用收集到内存队列
6
+ * 2. 定时(3s)或满批(20)触发 flush
7
+ * 3. flush 调 POST /api/events,失败重试 1 次
8
+ * 4. beforeunload 时用 navigator.sendBeacon 兜底刷出
9
+ *
10
+ * 注意:这是浏览器侧逻辑。SSR 阶段调 track() 会被丢弃(typeof window === 'undefined' 检查)。
11
+ */
12
+ const SESSION_COOKIE = 'sbb_sid';
13
+ const SESSION_TTL_DAYS = 365;
14
+ /**
15
+ * 读 sbb_sid cookie,没有则生成一个新的并 set。
16
+ * 仅浏览器环境调用。
17
+ */
18
+ function getOrCreateSessionId() {
19
+ if (typeof document === 'undefined')
20
+ return '';
21
+ const match = document.cookie.match(/(?:^|;\s*)sbb_sid=([^;]+)/);
22
+ if (match)
23
+ return match[1];
24
+ // 生成 UUID(不依赖 crypto.randomUUID 以兼容老浏览器)
25
+ const sid = crypto?.randomUUID?.() ?? generateFallbackUuid();
26
+ const maxAge = SESSION_TTL_DAYS * 24 * 60 * 60;
27
+ document.cookie = `${SESSION_COOKIE}=${sid}; max-age=${maxAge}; path=/; samesite=lax`;
28
+ return sid;
29
+ }
30
+ function generateFallbackUuid() {
31
+ // RFC4122 v4 简化版
32
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
33
+ const r = (Math.random() * 16) | 0;
34
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
35
+ return v.toString(16);
36
+ });
37
+ }
38
+ export class AnalyticsQueue {
39
+ config;
40
+ queue = [];
41
+ timer = null;
42
+ sessionId = '';
43
+ flushing = false;
44
+ constructor(config) {
45
+ this.config = {
46
+ apiBase: config.apiBase.replace(/\/+$/, ''),
47
+ publicAccessToken: config.publicAccessToken,
48
+ buyerId: config.buyerId ?? null,
49
+ debug: !!config.debug,
50
+ flushIntervalMs: config.flushIntervalMs ?? 3000,
51
+ flushBatchSize: config.flushBatchSize ?? 20,
52
+ };
53
+ }
54
+ start() {
55
+ if (typeof window === 'undefined')
56
+ return;
57
+ this.sessionId = getOrCreateSessionId();
58
+ if (this.timer)
59
+ return;
60
+ this.timer = setInterval(() => {
61
+ void this.flush();
62
+ }, this.config.flushIntervalMs);
63
+ // 页面卸载兜底
64
+ window.addEventListener('pagehide', () => this.flushBeacon());
65
+ window.addEventListener('beforeunload', () => this.flushBeacon());
66
+ if (typeof document !== 'undefined') {
67
+ document.addEventListener('visibilitychange', () => {
68
+ if (document.visibilityState === 'hidden') {
69
+ this.flushBeacon();
70
+ }
71
+ });
72
+ }
73
+ }
74
+ stop() {
75
+ if (this.timer) {
76
+ clearInterval(this.timer);
77
+ this.timer = null;
78
+ }
79
+ }
80
+ setBuyerId(id) {
81
+ this.config.buyerId = id;
82
+ }
83
+ track(event) {
84
+ if (typeof window === 'undefined') {
85
+ this.log('skip-ssr', event.type);
86
+ return;
87
+ }
88
+ if (!this.sessionId) {
89
+ this.sessionId = getOrCreateSessionId();
90
+ }
91
+ const queued = {
92
+ type: event.type,
93
+ occurredAt: event.occurredAt ?? Math.floor(Date.now() / 1000),
94
+ path: event.path !== undefined
95
+ ? event.path
96
+ : typeof location !== 'undefined'
97
+ ? location.pathname + location.search
98
+ : null,
99
+ referrer: event.referrer !== undefined
100
+ ? event.referrer
101
+ : typeof document !== 'undefined'
102
+ ? document.referrer || null
103
+ : null,
104
+ props: event.props ?? {},
105
+ };
106
+ this.queue.push(queued);
107
+ this.log('queued', queued.type, this.queue.length);
108
+ if (this.queue.length >= this.config.flushBatchSize) {
109
+ void this.flush();
110
+ }
111
+ }
112
+ /** 主动 flush。返回是否实际发送了请求 */
113
+ async flush() {
114
+ if (this.flushing)
115
+ return false;
116
+ if (this.queue.length === 0)
117
+ return false;
118
+ if (!this.config.publicAccessToken) {
119
+ this.log('skip-no-token');
120
+ return false;
121
+ }
122
+ this.flushing = true;
123
+ const batch = this.queue.splice(0, this.config.flushBatchSize);
124
+ const body = JSON.stringify({
125
+ events: batch.map((e) => ({
126
+ type: e.type,
127
+ occurredAt: e.occurredAt,
128
+ path: e.path ?? undefined,
129
+ referrer: e.referrer ?? undefined,
130
+ props: e.props,
131
+ })),
132
+ });
133
+ try {
134
+ const res = await fetch(`${this.config.apiBase}/api/events`, {
135
+ method: 'POST',
136
+ headers: this.headers(),
137
+ body,
138
+ keepalive: true,
139
+ });
140
+ if (!res.ok) {
141
+ this.log('flush-failed-status', res.status);
142
+ // 失败不重试入队(避免堆积),demo 阶段简化
143
+ return false;
144
+ }
145
+ this.log('flushed', batch.length);
146
+ return true;
147
+ }
148
+ catch (err) {
149
+ this.log('flush-error', err);
150
+ return false;
151
+ }
152
+ finally {
153
+ this.flushing = false;
154
+ }
155
+ }
156
+ /** 用 sendBeacon 兜底,页面卸载场景 */
157
+ flushBeacon() {
158
+ if (this.queue.length === 0)
159
+ return;
160
+ if (typeof navigator === 'undefined' || !navigator.sendBeacon)
161
+ return;
162
+ if (!this.config.publicAccessToken)
163
+ return;
164
+ const batch = this.queue.splice(0, this.config.flushBatchSize);
165
+ const body = JSON.stringify({
166
+ events: batch.map((e) => ({
167
+ type: e.type,
168
+ occurredAt: e.occurredAt,
169
+ path: e.path ?? undefined,
170
+ referrer: e.referrer ?? undefined,
171
+ props: e.props,
172
+ })),
173
+ // sendBeacon 无法设 header,所以把 token / session 塞进 body 作为兜底
174
+ // platform-api handler 优先认 header;body 字段用于 beacon 场景
175
+ _auth: {
176
+ token: this.config.publicAccessToken,
177
+ sessionId: this.sessionId,
178
+ buyerId: this.config.buyerId,
179
+ },
180
+ });
181
+ const blob = new Blob([body], { type: 'application/json' });
182
+ const ok = navigator.sendBeacon(`${this.config.apiBase}/api/events?beacon=1`, blob);
183
+ this.log('beacon', ok, batch.length);
184
+ }
185
+ headers() {
186
+ const h = {
187
+ 'Content-Type': 'application/json',
188
+ 'X-Storefront-Access-Token': this.config.publicAccessToken,
189
+ 'X-Session-Id': this.sessionId,
190
+ };
191
+ if (this.config.buyerId) {
192
+ h['X-Buyer-Id'] = this.config.buyerId;
193
+ }
194
+ return h;
195
+ }
196
+ log(...args) {
197
+ if (this.config.debug) {
198
+ // eslint-disable-next-line no-console
199
+ console.log('[helium-analytics]', ...args);
200
+ }
201
+ }
202
+ }
203
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/analytics/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * TrackingProvider + useTracking — React 绑定(后端事件埋点)
3
+ *
4
+ * 与 components/AnalyticsProvider 不同:
5
+ * - AnalyticsProvider(旧):客户端事件总线,商家挂 GA / Plausible 等 reporter
6
+ * - TrackingProvider(新):把 5 个核心事件发到 platform-api /api/events
7
+ *
8
+ * 用法:
9
+ * <TrackingProvider
10
+ * apiBase={store.apiBase}
11
+ * publicAccessToken={store.publicAccessToken}
12
+ * buyerId={buyer?.id}
13
+ * debug
14
+ * >
15
+ * <App />
16
+ * </TrackingProvider>
17
+ *
18
+ * const { track } = useTracking();
19
+ * track({ type: 'add_to_cart', props: { productId, quantity: 1 } });
20
+ *
21
+ * 自动事件:
22
+ * - 首次挂载发一次 page_view
23
+ * - 监听 history pushState/replaceState/popstate,每次 URL 变化补发 page_view
24
+ */
25
+ import * as React from 'react';
26
+ import type { AnalyticsConfig, TrackFn } from './types';
27
+ interface ContextValue {
28
+ track: TrackFn;
29
+ setBuyerId: (id: string | null) => void;
30
+ }
31
+ export interface TrackingProviderProps extends AnalyticsConfig {
32
+ children: React.ReactNode;
33
+ /** 是否自动发 page_view(默认 true) */
34
+ autoPageview?: boolean;
35
+ }
36
+ export declare function TrackingProvider(props: TrackingProviderProps): React.ReactElement;
37
+ /**
38
+ * 在组件里拿到 track 函数。
39
+ *
40
+ * 在 TrackingProvider 之外调用会得到一个 no-op,不报错(方便在测试/SSR 中使用)。
41
+ */
42
+ export declare function useTracking(): ContextValue;
43
+ export {};
44
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/analytics/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAkB,eAAe,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAExE,UAAU,YAAY;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACzC;AAID,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CAuFjF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,YAAY,CAI1C"}
@@ -0,0 +1,114 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * TrackingProvider + useTracking — React 绑定(后端事件埋点)
4
+ *
5
+ * 与 components/AnalyticsProvider 不同:
6
+ * - AnalyticsProvider(旧):客户端事件总线,商家挂 GA / Plausible 等 reporter
7
+ * - TrackingProvider(新):把 5 个核心事件发到 platform-api /api/events
8
+ *
9
+ * 用法:
10
+ * <TrackingProvider
11
+ * apiBase={store.apiBase}
12
+ * publicAccessToken={store.publicAccessToken}
13
+ * buyerId={buyer?.id}
14
+ * debug
15
+ * >
16
+ * <App />
17
+ * </TrackingProvider>
18
+ *
19
+ * const { track } = useTracking();
20
+ * track({ type: 'add_to_cart', props: { productId, quantity: 1 } });
21
+ *
22
+ * 自动事件:
23
+ * - 首次挂载发一次 page_view
24
+ * - 监听 history pushState/replaceState/popstate,每次 URL 变化补发 page_view
25
+ */
26
+ import * as React from 'react';
27
+ import { AnalyticsQueue } from './queue';
28
+ const TrackingCtx = React.createContext(null);
29
+ export function TrackingProvider(props) {
30
+ const { children, autoPageview = true, apiBase, publicAccessToken, buyerId, debug, flushIntervalMs, flushBatchSize, } = props;
31
+ // 用 ref 持有 queue,避免每次 re-render 重建
32
+ const queueRef = React.useRef(null);
33
+ if (queueRef.current === null) {
34
+ queueRef.current = new AnalyticsQueue({
35
+ apiBase,
36
+ publicAccessToken,
37
+ buyerId,
38
+ debug,
39
+ flushIntervalMs,
40
+ flushBatchSize,
41
+ });
42
+ }
43
+ // buyerId 变化时同步到 queue
44
+ React.useEffect(() => {
45
+ queueRef.current?.setBuyerId(buyerId ?? null);
46
+ }, [buyerId]);
47
+ // 启动 queue(只在浏览器侧)
48
+ React.useEffect(() => {
49
+ if (typeof window === 'undefined')
50
+ return;
51
+ const q = queueRef.current;
52
+ if (!q)
53
+ return;
54
+ q.start();
55
+ return () => q.stop();
56
+ }, []);
57
+ // 自动 page_view
58
+ React.useEffect(() => {
59
+ if (!autoPageview)
60
+ return;
61
+ if (typeof window === 'undefined')
62
+ return;
63
+ const q = queueRef.current;
64
+ if (!q)
65
+ return;
66
+ const send = () => {
67
+ q.track({
68
+ type: 'page_view',
69
+ props: { title: typeof document !== 'undefined' ? document.title : undefined },
70
+ });
71
+ };
72
+ // 首次
73
+ send();
74
+ // patch history methods 以捕获 SPA 导航
75
+ const origPush = history.pushState;
76
+ const origReplace = history.replaceState;
77
+ history.pushState = function (...args) {
78
+ origPush.apply(this, args);
79
+ send();
80
+ };
81
+ history.replaceState = function (...args) {
82
+ origReplace.apply(this, args);
83
+ send();
84
+ };
85
+ const onPop = () => send();
86
+ window.addEventListener('popstate', onPop);
87
+ return () => {
88
+ history.pushState = origPush;
89
+ history.replaceState = origReplace;
90
+ window.removeEventListener('popstate', onPop);
91
+ };
92
+ }, [autoPageview]);
93
+ const value = React.useMemo(() => ({
94
+ track: (e) => queueRef.current?.track(e),
95
+ setBuyerId: (id) => queueRef.current?.setBuyerId(id),
96
+ }), []);
97
+ return _jsx(TrackingCtx.Provider, { value: value, children: children });
98
+ }
99
+ /**
100
+ * 在组件里拿到 track 函数。
101
+ *
102
+ * 在 TrackingProvider 之外调用会得到一个 no-op,不报错(方便在测试/SSR 中使用)。
103
+ */
104
+ export function useTracking() {
105
+ const ctx = React.useContext(TrackingCtx);
106
+ if (ctx)
107
+ return ctx;
108
+ return NOOP;
109
+ }
110
+ const NOOP = {
111
+ track: () => { },
112
+ setBuyerId: () => { },
113
+ };
114
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../../src/analytics/react.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAQzC,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAsB,IAAI,CAAC,CAAC;AAQnE,MAAM,UAAU,gBAAgB,CAAC,KAA4B;IAC3D,MAAM,EACJ,QAAQ,EACR,YAAY,GAAG,IAAI,EACnB,OAAO,EACP,iBAAiB,EACjB,OAAO,EACP,KAAK,EACL,eAAe,EACf,cAAc,GACf,GAAG,KAAK,CAAC;IAEV,mCAAmC;IACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAwB,IAAI,CAAC,CAAC;IAE3D,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9B,QAAQ,CAAC,OAAO,GAAG,IAAI,cAAc,CAAC;YACpC,OAAO;YACP,iBAAiB;YACjB,OAAO;YACP,KAAK;YACL,eAAe;YACf,cAAc;SACf,CAAC,CAAC;IACL,CAAC;IAED,uBAAuB;IACvB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IAChD,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,mBAAmB;IACnB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,eAAe;IACf,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,YAAY;YAAE,OAAO;QAC1B,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,CAAC;YAAE,OAAO;QAEf,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,CAAC,CAAC,KAAK,CAAC;gBACN,IAAI,EAAE,WAAW;gBACjB,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE;aAC/E,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,KAAK;QACL,IAAI,EAAE,CAAC;QAEP,mCAAmC;QACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,OAAO,CAAC,SAAS,GAAG,UAAU,GAAG,IAAI;YACnC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;YAClC,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;QACF,OAAO,CAAC,YAAY,GAAG,UAAU,GAAG,IAAI;YACtC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;YACrC,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE3C,OAAO,GAAG,EAAE;YACV,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC;YAC7B,OAAO,CAAC,YAAY,GAAG,WAAW,CAAC;YACnC,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,GAAG,EAAE,CAAC,CAAC;QACL,KAAK,EAAE,CAAC,CAAiB,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACxD,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC;KACrD,CAAC,EACF,EAAE,CACH,CAAC;IAEF,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAwB,CAAC;AAC/E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,IAAI,GAAiB;IACzB,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;CACrB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Analytics SDK 类型
3
+ *
4
+ * Helium 的埋点接口。与 platform-api 的事件 schema 保持一致。
5
+ */
6
+ export type EventType = 'page_view' | 'product_view' | 'add_to_cart' | 'checkout_start' | 'checkout_paid';
7
+ /** 单条事件输入 */
8
+ export interface AnalyticsEvent {
9
+ /** 事件类型 */
10
+ type: EventType;
11
+ /** 客户端发生时间(秒,Unix)。默认 Date.now()/1000 */
12
+ occurredAt?: number;
13
+ /** 页面 path(默认 window.location.pathname) */
14
+ path?: string;
15
+ /** referrer(默认 document.referrer) */
16
+ referrer?: string;
17
+ /** 事件附加数据 */
18
+ props?: Record<string, unknown>;
19
+ }
20
+ /** 各事件的 props 形状 */
21
+ export interface PageViewProps {
22
+ title?: string;
23
+ }
24
+ export interface ProductViewProps {
25
+ productId: string;
26
+ variantId?: string;
27
+ priceCents?: number;
28
+ currency?: string;
29
+ }
30
+ export interface AddToCartProps {
31
+ productId: string;
32
+ variantId?: string;
33
+ quantity: number;
34
+ priceCents?: number;
35
+ currency?: string;
36
+ }
37
+ export interface CheckoutStartProps {
38
+ cartId?: string;
39
+ itemCount: number;
40
+ subtotalCents: number;
41
+ currency: string;
42
+ }
43
+ /** AnalyticsProvider 初始化配置 */
44
+ export interface AnalyticsConfig {
45
+ /** 平台 API base URL,例如 https://api.oxygen-demo.cloudc.top */
46
+ apiBase: string;
47
+ /** Storefront public access token */
48
+ publicAccessToken: string;
49
+ /** 当前买家 ID(已登录时传入) */
50
+ buyerId?: string | null;
51
+ /** 是否开启 debug 日志 */
52
+ debug?: boolean;
53
+ /** flush 间隔(毫秒),默认 3000 */
54
+ flushIntervalMs?: number;
55
+ /** 批量上限(条),默认 20 */
56
+ flushBatchSize?: number;
57
+ }
58
+ /** track 函数签名 */
59
+ export type TrackFn = (event: AnalyticsEvent) => void;
60
+ /** 内部队列条目 */
61
+ export interface QueuedEvent {
62
+ type: EventType;
63
+ occurredAt: number;
64
+ path: string | null;
65
+ referrer: string | null;
66
+ props: Record<string, unknown>;
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,cAAc,GACd,aAAa,GACb,gBAAgB,GAChB,eAAe,CAAC;AAEpB,aAAa;AACb,MAAM,WAAW,cAAc;IAC7B,WAAW;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,oBAAoB;AACpB,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8BAA8B;AAC9B,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,iBAAiB;AACjB,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAEtD,aAAa;AACb,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Analytics SDK 类型
3
+ *
4
+ * Helium 的埋点接口。与 platform-api 的事件 schema 保持一致。
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -17,6 +17,7 @@
17
17
  * 监听全局 fetcher 状态。Hydrogen demo store 用 `useAside().open()` 模式。
18
18
  */
19
19
  import * as React from 'react';
20
+ import { type CartLineInput } from './CartForm';
20
21
  export interface AddToCartButtonProps {
21
22
  /** variant GID */
22
23
  variantId: string;
@@ -39,6 +40,12 @@ export interface AddToCartButtonProps {
39
40
  route?: string;
40
41
  /** 按钮 children */
41
42
  children?: React.ReactNode;
43
+ /**
44
+ * 按钮被点击时触发(form 提交之前)。
45
+ * 用于埋点 / dataLayer / 自定义分析回调。
46
+ * 不影响表单提交流程。
47
+ */
48
+ onAdd?: (line: CartLineInput) => void;
42
49
  }
43
50
  export declare function AddToCartButton(props: AddToCartButtonProps): import("react/jsx-runtime").JSX.Element;
44
51
  //# sourceMappingURL=AddToCartButton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddToCartButton.d.ts","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,oBAAoB;IACnC,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,kDAAkD;IAClD,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,kBAAkB;IAClB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,sBAAsB;IACtB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAwC1D"}
1
+ {"version":3,"file":"AddToCartButton.d.ts","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,kDAAkD;IAClD,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,kBAAkB;IAClB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,sBAAsB;IACtB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACvC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAoD1D"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { CartForm } from './CartForm';
3
3
  export function AddToCartButton(props) {
4
- const { variantId, quantity = 1, attributes, selectedVariant, unavailableText = '缺货', loadingText = '加入中...', disabled = false, className, route = '/cart', children = '加入购物车', } = props;
4
+ const { variantId, quantity = 1, attributes, selectedVariant, unavailableText = '缺货', loadingText = '加入中...', disabled = false, className, route = '/cart', children = '加入购物车', onAdd, } = props;
5
5
  const line = { merchandiseId: variantId, quantity };
6
6
  if (attributes && attributes.length > 0)
7
7
  line.attributes = attributes;
@@ -9,7 +9,18 @@ export function AddToCartButton(props) {
9
9
  line.selectedVariant = selectedVariant;
10
10
  return (_jsx(CartForm, { route: route, action: CartForm.ACTIONS.LinesAdd, inputs: { lines: [line] }, children: (fetcher) => {
11
11
  const submitting = fetcher.state !== 'idle';
12
- return (_jsx("button", { type: "submit", className: className, disabled: disabled || submitting, "data-add-to-cart": true, "data-loading": submitting ? '' : undefined, children: submitting ? loadingText : disabled ? unavailableText : children }));
12
+ return (_jsx("button", { type: "submit", className: className, disabled: disabled || submitting, "data-add-to-cart": true, "data-loading": submitting ? '' : undefined, onClick: () => {
13
+ if (onAdd && !submitting && !disabled) {
14
+ try {
15
+ onAdd(line);
16
+ }
17
+ catch (err) {
18
+ if (typeof console !== 'undefined') {
19
+ console.warn('[AddToCartButton] onAdd threw', err);
20
+ }
21
+ }
22
+ }
23
+ }, children: submitting ? loadingText : disabled ? unavailableText : children }));
13
24
  } }));
14
25
  }
15
26
  //# sourceMappingURL=AddToCartButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddToCartButton.js","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":";AAoBA,OAAO,EAAE,QAAQ,EAAsB,MAAM,YAAY,CAAC;AAuB1D,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,EACJ,SAAS,EACT,QAAQ,GAAG,CAAC,EACZ,UAAU,EACV,eAAe,EACf,eAAe,GAAG,IAAI,EACtB,WAAW,GAAG,QAAQ,EACtB,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,KAAK,GAAG,OAAO,EACf,QAAQ,GAAG,OAAO,GACnB,GAAG,KAAK,CAAC;IAEV,MAAM,IAAI,GAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACnE,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACtE,IAAI,eAAe;QAAE,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IAE5D,OAAO,CACL,KAAC,QAAQ,IACP,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EACjC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,YAExB,CAAC,OAAO,EAAE,EAAE;YACX,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC;YAC5C,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,IAAI,UAAU,4CAElB,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,YAExC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,GAC1D,CACV,CAAC;QACJ,CAAC,GACQ,CACZ,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"AddToCartButton.js","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":";AAoBA,OAAO,EAAE,QAAQ,EAAsB,MAAM,YAAY,CAAC;AA6B1D,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,EACJ,SAAS,EACT,QAAQ,GAAG,CAAC,EACZ,UAAU,EACV,eAAe,EACf,eAAe,GAAG,IAAI,EACtB,WAAW,GAAG,QAAQ,EACtB,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,KAAK,GAAG,OAAO,EACf,QAAQ,GAAG,OAAO,EAClB,KAAK,GACN,GAAG,KAAK,CAAC;IAEV,MAAM,IAAI,GAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACnE,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACtE,IAAI,eAAe;QAAE,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IAE5D,OAAO,CACL,KAAC,QAAQ,IACP,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EACjC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,YAExB,CAAC,OAAO,EAAE,EAAE;YACX,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC;YAC5C,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,IAAI,UAAU,4CAElB,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EACzC,OAAO,EAAE,GAAG,EAAE;oBACZ,IAAI,KAAK,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACtC,IAAI,CAAC;4BACH,KAAK,CAAC,IAAI,CAAC,CAAC;wBACd,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;gCACnC,OAAO,CAAC,IAAI,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;4BACrD,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC,YAEA,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,GAC1D,CACV,CAAC;QACJ,CAAC,GACQ,CACZ,CAAC;AACJ,CAAC"}
@@ -70,6 +70,9 @@ export interface ClaimableDiscountListProps {
70
70
  /** 当前买家已领取的 claim 列表,用于标记「已领取 / 已使用」状态。
71
71
  * 传入时按钮自动切换为 disabled + claimedText / usedText。 */
72
72
  myClaims?: DiscountClaim[];
73
+ /** 点击「领取」时商家提供的实现。一般用 fetcher 提交到自己的 action route。
74
+ * 不提供时按钮点击无效果。 */
75
+ onClaim?: (discount: Discount) => Promise<void> | void;
73
76
  /** 一次最多渲染几张,默认 10 */
74
77
  first?: number;
75
78
  className?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"DiscountComponents.d.ts","sourceRoot":"","sources":["../../src/components/DiscountComponents.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DiscountComponents.d.ts","sourceRoot":"","sources":["../../src/components/DiscountComponents.tsx"],"names":[],"mappings":"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"}