Skip to content

chore(clerk-js,localizations): Tidy up some commerce localizations #6101

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

Merged
merged 11 commits into from
Jun 13, 2025

Conversation

aeliox
Copy link
Contributor

@aeliox aeliox commented Jun 11, 2025

Description

  • Adds localization to a bunch of straggling commerce strings.
  • Cleans up some loose-ends from this PR from last week.

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

    • Improved localization throughout billing, payment history, and subscription management interfaces, with dynamic text adjustments based on subscriber type.
    • Added context-sensitive localized messages, table headers, and section titles for payment attempts, payment sources, statements, and subscriptions.
    • Introduced a new hook to dynamically determine localization roots based on subscriber type.
    • Added a reusable, paginated DataTable component for consistent table rendering across billing UI.
  • Enhancements

    • Back links in plans pages now direct to the subscriptions tab instead of the plans tab.
    • Statement descriptions are now consistently displayed in lowercase for better readability.
    • Date formatting standardized and enhanced with a new "monthyear" format option.
    • Payment attempt and statement pages now conditionally show localized "not found" messages instead of early returns.
    • Payment attempt ID display and status badges improved for clarity and styling.
    • Removed unnecessary console logs and streamlined form submission handling.
    • Timestamps in payments and statements are now handled as Date objects for improved date management.
  • Localization

    • Expanded English localization resources with new billing, statements, and payment history keys.
    • Updated type definitions to support new localization keys and sections.

Copy link

changeset-bot bot commented Jun 11, 2025

🦋 Changeset detected

Latest commit: 7cb2b0f

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

This PR includes changesets to release 22 packages
Name Type
@clerk/localizations Patch
@clerk/clerk-js Patch
@clerk/types Patch
@clerk/clerk-react Patch
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/elements Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/shared Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/themes Patch
@clerk/vue 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

Copy link

vercel bot commented Jun 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
clerk-js-sandbox ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 13, 2025 7:27pm

Copy link
Contributor

coderabbitai bot commented Jun 11, 2025

📝 Walkthrough
## Walkthrough

This change introduces context-aware localization for billing-related UI components, dynamically adjusting localization keys based on whether the subscriber is a user or an organization. New localization keys and type definitions are added to support billing statements, payment history, and subscription lists. Minor navigation and UI adjustments are also included.

## Changes

| Files/Paths                                                                                      | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| .../OrganizationProfile/OrganizationPlansPage.tsx<br>.../UserProfile/PlansPage.tsx               | Updated the back link in header components to navigate to the parent route with the query parameter `tab=subscriptions` instead of `tab=plans`. No other logic or UI changes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| .../PaymentAttempts/PaymentAttemptPage.tsx<br>.../PaymentAttempts/PaymentAttemptsList.tsx        | Incorporated subscriber type context to dynamically select localization keys for messages, headers, and labels. Replaced hardcoded localization key prefixes with context-sensitive ones, enabling dynamic localization for both users and organizations in payment attempt components.                                                                                                                                                                                                                                                                                                                                                                                                |
| .../PaymentSources/AddPaymentSource.tsx<br>.../PaymentSources/PaymentSources.tsx                 | Introduced context-aware localization for button labels, titles, messages, and action labels based on subscriber type. Removed unnecessary console logs from error handling. All localization key usages now use a dynamic prefix according to subscriber context.                                                                                                                                                                                                                                                                                                                                                                            |
| .../Statements/Statement.tsx                                                                     | Applied a style override to render description text in lowercase within the `SectionContentDetailsHeader` component. No logic changes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| .../Statements/StatementPage.tsx<br>.../Statements/StatementsList.tsx                            | Enhanced localization by dynamically selecting keys based on subscriber type for all UI strings, captions, table headers, and empty state messages in statements components. All static text replaced with localized equivalents.                                                                                                                                                                                                                                                                                                                                                                                                              |
| .../Subscriptions/SubscriptionsList.tsx                                                          | Replaced static table header labels with dynamic localization keys based on subscriber type context for the subscriptions list. No other logic changes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| .../localizations/src/en-US.ts                                                                   | Added new localization keys for billing, payment history, statements, and subscription list sections under both user and organization profiles. Modified some existing keys for clarity and singular/plural consistency.                                                                                                                                                                                                                                                                                                                                                                                                                     |
| .../types/src/localization.ts                                                                    | Extended the `_LocalizationResource` type with new fields and nested objects for billing-related localization, including statements, payment history, and subscription list sections for both user and organization profiles, and added a `totalDue` field under `commerce`.                                                                                                                                                                                                                                                                                                                                                                |
| .../contexts/components/SubscriberType.ts                                                       | Added new hook `useSubscriberTypeLocalizationRoot` that returns the localization root key string based on subscriber type context ('userProfile' or 'organizationProfile').                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| .../core/resources/CommerceSettings.ts                                                         | Removed optional chaining from billing property accesses in `CommerceSettings.fromJSON`, assuming `data.billing` is always defined.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| .../core/resources/CommercePayment.ts                                                          | Changed timestamp properties `failedAt`, `paidAt`, and `updatedAt` from `number` to `Date` and updated deserialization logic accordingly.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| .../core/resources/CommercePaymentSource.ts                                                    | Added fallback default array `['card']` for `paymentMethodOrder` property if missing during deserialization in `CommerceInitializedPaymentSource.fromJSON`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| .../core/resources/CommerceStatement.ts                                                        | Changed `timestamp` property type from `number` to `Date` in `CommerceStatement` and `CommerceStatementGroup` classes, updating deserialization accordingly.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| .../ui/elements/DataTable.tsx                                                                   | Added new reusable `DataTable` React component with pagination, loading, and empty state support, along with `DataTableEmptyRow` and `DataTableRow` components for consistent table rendering and styling.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| .../ui/utils/formatDate.ts                                                                      | Extended `formatDate` utility to support a new `'monthyear'` format that omits the day component, including month and year.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| .../ui/utils/index.ts                                                                           | Exported new utility function `truncateTextWithEndVisible`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| .../clerk-js/bundlewatch.config.json                                                           | Increased maximum allowed bundle size limits slightly for `ui-common*.js` and `paymentSources*.js` files.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |

## Suggested reviewers

- tmilewski

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9b827f and 7cb2b0f.

📒 Files selected for processing (3)
  • packages/clerk-js/src/core/resources/CommercePayment.ts (2 hunks)
  • packages/clerk-js/src/core/resources/CommerceStatement.ts (4 hunks)
  • packages/clerk-js/src/ui/components/Statements/Statement.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/clerk-js/src/core/resources/CommerceStatement.ts
  • packages/clerk-js/src/ui/components/Statements/Statement.tsx
  • packages/clerk-js/src/core/resources/CommercePayment.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
  • GitHub Check: semgrep/ci
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

pkg-pr-new bot commented Jun 11, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@6101

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@6101

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@6101

@clerk/clerk-expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/clerk-react

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

@clerk/react-router

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

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@6101

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@6101

@clerk/types

npm i https://pkg.pr.new/@clerk/types@6101

@clerk/upgrade

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

@clerk/vue

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

commit: 7cb2b0f

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

🔭 Outside diff range comments (3)
packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (1)

191-205: 🛠️ Refactor suggestion

colSpan hard-coded to 4 – now mismatches 2-column table

DataTableEmptyRow still spans 4 columns, but headers/rows only render 2 cells after this change. Browsers tolerate the mismatch, yet it’s semantically wrong and may break future accessibility tooling.

-<Td colSpan={4}>
+<Td colSpan={headers.length}>

Update the prop (and pass headers down or compute locally) so the empty row always spans the correct number of columns.

packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (1)

121-124: ⚠️ Potential issue

Avoid in-place sort & fix comparator contract

Array.prototype.sort mutates the original array returned from SWR.

  1. This can break memoization elsewhere because SWR keeps a reference to the same array.
  2. A comparator must return 0 when two elements are equal; returning 1 unconditionally violates the spec and leads to unstable sorting.
-  const sortedPaymentSources = useMemo(
-    () => paymentSources.sort((a, b) => (a.isDefault && !b.isDefault ? -1 : 1)),
-    [paymentSources],
-  );
+  const sortedPaymentSources = useMemo(
+    () =>
+      [...paymentSources]                     // copy to keep SWR cache immutable
+        .sort((a, b) => {
+          if (a.isDefault === b.isDefault) {
+            return 0;                         // stable when equal
+          }
+          return a.isDefault ? -1 : 1;        // default card first
+        }),
+    [paymentSources],
+  );
packages/clerk-js/src/ui/components/Statements/StatementPage.tsx (1)

118-121: ⚠️ Potential issue

“Total paid” is still hard-coded

After the localization overhaul nearly every label is keyed except the footer:

<Statement.Footer
  label='Total paid'   // <-- hard-coded

Add a key, e.g.:

- label='Total paid'
+ label={localizationKeys('commerce.totalPaid')}

(And of course supply translations under both user/organization roots if required.)

♻️ Duplicate comments (3)
packages/clerk-js/src/ui/components/UserProfile/PlansPage.tsx (1)

22-24: See previous comment – duplicated literal

Same comment as in OrganizationPlansPage.tsx. Extract the "subscriptions" tab literal to a shared constant.

packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (1)

33-35: Same helper / duplication comment applies

The ternary for localizationRoot re-appears here. Centralising avoids risking typos (e.g. 'org' vs 'organization') and makes tests simpler.

packages/clerk-js/src/ui/components/Statements/StatementPage.tsx (1)

13-16: Consistency: reuse helper for localizationRoot

Same duplication note as above.

🧹 Nitpick comments (12)
packages/clerk-js/src/ui/components/Statements/Statement.tsx (1)

215-217: Avoid forcing lowercase on localized strings

textTransform: 'lowercase' will indiscriminately lowercase the description for every locale, which can mangle proper nouns, brand names, and non-Latin scripts (e.g. German “ß”, Turkish “İ”, etc.). Let translators decide the exact casing or provide an already-formatted key instead.

-  sx={() => ({
-    textTransform: 'lowercase',
-  })}
+  // Deliberately leave casing untouched; translators/localization keys control presentation.

Do you foresee any actual UI where forcing lowercase is required? If not, consider dropping the rule entirely.

packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationPlansPage.tsx (1)

25-27: Hard-coded query param duplicated in several files

new URLSearchParams('tab=subscriptions') appears here (and in UserProfile/PlansPage.tsx). Duplicating the string literal increases drift-risk if the tab name ever changes.

-onClick={() => void navigate('../', { searchParams: new URLSearchParams('tab=subscriptions') })}
+onClick={() => void navigate('../', { searchParams: new URLSearchParams(`tab=${SUBSCRIPTIONS_TAB}`) })}
...
+const SUBSCRIPTIONS_TAB = 'subscriptions';

Expose SUBSCRIPTIONS_TAB from a shared config to keep both pages in sync.

packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1)

38-97: Repeated localizationRoot logic could live in a hook/utility

Several components now compute the root with
subscriberType === 'user' ? 'userProfile' : 'organizationProfile'.
Consider a helper such as useLocalizationRoot() to avoid repetition and typos:

const localizationRoot = useLocalizationRoot(); // returns 'userProfile' | 'organizationProfile'

This keeps the component lean and centralises future changes (e.g. a third
subscriber type).

packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (2)

6-20: Import path consistency

Most sibling components import contexts via '../../contexts'; this file uses '../../../ui/contexts'. Both resolve, but mixing styles hampers grepping and may break if folder depth changes. Prefer the two-level path for consistency:

-import { useStatements, useSubscriberTypeContext } from '../../../ui/contexts';
+import { useStatements, useSubscriberTypeContext } from '../../contexts';

32-47: Helper for localizationRoot

Same duplication observation as in SubscriptionsList.tsx. A shared helper keeps logic DRY and consistent.

packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (1)

26-27: Factor-out repeated localizationRoot calculation

The ternary subscriberType === 'user' ? 'userProfile' : 'organizationProfile' is duplicated four times in this file (and many more across the PR).
Placing this logic in useSubscriberTypeContext (e.g. useLocalizationRoot()) or a tiny helper eliminates repetition and the risk of drifting logic if new subscriber types appear ('org' vs 'organization', etc.).

Also applies to: 68-69, 114-115, 203-204

packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (1)

314-316: Type-safety lost with dynamic template literal

localizationKeys(...) is designed to narrow to specific union literals for type-safety. Passing a runtime–built string (${localizationRoot}...) degrades that guarantee to string.
If you adopt a helper as proposed (getBillingKey('paymentSourcesSection.formButtonPrimary__add')) you can preserve compile-time checking while still being dynamic.

packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (1)

44-48: Missing localizationKeys for “copy” aria-label

Most visible strings are now localized, but the aria-label in CopyButton (“Copy” / “Copied”) remains hard-coded a few lines below.
Leaving mixed locales is jarring for screen-reader users. Please create keys under commerce.copy / commerce.copied (or similar) and reference them.

packages/types/src/localization.ts (3)

765-775: Consider extracting a shared BillingStatementsSection type to avoid duplication.

statementsSection is declared twice (user & org profiles) with identical shape. Typing it once and re-using would:

  1. Remove boilerplate from this already-huge declaration.
  2. Guarantee both sections stay in sync when new fields are introduced.

Something along the lines of:

type _StatementsSection = {
  empty: LocalizationValue;
  itemCaption__paidForPlan: LocalizationValue;
  itemCaption__proratedCredit: LocalizationValue;
  itemCaption__subscribedAndPaidForPlan: LocalizationValue;
  notFound: LocalizationValue;
  tableHeaders__date: LocalizationValue;
  tableHeaders__amount: LocalizationValue;
  title: LocalizationValue;
  totalPaid: LocalizationValue;
};

...

billingPage: {
  ...
  statementsSection: _StatementsSection;
  ...
}

780-786: Minor ordering nit – keep table header keys grouped.

For readability, list all tableHeaders__* keys together (plan, startDate, edit) and then the non-header keys.
Not a blocker, but helps when scanning the giant type file.


788-793: paymentHistorySection mirrors statementsSection – same refactor applies.

A shared _PaymentHistorySection (empty, notFound, tableHeaders__…) reused for user & org keeps the type lean.

packages/localizations/src/en-US.ts (1)

193-200: Keep key order consistent with type definition.

The notFound key is declared after the table headers in the EN resource but before them in the type file.
Order does not affect runtime, yet aligning helps future diffing.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97749d5 and 9492943.

📒 Files selected for processing (12)
  • packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationPlansPage.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (5 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (9 hunks)
  • packages/clerk-js/src/ui/components/Statements/Statement.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementPage.tsx (6 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/UserProfile/PlansPage.tsx (1 hunks)
  • packages/localizations/src/en-US.ts (5 hunks)
  • packages/types/src/localization.ts (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/clerk-js/src/ui/components/UserProfile/PlansPage.tsx (1)
packages/clerk-js/src/ui/elements/Header.tsx (1)
  • Header (103-108)
packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationPlansPage.tsx (1)
packages/clerk-js/src/ui/elements/Header.tsx (1)
  • Header (103-108)
packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • Th (61-61)
packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (2)
packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (1)
  • useSubscriberTypeContext (6-6)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • localizationKeys (11-11)
packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (2)
packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (1)
  • useSubscriberTypeContext (6-6)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • localizationKeys (11-11)
packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (2)
packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (1)
  • useSubscriberTypeContext (6-6)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • localizationKeys (11-11)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (8)
packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (1)

239-241: subscriberType value mismatch can cause wrong locale branch

All other branches treat the organization case as 'org', but the ternary here only checks for 'user'.
If a future (or existing) value like 'organization' is introduced, it will silently fall into the organization path without an explicit check. Consider:

-const localizationRoot = subscriberType === 'user' ? 'userProfile' : 'organizationProfile';
+const localizationRoot =
+  subscriberType === 'user'
+    ? 'userProfile'
+    : subscriberType === 'org'
+    ? 'organizationProfile'
+    : 'userProfile'; // sensible fallback + exhaustiveness

Or, even better, centralise this mapping as suggested in the previous comment.

packages/types/src/localization.ts (2)

134-135: totalDue addition looks good – verify downstream usage.

The new totalDue key completes the billing vocabulary and is typed correctly.
Just ensure every component that renders totals (e.g. CheckoutSummary, InvoicesList) is now reading commerce.totalDue instead of building the string ad-hoc.


991-1019: Keep user/org shapes perfectly in sync.

The organization profile copies the exact keys introduced for the user profile – good.
After factoring the common sub-types (see above), only one place will need updates, avoiding future divergence.

packages/localizations/src/en-US.ts (5)

95-97: 👍 English copy for totalDue reads naturally.

No wording issues spotted.


219-223: Double-check singular “Subscription” wording matches UI context.

The label switched from “Subscriptions” → “Subscription” while the key remains headerTitle__subscriptions.
If the pane can still show multiple subscriptions for legacy customers, the singular text might confuse.


223-234: Great to see concise captions; verify interpolation placeholders.

{{plan}} and {{period}} placeholders in itemCaption__… must be provided by the caller – confirm all usages supply both to avoid showing raw braces.


235-242: Edit header added – ensure role-based visibility.

If editing subscriptions is gated behind admin / owner roles, confirm components hide the column when the action is disallowed; otherwise the column looks empty.


842-890: User & org sections kept in lock-step – nice.

String set mirrors organization section perfectly; no gaps detected.

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

🧹 Nitpick comments (2)
packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (2)

3-4: Rename constant to DEFAULT & use as const for literal-type safety

The current identifier DEFAUlT (lower-case “l” instead of upper-case “L”) looks like a typo and makes the code harder to scan.
While only local, adopting the conventional DEFAULT (all caps) clarifies intent and eliminates the visual confusion.

-const DEFAUlT = 'user';
-export const SubscriberTypeContext = createContext<'user' | 'org'>(DEFAUlT);
+const DEFAULT = 'user' as const;
+export const SubscriberTypeContext = createContext<'user' | 'org'>(DEFAULT);

6-6: Drop the redundant fallback || DEFAUlT

useContext already returns the context’s default value when no provider is mounted, so the logical-OR is never reached. Removing it tightens the hook and avoids the extra branch.

-export const useSubscriberTypeContext = () => useContext(SubscriberTypeContext) || DEFAUlT;
+export const useSubscriberTypeContext = () => useContext(SubscriberTypeContext);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9492943 and 69c40a7.

📒 Files selected for processing (11)
  • .changeset/soft-toys-flow.md (1 hunks)
  • packages/clerk-js/bundlewatch.config.json (2 hunks)
  • packages/clerk-js/src/core/resources/CommerceSettings.ts (1 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (5 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (10 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementPage.tsx (7 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/clerk-js/bundlewatch.config.json
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • .changeset/soft-toys-flow.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx
  • packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx
  • packages/clerk-js/src/ui/components/Statements/StatementsList.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx
  • packages/clerk-js/src/ui/components/Statements/StatementPage.tsx
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
packages/clerk-js/src/ui/contexts/components/SubscriberType.ts (1)

8-11: Hook logic looks good – maps subscriber type to localization root correctly
No further issues found in this block.

Copy link
Member

@panteliselef panteliselef left a comment

Choose a reason for hiding this comment

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

Remaining issues from the PR that got merged last week

  • Hard coded "USD"
  • Replace in place date formatting with existing utils/patterns. Either use formatDate that you introduced or preferably or introduce use a localizationModifier
  • <DataTable/> should not be duplicated per AIO component.
  • 🧹 Drop the leftover console.logs
  • In a follow-up PR let's fix the useSWR + React.Context usage in PaymentAttempts.tsx as it adds unnecessary mental overhead. The fetched data are already accessible from any other component due to the shared cache.
    • Looping through the cached data to find by id will not work the moment that resource you are looking for is anywhere but the first paginated page. What happens if the resource does exist in the DB but it is never fetched as part of the paginated hooks ? Consider fetching the resources by id.

@aeliox aeliox requested a review from wobsoriano as a code owner June 13, 2025 16:44
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: 3

🧹 Nitpick comments (2)
packages/types/src/commerce.ts (1)

117-122: Breaking API change – timestamps switched from number to Date

All consuming apps compiled against the public @clerk/types package will receive a compile-time break and may need migration logic.
Add this to the CHANGELOG and bump the major version, or provide overloads accepting both types.

Consider shipping a helper:

export const toDate = (d: number | string | Date | undefined) =>
  d instanceof Date ? d : d ? new Date(d) : undefined;

…so external code mirrors the internal deserialization strategy.

Also applies to: 135-145

packages/clerk-js/src/core/resources/CommercePayment.ts (1)

35-39: Inconsistent nullability handling for date fields

paid_at and failed_at are optional, but updated_at is mandatory.
If back-end ever omits updated_at the current code will construct an invalid Date(NaN).

-this.updatedAt = new Date(data.updated_at);
+this.updatedAt = data.updated_at ? new Date(data.updated_at) : new Date();

Also consider normalising through a shared utility (toDate as suggested above) to avoid triplication.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 561c74b and d69ab4d.

📒 Files selected for processing (17)
  • packages/clerk-js/bundlewatch.config.json (2 hunks)
  • packages/clerk-js/src/core/resources/CommercePayment.ts (2 hunks)
  • packages/clerk-js/src/core/resources/CommercePaymentSource.ts (1 hunks)
  • packages/clerk-js/src/core/resources/CommerceStatement.ts (4 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx (4 hunks)
  • packages/clerk-js/src/ui/components/Statements/Statement.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementPage.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (4 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (3 hunks)
  • packages/clerk-js/src/ui/elements/DataTable.tsx (1 hunks)
  • packages/clerk-js/src/ui/utils/formatDate.ts (1 hunks)
  • packages/clerk-js/src/ui/utils/index.ts (1 hunks)
  • packages/localizations/src/en-US.ts (5 hunks)
  • packages/types/src/commerce.ts (2 hunks)
  • packages/types/src/localization.ts (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/clerk-js/src/ui/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • packages/clerk-js/bundlewatch.config.json
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx
  • packages/clerk-js/src/ui/components/Statements/StatementsList.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/Statements/StatementPage.tsx
  • packages/types/src/localization.ts
  • packages/clerk-js/src/ui/components/Statements/Statement.tsx
  • packages/localizations/src/en-US.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/types/src/commerce.ts (1)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (38-57)
packages/clerk-js/src/ui/elements/DataTable.tsx (2)
packages/clerk-js/src/ui/customizables/index.ts (10)
  • LocalizationKey (12-12)
  • Col (17-17)
  • Flex (16-16)
  • Thead (58-58)
  • Tr (60-60)
  • Th (61-61)
  • Tbody (59-59)
  • Td (62-62)
  • Spinner (48-48)
  • Text (29-29)
packages/clerk-js/src/ui/styledSystem/types.ts (1)
  • PropsOfComponent (58-58)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
packages/clerk-js/src/core/resources/CommercePaymentSource.ts (1)

89-92: Validate the 'card' hard-coded fallback against backend contract

Defaulting to ['card'] guarantees the property is never undefined, which is good, but it also silently overrides any future change where the backend might intentionally omit the field to let the client decide the order (or use a different default).
Please confirm that this assumption is stable and documented in the API contract; otherwise consider falling back to an empty array and letting the rendering layer decide, e.g.:

-this.paymentMethodOrder = data.payment_method_order ?? ['card'];
+this.paymentMethodOrder = data.payment_method_order ?? [];

or make the intent explicit with a comment.

packages/clerk-js/src/ui/elements/DataTable.tsx (1)

37-38: Guard against out-of-range page numbers

If page is 0 or exceeds pageCount, startingRow/endingRow become inconsistent.
Consider clamping page before these calculations or early-returning an empty state.

packages/clerk-js/src/core/resources/CommerceStatement.ts (1)

31-32: Interface mismatch: CommerceStatementJSON.timestamp still typed as number

new Date(data.timestamp) presumes timestamp is present. If the JSON interface wasn’t updated (or the back-end starts returning ISO strings) this will throw.
Please confirm that:

  1. CommerceStatementJSON.timestamp and CommerceStatementGroupJSON.timestamp were updated to string | number.
  2. A falsy guard is added:
-this.timestamp = new Date(data.timestamp);
+this.timestamp = data.timestamp ? new Date(data.timestamp) : new Date();

Also applies to: 52-54

Comment on lines +60 to +70
{isLoading ? (
<Tr>
<Td colSpan={4}>
<Spinner
colorScheme='primary'
sx={{ margin: 'auto', display: 'block' }}
elementDescriptor={descriptors.spinner}
/>
</Td>
</Tr>
) : !rows.length ? (
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Hard-coded colSpan={4} breaks when headers.length !== 4

Both the spinner row and the empty-state row assume exactly four columns.
If a caller renders 3 or 6 headers the table markup becomes invalid and causes layout glitches.

-<Td colSpan={4}>
+<Td colSpan={headers.length}>

Apply the same change in DataTableEmptyRow.

Also applies to: 100-111

🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/elements/DataTable.tsx around lines 60 to 70 and 100
to 111, the colSpan attribute is hard-coded to 4 for the spinner and empty-state
rows, which breaks the table layout if the number of headers is not 4. Replace
the hard-coded colSpan={4} with colSpan={headers.length} to dynamically match
the number of columns. Apply this change both in the spinner row and in the
DataTableEmptyRow component to ensure consistent and valid table markup
regardless of the headers count.

Comment on lines +115 to +120
export const DataTableRow = (props: PropsOfComponent<typeof Tr>) => {
return (
<Tr
{...props}
sx={t => ({ ':hover': { backgroundColor: t.colors.$neutralAlpha50 } })}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

DataTableRow overrides consumer-provided sx prop

Spreading props first and then specifying sx discards any custom styles passed in by the caller.

-export const DataTableRow = (props: PropsOfComponent<typeof Tr>) => {
-  return (
-    <Tr
-      {...props}
-      sx={t => ({ ':hover': { backgroundColor: t.colors.$neutralAlpha50 } })}
-    />
-  );
-};
+export const DataTableRow = React.forwardRef<HTMLTableRowElement, PropsOfComponent<typeof Tr>>(
+  ({ sx, ...rest }, ref) => (
+    <Tr
+      ref={ref}
+      {...rest}
+      sx={[
+        t => ({ ':hover': { backgroundColor: t.colors.$neutralAlpha50 } }),
+        sx,
+      ]}
+    />
+  ),
+);
📝 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.

Suggested change
export const DataTableRow = (props: PropsOfComponent<typeof Tr>) => {
return (
<Tr
{...props}
sx={t => ({ ':hover': { backgroundColor: t.colors.$neutralAlpha50 } })}
/>
export const DataTableRow = React.forwardRef<
HTMLTableRowElement,
PropsOfComponent<typeof Tr>
>(({ sx, ...rest }, ref) => (
<Tr
ref={ref}
{...rest}
sx={[
t => ({ ':hover': { backgroundColor: t.colors.$neutralAlpha50 } }),
sx,
]}
/>
));
🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/elements/DataTable.tsx around lines 115 to 120, the
DataTableRow component spreads props before specifying the sx prop, which causes
any sx styles passed by the consumer to be overridden. To fix this, spread props
after defining the sx prop and merge the consumer's sx styles with the hover
style, ensuring custom styles are preserved and combined correctly.

Copy link
Member

@panteliselef panteliselef left a comment

Choose a reason for hiding this comment

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

Added a few final comments. I recommend adding e2e tests for at least some of the functionality or things you consider easy to break that shouldn't.

For the changeset you can probably use an empty changeset since we haven't release the last one which is regarding the same feature.

@aeliox aeliox merged commit 2c6f805 into main Jun 13, 2025
39 checks passed
@aeliox aeliox deleted the keiran/cleanup-commerce-localizations branch June 13, 2025 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants