Skip to content

Fix: Add recovery dialogs for missing payment method and verification required#305

Open
sarimrmalik wants to merge 25 commits intomainfrom
fix/team-blocked-missing-payment-method
Open

Fix: Add recovery dialogs for missing payment method and verification required#305
sarimrmalik wants to merge 25 commits intomainfrom
fix/team-blocked-missing-payment-method

Conversation

@sarimrmalik
Copy link
Copy Markdown
Collaborator

@sarimrmalik sarimrmalik commented Apr 28, 2026

Ticket

Summary

  • Show an in-app blocking dialog when the active team is blocked for a missing payment method.
  • Add a billing tRPC mutation for creating payment method setup sessions and render the Stripe Payment Element in the dialog.
  • Poll team state after successful setup and close the dialog once the missing-payment-method block clears.

Test plan

  • Manually verified the diff flow against the billing-server payment methods session contract.

Images

  • When team is blocked, the dialog automatically opens
image - Clicking on banner also opens dialog image - Dialog when reason is `verification required` image

- Introduces a new `PaymentMethodsSession` interface to handle payment method sessions.
- Updates the `BillingRepository` to include a method for creating payment methods sessions.
- Implements a new `MissingPaymentMethodDialog` component to prompt users for payment method input when their team is blocked due to missing payment methods.
- Enhances the `TeamBlockageAlert` to open the payment method dialog when appropriate.
- Adds utility functions to check for missing payment method blockage reasons.

This update improves the user experience by allowing teams to add payment methods directly from the dashboard when blocked.
- Introduces a constant for the loading message in the MissingPaymentMethodDialog component to improve consistency and maintainability.
- Updates the LoadingState component to use the new constant for loading payment method messages, enhancing clarity in the user interface.
- Removes the standalone `parsePaymentMethodsSession` function and integrates its logic directly into the `getCustomerSession` method.
- Updates the API endpoint for fetching the customer session to align with the new structure.
- Enhances error handling for invalid payment methods session responses, ensuring consistent error reporting.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web Building Building Preview, Comment May 6, 2026 8:40pm
web-juliett Building Building Preview, Comment May 6, 2026 8:40pm

Request Review

@sarimrmalik sarimrmalik marked this pull request as draft April 28, 2026 18:03
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f33b1b3ba6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/features/dashboard/sidebar/missing-payment-method-dialog.tsx Outdated
- Introduces a new `capitalize` utility function for consistent string formatting.
- Updates `TeamBlockageAlert` to use the new `capitalize` function for displaying blocked reasons, improving readability.
- Replaces the deprecated `isMissingPaymentMethodBlockReason` function with a new implementation that utilizes the `capitalize` function.
- Removes the unused `team-blockage.ts` file, streamlining the codebase.
…syntax

- Changes function declarations to arrow function expressions for `MissingPaymentMethodDialog`, `MissingPaymentMethodDialogContent`, `PaymentMethodsSessionError`, `LoadingState`, `PaymentMethodsSetupElements`, and `PaymentMethodsSetupForm`.
- This update enhances consistency in the codebase and aligns with modern React practices.
…remove unused components

- Eliminates the `PaymentMethodsSessionError` component and associated error handling logic, simplifying the dialog's structure.
- Updates the `PaymentMethodsSetupForm` to remove unnecessary state variables and error messages, enhancing clarity and maintainability.
- Integrates toast notifications for error handling, improving user feedback during payment method interactions.
- Adjusts the loading state management to ensure a smoother user experience when loading payment elements.
Comment thread src/features/dashboard/sidebar/missing-payment-method-dialog.tsx Outdated
- Introduced a new `VerificationPaymentResponse` interface to handle verification payment responses.
- Updated `BillingRepository` to include a `createVerificationPayment` method for initiating verification payments.
- Implemented the `createVerificationPayment` method in the billing repository, which fetches the verification payment from the API and handles errors appropriately.
- Added a new `VerificationRequiredDialog` component to prompt users for verification payments, including loading states and error handling.
- Updated the `TeamBlockedIndicator` to open the verification dialog when the team is blocked due to verification requirements.

This change enhances the billing process by allowing teams to verify their accounts through a payment mechanism.
…ation messaging

- Updated the success toast message in the PaymentMethodsSetupForm to clarify that a payment method was added.
- Added a success toast in the VerificationPaymentForm to notify users when their team has been verified and unblocked.
- Changed the dialog title and description in the VerificationRequiredDialogContent to reflect that the team requires verification instead of the account.
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 5, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @sarimrmalik on file. You can sign our CLA at https://e2b.dev/docs/cla . Once you've signed, post a comment here that says '@cla-bot check'

@sarimrmalik sarimrmalik changed the title Fix: Add missing payment method recovery dialog Fix: Add recovery dialogs for missing payment method and verification required May 5, 2026
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 5, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @sarimrmalik on file. You can sign our CLA at https://e2b.dev/docs/cla . Once you've signed, post a comment here that says '@cla-bot check'

@sarimrmalik sarimrmalik marked this pull request as ready for review May 5, 2026 20:35
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 674fdfe68e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/features/dashboard/layouts/team-blocked-indicator.tsx Outdated
Comment thread src/features/dashboard/sidebar/missing-payment-method-dialog.tsx Outdated
Comment thread src/features/dashboard/sidebar/verification-required-dialog.tsx Outdated
…ltiple blocked reasons

- Updated the condition checks for BLOCKED_REASONS to use includes() for better flexibility in matching blocked reasons.
- Simplified the logic for determining the blocked reason dialog by utilizing Object.values() to find the appropriate reason, enhancing code readability and maintainability.
- Removed redundant assignment of hasHandledSetupIntent.current to improve code clarity.
- Ensured that setup intent parameters are set correctly when creating a payment methods session.
- Introduced useCallback for creating payment methods session to optimize performance and prevent unnecessary re-renders.
- Enhanced state management for payment methods session and loading state, improving user experience during session creation.
- Updated useEffect hooks to better handle setup intent parameters and session resets based on dialog visibility.
…ing in VerificationRequiredDialog

- Introduced a custom hook for polling team status until unblocked, improving user experience during verification.
- Enhanced payment intent handling with state management and error handling for better feedback on payment status.
- Updated component structure to manage loading states and payment intent parameters effectively.
- Improved toast notifications to provide clearer user feedback on verification payment outcomes.
Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context-gathering pass on the recovery dialogs. headline asks: extract the shared logic so the two dialogs become small adapters, and move them out of sidebar/ since they're not sidebar-specific. inline notes for the per-file items.

Comment thread src/features/dashboard/sidebar/missing-payment-method-dialog.tsx Outdated
Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probe — github 422 debug, ignore)

Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(continuation of review above — part 1)

Comment thread src/features/dashboard/sidebar/verification-required-dialog.tsx Outdated
Comment thread src/features/dashboard/sidebar/verification-required-dialog.tsx Outdated
const setupIntentClientSecret = setupIntentParams.setup_intent_client_secret

if (hasHandledSetupIntent.current) return
hasHandledSetupIntent.current = true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flipping the ref to true before the async work runs is fragile — if checkSetupIntent fails before resolving, the ref is already set and the same mount can't retry. let's flip it after the async resolves, or move to a state-machine style with explicit success/error states.

Comment thread src/features/dashboard/layouts/team-blocked-indicator.tsx
Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(continuation of review above — part 2)

import { useDashboard } from '../context'

const TEAM_UNBLOCK_POLL_ATTEMPTS = 15
const TEAM_UNBLOCK_POLL_INTERVAL_MS = 2000
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2000ms between polls feels long for an in-flight unblock check — let's drop it (e.g. 750-1000ms) so user feedback tightens up. total cap can stay roughly the same by bumping TEAM_UNBLOCK_POLL_ATTEMPTS. also: this constant is duplicated in verification-required-dialog.tsx:33 — should live in the shared module from the M1 comment.

}
}, [paymentMethodsSessionMutation.mutateAsync, team.slug])

useEffect(() => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this effect is mostly redundant — radix unmounts DialogContent on close, so the next open remounts with fresh state anyway. mutation.reset() also doesn't abort in-flight fetches. let's drop the effect, or wire an AbortController if we genuinely want to cancel pending requests.

{message.cta}
</Link>
) : (
<button
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use the <Button> primitive (e.g. variant="quaternary") instead of a raw <button> with manual cursor-pointer underline. matches the rest of the codebase.

return
}

toast({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the addon dialog tracks payment events via posthog — recovery flows don't. recovery is a high-value funnel; let's add posthog.capture('payment_method_added') here and the verification equivalent so we can see drop-off.

- Moved MissingPaymentMethodDialog and VerificationRequiredDialog to a new team-blocked directory for better organization.
- Introduced a shared recovery component to handle payment processing logic, improving code reusability.
- Enhanced state management and error handling for payment sessions, ensuring clearer user feedback during payment processes.
- Updated imports in team-blocked indicator to reflect new dialog locations, streamlining the component structure.
- Added `amount_due_cents` to the `VerificationPaymentResponse` interface for clearer payment tracking.
- Updated the `VerificationPaymentResponseSchema` to validate the new `amount_due_cents` field.
- Modified the `VerificationRequiredDialogContent` to dynamically display the payment amount, improving user clarity on verification costs.
- Introduced a new custom hook, `useSessionStorage`, for managing session storage interactions.
- Updated `TeamBlockedIndicator` to utilize session storage for tracking dismissed dialog states, improving user experience by preventing re-prompting of already dismissed dialogs.
- Refactored dialog open/close logic to streamline state management and enhance clarity in handling user interactions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants