Skip to content

fix(ui): locale-aware negative amount formatting#9064

Merged
dstaley merged 1 commit into
mainfrom
ds.fix/negative-amounts
Jul 1, 2026
Merged

fix(ui): locale-aware negative amount formatting#9064
dstaley merged 1 commit into
mainfrom
ds.fix/negative-amounts

Conversation

@dstaley

@dstaley dstaley commented Jul 1, 2026

Copy link
Copy Markdown
Member

Description

This PR introduces locale- and currency-aware formatting of negative monetary values. For example, formatting a negative value in Chilean peso would result in $-5.000 instead of the previous implementation which would have put the - symbol before the currency symbol.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Negative billing amounts now display correctly with locale-aware currency formatting, including proration, credits, and payer/account credits.
  • Bug Fixes

    • Fixed spacing in negative money values so amounts now render like -$5.00 instead of - $5.00.
    • Preserved already-negative amounts while normalizing positive values shown as credits or discounts.

@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 83f12d7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@clerk/ui Patch
@clerk/chrome-extension Patch
@clerk/swingset Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 1, 2026 6:07pm
swingset Ready Ready Preview, Comment Jul 1, 2026 6:07pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces a toNegativeAmount billing utility that negates a BillingMoneyAmount's numeric and formatted values, and applies it in CheckoutForm and PaymentAttemptPage to render negative line item amounts, replacing manual - string prefixing. Includes new tests and a changeset for @clerk/ui.

Changes

Negative amount formatting

Layer / File(s) Summary
toNegativeAmount utility
packages/ui/src/utils/billing.ts, packages/ui/src/utils/__tests__/billing.test.ts
New toNegativeAmount function negates amount.amount and prefixes amount.amountFormatted with - for positive inputs, returning unchanged values when already negative; covered by new tests.
CheckoutForm line items
packages/ui/src/components/Checkout/CheckoutForm.tsx, packages/ui/src/components/Checkout/__tests__/Checkout.test.tsx
Prorated discount, prorated credit, and payer account credit descriptions now use toNegativeAmount instead of a hardcoded - prefix; test assertions updated to expect -$X.XX without a space.
PaymentAttemptPage line items
packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
Proration discount, proration credit, and account credit line items in PaymentAttemptBody now use toNegativeAmount instead of string interpolation with a literal -.
Changeset
.changeset/sixty-hairs-sniff.md
Adds a patch changeset for @clerk/ui describing locale- and currency-aware formatting for negative amounts.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: mauricioabreu

Poem

A hop, a skip, a minus sign,
No more space where numbers align.
toNegativeAmount does its trick,
Formatting credits smooth and quick.
🐰 -$5.00, tidy and fine!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: locale-aware formatting of negative monetary amounts in the UI.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@github-actions github-actions Bot added the ui label Jul 1, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9064

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9064

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9064

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9064

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9064

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9064

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9064

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9064

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9064

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9064

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9064

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9064

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9064

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9064

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9064

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9064

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9064

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9064

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9064

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9064

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9064

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9064

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9064

commit: 83f12d7

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-01T18:11:29.606Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 83f12d7.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/ui/src/utils/billing.ts (1)

7-8: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Negative-zero edge case.

If amount.amount is 0, 0 < 0 is false, so the function negates it to -0 and prefixes amountFormatted with -, producing something like -$0.00 for a zero value. Minor edge case, likely rare in practice (line items with zero amounts probably aren't rendered as discounts/credits), but worth a guard if zero amounts can reach this function.

🤖 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 `@packages/ui/src/utils/billing.ts` around lines 7 - 8, The zero-value edge
case in the billing amount formatter can produce a negative zero display, so
update the logic in the amount formatting function in billing.ts to treat zero
as a non-negative value before applying the negation/prefix. Adjust the existing
negative check around amount.amount so only values strictly less than zero are
negated, and ensure zero returns without the minus sign while preserving the
current behavior for real negatives in the same helper.
packages/ui/src/utils/__tests__/billing.test.ts (1)

5-35: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test suite doesn't validate the "locale/currency-aware" claim.

Both tests use a USD-style amountFormatted ('1.00' / '-1.00') and only assert the blanket - prefix behavior. Given the PR's objective is specifically about correct sign placement for non-USD locales (e.g., CLP $-5.000), consider adding a case with a formatted string where the currency symbol trails the number, or where the expected placement differs, to actually exercise the locale-aware behavior this PR claims to introduce.

🤖 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 `@packages/ui/src/utils/__tests__/billing.test.ts` around lines 5 - 35, The
current `toNegativeAmount` tests only cover USD-style formatting, so they do not
verify the locale/currency-aware sign placement behavior this PR is meant to
add. Update the `toNegativeAmount` test suite to include a non-USD locale case
(for example, a format where the currency symbol trails the number or uses a
different sign position) and assert the expected `amountFormatted` output after
calling `toNegativeAmount`. Keep the existing positive/negative amount
assertions, but make sure the new case exercises the locale-sensitive formatting
logic in `toNegativeAmount` rather than only checking a simple `-` prefix.
🤖 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.

Nitpick comments:
In `@packages/ui/src/utils/__tests__/billing.test.ts`:
- Around line 5-35: The current `toNegativeAmount` tests only cover USD-style
formatting, so they do not verify the locale/currency-aware sign placement
behavior this PR is meant to add. Update the `toNegativeAmount` test suite to
include a non-USD locale case (for example, a format where the currency symbol
trails the number or uses a different sign position) and assert the expected
`amountFormatted` output after calling `toNegativeAmount`. Keep the existing
positive/negative amount assertions, but make sure the new case exercises the
locale-sensitive formatting logic in `toNegativeAmount` rather than only
checking a simple `-` prefix.

In `@packages/ui/src/utils/billing.ts`:
- Around line 7-8: The zero-value edge case in the billing amount formatter can
produce a negative zero display, so update the logic in the amount formatting
function in billing.ts to treat zero as a non-negative value before applying the
negation/prefix. Adjust the existing negative check around amount.amount so only
values strictly less than zero are negated, and ensure zero returns without the
minus sign while preserving the current behavior for real negatives in the same
helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: ac07ce35-29a4-414b-b0c5-46b5a608a4d9

📥 Commits

Reviewing files that changed from the base of the PR and between 5a51943 and 83f12d7.

📒 Files selected for processing (6)
  • .changeset/sixty-hairs-sniff.md
  • packages/ui/src/components/Checkout/CheckoutForm.tsx
  • packages/ui/src/components/Checkout/__tests__/Checkout.test.tsx
  • packages/ui/src/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/ui/src/utils/__tests__/billing.test.ts
  • packages/ui/src/utils/billing.ts

@dstaley dstaley merged commit c01b937 into main Jul 1, 2026
53 checks passed
@dstaley dstaley deleted the ds.fix/negative-amounts branch July 1, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants