Small onboarding fixes#1489
Conversation
…efer payment setup or connect their Stripe account directly.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR adds deferred payments setup to the onboarding wizard with action-state tracking, two setup callbacks, conditional full-page navigation for link-existing mode, test coverage updates, and Stripe cache refreshes; it also enhances analytics pie chart animations, exposes a ChangesDeferred Payments Setup in Onboarding
Analytics Chart Enhancements
Sequence DiagramsequenceDiagram
participant User
participant OnboardingWizard
participant AdminApp
participant StripeProvider
participant Browser
User->>OnboardingWizard: Click "Do Later" in payments_setup
OnboardingWizard->>OnboardingWizard: Set paymentsSetupAction="defer"
OnboardingWizard->>AdminApp: setupPayments() (US only)
AdminApp->>StripeProvider: Create deferred Stripe account
StripeProvider-->>AdminApp: Account response
AdminApp->>AdminApp: Refresh _stripeAccountInfoCache
AdminApp-->>OnboardingWizard: Return result
OnboardingWizard->>OnboardingWizard: Persist onboarding state
OnboardingWizard->>OnboardingWizard: Transition to "welcome" step
OnboardingWizard->>OnboardingWizard: Clear paymentsSetupAction
User->>OnboardingWizard: Click "Connect" in payments_setup
OnboardingWizard->>OnboardingWizard: Set paymentsSetupAction="connect"
OnboardingWizard->>AdminApp: setupPayments()
AdminApp->>StripeProvider: Create Stripe account
StripeProvider-->>AdminApp: Account with redirect URL
AdminApp->>AdminApp: Refresh _stripeAccountInfoCache
AdminApp-->>OnboardingWizard: Return result with redirect URL
OnboardingWizard->>OnboardingWizard: Validate HTTPS redirect URL
OnboardingWizard->>Browser: window.location.href to provider
Browser->>StripeProvider: Navigate to payments flow
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR makes a set of small onboarding and dashboard UI refinements, primarily around payments onboarding behavior and analytics chart presentation.
Changes:
- Refresh Stripe account info cache after
setupPayments()and improve payments onboarding actions (defer/connect) with clearer loading/disabled behavior plus new tests. - Add a
showDateRangeoption to the analytics pie chart and improve hover/center-display transitions. - Tweak dashboard overview charts (donut sizing and revenue bar rounding) and adjust post-onboarding navigation behavior for “link-existing” mode.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts | Refreshes Stripe account info cache after payments setup to keep client state in sync. |
| packages/dashboard-ui-components/src/components/analytics-chart/types.ts | Extends pie chart config with showDateRange. |
| packages/dashboard-ui-components/src/components/analytics-chart/analytics-chart-pie.tsx | Implements showDateRange and smooths pie hover/center label transitions. |
| apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/line-chart.tsx | Updates donut sizing, refines revenue tooltip marker styling, and splits revenue bars to control rounding in stacked bars. |
| apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx | Adds explicit payments action state for “Do Later” vs “Connect” flows (including deferred US Stripe account creation). |
| apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx | Adds coverage for deferred payments behavior and per-button loading/disable states. |
| apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx | Uses full page navigation on completion when in “link-existing” mode. |
Comments suppressed due to low confidence (1)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/line-chart.tsx:2492
- The tooltip marker for "Revenue" was updated to use the theme color CSS variable, but the "Refunds" marker a few lines below is still hard-coded (hsl(355,...)). This can desync the tooltip from
revenueHoverChartConfig(and won’t adapt to dark theme). Use the samevar(--color-refund_cents)approach for the refunds marker as well.
<span className="h-2 w-2 rounded-full ring-2 ring-white/20" style={{ backgroundColor: "var(--color-new_cents)" }} />
<span className="text-[11px] text-muted-foreground">Revenue</span>
<span className="ml-auto font-mono text-xs font-semibold tabular-nums text-foreground">
{formatUsdCompact(row.new_cents)}
</span>
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryThis PR makes several small onboarding fixes: it introduces per-button loading states for the payments wizard step so "Do Later" and "Connect" each show their own spinner while disabling the other, forces a full page reload on
Confidence Score: 4/5Safe to merge; all logic changes are well-tested and the payments flow handles error paths correctly. The per-action loading state pattern is correct in practice because DesignButton internally sets disabled = props.disabled || loading, so a stuck paymentsSetupAction won't allow duplicate clicks. However, setPaymentsSetupAction is set before runWithSaving starts, while its finally reset lives inside the callback — if runWithSaving ever threw before entering the callback the action state would leak. The fix is minor but makes the lifecycle symmetric with how saving is managed. project-onboarding-wizard.tsx — the setPaymentsSetupAction / runWithSaving ordering in both deferPaymentsSetup and connectPaymentsSetup. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([User on payments_setup step]) --> B{Click button}
B -->|Do Later| C[setPaymentsSetupAction 'defer']
B -->|Connect| D[setPaymentsSetupAction 'connect']
C --> E[runWithSaving starts\nsaving = true]
D --> F[runWithSaving starts\nsaving = true]
E --> G{selectedPaymentsCountry}
G -->|US| H[setupPayments\ncreates deferred account\ncache refreshed]
G -->|Other| I[skip setupPayments]
H --> J[persistOnboardingState]
I --> J
J --> K[setStatus 'welcome']
K --> L[setPaymentsSetupAction null\nsaving = false]
F --> M[setupPayments\nget redirect URL]
M --> N{protocol https?}
N -->|No| O[throw error → alert shown]
N -->|Yes| P[window.location.href = url\nredirect to Stripe]
P --> Q[finally: setPaymentsSetupAction null]
O --> Q
style H fill:#d4edda
style P fill:#cce5ff
style O fill:#f8d7da
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:380-393
The `setPaymentsSetupAction("defer")` call sits outside `runWithSaving`, while its matching reset (`setPaymentsSetupAction(null)`) lives inside the callback's `finally` block. If `runWithSaving` itself were to throw before ever entering the callback (an internal invariant break), `paymentsSetupAction` would be stuck at `"defer"` with `saving` back at `false`, leaving the "Do Later" button permanently in a loading state for that session. Moving the initial set inside `runWithSaving` — mirroring how `saving` is managed — makes the lifecycle symmetric and eliminates the leak.
```suggestion
const deferPaymentsSetup = useCallback(async () => {
await runWithSaving(async () => {
setPaymentsSetupAction("defer");
try {
if (selectedPaymentsCountry === "US") {
await props.project.app.setupPayments();
}
await persistOnboardingState();
await setStatus("welcome");
} finally {
setPaymentsSetupAction(null);
}
});
}, [persistOnboardingState, props.project.app, runWithSaving, selectedPaymentsCountry, setStatus]);
```
### Issue 2 of 2
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:395-409
Same asymmetry for `connectPaymentsSetup`: `setPaymentsSetupAction("connect")` is set before entering `runWithSaving`, but cleared inside it. Apply the same fix for consistency.
```suggestion
const connectPaymentsSetup = useCallback(async () => {
await runWithSaving(async () => {
setPaymentsSetupAction("connect");
try {
const setup = await props.project.app.setupPayments();
const redirectUrl = new URL(setup.url);
if (redirectUrl.protocol !== "https:") {
throw new Error("Payments setup redirect URL must use HTTPS.");
}
window.location.href = redirectUrl.toString();
} finally {
setPaymentsSetupAction(null);
}
});
}, [props.project.app, runWithSaving]);
```
Reviews (1): Last reviewed commit: "made the chart consistent with others" | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx (1)
929-943:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDisable both payment actions while a payment action is in-flight.
Line 929 and Line 940 keep the currently-running action button enabled. That allows repeated clicks and duplicate
setupPayments()calls.Proposed fix
- disabled={saving && paymentsSetupAction !== "defer"} + disabled={saving || paymentsSetupAction != null} loading={paymentsSetupAction === "defer"} onClick={() => runAsynchronouslyWithAlert(deferPaymentsSetup)} @@ - disabled={saving && paymentsSetupAction !== "connect"} + disabled={saving || paymentsSetupAction != null} loading={paymentsSetupAction === "connect"} onClick={() => runAsynchronouslyWithAlert(connectPaymentsSetup)}🤖 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/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx around lines 929 - 943, Both payment buttons (the DesignButton that triggers deferPaymentsSetup and the one that triggers connectPaymentsSetup) are still enabled for the currently-running action, allowing duplicate submits; change their disabled prop to disable whenever a payment action is in flight (use the existing saving flag or paymentsSetupAction !== null) and keep loading tied to the specific action. Concretely, update the primary DesignButton (onClick -> runAsynchronouslyWithAlert(deferPaymentsSetup)) and the secondary DesignButton (onClick -> runAsynchronouslyWithAlert(connectPaymentsSetup)) to use disabled={saving} (or disabled={paymentsSetupAction !== null}) and keep loading={paymentsSetupAction === "defer"} / loading={paymentsSetupAction === "connect"} respectively so no button is clickable while a payment setup is running.
🤖 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
`@packages/dashboard-ui-components/src/components/analytics-chart/analytics-chart-pie.tsx`:
- Around line 170-172: The truthy checks for hoverKey and centerDisplayKey
incorrectly treat an empty string as absent; update the conditions so activeRow
(where hoverKey is used), activeIdx, and centerDisplayRow use explicit
null/undefined checks (e.g., hoverKey !== null && hoverKey !== undefined or
hoverKey != null) before calling legendRows.find(r => r.key === hoverKey) or
r.key === centerDisplayKey so that empty-string segment keys ("") are matched
correctly; locate the usages in activeRow, activeIdx and centerDisplayRow and
replace the ternary/truthy guards with explicit null checks.
---
Outside diff comments:
In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:
- Around line 929-943: Both payment buttons (the DesignButton that triggers
deferPaymentsSetup and the one that triggers connectPaymentsSetup) are still
enabled for the currently-running action, allowing duplicate submits; change
their disabled prop to disable whenever a payment action is in flight (use the
existing saving flag or paymentsSetupAction !== null) and keep loading tied to
the specific action. Concretely, update the primary DesignButton (onClick ->
runAsynchronouslyWithAlert(deferPaymentsSetup)) and the secondary DesignButton
(onClick -> runAsynchronouslyWithAlert(connectPaymentsSetup)) to use
disabled={saving} (or disabled={paymentsSetupAction !== null}) and keep
loading={paymentsSetupAction === "defer"} / loading={paymentsSetupAction ===
"connect"} respectively so no button is clickable while a payment setup is
running.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6c2f1486-4576-476c-afd6-e6fbc192edcc
📒 Files selected for processing (7)
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsxapps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/line-chart.tsxpackages/dashboard-ui-components/src/components/analytics-chart/analytics-chart-pie.tsxpackages/dashboard-ui-components/src/components/analytics-chart/types.tspackages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
There was a problem hiding this comment.
No issues found across 7 files
Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more
Re-trigger cubic
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx (1)
395-409:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPersist the payments step state before redirecting.
selectedPaymentsCountryis part ofProjectOnboardingState, but this path skipspersistOnboardingState(). If a user switches from"OTHER"to"US"here and then comes back from Stripe without finishing, the wizard rehydrates from stale state and hides the Connect action again.💡 Suggested fix
const connectPaymentsSetup = useCallback(async () => { await runWithSaving(async () => { setPaymentsSetupAction("connect"); try { + await persistOnboardingState(); const setup = await props.project.app.setupPayments(); const redirectUrl = new URL(setup.url); if (redirectUrl.protocol !== "https:") { throw new Error("Payments setup redirect URL must use HTTPS."); } window.location.href = redirectUrl.toString(); } finally { setPaymentsSetupAction(null); } }); - }, [props.project.app, runWithSaving]); + }, [persistOnboardingState, props.project.app, runWithSaving]);🤖 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/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx around lines 395 - 409, In connectPaymentsSetup, persist the updated onboarding state (including selectedPaymentsCountry) before navigating away: after setPaymentsSetupAction("connect") and after awaiting props.project.app.setupPayments(), call persistOnboardingState() (ensuring it uses the current ProjectOnboardingState) then validate the redirect URL and set window.location.href; ensure setPaymentsSetupAction(null) still runs in the finally block. This change should be made inside the connectPaymentsSetup function and references persistOnboardingState, setPaymentsSetupAction, selectedPaymentsCountry, and props.project.app.setupPayments.
🤖 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.
Outside diff comments:
In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:
- Around line 395-409: In connectPaymentsSetup, persist the updated onboarding
state (including selectedPaymentsCountry) before navigating away: after
setPaymentsSetupAction("connect") and after awaiting
props.project.app.setupPayments(), call persistOnboardingState() (ensuring it
uses the current ProjectOnboardingState) then validate the redirect URL and set
window.location.href; ensure setPaymentsSetupAction(null) still runs in the
finally block. This change should be made inside the connectPaymentsSetup
function and references persistOnboardingState, setPaymentsSetupAction,
selectedPaymentsCountry, and props.project.app.setupPayments.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fd05a5c6-df3e-4108-b5f1-fac00a4d8303
📒 Files selected for processing (4)
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsxapps/dashboard/src/app/(main)/(protected)/projects/[projectId]/(overview)/line-chart.tsxpackages/dashboard-ui-components/src/components/analytics-chart/analytics-chart-pie.tsx
Summary by cubic
Improves onboarding and analytics visuals. Adds clear Stripe setup actions (Connect or Do Later) with safe redirects and precise loading/disabled states, and fixes a stuck dashboard reload after linking an existing project.
New Features
setupPayments()to avoid stale data on return.showDateRange; dashboard donut hides date range and adjusts radii; revenue hover chart uses split bars for rounded tops and an avg line.Bug Fixes
Written for commit c80034a. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
New Features
Improvements
Tests