Skip to content

Conversation

@mfts
Copy link
Owner

@mfts mfts commented Nov 25, 2025

Summary by CodeRabbit

  • New Features

    • Added an Invoices page in Settings > Billing, allowing users to view, download, and manage all invoices with detailed information including dates, amounts, and status.
  • Bug Fixes

    • Fixed incorrect tab navigation state on the Billing settings page.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 25, 2025

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

Project Deployment Preview Comments Updated (UTC)
papermark Ready Ready Preview Comment Nov 25, 2025 11:48am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 25, 2025

Walkthrough

This PR introduces a new invoices management feature to the billing section. It adds a new invoices page, backend API endpoint to fetch Stripe invoices, a custom SWR hook for data fetching, and updates navigation components to support the new invoices route alongside the existing subscription management.

Changes

Cohort / File(s) Summary
Billing UI Navigation
components/billing/upgrade-plan-container.tsx, components/layouts/breadcrumb.tsx, pages/settings/billing.tsx
Modified "View invoices" action from API-driven flow to direct client-side navigation; added breadcrumb handling for invoices route; added TabMenu component with Subscription and Invoices tabs to billing page.
Invoices Data Layer
lib/swr/use-invoices.ts
Introduced new Invoice interface and useInvoices hook that fetches invoices from the API endpoint with SWR configuration (60s dedup interval, no revalidate on focus).
Invoices Backend API
pages/api/teams/[teamId]/billing/invoices.ts
Added new GET-only API route that authenticates requests, verifies team membership, fetches up to 100 Stripe invoices for the team, and returns transformed invoice data with id, number, status, amount, currency, dates, and URLs.
Invoices Page
pages/settings/billing/invoices.tsx
Created new page component that displays a list of invoices with loading, error, and empty states; formats dates and currency; provides actions to view or download invoice PDFs.

Possibly related PRs

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add invoices page' clearly and concisely describes the main change—introducing a new invoices page to the billing section of the application, which is the primary feature across all modified files.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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)
components/billing/upgrade-plan-container.tsx (1)

214-220: Fix inconsistency: Free tier users still use old API-based navigation.

Line 216 still calls manageSubscription({ type: "invoices" }) for free tier users, while Line 275 uses the new router.push("/settings/billing/invoices") for paid users. This creates inconsistent behavior.

Apply this diff to use consistent navigation:

               <DropdownMenuContent align="end">
                 <DropdownMenuItem
-                  onClick={() => manageSubscription({ type: "invoices" })}
+                  onClick={() => router.push("/settings/billing/invoices")}
                 >
                   <ReceiptTextIcon className="h-4 w-4" />
                   View invoices
🧹 Nitpick comments (3)
pages/settings/billing/invoices.tsx (2)

93-99: Use SWR's mutate instead of router.reload().

The retry button uses router.reload() which reloads the entire page. Consider using SWR's mutate function to re-fetch just the invoices data for a better user experience.

Apply this diff:

+import { mutate } from "swr";
+import { useTeam } from "@/context/team-context";
+
 export default function Invoices() {
   const router = useRouter();
+  const teamInfo = useTeam();
+  const teamId = teamInfo?.currentTeam?.id;
   const { invoices, loading, error } = useInvoices();
   
   // ... rest of code ...
   
                 <Button
                   variant="outline"
                   size="sm"
-                  onClick={() => router.reload()}
+                  onClick={() => mutate(`/api/teams/${teamId}/billing/invoices`)}
                 >
                   Retry
                 </Button>

126-136: Consider using dynamic description from invoice data.

The description is hardcoded to "Papermark Subscription" but the API returns a description field from the invoice. While this works for most cases, it might not accurately reflect all invoice types.

Consider using the invoice description:

                       <TableCell>
                         <div className="flex flex-col">
                           <span className="font-medium">
-                            Papermark Subscription
+                            {invoice.description || "Papermark Subscription"}
                           </span>
                           {invoice.number && (
pages/api/teams/[teamId]/billing/invoices.ts (1)

57-61: Consider future pagination for invoices.

The current limit of 100 invoices is reasonable for most use cases, but teams with long billing histories might exceed this. Consider adding pagination in a future iteration.

Add a comment to document the limitation:

     // Fetch invoices from Stripe
+    // Note: Limited to 100 most recent invoices. Consider adding pagination for teams with extensive billing history.
     const stripe = stripeInstance(isOldAccount(team.plan));
     const invoices = await stripe.invoices.list({
       customer: team.stripeId,
       limit: 100,
     });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6a133b and e597960.

📒 Files selected for processing (6)
  • components/billing/upgrade-plan-container.tsx (1 hunks)
  • components/layouts/breadcrumb.tsx (3 hunks)
  • lib/swr/use-invoices.ts (1 hunks)
  • pages/api/teams/[teamId]/billing/invoices.ts (1 hunks)
  • pages/settings/billing.tsx (2 hunks)
  • pages/settings/billing/invoices.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
pages/settings/billing.tsx (1)
components/tab-menu.tsx (1)
  • TabMenu (23-52)
pages/settings/billing/invoices.tsx (3)
lib/swr/use-invoices.ts (1)
  • useInvoices (20-38)
lib/utils.ts (1)
  • formatDate (301-312)
components/tab-menu.tsx (1)
  • TabMenu (23-52)
lib/swr/use-invoices.ts (2)
context/team-context.tsx (1)
  • useTeam (87-87)
lib/utils.ts (1)
  • fetcher (48-62)
⏰ 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: Analyze (javascript-typescript)
🔇 Additional comments (5)
components/layouts/breadcrumb.tsx (1)

222-266: LGTM! Clean breadcrumb implementation for the invoices sub-route.

The breadcrumb logic correctly handles the invoices page hierarchy (Settings > Billing > Invoices) and follows the existing patterns in the codebase.

pages/settings/billing.tsx (1)

59-74: LGTM! TabMenu integration looks good.

The tab navigation is correctly configured with both Subscription and Invoices tabs. The currentValue="subscription" for both tabs on this page will properly highlight the Subscription tab since we're on the billing page.

lib/swr/use-invoices.ts (1)

1-39: LGTM! Well-structured hook implementation.

The Invoice interface is comprehensive, and the useInvoices hook follows best practices with proper SWR configuration. The deduplication interval and revalidation settings are appropriate for invoice data.

pages/settings/billing/invoices.tsx (1)

56-71: LGTM! Proper tab menu configuration for the invoices page.

The TabMenu correctly sets currentValue="invoices" to highlight the Invoices tab when on this page.

pages/api/teams/[teamId]/billing/invoices.ts (1)

14-83: LGTM! Solid API endpoint implementation with proper authentication and error handling.

The endpoint correctly:

  • Enforces GET-only method
  • Validates user authentication and team membership
  • Handles teams without Stripe customers gracefully
  • Transforms Stripe data into a clean format
  • Includes proper error handling

@mfts mfts merged commit 0b4d55b into main Nov 25, 2025
9 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Nov 25, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants