-
Notifications
You must be signed in to change notification settings - Fork 543
[Dashboard] Add crypto top-up functionality for account credits #7239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Dashboard] Add crypto top-up functionality for account credits #7239
Conversation
|
WalkthroughThe changes introduce new Stripe-related actions for retrieving customer and balance information, add a crypto top-up URL utility, and refactor the billing page to use modular components. A new credit balance section with top-up functionality is implemented, and the legacy Billing component is removed. Checkout logic is updated to support crypto top-ups. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant BillingPage
participant CreditBalanceSection
participant StripeActions
participant StripeAPI
User->>BillingPage: Loads billing page
BillingPage->>CreditBalanceSection: Renders with teamSlug and balancePromise
CreditBalanceSection->>StripeActions: Calls getStripeBalance(team.stripeCustomerId)
StripeActions->>StripeAPI: Fetch Stripe customer by ID
StripeAPI-->>StripeActions: Returns customer object
StripeActions-->>CreditBalanceSection: Returns customer balance
CreditBalanceSection-->>User: Displays balance and top-up UI
User->>CreditBalanceSection: Selects top-up amount and clicks Top Up
CreditBalanceSection->>BillingPage: Navigates to /checkout/[team_slug]/topup?amount=X
BillingPage->>CheckoutPage: Loads with team_slug, sku=topup, searchParams.amount
CheckoutPage->>BillingUtils: Calls getCryptoTopupUrl({ teamSlug, amountUSD })
BillingUtils->>API: POST /v1/teams/{teamSlug}/checkout/crypto-top-up
API-->>BillingUtils: Returns { result: url }
BillingUtils-->>CheckoutPage: Returns crypto top-up URL
CheckoutPage-->>User: Redirects to crypto top-up URL
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (5)
⏰ Context from checks skipped due to timeout of 90000ms (7)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7239 +/- ##
=======================================
Coverage 55.57% 55.57%
=======================================
Files 909 909
Lines 58681 58681
Branches 4167 4167
=======================================
Hits 32612 32612
Misses 25961 25961
Partials 108 108
🚀 New features to boost your workflow:
|
907f19a
to
ce3f201
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 6
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx (1)
134-139
: Currency formatting function could be extracted to a shared utility.The
formatUsd
function is simple and correct, but consider extracting it to a shared utility module for reusability across the application.-function formatUsd(amount: number) { - return amount.toLocaleString("en-US", { - style: "currency", - currency: "USD", - }); -}Consider moving this to a shared utility file like
utils/currency.ts
:export function formatUsd(amount: number): string { return amount.toLocaleString("en-US", { style: "currency", currency: "USD", }); }
🛑 Comments failed to post (6)
apps/dashboard/src/@/actions/stripe-actions.ts (2)
67-73: 🛠️ Refactor suggestion
Improve error handling and type safety.
The
getStripeBalance
function could benefit from better error handling and should handle the case wheregetStripeCustomer
might throw an error.export async function getStripeBalance(customerId: string) { - const customer = await getStripeCustomer(customerId); - if (customer.deleted) { - return 0; - } - return customer.balance; + try { + const customer = await getStripeCustomer(customerId); + if (customer.deleted) { + return 0; + } + return customer.balance || 0; + } catch (error) { + console.error("Error fetching customer balance:", error); + return 0; // Return 0 balance as fallback + } }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.export async function getStripeBalance(customerId: string) { try { const customer = await getStripeCustomer(customerId); if (customer.deleted) { return 0; } return customer.balance || 0; } catch (error) { console.error("Error fetching customer balance:", error); return 0; // Return 0 balance as fallback } }
🤖 Prompt for AI Agents
In apps/dashboard/src/@/actions/stripe-actions.ts around lines 67 to 73, the getStripeBalance function lacks error handling for potential exceptions thrown by getStripeCustomer. Wrap the call to getStripeCustomer in a try-catch block to handle errors gracefully, and ensure the function returns a default value or propagates the error appropriately. Additionally, add type checks to confirm the customer object and its properties exist before accessing them to improve type safety.
63-65: 🛠️ Refactor suggestion
Add error handling for missing customers.
The
getStripeCustomer
function lacks error handling for cases where the customer doesn't exist, which could cause unhandled exceptions. Consider implementing similar error handling as seen ingetTeamInvoices
(lines 49-57).-async function getStripeCustomer(customerId: string) { - return await getStripe().customers.retrieve(customerId); -} +async function getStripeCustomer(customerId: string) { + try { + return await getStripe().customers.retrieve(customerId); + } catch (error) { + if ( + error instanceof Stripe.errors.StripeError && + error.message.includes("No such customer") + ) { + return { deleted: true, balance: 0 }; + } + throw error; + } +}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.async function getStripeCustomer(customerId: string) { try { return await getStripe().customers.retrieve(customerId); } catch (error) { if ( error instanceof Stripe.errors.StripeError && error.message.includes("No such customer") ) { return { deleted: true, balance: 0 }; } throw error; } }
🤖 Prompt for AI Agents
In apps/dashboard/src/@/actions/stripe-actions.ts around lines 63 to 65, the getStripeCustomer function does not handle errors when a customer is missing, potentially causing unhandled exceptions. Add error handling similar to getTeamInvoices by catching errors from the Stripe API call, checking if the error indicates a missing customer, and returning null or an appropriate fallback value instead of throwing. Ensure other errors are rethrown or handled properly.
apps/dashboard/src/components/settings/Account/Billing/index.tsx (1)
43-43: 💡 Verification agent
🧩 Analysis chain
Hardcoded balance may not reflect actual credit balance.
The
currentBalance={0}
appears to be hardcoded rather than using the actual Stripe balance. With the newgetStripeBalance
function available instripe-actions.ts
, this should ideally display the real balance.Is this hardcoded value intentional for this component, or should it fetch the actual balance using
getStripeBalance
?
🏁 Script executed:
#!/bin/bash # Description: Check if this billing component is used elsewhere or if there's a pattern for balance retrieval # Search for other usage of CreditTopupSection to see how currentBalance is typically handled rg -A 3 -B 3 "CreditTopupSection.*currentBalance" # Search for usage of getStripeBalance to see the pattern rg -A 5 "getStripeBalance"Length of output: 2699
🏁 Script executed:
#!/bin/bash set -e # Display first 30 lines of the Billing index component to inspect import path echo "----- index.tsx (first 30 lines) -----" sed -n '1,30p' apps/dashboard/src/components/settings/Account/Billing/index.tsx # List all files in the Billing component directory echo "----- Files in Billing directory -----" ls apps/dashboard/src/components/settings/Account/Billing # Locate and display the implementation of CreditTopupSection file=$(fd CreditTopupSection -t f apps/dashboard/src/components/settings/Account/Billing) echo "----- Implementation file: $file -----" sed -n '1,200p' "$file"Length of output: 1856
🏁 Script executed:
#!/bin/bash set -e echo "Searching for the Topup section component file..." fd top-up-section.client.tsx -t f echo "Looking for any references to CreditTopupSection across the repo..." rg -n "CreditTopupSection" --glob '*.ts*' file=$(fd top-up-section.client.tsx -t f) if [[ -n "$file" ]]; then echo "----- Displaying first 200 lines of $file -----" sed -n '1,200p' "$file" else echo "Component file not found; please verify its path manually." exit 1 fiLength of output: 7012
Replace hardcoded balance with real Stripe balance.
The
currentBalance={0}
in apps/dashboard/src/components/settings/Account/Billing/index.tsx (line 43) should be driven by the customer’s actual Stripe balance rather than a constant zero. You can import and call the existing getStripeBalance function (from@/actions/stripe-actions
) usingteam.stripeCustomerId
and pass its result intoCreditTopupSection
.—for example—
import CreditTopupSection from ".../top-up-section.client"; + import { getStripeBalance } from "@/actions/stripe-actions"; … export const Billing: React.FC<BillingProps> = ({ team, … }) => { - return ( - <CreditTopupSection currentBalance={0} teamSlug={team.slug} /> - ); + const [balance, setBalance] = useState<number>(0); + + useEffect(() => { + if (team.stripeCustomerId) { + getStripeBalance(team.stripeCustomerId).then(setBalance); + } + }, [team.stripeCustomerId]); + + return ( + <CreditTopupSection + currentBalance={balance} + teamSlug={team.slug} + /> + ); };This ensures your UI reflects the user’s real credit balance.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/dashboard/src/components/settings/Account/Billing/index.tsx at line 43, replace the hardcoded currentBalance={0} with the actual Stripe balance. Import the getStripeBalance function from '@/actions/stripe-actions', call it with team.stripeCustomerId to fetch the real balance asynchronously, and pass the retrieved balance as the currentBalance prop to CreditTopupSection. Ensure this data fetching is done appropriately (e.g., in a useEffect or server-side) so the UI reflects the user's real credit balance.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx (2)
51-59: 💡 Verification agent
🧩 Analysis chain
Verify currency formatting behavior for edge cases.
The current balance display looks good, but the
formatUsd
function should handle edge cases properly.
🏁 Script executed:
#!/bin/bash # Search for other usages of currency formatting in the codebase to ensure consistency rg -A 3 -B 3 "toLocaleString.*currency.*USD"Length of output: 46
Let's locate the
formatUsd
implementation to verify how it handles edge cases (e.g., null/undefined, negatives, zero, large values):
🏁 Script executed:
#!/bin/bash # Find all references and the definition of formatUsd rg -n "formatUsd" -C 3Length of output: 3961
🏁 Script executed:
#!/bin/bash # Retrieve the full formatUsd function to inspect edge case handling rg -C 10 "function formatUsd" .Length of output: 2117
🏁 Script executed:
#!/bin/bash # Locate currentBalance definition and its type within the component rg -n "currentBalance" -C 5 apps/dashboard/src/app/\(app\)/team/\[team_slug\]/\(team\)/\~/settings/billing/components/top-up-section.client.tsxLength of output: 1446
Ensure
formatUsd
Handles Non-finite Values and Consistent DecimalsThe
formatUsd
helper at
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx:134-137
currently does:function formatUsd(amount: number) { return amount.toLocaleString("en-US", { style: "currency", currency: "USD", }); }While
toLocaleString
will format positive, zero, and negative numbers correctly, it will render"NaN"
ifamount
is not finite and may omit explicit control over decimal places. To guard edge cases, consider adding:
- A check for non-finite inputs (e.g.
!isFinite(amount)
) with a fallback ("$0.00"
or an empty state).- Explicit
minimumFractionDigits: 2
andmaximumFractionDigits: 2
to ensure exactly two decimal places.Suggested update:
function formatUsd(amount: number) { if (!isFinite(amount)) return "$0.00"; return amount.toLocaleString("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 2, }); }🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx around lines 134 to 137, the formatUsd function does not handle non-finite values and lacks explicit decimal formatting. Update formatUsd to check if the input amount is finite, returning "$0.00" if not, and add minimumFractionDigits and maximumFractionDigits set to 2 in the toLocaleString options to ensure consistent two-decimal formatting.
117-127: 💡 Verification agent
🧩 Analysis chain
Consider security implications of opening checkout in new tab.
Opening the checkout in a new tab with
target="_blank"
withoutrel="noopener noreferrer"
could pose security risks. Next.js Link component handles this automatically, but it's worth verifying.
🏁 Script executed:
#!/bin/bash # Check if Next.js Link component automatically adds security attributes rg -A 5 -B 5 "target.*_blank" --type tsx --type tsLength of output: 80
🏁 Script executed:
#!/bin/bash # Search for any target="_blank" usage in TSX files rg 'target="_blank"' -g '*.tsx' -A5 -B5 # Ensure the Link component is imported from Next.js rg "import .*Link from ['\"]next/link['\"]" -g '*.tsx' # Look for any rel attributes alongside links rg 'rel=' -g '*.tsx' -A2 -B2Length of output: 66732
🏁 Script executed:
#!/bin/bash # Locate the exact path of top-up-section.client.tsx find apps/dashboard/src/app -type f | rg 'top-up-section.client.tsx' # Show how Link is imported in that file find apps/dashboard/src/app -type f | rg 'top-up-section.client.tsx' -print0 | xargs -0 rg -n '^import Link' # Show the Link element around target="_blank" find apps/dashboard/src/app -type f | rg 'top-up-section.client.tsx' -print0 | xargs -0 rg -n 'target="_blank"' -A2 -B2Length of output: 672
Add missing rel="noopener noreferrer" to the new-tab Link
Next.js’ Link passes props through to the underlying
<a>
, but it does not automatically injectrel="noopener noreferrer"
. Without it, your checkout page opened in a new tab can accesswindow.opener
.Please update in
• apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
lines 117–127Suggested diff:
<Button asChild className="w-full" size="lg"> <Link href={`/checkout/${teamSlug}/topup?amount=${selectedAmount}`} prefetch={false} target="_blank" + rel="noopener noreferrer" > Top Up Credits <ArrowRightIcon className="ml-2 h-4 w-4" /> </Link> </Button>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.<Button asChild className="w-full" size="lg"> <Link href={`/checkout/${teamSlug}/topup?amount=${selectedAmount}`} prefetch={false} target="_blank" rel="noopener noreferrer" > Top Up Credits <ArrowRightIcon className="ml-2 h-4 w-4" /> </Link> </Button>
🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx around lines 117 to 127, the Link component opens the checkout page in a new tab using target="_blank" but is missing the rel="noopener noreferrer" attribute. To fix this, add rel="noopener noreferrer" to the Link component to prevent the new page from accessing window.opener and mitigate security risks.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx (1)
78-78: 🛠️ Refactor suggestion
Consider edge case handling for balance calculation.
The balance calculation handles the zero case explicitly, but consider what happens if
stripeBalance
is undefined or null from the API call.- currentBalance={stripeBalance === 0 ? 0 : stripeBalance / -100} + currentBalance={stripeBalance ? stripeBalance / -100 : 0}This change handles potential undefined/null values more robustly.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.currentBalance={stripeBalance ? stripeBalance / -100 : 0}
🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx at line 78, the currentBalance calculation only explicitly handles zero but does not account for stripeBalance being undefined or null. Update the expression to first check if stripeBalance is a valid number before performing the division, and provide a sensible default (such as 0) if it is undefined or null to avoid runtime errors and ensure robust handling of API response edge cases.
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx (1)
75-80
: Simplify balance calculation logic.The conditional check
stripeBalance === 0 ? 0 : stripeBalance / -100
is redundant since0 / -100 = 0
. The division and negation will handle the zero case correctly.- currentBalance={stripeBalance === 0 ? 0 : stripeBalance / -100} + currentBalance={stripeBalance / -100}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/dashboard/src/@/actions/stripe-actions.ts
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
(3 hunks)apps/dashboard/src/components/settings/Account/Billing/index.tsx
(0 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/components/settings/Account/Billing/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/dashboard/src/@/actions/stripe-actions.ts
- apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
- apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx (3)
1-1
: LGTM: New stripe balance action imported.The import of
getStripeBalance
aligns with the new credit top-up functionality.
6-11
: LGTM: Modular component imports support the refactor.The imports show a clear move from a monolithic
Billing
component to modular components (CreditsInfoCard
,Coupons
,PlanInfoCardClient
,CreditTopupSection
), which improves maintainability.
65-88
: LGTM: Well-structured component composition.The modular approach with clear separation of concerns between plan info, credit top-up, credits info, and coupons improves code organization and maintainability. The prop passing is clean and follows React best practices.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
Show resolved
Hide resolved
ce3f201
to
36b32b9
Compare
36b32b9
to
4d4ac67
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx (2)
20-25
: Consider making predefined amounts configurable.The hard-coded amounts limit flexibility for different markets or customer tiers.
Consider accepting predefined amounts as a prop or loading them from configuration:
+interface PredefinedAmount { + value: string; + label: string; +} + -const predefinedAmounts = [ - { value: "25", label: "$25" }, - { value: "100", label: "$100" }, - { value: "500", label: "$500" }, - { value: "1000", label: "$1,000" }, -] as const; +const defaultPredefinedAmounts: PredefinedAmount[] = [ + { value: "25", label: "$25" }, + { value: "100", label: "$100" }, + { value: "500", label: "$500" }, + { value: "1000", label: "$1,000" }, +]; interface CreditBalanceSectionProps { balancePromise: Promise<number>; teamSlug: string; + predefinedAmounts?: PredefinedAmount[]; }
116-126
: Add loading state for checkout navigation.Consider adding a loading state when the checkout link is clicked to improve UX.
+ const [isNavigating, setIsNavigating] = useState(false); + + const handleCheckoutClick = () => { + setIsNavigating(true); + // The navigation will happen via the Link component + }; - <Button asChild className="w-full" size="lg"> + <Button + asChild + className="w-full" + size="lg" + disabled={isNavigating} + > <Link href={`/checkout/${teamSlug}/topup?amount=${selectedAmount}`} prefetch={false} target="_blank" + onClick={handleCheckoutClick} > - Top Up Credits + {isNavigating ? "Redirecting..." : "Top Up Credits"} <ArrowRightIcon className="ml-2 h-4 w-4" /> </Link> </Button>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/dashboard/src/@/actions/stripe-actions.ts
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
- apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
- apps/dashboard/src/@/actions/stripe-actions.ts
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Build Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx (1)
241-246
: LGTM! Clean utility function.The formatUsd utility function is well-implemented and handles currency formatting correctly.
...rc/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
Outdated
Show resolved
Hide resolved
...rc/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
Outdated
Show resolved
Hide resolved
...rc/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
Outdated
Show resolved
Hide resolved
...rc/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/top-up-section.client.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/dashboard/src/@/actions/stripe-actions.ts
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/credit-balance-section.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
(3 hunks)apps/dashboard/src/components/settings/Account/Billing/index.tsx
(0 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/components/settings/Account/Billing/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx
- apps/dashboard/src/@/actions/stripe-actions.ts
- apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
- apps/dashboard/src/app/(app)/(stripe)/checkout/[team_slug]/[sku]/page.tsx
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/credit-balance-section.client.tsx (3)
27-131
: Excellent component structure and React patterns.The implementation demonstrates good practices:
- Proper use of Suspense and ErrorBoundary for async operations
- Well-structured accessibility with radio group and labels
- Appropriate use of
target="_blank"
for checkout flow- Clean separation of concerns with helper components
133-172
: Well-implemented async data handling.The current balance components properly handle loading and error states with consistent UI patterns and user-friendly messaging.
240-246
: Clean utility function implementation.The USD formatting function correctly uses the standard browser API with proper locale and currency settings.
...app)/team/[team_slug]/(team)/~/settings/billing/components/credit-balance-section.client.tsx
Outdated
Show resolved
Hide resolved
...app)/team/[team_slug]/(team)/~/settings/billing/components/credit-balance-section.client.tsx
Outdated
Show resolved
Hide resolved
4d4ac67
to
d04a91c
Compare
Add Crypto Top-Up Feature for Team Credits
This PR adds a new feature allowing teams to top up their credit balance using cryptocurrency. The implementation includes:
Key Changes
getStripeBalance
function to retrieve a customer's current balancegetCryptoTopupUrl
to generate checkout URLs for crypto paymentsCreditTopupSection
component with predefined amount options ($25, $100, $500, $1,000)The credit balance is displayed prominently and automatically applies to subscription charges before the default payment method is charged.
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
PR-Codex overview
This PR introduces functionality for managing credit balances and crypto top-ups in the billing section. It adds new utilities for fetching Stripe customer data and balance, and integrates a credit balance section in the billing page, enhancing user experience for managing payments.
Detailed summary
getStripeCustomer
andgetStripeBalance
functions to retrieve customer balance from Stripe.getCryptoTopupUrl
function for generating crypto top-up URLs.CheckoutPage
to handle crypto top-ups.Page
component in billing settings to include aCreditBalanceSection
.CreditBalanceSection
component to display current credit balance and allow top-ups.