feat: invoice history icon in top bar, visible under the billing paywall - #1844
Open
giladresisi wants to merge 1 commit into
Open
feat: invoice history icon in top bar, visible under the billing paywall#1844giladresisi wants to merge 1 commit into
giladresisi wants to merge 1 commit into
Conversation
Customers who cancel their subscription drop to FREE tier and hit the billing paywall, which blocks the settings page - so they could no longer download their past invoices. This adds a small invoice icon in the top-right header (between the organization switcher and the mode toggle) that opens a read-only Invoices modal listing the org's past charges with a download link per charge. The icon is rendered in both the normal layout header and the paywall screen's separate header, and only when billingEnabled && isGeneral. Backend: new GET /billing/invoices returning the caller's own org charges via the existing StripeService.getCharges (lazy - fetched only when the modal opens). The superAdmin-only GET /billing/charges admin endpoint is untouched. Includes lingo.dev translations for the new `invoices` key. Testing (local dev, real Stripe test data): - Normal header: icon appears, modal lists 3 real charges with correct date, amount ($X.XX USD) and Paid status; no checkboxes or admin footer buttons. - Paywall: impersonated a FREE-tier org with a Stripe customer - the paywall header shows the icon and the modal opens (empty state "No charges found" for an org with no succeeded charges). - Download link verified: clicking the row's download icon opens the Stripe-hosted receipt/invoice page in a new tab with working "Download invoice" / "Download receipt" buttons. - GET /billing/invoices returns 200 [] for an org without charges and the charge list otherwise; frontend + backend production builds pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What kind of change does this PR introduce?
Feature.
Why was this change needed?
Customers who cancel their subscription drop to the FREE tier and hit the billing paywall, which blocks the settings/billing page - so they can no longer see or download their past invoices, and several unsubscribed customers asked for exactly that.
This adds a small invoice icon in the top-right header (between the organization switcher and the light/dark toggle) that opens a read-only Invoices modal: Date / Amount / Status per charge, with a download link to the Stripe invoice PDF (or receipt). It is a read-only version of the admin Manage Billing modal - no checkboxes, no refund/coupon/cancel buttons. The icon renders in both the normal layout header and the paywall screen's separate header (the whole point - cancelled users live on that screen), and only when billingEnabled && isGeneral, so self-hosted instances never see it.
Backend: one new endpoint, GET /billing/invoices, returning the caller's own org charges via the existing StripeService.getCharges. Charges are fetched lazily - only when the modal opens, never on layout mount. The superAdmin-only GET /billing/charges admin endpoint is untouched.
Includes lingo.dev translations for the new
invoiceskey.Other information:
Tested locally against real Stripe test data: populated modal (3 charges, correct amounts/status), empty state ("No charges found") for orgs without charges, paywall header via an impersonated FREE-tier org, and the download link click-through to the Stripe-hosted receipt/invoice page. Frontend and backend production builds pass.
Checklist:
🤖 Generated with Claude Code