From 3bee2ee067e4c19d884607bdd37d2f07698bea89 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:41:18 +0800 Subject: [PATCH] refactor(contract): restructure console contracts with nested billing module (#30999) --- .../pricing/plans/cloud-plan-item/index.spec.tsx | 12 +++++++----- .../billing/pricing/plans/cloud-plan-item/index.tsx | 2 +- web/contract/{console.ts => console/billing.ts} | 13 ++----------- web/contract/console/system.ts | 11 +++++++++++ web/contract/router.ts | 9 ++++++--- web/service/use-billing.ts | 8 ++++---- 6 files changed, 31 insertions(+), 24 deletions(-) rename web/contract/{console.ts => console/billing.ts} (59%) create mode 100644 web/contract/console/system.ts diff --git a/web/app/components/billing/pricing/plans/cloud-plan-item/index.spec.tsx b/web/app/components/billing/pricing/plans/cloud-plan-item/index.spec.tsx index 680243a474..a7945a7203 100644 --- a/web/app/components/billing/pricing/plans/cloud-plan-item/index.spec.tsx +++ b/web/app/components/billing/pricing/plans/cloud-plan-item/index.spec.tsx @@ -27,7 +27,9 @@ vi.mock('@/service/billing', () => ({ vi.mock('@/service/client', () => ({ consoleClient: { - billingUrl: vi.fn(), + billing: { + invoices: vi.fn(), + }, }, })) @@ -43,7 +45,7 @@ vi.mock('../../assets', () => ({ const mockUseAppContext = useAppContext as Mock const mockUseAsyncWindowOpen = useAsyncWindowOpen as Mock -const mockBillingUrl = consoleClient.billingUrl as Mock +const mockBillingInvoices = consoleClient.billing.invoices as Mock const mockFetchSubscriptionUrls = fetchSubscriptionUrls as Mock const mockToastNotify = Toast.notify as Mock @@ -75,7 +77,7 @@ beforeEach(() => { vi.clearAllMocks() mockUseAppContext.mockReturnValue({ isCurrentWorkspaceManager: true }) mockUseAsyncWindowOpen.mockReturnValue(vi.fn(async open => await open())) - mockBillingUrl.mockResolvedValue({ url: 'https://billing.example' }) + mockBillingInvoices.mockResolvedValue({ url: 'https://billing.example' }) mockFetchSubscriptionUrls.mockResolvedValue({ url: 'https://subscription.example' }) assignedHref = '' }) @@ -149,7 +151,7 @@ describe('CloudPlanItem', () => { type: 'error', message: 'billing.buyPermissionDeniedTip', })) - expect(mockBillingUrl).not.toHaveBeenCalled() + expect(mockBillingInvoices).not.toHaveBeenCalled() }) it('should open billing portal when upgrading current paid plan', async () => { @@ -168,7 +170,7 @@ describe('CloudPlanItem', () => { fireEvent.click(screen.getByRole('button', { name: 'billing.plansCommon.currentPlan' })) await waitFor(() => { - expect(mockBillingUrl).toHaveBeenCalledTimes(1) + expect(mockBillingInvoices).toHaveBeenCalledTimes(1) }) expect(openWindow).toHaveBeenCalledTimes(1) }) diff --git a/web/app/components/billing/pricing/plans/cloud-plan-item/index.tsx b/web/app/components/billing/pricing/plans/cloud-plan-item/index.tsx index d9c4d3f75b..0807381bcd 100644 --- a/web/app/components/billing/pricing/plans/cloud-plan-item/index.tsx +++ b/web/app/components/billing/pricing/plans/cloud-plan-item/index.tsx @@ -77,7 +77,7 @@ const CloudPlanItem: FC = ({ try { if (isCurrentPaidPlan) { await openAsyncWindow(async () => { - const res = await consoleClient.billingUrl() + const res = await consoleClient.billing.invoices() if (res.url) return res.url throw new Error('Failed to open billing page') diff --git a/web/contract/console.ts b/web/contract/console/billing.ts similarity index 59% rename from web/contract/console.ts rename to web/contract/console/billing.ts index ec929d1357..08e1d0668f 100644 --- a/web/contract/console.ts +++ b/web/contract/console/billing.ts @@ -1,16 +1,7 @@ -import type { SystemFeatures } from '@/types/feature' import { type } from '@orpc/contract' -import { base } from './base' +import { base } from '../base' -export const systemFeaturesContract = base - .route({ - path: '/system-features', - method: 'GET', - }) - .input(type()) - .output(type()) - -export const billingUrlContract = base +export const invoicesContract = base .route({ path: '/billing/invoices', method: 'GET', diff --git a/web/contract/console/system.ts b/web/contract/console/system.ts new file mode 100644 index 0000000000..bce0a8226e --- /dev/null +++ b/web/contract/console/system.ts @@ -0,0 +1,11 @@ +import type { SystemFeatures } from '@/types/feature' +import { type } from '@orpc/contract' +import { base } from '../base' + +export const systemFeaturesContract = base + .route({ + path: '/system-features', + method: 'GET', + }) + .input(type()) + .output(type()) diff --git a/web/contract/router.ts b/web/contract/router.ts index d83cffb7b8..b1c100ab08 100644 --- a/web/contract/router.ts +++ b/web/contract/router.ts @@ -1,5 +1,6 @@ import type { InferContractRouterInputs } from '@orpc/contract' -import { billingUrlContract, bindPartnerStackContract, systemFeaturesContract } from './console' +import { bindPartnerStackContract, invoicesContract } from './console/billing' +import { systemFeaturesContract } from './console/system' import { collectionPluginsContract, collectionsContract, searchAdvancedContract } from './marketplace' export const marketplaceRouterContract = { @@ -12,8 +13,10 @@ export type MarketPlaceInputs = InferContractRouterInputs diff --git a/web/service/use-billing.ts b/web/service/use-billing.ts index 794b192d5c..84af077656 100644 --- a/web/service/use-billing.ts +++ b/web/service/use-billing.ts @@ -3,8 +3,8 @@ import { consoleClient, consoleQuery } from '@/service/client' export const useBindPartnerStackInfo = () => { return useMutation({ - mutationKey: consoleQuery.bindPartnerStack.mutationKey(), - mutationFn: (data: { partnerKey: string, clickId: string }) => consoleClient.bindPartnerStack({ + mutationKey: consoleQuery.billing.bindPartnerStack.mutationKey(), + mutationFn: (data: { partnerKey: string, clickId: string }) => consoleClient.billing.bindPartnerStack({ params: { partnerKey: data.partnerKey }, body: { click_id: data.clickId }, }), @@ -13,10 +13,10 @@ export const useBindPartnerStackInfo = () => { export const useBillingUrl = (enabled: boolean) => { return useQuery({ - queryKey: consoleQuery.billingUrl.queryKey(), + queryKey: consoleQuery.billing.invoices.queryKey(), enabled, queryFn: async () => { - const res = await consoleClient.billingUrl() + const res = await consoleClient.billing.invoices() return res.url }, })