-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Complete TODOs: links & payouts limit updates #2866
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
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughEnterprise plans are exempted from link usage limits across API, checks, UI gating, and email copy. Payouts now enforce a $10 minimum with corresponding UI tooltip. No public/exported API signatures changed; logic updates are conditional checks and UI tooltips. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Web UI
participant API as Bulk Links API
participant UC as UsageChecks
User->>UI: Create bulk links
UI->>API: POST /api/links/bulk (links, workspace)
API->>UC: checkLinksOverage(workspace, links.length)
alt plan !== "enterprise" AND over limit
UC-->>API: throw exceeded_limit
API-->>UI: 4xx exceeded_limit
UI-->>User: Show upgrade tooltip (non-enterprise)
else enterprise OR within limit
UC-->>API: ok
API-->>UI: 200 created
UI-->>User: Links created
end
sequenceDiagram
autonumber
actor Partner
participant UI as Payout Sheet
participant ACT as confirmPayouts()
participant Stripe as Stripe API
Partner->>UI: Click Confirm Payouts
UI->>ACT: confirmPayouts(amount)
alt amount < $10 (1000 cents)
ACT-->>UI: Error "minimum invoice amount $10"
UI-->>Partner: Tooltip: minimum $10
else amount ≥ $10
ACT->>Stripe: Retrieve payment method
ACT->>Stripe: Create invoice / payout
Stripe-->>ACT: Success/Failure
ACT-->>UI: Result
UI-->>Partner: Show result
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/ui/modals/link-builder/index.tsx (1)
281-287: Bug: paste-to-create is still blocked for enterprise when exceeded.Paste handler only checks
!exceededLinks; enterprise should bypass the limit. Update the condition.- !existingModalBackdrop && - !exceededLinks + !existingModalBackdrop && + (plan === "enterprise" || !exceededLinks)
🧹 Nitpick comments (6)
apps/web/lib/api/links/usage-checks.ts (1)
20-23: Enterprise exemption is correct; consider centralizing plan checks.LGTM on not throwing for enterprise. To avoid drift across files, consider a shared helper like
isEnterprisePlan(plan)(or enum) and reuse it here and in routes/UI.packages/email/src/templates/links-limit.tsx (1)
83-94: Fix copy: missing “to” (twice).Reads awkwardly: “upgrade the … plan add more links.” Suggest:
- All your existing links will continue to work, and we are still - collecting data on them, but you'll need to upgrade the{" "} + All your existing links will continue to work, and we are still + collecting data on them, but you'll need to upgrade to the{" "} ... - </Link>{" "} - add more links. + </Link>{" "} + to add more links.apps/web/lib/actions/partners/confirm-payouts.ts (2)
62-66: Use a shared constant for the $10 minimum and reuse the message.Hardcoding 1000 and the string here will drift from UI. Define a single source of truth and reference it.
- if (amount < 1000) { - throw new Error( - "Your payout total is less than the minimum invoice amount of $10.", - ); - } + if (amount < MIN_PAYOUT_CENTS) { + throw new Error(MIN_PAYOUT_ERROR); + }Outside this hunk, add:
// top-level (shared location preferred, e.g., lib/partners/constants) export const MIN_PAYOUT_CENTS = 1_000 as const; export const MIN_PAYOUT_ERROR = `Your payout total is less than the minimum invoice amount of $${MIN_PAYOUT_CENTS / 100}.`;
14-22: Tighten schema: enforce integer, nonnegative cents.Prevents negative or float values slipping in.
- amount: z.number(), - fee: z.number(), - total: z.number(), + amount: z.number().int().nonnegative(), + fee: z.number().int().nonnegative(), + total: z.number().int().nonnegative(),apps/web/ui/partners/payout-invoice-sheet.tsx (2)
503-505: Good: tooltip explains the $10 minimum. Also block the button for < $10.Currently the button isn’t disabled when 0 < amount < $10; ConfirmPayoutsButton suppresses hold on
disabledTooltip, but also setdisabledfor clarity. Reuse a shared constant.- disabled={ - eligiblePayoutsLoading || !selectedPaymentMethod || amount === 0 - } + disabled={ + eligiblePayoutsLoading || + !selectedPaymentMethod || + amount === 0 || + (amount !== undefined && amount < MIN_PAYOUT_CENTS) + } ... - ) : amount && amount < 1000 ? ( - "Your payout total is less than the minimum invoice amount of $10." + ) : amount && amount < MIN_PAYOUT_CENTS ? ( + MIN_PAYOUT_ERROR ) : (Add near the top (or import from a shared constants module used by the server action):
const MIN_PAYOUT_CENTS = 1_000; const MIN_PAYOUT_ERROR = `Your payout total is less than the minimum invoice amount of $${MIN_PAYOUT_CENTS / 100}.`;
135-169: Stale memo deps: include payoutFee/paymentMethodsLoading; drop plan.
finalPaymentMethodsdepends onpayoutFee, notplan.invoiceDatausespaymentMethodsLoadingin render but it’s not a dep, risking a stale skeleton.- const finalPaymentMethods = useMemo( + const finalPaymentMethods = useMemo( () => paymentMethods?.map((pm) => { const paymentMethod = PAYMENT_METHODS[pm.type]; const base = { ...paymentMethod, id: pm.id, fee: calculatePayoutFeeForMethod({ paymentMethod: pm.type, payoutFee, }), }; ... }), - [paymentMethods, plan], + [paymentMethods, payoutFee], );- }, [amount, paymentMethods, selectedPaymentMethod, cutoffPeriod]); + }, [amount, paymentMethods, paymentMethodsLoading, selectedPaymentMethod, cutoffPeriod]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/app/api/links/bulk/route.ts(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/links/page-client.tsx(1 hunks)apps/web/lib/actions/partners/confirm-payouts.ts(1 hunks)apps/web/lib/api/links/usage-checks.ts(1 hunks)apps/web/ui/modals/link-builder/index.tsx(2 hunks)apps/web/ui/partners/payout-invoice-sheet.tsx(1 hunks)packages/email/src/templates/links-limit.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-06T07:59:03.120Z
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
Applied to files:
apps/web/app/api/links/bulk/route.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (6)
apps/web/app/api/links/bulk/route.ts (1)
45-47: Bulk limit check now exempts enterprise — consistent with usage checks.Matches
throwIfLinksUsageExceededbehavior. Keep it this way so non‑enterprise is blocked pre-create (>=) and over-create (>) while enterprise proceeds.If clients rely on error codes, note this block uses
exceeded_limitwhilethrowIfLinksUsageExceededthrowsforbidden. Verify downstream handling isn’t brittle.packages/email/src/templates/links-limit.tsx (1)
74-81: Copy path for enterprise looks good.Message is clear and aligned with the exemption.
apps/web/app/app.dub.co/(dashboard)/[slug]/links/page-client.tsx (2)
397-401: Tooltip gate respects enterprise — nice.Import options are disabled with an upgrade tooltip only for non‑enterprise when exceeded. Matches API behavior.
403-407: Verify upgrade path.Here we link to
/${slug}/upgrade; elsewhere (payouts) we use/${slug}/settings/billing/upgrade. Confirm both routes exist or standardize.apps/web/ui/modals/link-builder/index.tsx (2)
265-266: Create button gating matches enterprise policy.Reading
planhere is correct and consistent with other UI gates.
301-309: Upgrade tooltip gated for non‑enterprise only — good.Matches server checks.
Summary by CodeRabbit