feat(billing): add credits sheet to unlock gated LLM template#3240
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Sheet/Field UI primitives, a Stripe-backed Add Credits flow (amount selection, payment-method collection, 3DS/polling orchestration), onboarding LLM gating by wallet/trial state, a wallet refresh hook, unit tests, and Playwright E2E/page objects. ChangesUI Primitives: Sheet and Field Components
Payment Flow Components
Sheet Container and Onboarding Integration
Testing & Test Utilities
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3240 +/- ##
==========================================
- Coverage 66.68% 65.64% -1.05%
==========================================
Files 1065 985 -80
Lines 26123 24224 -1899
Branches 6292 5921 -371
==========================================
- Hits 17421 15901 -1520
+ Misses 7609 7257 -352
+ Partials 1093 1066 -27
*This pull request uses carry forward flags. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (3)
apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts (2)
65-81: 💤 Low valueFragile iframe selection using parent traversal.
Both
getAddressFrameandgetCardFrameuse.locator("..")to traverse up from a heading and then select.first()iframe. If the DOM structure changes (e.g., wrapper divs added) or multiple iframes exist in the parent, these selectors will break.♻️ More robust iframe selection
Consider using test IDs or more specific selectors that don't rely on DOM structure:
private getAddressFrame(): FrameLocator { // Option 1: Use iframe title/name if Stripe provides it return this.page.frameLocator('iframe[title*="billing"]').first().contentFrame(); // Option 2: Use a more specific ancestor selector return this.page .locator('[data-testid="billing-address-section"]') // if you can add test IDs .locator('iframe') .first() .contentFrame(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts` around lines 65 - 81, getAddressFrame and getCardFrame are fragile because they use .locator("..") and .first() which break if DOM wrappers or multiple iframes are added; instead select the iframe more robustly by targeting an intrinsic iframe attribute or a dedicated test hook: update getAddressFrame and getCardFrame to use frameLocator('iframe[title*="billing"]') / frameLocator('iframe[title*="payment"]') or to locate a specific ancestor with a stable data attribute (e.g., '[data-testid="billing-address-section"]' or '[data-testid="payment-method-section"]') and then select its iframe, and if necessary add those data-testid attributes in the component markup so the tests can reliably find the correct iframe without parent traversal.
25-25: 💤 Low valueHardcoded country limits address test coverage.
The method accepts
name,line1,city,state,zipfrom the caller but always selects "United States". If you later need to test international billing addresses, you'll have to modify this method.🌍 Optional: parameterize country selection
-async fillStripeAddress(input: { name: string; line1: string; city: string; state: string; zip: string }) { +async fillStripeAddress(input: { name: string; country?: string; line1: string; city: string; state: string; zip: string }) { const addressFrame = this.getAddressFrame(); const nameInput = addressFrame.getByLabel("Full name"); await nameInput.click(); await nameInput.pressSequentially(input.name); - await addressFrame.getByLabel("Country or region").selectOption("United States"); + await addressFrame.getByLabel("Country or region").selectOption(input.country ?? "United States");🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts` at line 25, The address selection is hardcoded to "United States" in AddCreditsSheetPage; update the method that fills the address (the method accepting name, line1, city, state, zip in AddCreditsSheetPage) to accept an optional country parameter (defaulting to "United States") and replace the hardcoded addressFrame.getByLabel("Country or region").selectOption("United States") with selectOption(country). Propagate the new parameter to callers/tests that need non-US addresses and leave callers that don't pass it unaffected by the default.apps/deploy-web/tests/ui/pages/OnboardingPickerPage.ts (1)
32-32: 💤 Low valueLoose button selectors risk selecting the wrong element.
Line 32 filters the card by "has any button" without specifying which button, and line 37 retrieves "any button" from the card. If the LLM card gains additional buttons (info, menu, etc.) in the future, these selectors could return the wrong container or button.
🎯 More specific button selection
getLlmChatbotCard(): Locator { const heading = this.page.getByRole("heading", { name: "LLM Chatbot", exact: true }); return this.page .locator("div") .filter({ has: heading }) - .filter({ has: this.page.getByRole("button") }) + .filter({ has: this.page.getByRole("button", { name: /deploy|unlock/i }) }) .last(); } getLlmChatbotCta(): Locator { - return this.getLlmChatbotCard().getByRole("button"); + return this.getLlmChatbotCard().getByRole("button", { name: /deploy|unlock/i }); }Also applies to: 37-37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/deploy-web/tests/ui/pages/OnboardingPickerPage.ts` at line 32, The current selector in OnboardingPickerPage uses a broad filter and retrieval via filter({ has: this.page.getByRole("button") }) and later this.page.getByRole("button"), which is fragile if cards gain extra buttons; narrow the selectors to target the exact button (e.g., use getByRole("button", { name: /choose|select|LLM name/i }) or a data-testid/aria-label) and update both the filter call and the subsequent getByRole call to use the specific accessible name or test id so you reliably select the intended card and button.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx`:
- Line 89: The form currently only checks amount <= 0 (e.g., in
AddCreditsForm.tsx at the early guard) but the UI indicates a minimum of 20;
update all validation points (the initial guard where it checks user?.id and
amount, the submit handler(s) around lines ~166 and ~222) to enforce amount >=
20 (i.e., reject if amount < 20), return early to prevent charging, and surface
a clear validation error message (e.g., "Minimum 20 credits") via the same error
state/handler the component uses so the user sees why submission was blocked.
In `@apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsx`:
- Around line 133-135: The CTA label gating uses "isTrialing || !isWalletReady"
but the CTA icon only checks "isTrialing", causing a mismatch when wallet is not
ready; update the ctaIcon prop in OnboardingPickerPage (the JSX that sets
ctaLabel and ctaIcon) to use the same condition (isTrialing || !isWalletReady)
so the icon (lock vs arrow) matches the label state.
In `@apps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.ts`:
- Around line 23-24: Update the test step description so it matches the amount
being selected: change the test.step string that currently reads "submit a $50
credit purchase with a test card" to reflect "$100" (or alternatively change
addCreditsSheet.pickPredefinedAmount("100") to "50" if you intended $50); ensure
the human-readable step text and the call to
addCreditsSheet.pickPredefinedAmount(...) are consistent.
In `@packages/ui/components/field.tsx`:
- Around line 146-155: The rendered error block currently returns an empty <ul>
when errors exists but none have a truthy message; update the logic in the
component (around the filtered variable and the errors handling in
Field/component) to check if filtered.length === 0 and return null instead of
rendering the <ul>, keeping the existing early-return for filtered.length === 1
and the mapped <li> path unchanged.
---
Nitpick comments:
In `@apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts`:
- Around line 65-81: getAddressFrame and getCardFrame are fragile because they
use .locator("..") and .first() which break if DOM wrappers or multiple iframes
are added; instead select the iframe more robustly by targeting an intrinsic
iframe attribute or a dedicated test hook: update getAddressFrame and
getCardFrame to use frameLocator('iframe[title*="billing"]') /
frameLocator('iframe[title*="payment"]') or to locate a specific ancestor with a
stable data attribute (e.g., '[data-testid="billing-address-section"]' or
'[data-testid="payment-method-section"]') and then select its iframe, and if
necessary add those data-testid attributes in the component markup so the tests
can reliably find the correct iframe without parent traversal.
- Line 25: The address selection is hardcoded to "United States" in
AddCreditsSheetPage; update the method that fills the address (the method
accepting name, line1, city, state, zip in AddCreditsSheetPage) to accept an
optional country parameter (defaulting to "United States") and replace the
hardcoded addressFrame.getByLabel("Country or region").selectOption("United
States") with selectOption(country). Propagate the new parameter to
callers/tests that need non-US addresses and leave callers that don't pass it
unaffected by the default.
In `@apps/deploy-web/tests/ui/pages/OnboardingPickerPage.ts`:
- Line 32: The current selector in OnboardingPickerPage uses a broad filter and
retrieval via filter({ has: this.page.getByRole("button") }) and later
this.page.getByRole("button"), which is fragile if cards gain extra buttons;
narrow the selectors to target the exact button (e.g., use getByRole("button", {
name: /choose|select|LLM name/i }) or a data-testid/aria-label) and update both
the filter call and the subsequent getByRole call to use the specific accessible
name or test id so you reliably select the intended card and button.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9f4077eb-18f5-4d13-8e33-8221b7440c70
📒 Files selected for processing (17)
apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsxapps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.spec.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsxapps/deploy-web/src/hooks/useEnsureTrialStarted.tsapps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.tsapps/deploy-web/tests/ui/pages/AddCreditsSheetPage.tsapps/deploy-web/tests/ui/pages/OnboardingPickerPage.tspackages/ui/components/field.tsxpackages/ui/components/index.tsxpackages/ui/components/sheet.tsx
a3d46a0 to
c08d1e7
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/deploy-web/playwright.config.ts`:
- Around line 30-33: Parse process.env.PW_SLOW_MO once to a numeric value and
use that numeric check for both the video setting and launchOptions.slowMo:
replace the current string-truthy check in the video property with a numeric
comparison (use slowMo > 0 ? "on" : "retain-on-failure") and set
launchOptions.slowMo to the parsed numeric slowMo value (instead of Number(...)
|| 0 inline) so PW_SLOW_MO="0" behaves correctly; apply these changes where the
video and launchOptions objects are defined.
In
`@apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsx`:
- Around line 322-323: Replace the unsafe double-casts by providing proper typed
mocks: change the assignment for makePaymentMethodFieldsMock (currently set to
Mock as unknown as typeof DEPENDENCIES.AddCreditsNewPaymentMethodFields) to use
a typed mock helper or explicit typed object matching typeof
DEPENDENCIES.AddCreditsNewPaymentMethodFields (e.g., mock<typeof
DEPENDENCIES.AddCreditsNewPaymentMethodFields>(...)), and similarly replace the
(...) as unknown as ReturnType<typeof DEPENDENCIES.useSetupIntentMutation>
occurrences in buildElement / useSetupIntentMutation with a properly typed mock
or variable typed as ReturnType<typeof DEPENDENCIES.useSetupIntentMutation>,
ensuring the mock implementations conform to the real types instead of
double-casting.
In `@apps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.ts`:
- Around line 41-43: The test step label claims an ordered snackbar sequence but
only asserts the final text; update the test.step block in
onboarding-picker-unlock-trial.spec.ts to either (A) assert the intermediate
states in sequence by using page.getByText("Processing…") and
page.getByText("Successful") with expects that wait for visibility then assert
they become hidden before the next appears (use toBeVisible and then
toBeHidden/timeouts to enforce order), or (B) if you only want to validate the
final state, rename the test.step description to "snackbar finishes with welcome
message" and keep the existing expect(page.getByText("Welcome to Akash!")).
Ensure you modify the test.step containing test.step(...) and the
page.getByText(...) assertions accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ba7d5b8d-0265-4e78-b2c4-221ada992dec
📒 Files selected for processing (18)
apps/deploy-web/playwright.config.tsapps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsxapps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.spec.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsxapps/deploy-web/src/hooks/useEnsureTrialStarted.tsapps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.tsapps/deploy-web/tests/ui/pages/AddCreditsSheetPage.tsapps/deploy-web/tests/ui/pages/OnboardingPickerPage.tspackages/ui/components/field.tsxpackages/ui/components/index.tsxpackages/ui/components/sheet.tsx
🚧 Files skipped from review as they are similar to previous changes (15)
- apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsx
- apps/deploy-web/tests/ui/pages/OnboardingPickerPage.ts
- apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsx
- packages/ui/components/sheet.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsx
- apps/deploy-web/src/hooks/useEnsureTrialStarted.ts
- apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsx
- apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts
- apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsx
- apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.spec.tsx
- packages/ui/components/index.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.spec.tsx
- packages/ui/components/field.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx
c08d1e7 to
a8e79c7
Compare
|
Is there a way we can avoid the redirect to the home page in between the signup and the 3 templates select in the video? |
a8e79c7 to
27389cc
Compare
…plate Introduce an Add Credits sheet (amount selection + Stripe payment method collection) and wire it into the onboarding picker so the gated LLM template prompts for a purchase before deploying.
27389cc to
00adf4d
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
apps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.ts (1)
41-45:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winOrdering is still not actually enforced, and the re-check of the processing toast is racy.
The step claims "processing → successful → welcome", but three back-to-back
toBeVisiblecalls only assert each text becomes visible at some point within its timeout — they do not prove sequence. Worse, "Processing payment..." was already asserted at Line 37; if that transient snackbar auto-dismisses before Line 42 runs, this assertion can flake. Either drop the redundant L42 re-check, or assert each prior toast becomes hidden before the next appears to genuinely validate order.📝 Suggested tightening
await test.step("snackbars appear in order: processing → successful → welcome", async () => { - await expect(page.getByText("Processing payment...")).toBeVisible({ timeout: 30_000 }); await expect(page.getByText("Payment successful!")).toBeVisible({ timeout: 30_000 }); + await expect(page.getByText("Payment successful!")).toBeHidden({ timeout: 30_000 }); await expect(page.getByText("Welcome to Akash!")).toBeVisible({ timeout: 30_000 }); });As per coding guidelines: "Verify meaningful assertions, not just snapshot coverage."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.ts` around lines 41 - 45, The step "snackbars appear in order: processing → successful → welcome" currently only calls three back-to-back await expect(page.getByText(...)).toBeVisible(...) checks which do not enforce sequence and re-checks the already-asserted "Processing payment..." (page.getByText("Processing payment...")) risk flakiness; update the test.step so it either removes the redundant re-check for "Processing payment..." or, to enforce ordering, wait for each prior toast to disappear before asserting the next (use await expect(page.getByText("Processing payment...")).toBeHidden() before checking "Payment successful!" and similarly await expect(page.getByText("Payment successful!")).toBeHidden() before checking "Welcome to Akash!"), keeping the visible checks for page.getByText("Payment successful!") and page.getByText("Welcome to Akash!") as the sequence assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@apps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.ts`:
- Around line 41-45: The step "snackbars appear in order: processing →
successful → welcome" currently only calls three back-to-back await
expect(page.getByText(...)).toBeVisible(...) checks which do not enforce
sequence and re-checks the already-asserted "Processing payment..."
(page.getByText("Processing payment...")) risk flakiness; update the test.step
so it either removes the redundant re-check for "Processing payment..." or, to
enforce ordering, wait for each prior toast to disappear before asserting the
next (use await expect(page.getByText("Processing payment...")).toBeHidden()
before checking "Payment successful!" and similarly await
expect(page.getByText("Payment successful!")).toBeHidden() before checking
"Welcome to Akash!"), keeping the visible checks for page.getByText("Payment
successful!") and page.getByText("Welcome to Akash!") as the sequence
assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 08c52f4a-c59e-465a-98c3-d2869e60bda1
📒 Files selected for processing (18)
apps/deploy-web/playwright.config.tsapps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsxapps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.spec.tsxapps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.spec.tsxapps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsxapps/deploy-web/src/hooks/useEnsureTrialStarted.tsapps/deploy-web/tests/ui/onboarding-picker-unlock-trial.spec.tsapps/deploy-web/tests/ui/pages/AddCreditsSheetPage.tsapps/deploy-web/tests/ui/pages/OnboardingPickerPage.tspackages/ui/components/field.tsxpackages/ui/components/index.tsxpackages/ui/components/sheet.tsx
✅ Files skipped from review due to trivial changes (1)
- packages/ui/components/index.tsx
🚧 Files skipped from review as they are similar to previous changes (16)
- apps/deploy-web/playwright.config.ts
- apps/deploy-web/tests/ui/pages/AddCreditsSheetPage.ts
- apps/deploy-web/tests/ui/pages/OnboardingPickerPage.ts
- apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.spec.tsx
- apps/deploy-web/src/hooks/useEnsureTrialStarted.ts
- apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsAmountFields/AddCreditsAmountFields.tsx
- apps/deploy-web/src/components/auth/AddCreditsSheet/AddCreditsSheet.spec.tsx
- apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.spec.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.tsx
- packages/ui/components/sheet.tsx
- apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsNewPaymentMethodFields/AddCreditsNewPaymentMethodFields.spec.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.tsx
- packages/ui/components/field.tsx
- apps/deploy-web/src/components/billing-usage/AddCreditsForm/AddCreditsForm.spec.tsx
Closes CON-366
Why
Onboarding gates the LLM template behind a credits purchase. This PR adds the Add Credits sheet (amount selection + Stripe payment method) and wires it into the onboarding picker so the gated CTA prompts the user to top up before they can deploy.
What
AddCreditsSheetwithAddCreditsForm(amount + new payment method fields) underapps/deploy-web/src/components/auth/AddCreditsSheet/.AddCreditsFormis built as an orchestrator/container: it owns the purchase lifecycle (setup intent, payment-method confirmation, wallet-ready wait, 3D Secure handoff, payment polling) and delegates the visible pieces to swappable children (AddCreditsAmountFields,AddCreditsNewPaymentMethodFields) via thedependenciesprop. As the new flow spreads, the same form can opt into additional sections — a saved-payment-method picker, coupon code input, transaction summary, alternative amount widgets — without reworking the orchestration layer.useEnsureTrialStartedadjusted to feed the gated state.sheet+fieldprimitives added topackages/ui/components.onboarding-picker-unlock-trial.spec.tscovers passwordless sign-in → gated CTA → $100 purchase → trial flips → CTA unlocks, plus a Page Object for the sheet.Screen.Recording.2026-05-29.at.10.11.18.1080.mov
Summary by CodeRabbit
New Features
Bug Fixes / UX
Tests