refactor(contract): restructure console contracts with nested billing module (#30999)

This commit is contained in:
yyh 2026-01-15 10:41:18 +08:00 committed by GitHub
parent 328897f81c
commit 3bee2ee067
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 31 additions and 24 deletions

View File

@ -27,7 +27,9 @@ vi.mock('@/service/billing', () => ({
vi.mock('@/service/client', () => ({ vi.mock('@/service/client', () => ({
consoleClient: { consoleClient: {
billingUrl: vi.fn(), billing: {
invoices: vi.fn(),
},
}, },
})) }))
@ -43,7 +45,7 @@ vi.mock('../../assets', () => ({
const mockUseAppContext = useAppContext as Mock const mockUseAppContext = useAppContext as Mock
const mockUseAsyncWindowOpen = useAsyncWindowOpen 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 mockFetchSubscriptionUrls = fetchSubscriptionUrls as Mock
const mockToastNotify = Toast.notify as Mock const mockToastNotify = Toast.notify as Mock
@ -75,7 +77,7 @@ beforeEach(() => {
vi.clearAllMocks() vi.clearAllMocks()
mockUseAppContext.mockReturnValue({ isCurrentWorkspaceManager: true }) mockUseAppContext.mockReturnValue({ isCurrentWorkspaceManager: true })
mockUseAsyncWindowOpen.mockReturnValue(vi.fn(async open => await open())) 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' }) mockFetchSubscriptionUrls.mockResolvedValue({ url: 'https://subscription.example' })
assignedHref = '' assignedHref = ''
}) })
@ -149,7 +151,7 @@ describe('CloudPlanItem', () => {
type: 'error', type: 'error',
message: 'billing.buyPermissionDeniedTip', message: 'billing.buyPermissionDeniedTip',
})) }))
expect(mockBillingUrl).not.toHaveBeenCalled() expect(mockBillingInvoices).not.toHaveBeenCalled()
}) })
it('should open billing portal when upgrading current paid plan', async () => { 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' })) fireEvent.click(screen.getByRole('button', { name: 'billing.plansCommon.currentPlan' }))
await waitFor(() => { await waitFor(() => {
expect(mockBillingUrl).toHaveBeenCalledTimes(1) expect(mockBillingInvoices).toHaveBeenCalledTimes(1)
}) })
expect(openWindow).toHaveBeenCalledTimes(1) expect(openWindow).toHaveBeenCalledTimes(1)
}) })

View File

@ -77,7 +77,7 @@ const CloudPlanItem: FC<CloudPlanItemProps> = ({
try { try {
if (isCurrentPaidPlan) { if (isCurrentPaidPlan) {
await openAsyncWindow(async () => { await openAsyncWindow(async () => {
const res = await consoleClient.billingUrl() const res = await consoleClient.billing.invoices()
if (res.url) if (res.url)
return res.url return res.url
throw new Error('Failed to open billing page') throw new Error('Failed to open billing page')

View File

@ -1,16 +1,7 @@
import type { SystemFeatures } from '@/types/feature'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from './base' import { base } from '../base'
export const systemFeaturesContract = base export const invoicesContract = base
.route({
path: '/system-features',
method: 'GET',
})
.input(type<unknown>())
.output(type<SystemFeatures>())
export const billingUrlContract = base
.route({ .route({
path: '/billing/invoices', path: '/billing/invoices',
method: 'GET', method: 'GET',

View File

@ -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<unknown>())
.output(type<SystemFeatures>())

View File

@ -1,5 +1,6 @@
import type { InferContractRouterInputs } from '@orpc/contract' 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' import { collectionPluginsContract, collectionsContract, searchAdvancedContract } from './marketplace'
export const marketplaceRouterContract = { export const marketplaceRouterContract = {
@ -12,8 +13,10 @@ export type MarketPlaceInputs = InferContractRouterInputs<typeof marketplaceRout
export const consoleRouterContract = { export const consoleRouterContract = {
systemFeatures: systemFeaturesContract, systemFeatures: systemFeaturesContract,
billingUrl: billingUrlContract, billing: {
bindPartnerStack: bindPartnerStackContract, invoices: invoicesContract,
bindPartnerStack: bindPartnerStackContract,
},
} }
export type ConsoleInputs = InferContractRouterInputs<typeof consoleRouterContract> export type ConsoleInputs = InferContractRouterInputs<typeof consoleRouterContract>

View File

@ -3,8 +3,8 @@ import { consoleClient, consoleQuery } from '@/service/client'
export const useBindPartnerStackInfo = () => { export const useBindPartnerStackInfo = () => {
return useMutation({ return useMutation({
mutationKey: consoleQuery.bindPartnerStack.mutationKey(), mutationKey: consoleQuery.billing.bindPartnerStack.mutationKey(),
mutationFn: (data: { partnerKey: string, clickId: string }) => consoleClient.bindPartnerStack({ mutationFn: (data: { partnerKey: string, clickId: string }) => consoleClient.billing.bindPartnerStack({
params: { partnerKey: data.partnerKey }, params: { partnerKey: data.partnerKey },
body: { click_id: data.clickId }, body: { click_id: data.clickId },
}), }),
@ -13,10 +13,10 @@ export const useBindPartnerStackInfo = () => {
export const useBillingUrl = (enabled: boolean) => { export const useBillingUrl = (enabled: boolean) => {
return useQuery({ return useQuery({
queryKey: consoleQuery.billingUrl.queryKey(), queryKey: consoleQuery.billing.invoices.queryKey(),
enabled, enabled,
queryFn: async () => { queryFn: async () => {
const res = await consoleClient.billingUrl() const res = await consoleClient.billing.invoices()
return res.url return res.url
}, },
}) })