@windrun-huaiin/third-ui 7.5.3 → 7.6.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.
@@ -17,17 +17,30 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
17
17
  const fingerprintContext = fingerprintProvider.useFingerprintContextSafe();
18
18
  const { redirectToSignIn, user } = nextjs.useClerk();
19
19
  const router = navigation.useRouter();
20
- // 根据用户订阅状态确定初始 billing type
21
- const getInitialBillingType = React.useCallback(() => {
20
+ const [billingType, setBillingType] = React.useState(() => {
22
21
  var _a;
23
- // 如果用户有活跃订阅,使用订阅的计费周期
22
+ // 懒初始化:只在组件首次渲染时计算一次
23
+ // 如果用户有活跃订阅,通过 priceId 精确匹配计费周期
24
24
  if (((_a = fingerprintContext === null || fingerprintContext === void 0 ? void 0 : fingerprintContext.xSubscription) === null || _a === void 0 ? void 0 : _a.status) === 'active' && fingerprintContext.xSubscription.priceId) {
25
- return fingerprintContext.xSubscription.priceId.includes('yearly') ? 'yearly' : 'monthly';
25
+ const userPriceId = fingerprintContext.xSubscription.priceId;
26
+ const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
27
+ // 检查所有年付计划的 priceId
28
+ const yearlyPriceIds = [
29
+ providerConfig.products.free.plans.yearly.priceId,
30
+ providerConfig.products.pro.plans.yearly.priceId,
31
+ providerConfig.products.ultra.plans.yearly.priceId
32
+ ];
33
+ // 如果匹配到年付计划,返回 yearly,否则返回 monthly
34
+ if (yearlyPriceIds.includes(userPriceId)) {
35
+ return 'yearly';
36
+ }
37
+ else {
38
+ return 'monthly';
39
+ }
26
40
  }
27
41
  // 否则使用默认值
28
42
  return data.billingSwitch.defaultKey;
29
- }, [fingerprintContext, data.billingSwitch.defaultKey]);
30
- const [billingType, setBillingType] = React.useState(getInitialBillingType());
43
+ });
31
44
  const [isProcessing, setIsProcessing] = React.useState(false);
32
45
  const [tooltip, setTooltip] = React.useState({ show: false, content: '', x: 0, y: 0 });
33
46
  // 确定用户状态
@@ -220,19 +233,6 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
220
233
  }, []);
221
234
  // State for button portals
222
235
  const [buttonPortals, setButtonPortals] = React.useState([]);
223
- // 当 fingerprint context 变化时,更新 billing type 以匹配用户的订阅状态
224
- React.useEffect(() => {
225
- const newBillingType = getInitialBillingType();
226
- if (newBillingType !== billingType) {
227
- setBillingType(newBillingType);
228
- // 延迟执行以确保 DOM 已渲染
229
- setTimeout(() => {
230
- updatePriceDisplay(newBillingType);
231
- updateButtonStyles(newBillingType);
232
- updateDiscountInfo(newBillingType);
233
- }, 0);
234
- }
235
- }, [fingerprintContext, getInitialBillingType, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
236
236
  // 处理月付/年付切换和 tooltip 功能
237
237
  React.useEffect(() => {
238
238
  const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
@@ -286,10 +286,6 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
286
286
  }
287
287
  });
288
288
  });
289
- // Initial updates
290
- updatePriceDisplay(billingType);
291
- updateDiscountInfo(billingType);
292
- updateButtonStyles(billingType);
293
289
  return () => {
294
290
  if (monthlyButton) {
295
291
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -303,7 +299,28 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
303
299
  element.removeEventListener('mouseleave', handlers.mouseleave);
304
300
  });
305
301
  };
306
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
302
+ }, [data, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
303
+ // 单独的 effect 用于初始更新,只在组件挂载时执行一次
304
+ React.useEffect(() => {
305
+ // 直接在这里重新计算,避免闭包问题
306
+ const initialBillingType = (() => {
307
+ var _a;
308
+ if (((_a = fingerprintContext === null || fingerprintContext === void 0 ? void 0 : fingerprintContext.xSubscription) === null || _a === void 0 ? void 0 : _a.status) === 'active' && fingerprintContext.xSubscription.priceId) {
309
+ const userPriceId = fingerprintContext.xSubscription.priceId;
310
+ const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
311
+ const yearlyPriceIds = [
312
+ providerConfig.products.free.plans.yearly.priceId,
313
+ providerConfig.products.pro.plans.yearly.priceId,
314
+ providerConfig.products.ultra.plans.yearly.priceId
315
+ ];
316
+ return yearlyPriceIds.includes(userPriceId) ? 'yearly' : 'monthly';
317
+ }
318
+ return data.billingSwitch.defaultKey;
319
+ })();
320
+ updatePriceDisplay(initialBillingType);
321
+ updateDiscountInfo(initialBillingType);
322
+ updateButtonStyles(initialBillingType);
323
+ }, []); // 空依赖数组,只执行一次
307
324
  // Create button portals after component mounts
308
325
  React.useEffect(() => {
309
326
  const portals = [];
@@ -2,7 +2,7 @@
2
2
  import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.mjs';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useClerk } from '@clerk/nextjs';
5
- import { useCallback, useState, useMemo, useEffect } from 'react';
5
+ import { useState, useCallback, useMemo, useEffect } from 'react';
6
6
  import { useFingerprintContextSafe } from '../../clerk/fingerprint/fingerprint-provider.mjs';
7
7
  import { cn } from '@windrun-huaiin/lib/utils';
8
8
  import { useRouter } from 'next/navigation';
@@ -15,17 +15,30 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
15
15
  const fingerprintContext = useFingerprintContextSafe();
16
16
  const { redirectToSignIn, user } = useClerk();
17
17
  const router = useRouter();
18
- // 根据用户订阅状态确定初始 billing type
19
- const getInitialBillingType = useCallback(() => {
18
+ const [billingType, setBillingType] = useState(() => {
20
19
  var _a;
21
- // 如果用户有活跃订阅,使用订阅的计费周期
20
+ // 懒初始化:只在组件首次渲染时计算一次
21
+ // 如果用户有活跃订阅,通过 priceId 精确匹配计费周期
22
22
  if (((_a = fingerprintContext === null || fingerprintContext === void 0 ? void 0 : fingerprintContext.xSubscription) === null || _a === void 0 ? void 0 : _a.status) === 'active' && fingerprintContext.xSubscription.priceId) {
23
- return fingerprintContext.xSubscription.priceId.includes('yearly') ? 'yearly' : 'monthly';
23
+ const userPriceId = fingerprintContext.xSubscription.priceId;
24
+ const providerConfig = getActiveProviderConfig(config);
25
+ // 检查所有年付计划的 priceId
26
+ const yearlyPriceIds = [
27
+ providerConfig.products.free.plans.yearly.priceId,
28
+ providerConfig.products.pro.plans.yearly.priceId,
29
+ providerConfig.products.ultra.plans.yearly.priceId
30
+ ];
31
+ // 如果匹配到年付计划,返回 yearly,否则返回 monthly
32
+ if (yearlyPriceIds.includes(userPriceId)) {
33
+ return 'yearly';
34
+ }
35
+ else {
36
+ return 'monthly';
37
+ }
24
38
  }
25
39
  // 否则使用默认值
26
40
  return data.billingSwitch.defaultKey;
27
- }, [fingerprintContext, data.billingSwitch.defaultKey]);
28
- const [billingType, setBillingType] = useState(getInitialBillingType());
41
+ });
29
42
  const [isProcessing, setIsProcessing] = useState(false);
30
43
  const [tooltip, setTooltip] = useState({ show: false, content: '', x: 0, y: 0 });
31
44
  // 确定用户状态
@@ -218,19 +231,6 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
218
231
  }, []);
219
232
  // State for button portals
220
233
  const [buttonPortals, setButtonPortals] = useState([]);
221
- // 当 fingerprint context 变化时,更新 billing type 以匹配用户的订阅状态
222
- useEffect(() => {
223
- const newBillingType = getInitialBillingType();
224
- if (newBillingType !== billingType) {
225
- setBillingType(newBillingType);
226
- // 延迟执行以确保 DOM 已渲染
227
- setTimeout(() => {
228
- updatePriceDisplay(newBillingType);
229
- updateButtonStyles(newBillingType);
230
- updateDiscountInfo(newBillingType);
231
- }, 0);
232
- }
233
- }, [fingerprintContext, getInitialBillingType, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
234
234
  // 处理月付/年付切换和 tooltip 功能
235
235
  useEffect(() => {
236
236
  const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
@@ -284,10 +284,6 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
284
284
  }
285
285
  });
286
286
  });
287
- // Initial updates
288
- updatePriceDisplay(billingType);
289
- updateDiscountInfo(billingType);
290
- updateButtonStyles(billingType);
291
287
  return () => {
292
288
  if (monthlyButton) {
293
289
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -301,7 +297,28 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
301
297
  element.removeEventListener('mouseleave', handlers.mouseleave);
302
298
  });
303
299
  };
304
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
300
+ }, [data, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
301
+ // 单独的 effect 用于初始更新,只在组件挂载时执行一次
302
+ useEffect(() => {
303
+ // 直接在这里重新计算,避免闭包问题
304
+ const initialBillingType = (() => {
305
+ var _a;
306
+ if (((_a = fingerprintContext === null || fingerprintContext === void 0 ? void 0 : fingerprintContext.xSubscription) === null || _a === void 0 ? void 0 : _a.status) === 'active' && fingerprintContext.xSubscription.priceId) {
307
+ const userPriceId = fingerprintContext.xSubscription.priceId;
308
+ const providerConfig = getActiveProviderConfig(config);
309
+ const yearlyPriceIds = [
310
+ providerConfig.products.free.plans.yearly.priceId,
311
+ providerConfig.products.pro.plans.yearly.priceId,
312
+ providerConfig.products.ultra.plans.yearly.priceId
313
+ ];
314
+ return yearlyPriceIds.includes(userPriceId) ? 'yearly' : 'monthly';
315
+ }
316
+ return data.billingSwitch.defaultKey;
317
+ })();
318
+ updatePriceDisplay(initialBillingType);
319
+ updateDiscountInfo(initialBillingType);
320
+ updateButtonStyles(initialBillingType);
321
+ }, []); // 空依赖数组,只执行一次
305
322
  // Create button portals after component mounts
306
323
  useEffect(() => {
307
324
  const portals = [];
@@ -1,4 +1,4 @@
1
- import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.mjs';
1
+ import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.mjs';
2
2
  import { __require as requireLayoutBase } from '../../../layout-base@1.0.2/node_modules/layout-base/layout-base.mjs';
3
3
 
4
4
  var coseBase = coseBase$1.exports;
@@ -1,4 +1,4 @@
1
- import { __module as coseBase$1 } from '../../../../../_virtual/cose-base2.mjs';
1
+ import { __module as coseBase$1 } from '../../../../../_virtual/cose-base.mjs';
2
2
  import { __require as requireLayoutBase } from '../../../layout-base@2.0.1/node_modules/layout-base/layout-base.mjs';
3
3
 
4
4
  var coseBase = coseBase$1.exports;
@@ -1,4 +1,4 @@
1
- import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base.mjs';
1
+ import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base2.mjs';
2
2
 
3
3
  var layoutBase = layoutBase$1.exports;
4
4
 
@@ -1,4 +1,4 @@
1
- import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base2.mjs';
1
+ import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base.mjs';
2
2
 
3
3
  var layoutBase = layoutBase$1.exports;
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "7.5.3",
3
+ "version": "7.6.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -328,11 +328,6 @@ export function MoneyPriceInteractive({
328
328
  });
329
329
  });
330
330
 
331
- // Initial updates
332
- updatePriceDisplay(billingType);
333
- updateDiscountInfo(billingType);
334
- updateButtonStyles(billingType);
335
-
336
331
  return () => {
337
332
  if (monthlyButton) {
338
333
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -347,7 +342,31 @@ export function MoneyPriceInteractive({
347
342
  element.removeEventListener('mouseleave', handlers.mouseleave);
348
343
  });
349
344
  };
350
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
345
+ }, [data, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
346
+
347
+ // 单独的 effect 用于初始更新,只在组件挂载时执行一次
348
+ useEffect(() => {
349
+ // 直接在这里重新计算,避免闭包问题
350
+ const initialBillingType = (() => {
351
+ if (fingerprintContext?.xSubscription?.status === 'active' && fingerprintContext.xSubscription.priceId) {
352
+ const userPriceId = fingerprintContext.xSubscription.priceId;
353
+ const providerConfig = getActiveProviderConfig(config);
354
+
355
+ const yearlyPriceIds = [
356
+ providerConfig.products.free.plans.yearly.priceId,
357
+ providerConfig.products.pro.plans.yearly.priceId,
358
+ providerConfig.products.ultra.plans.yearly.priceId
359
+ ];
360
+
361
+ return yearlyPriceIds.includes(userPriceId) ? 'yearly' : 'monthly';
362
+ }
363
+ return data.billingSwitch.defaultKey as 'monthly' | 'yearly';
364
+ })();
365
+
366
+ updatePriceDisplay(initialBillingType);
367
+ updateDiscountInfo(initialBillingType);
368
+ updateButtonStyles(initialBillingType);
369
+ }, []); // 空依赖数组,只执行一次
351
370
 
352
371
  // Create button portals after component mounts
353
372
  useEffect(() => {