diff --git a/apps/x/apps/main/src/ipc.ts b/apps/x/apps/main/src/ipc.ts index e05b57b3..ad173678 100644 --- a/apps/x/apps/main/src/ipc.ts +++ b/apps/x/apps/main/src/ipc.ts @@ -40,7 +40,7 @@ import { triggerRun as triggerAgentScheduleRun } from '@x/core/dist/agent-schedu import { search } from '@x/core/dist/search/search.js'; import { versionHistory, voice } from '@x/core'; import { classifySchedule, processRowboatInstruction } from '@x/core/dist/knowledge/inline_tasks.js'; -import { getBillingInfo } from '@x/core/dist/billing/billing.js'; +import { getBillingInfo, getBillingPortalUrl } from '@x/core/dist/billing/billing.js'; import { summarizeMeeting } from '@x/core/dist/knowledge/summarize_meeting.js'; import { getAccessToken } from '@x/core/dist/auth/tokens.js'; import { getRowboatConfig } from '@x/core/dist/config/rowboat.js'; @@ -759,5 +759,9 @@ export function setupIpcHandlers() { 'billing:getInfo': async () => { return await getBillingInfo(); }, + 'billing:getPortalUrl': async () => { + const url = await getBillingPortalUrl(); + return { url }; + }, }); } diff --git a/apps/x/apps/renderer/src/components/settings/account-settings.tsx b/apps/x/apps/renderer/src/components/settings/account-settings.tsx index 1860305d..32d732ba 100644 --- a/apps/x/apps/renderer/src/components/settings/account-settings.tsx +++ b/apps/x/apps/renderer/src/components/settings/account-settings.tsx @@ -179,8 +179,8 @@ export function AccountSettings({ dialogOpen }: AccountSettingsProps) {

Subscribe to access AI features

)} - @@ -204,7 +204,14 @@ export function AccountSettings({ dialogOpen }: AccountSettingsProps) { variant="outline" size="sm" disabled={!billing?.subscriptionPlan} - onClick={() => appUrl && window.open(appUrl)} + onClick={async () => { + try { + const { url } = await window.ipc.invoke('billing:getPortalUrl', null); + window.open(url); + } catch { + toast.error('Failed to open billing portal'); + } + }} className="gap-1.5" > diff --git a/apps/x/packages/core/src/billing/billing.ts b/apps/x/packages/core/src/billing/billing.ts index 2365364d..3e05feec 100644 --- a/apps/x/packages/core/src/billing/billing.ts +++ b/apps/x/packages/core/src/billing/billing.ts @@ -11,6 +11,19 @@ export interface BillingInfo { availableCredits: number; } +export async function getBillingPortalUrl(): Promise { + const accessToken = await getAccessToken(); + const response = await fetch(`${API_URL}/v1/billing/portal-session`, { + method: 'POST', + headers: { Authorization: `Bearer ${accessToken}` }, + }); + if (!response.ok) { + throw new Error(`Portal session failed: ${response.status}`); + } + const body = await response.json() as { url: string }; + return body.url; +} + export async function getBillingInfo(): Promise { const accessToken = await getAccessToken(); const response = await fetch(`${API_URL}/v1/me`, { diff --git a/apps/x/packages/shared/src/ipc.ts b/apps/x/packages/shared/src/ipc.ts index a8709aa2..5601f349 100644 --- a/apps/x/packages/shared/src/ipc.ts +++ b/apps/x/packages/shared/src/ipc.ts @@ -572,6 +572,12 @@ const ipcSchemas = { availableCredits: z.number(), }), }, + 'billing:getPortalUrl': { + req: z.null(), + res: z.object({ + url: z.string(), + }), + }, } as const; // ============================================================================