feat(billing) - facilitate top up in ai chat (#21645)
Today, when a trialing user hits their AI usage cap inside the Ask AI chat, ending the trial bounces them to the Stripe billing portal (and, for card-less users, loses their place in the conversation). This PR makes activating a paid plan / topping up credits feel seamless from within the chat: Trial users with a card on file activate their subscription in place, without leaving the app. Trial users without a card are sent to the Stripe payment-method portal and, on return, the trial is ended automatically and they're dropped back into the exact Ask AI thread they came from. Credit-exhaustion and trial banners now reflect whether a payment method exists (Add Credit Card vs Subscribe Now / End Trial Period) and upgrade inline via a confirmation modal instead of redirecting to Settings. Uploading Screen Recording 2026-06-16 at 07.51.12.mov… https://github.com/user-attachments/assets/4ea77273-da63-4b32-b6f1-5ac9e9560651 <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21645?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -964,6 +964,7 @@ type Workspace {
|
||||
billingSubscriptions: [BillingSubscription!]!
|
||||
installedApplications: [Application!]!
|
||||
currentBillingSubscription: BillingSubscription
|
||||
billingCustomer: BillingCustomer
|
||||
billingEntitlements: [BillingEntitlement!]!
|
||||
hasValidSignedEnterpriseKey: Boolean!
|
||||
hasValidEnterpriseValidityToken: Boolean!
|
||||
@@ -1554,6 +1555,11 @@ type BillingSubscriptionItem {
|
||||
billingProduct: BillingProductDTO!
|
||||
}
|
||||
|
||||
type BillingCustomer {
|
||||
id: UUID!
|
||||
hasPaymentMethod: Boolean
|
||||
}
|
||||
|
||||
type BillingSubscription {
|
||||
id: UUID!
|
||||
status: SubscriptionStatus!
|
||||
@@ -3029,7 +3035,7 @@ type Query {
|
||||
apiKey(input: GetApiKeyInput!): ApiKey
|
||||
getInviteSuggestions: [InviteSuggestion!]!
|
||||
applicationConnectionProviders(applicationId: UUID!): [ApplicationConnectionProvider!]!
|
||||
billingPortalSession(returnUrlPath: String): BillingSession!
|
||||
billingPortalSession(returnUrlPath: String, forPaymentMethodUpdate: Boolean): BillingSession!
|
||||
listPlans: [BillingPlan!]!
|
||||
getResourceCreditUsage: [BillingResourceCreditUsage!]!
|
||||
findWorkspaceInvitations: [WorkspaceInvitation!]!
|
||||
|
||||
@@ -682,6 +682,7 @@ export interface Workspace {
|
||||
billingSubscriptions: BillingSubscription[]
|
||||
installedApplications: Application[]
|
||||
currentBillingSubscription?: BillingSubscription
|
||||
billingCustomer?: BillingCustomer
|
||||
billingEntitlements: BillingEntitlement[]
|
||||
hasValidSignedEnterpriseKey: Scalars['Boolean']
|
||||
hasValidEnterpriseValidityToken: Scalars['Boolean']
|
||||
@@ -1212,6 +1213,12 @@ export interface BillingSubscriptionItem {
|
||||
__typename: 'BillingSubscriptionItem'
|
||||
}
|
||||
|
||||
export interface BillingCustomer {
|
||||
id: Scalars['UUID']
|
||||
hasPaymentMethod?: Scalars['Boolean']
|
||||
__typename: 'BillingCustomer'
|
||||
}
|
||||
|
||||
export interface BillingSubscription {
|
||||
id: Scalars['UUID']
|
||||
status: SubscriptionStatus
|
||||
@@ -3691,6 +3698,7 @@ export interface WorkspaceGenqlSelection{
|
||||
billingSubscriptions?: BillingSubscriptionGenqlSelection
|
||||
installedApplications?: ApplicationGenqlSelection
|
||||
currentBillingSubscription?: BillingSubscriptionGenqlSelection
|
||||
billingCustomer?: BillingCustomerGenqlSelection
|
||||
billingEntitlements?: BillingEntitlementGenqlSelection
|
||||
hasValidSignedEnterpriseKey?: boolean | number
|
||||
hasValidEnterpriseValidityToken?: boolean | number
|
||||
@@ -4246,6 +4254,13 @@ export interface BillingSubscriptionItemGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingCustomerGenqlSelection{
|
||||
id?: boolean | number
|
||||
hasPaymentMethod?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingSubscriptionGenqlSelection{
|
||||
id?: boolean | number
|
||||
status?: boolean | number
|
||||
@@ -5782,7 +5797,7 @@ export interface QueryGenqlSelection{
|
||||
apiKey?: (ApiKeyGenqlSelection & { __args: {input: GetApiKeyInput} })
|
||||
getInviteSuggestions?: InviteSuggestionGenqlSelection
|
||||
applicationConnectionProviders?: (ApplicationConnectionProviderGenqlSelection & { __args: {applicationId: Scalars['UUID']} })
|
||||
billingPortalSession?: (BillingSessionGenqlSelection & { __args?: {returnUrlPath?: (Scalars['String'] | null)} })
|
||||
billingPortalSession?: (BillingSessionGenqlSelection & { __args?: {returnUrlPath?: (Scalars['String'] | null), forPaymentMethodUpdate?: (Scalars['Boolean'] | null)} })
|
||||
listPlans?: BillingPlanGenqlSelection
|
||||
getResourceCreditUsage?: BillingResourceCreditUsageGenqlSelection
|
||||
findWorkspaceInvitations?: WorkspaceInvitationGenqlSelection
|
||||
@@ -7272,6 +7287,14 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const BillingCustomer_possibleTypes: string[] = ['BillingCustomer']
|
||||
export const isBillingCustomer = (obj?: { __typename?: any } | null): obj is BillingCustomer => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingCustomer"')
|
||||
return BillingCustomer_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BillingSubscription_possibleTypes: string[] = ['BillingSubscription']
|
||||
export const isBillingSubscription = (obj?: { __typename?: any } | null): obj is BillingSubscription => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingSubscription"')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user