refactor(store): saasStore 拆分为子模块 (Phase 2B)
1025行单文件 → 5个文件 + barrel re-export: - saas/types.ts (103行) — 类型定义 - saas/shared.ts (93行) — Device ID、常量、recovery probe - saas/auth.ts (362行) — 登录/注册/登出/恢复/TOTP - saas/billing.ts (84行) — 计划/订阅/支付 - saas/index.ts (309行) — Store 组装 + 连接/模板/配置 - saasStore.ts (15行) — re-export barrel(外部零改动) 所有 25+ 消费者 import 路径不变,`tsc --noEmit` ✓
This commit is contained in:
84
desktop/src/store/saas/billing.ts
Normal file
84
desktop/src/store/saas/billing.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* SaaS Billing Slice
|
||||
*
|
||||
* Plans, subscription, and payment actions.
|
||||
*/
|
||||
|
||||
import { saasClient } from '../../lib/saas-client';
|
||||
import { createLogger } from '../../lib/logger';
|
||||
import type { SaaSStore } from './types';
|
||||
|
||||
const log = createLogger('SaaSStore:Billing');
|
||||
|
||||
type SetFn = (partial: Partial<SaaSStore> | ((state: SaaSStore) => Partial<SaaSStore>)) => void;
|
||||
type GetFn = () => SaaSStore;
|
||||
|
||||
export function createBillingSlice(set: SetFn, _get: GetFn) {
|
||||
return {
|
||||
plans: [],
|
||||
subscription: null,
|
||||
billingLoading: false,
|
||||
billingError: null,
|
||||
|
||||
fetchPlans: async () => {
|
||||
try {
|
||||
const plans = await saasClient.listPlans();
|
||||
set({ plans });
|
||||
} catch (err: unknown) {
|
||||
log.warn('Failed to fetch plans:', err);
|
||||
}
|
||||
},
|
||||
|
||||
fetchSubscription: async () => {
|
||||
try {
|
||||
const sub = await saasClient.getSubscription();
|
||||
set({ subscription: sub });
|
||||
} catch (err: unknown) {
|
||||
log.warn('Failed to fetch subscription:', err);
|
||||
set({ subscription: null });
|
||||
}
|
||||
},
|
||||
|
||||
fetchBillingOverview: async () => {
|
||||
set({ billingLoading: true, billingError: null });
|
||||
try {
|
||||
const [plans, sub] = await Promise.all([
|
||||
saasClient.listPlans(),
|
||||
saasClient.getSubscription(),
|
||||
]);
|
||||
set({ plans, subscription: sub, billingLoading: false });
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
set({ billingLoading: false, billingError: msg });
|
||||
}
|
||||
},
|
||||
|
||||
createPayment: async (planId: string, method: 'alipay' | 'wechat') => {
|
||||
set({ billingLoading: true, billingError: null });
|
||||
try {
|
||||
const result = await saasClient.createPayment({ plan_id: planId, payment_method: method });
|
||||
set({ billingLoading: false });
|
||||
return result;
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
set({ billingLoading: false, billingError: msg });
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
pollPaymentStatus: async (paymentId: string) => {
|
||||
try {
|
||||
const status = await saasClient.getPaymentStatus(paymentId);
|
||||
if (status.status === 'succeeded') {
|
||||
await _get().fetchSubscription();
|
||||
}
|
||||
return status;
|
||||
} catch (err: unknown) {
|
||||
log.warn('Failed to poll payment status:', err);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
clearBillingError: () => set({ billingError: null }),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user