Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,7 @@ export default function CommissionsPageClient() {
id: "commissions",
header: "Commissions",
accessorKey: "commissions",
cell: ({ row }) =>
currencyFormatter(row.original.commissions / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.commissions / 100),
},
],
pagination,
Expand Down
18 changes: 3 additions & 15 deletions apps/web/app/(ee)/admin.dub.co/(dashboard)/payouts/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,31 +151,19 @@ export default function PayoutsPageClient() {
id: "amount",
header: "Amount",
accessorKey: "amount",
cell: ({ row }) =>
currencyFormatter(row.original.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.amount / 100),
},
{
id: "fee",
header: "Fee",
accessorKey: "fee",
cell: ({ row }) =>
currencyFormatter(row.original.fee / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.fee / 100),
},
{
id: "total",
header: "Total",
accessorKey: "total",
cell: ({ row }) =>
currencyFormatter(row.original.total / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.total / 100),
},
],
pagination,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,7 @@ export default function RevenuePageClient() {
id: "revenue",
header: "Affiliate Revenue",
accessorKey: "revenue",
cell: ({ row }) =>
currencyFormatter(row.original.saleAmount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.saleAmount / 100),
},
],
pagination,
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export async function POST(req: Request) {

if (availableBalance <= 0) {
return logAndRespond(
`The available balance (${currencyFormatter(availableBalance / 100, { maximumFractionDigits: 2, currency })}) for partner ${partner.email} (${stripeAccount}) is less than or equal to 0 after subtracting pending payouts. Skipping...`,
`The available balance (${currencyFormatter(availableBalance / 100, { currency })}) for partner ${partner.email} (${stripeAccount}) is less than or equal to 0 after subtracting pending payouts. Skipping...`,
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

Bug: dividing by 100 is incorrect for non-2-decimal currencies

Stripe amounts are in minor units. Using /100 breaks for zero-decimal (e.g., JPY, HUF, TWD) and 3-decimal (e.g., KWD, BHD) currencies. Convert by currency exponent and normalize the code to uppercase for Intl.

Apply this minimal change:

- `The available balance (${currencyFormatter(availableBalance / 100, { currency })}) for partner ${partner.email} (${stripeAccount}) is less than or equal to 0 after subtracting pending payouts. Skipping...`,
+ `The available balance (${currencyFormatter(minorToMajor(availableBalance, currency), { currency: currency.toUpperCase() })}) for partner ${partner.email} (${stripeAccount}) is less than or equal to 0 after subtracting pending payouts. Skipping...`,

Helper (outside this hunk):

const EXPONENT: Record<string, number> = {
  // zero-decimal
  jpy: 0, huf: 0, twd: 0, krw: 0, vnd: 0, clp: 0, pyg: 0, rwf: 0, bif: 0,
  djf: 0, gnf: 0, kmf: 0, mga: 0, vuv: 0, xaf: 0, xof: 0, xpf: 0,
  // three-decimal
  kwd: 3, bhd: 3, jod: 3, omr: 3, tnd: 3, iqd: 3,
};
const minorToMajor = (amountMinor: number, ccy: string) =>
  amountMinor / 10 ** (EXPONENT[ccy.toLowerCase()] ?? 2);
🤖 Prompt for AI Agents
In apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts around line 83,
the template currently divides availableBalance by 100 which is wrong for
currencies with non-2 decimal exponents; add the provided EXPONENT map and
minorToMajor helper outside this hunk, then replace the /100 conversion with
minorToMajor(availableBalance, currency) and ensure the currency passed to Intl
formatting is normalized to uppercase (e.g., { currency: currency.toUpperCase()
}) so amounts are correctly converted and formatted for zero-, two- and
three-decimal currencies.

);
}

Expand All @@ -104,7 +104,7 @@ export async function POST(req: Request) {
);

console.log(
`Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(stripePayout.amount / 100, { maximumFractionDigits: 2, currency: stripePayout.currency })})`,
`Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(stripePayout.amount / 100, { currency: stripePayout.currency })})`,
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

Same currency-scale issue here + normalize currency

Use exponent-aware conversion and uppercase the currency code for Intl.

- `Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(stripePayout.amount / 100, { currency: stripePayout.currency })})`,
+ `Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(minorToMajor(stripePayout.amount, stripePayout.currency), { currency: stripePayout.currency.toUpperCase() })})`,
📝 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
`Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(stripePayout.amount / 100, { currency: stripePayout.currency })})`,
`Stripe payout created for partner ${partner.email} (${stripeAccount}): ${stripePayout.id} (${currencyFormatter(minorToMajor(stripePayout.amount, stripePayout.currency), { currency: stripePayout.currency.toUpperCase() })})`,
🤖 Prompt for AI Agents
In apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts around line
107, the payout log uses a naive cents-to-major conversion and a lowercase
currency code; change it to use an exponent-aware conversion (divide
stripePayout.amount by 10**minorUnits for the currency) and normalize the
currency code to uppercase before formatting with Intl.NumberFormat so the
displayed amount and currency are correct for currencies with different
minor-unit scales.

);

const transfers = await stripe.transfers.list({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ export function ReferralsEmbedEarningsSummary({
<div key={label} className="flex justify-between text-sm">
<span className="text-content-subtle font-medium">{label}</span>
<span className="text-content-default font-semibold">
{currencyFormatter(value / 100, {
style: "currency",
currency: "USD",
maximumFractionDigits: 2,
})}
{currencyFormatter(value / 100)}
</span>
</div>
))}
Expand Down
10 changes: 2 additions & 8 deletions apps/web/app/(ee)/app.dub.co/embed/referrals/earnings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,15 @@ export function ReferralsEmbedEarnings({ salesCount }: { salesCount: number }) {
id: "amount",
header: "Amount",
cell: ({ row }) => {
return currencyFormatter(row.original.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return currencyFormatter(row.original.amount / 100);
},
},
{
id: "earnings",
header: "Earnings",
accessorKey: "earnings",
cell: ({ row }) => {
return currencyFormatter(row.original.earnings / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return currencyFormatter(row.original.earnings / 100);
},
},
{
Expand Down
5 changes: 1 addition & 4 deletions apps/web/app/(ee)/app.dub.co/embed/referrals/leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,7 @@ export function ReferralsEmbedLeaderboard() {
id: "totalCommissions",
header: "Earnings",
cell: ({ row }) => {
return currencyFormatter(row.original.totalCommissions / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return currencyFormatter(row.original.totalCommissions / 100);
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,15 @@ export async function DomainRenewalInvoice({
const invoiceSummaryDetails = [
{
label: "Invoice amount",
value: currencyFormatter(invoice.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
value: currencyFormatter(invoice.amount / 100),
},
{
label: `Platform fees (${Math.round((invoice.fee / invoice.amount) * 100)}%)`,
value: `${currencyFormatter(invoice.fee / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`,
value: `${currencyFormatter(invoice.fee / 100)}`,
},
{
label: "Invoice total",
value: currencyFormatter(invoice.total / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
value: currencyFormatter(invoice.total / 100),
},
];

Expand Down Expand Up @@ -212,10 +203,7 @@ export async function DomainRenewalInvoice({
Total
</Text>
<Text style={tw("text-neutral-800 font-medium text-[16px]")}>
{currencyFormatter(invoice.total / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(invoice.total / 100)}
</Text>
</View>
</View>
Expand Down Expand Up @@ -244,10 +232,7 @@ export async function DomainRenewalInvoice({
>
<Text style={tw("w-[70%] p-2.5")}>{domain.slug}</Text>
<Text style={tw("w-[30%] p-2.5")}>
{currencyFormatter(domain.renewalFee / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(domain.renewalFee / 100)}
</Text>
</View>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,37 +129,23 @@ export async function PartnerPayoutInvoice({

const nonUsdTransactionDisplay =
chargeAmount && chargeCurrency && chargeCurrency !== "usd"
? ` (${currencyFormatter(
chargeAmount / 100,
{
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
chargeCurrency.toUpperCase(),
)})`
? ` (${currencyFormatter(chargeAmount / 100, {
currency: chargeCurrency.toUpperCase(),
})})`
: "";

Comment on lines 130 to 136
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

Incorrect minor-unit conversion for non-USD currencies

Stripe amounts are in the currency’s smallest unit (0/2/3 digits). Dividing by 100 will be wrong for JPY (0) and KWD/BHD/JOD… (3). Convert using the currency’s fraction digits.

-  const nonUsdTransactionDisplay =
-    chargeAmount && chargeCurrency && chargeCurrency !== "usd"
-      ? ` (${currencyFormatter(chargeAmount / 100, {
-          currency: chargeCurrency.toUpperCase(),
-        })})`
-      : "";
+  const nonUsdTransactionDisplay =
+    chargeAmount && chargeCurrency && chargeCurrency !== "usd"
+      ? ` (${currencyFormatter(
+          chargeAmount /
+            Math.pow(
+              10,
+              new Intl.NumberFormat("en-US", {
+                style: "currency",
+                currency: chargeCurrency.toUpperCase(),
+              }).resolvedOptions().maximumFractionDigits,
+            ),
+          { currency: chargeCurrency.toUpperCase() },
+        )})`
+      : "";
📝 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
const nonUsdTransactionDisplay =
chargeAmount && chargeCurrency && chargeCurrency !== "usd"
? ` (${currencyFormatter(
chargeAmount / 100,
{
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
chargeCurrency.toUpperCase(),
)})`
? ` (${currencyFormatter(chargeAmount / 100, {
currency: chargeCurrency.toUpperCase(),
})})`
: "";
const nonUsdTransactionDisplay =
chargeAmount && chargeCurrency && chargeCurrency !== "usd"
? ` (${currencyFormatter(
chargeAmount /
Math.pow(
10,
new Intl.NumberFormat("en-US", {
style: "currency",
currency: chargeCurrency.toUpperCase(),
}).resolvedOptions().maximumFractionDigits,
),
{ currency: chargeCurrency.toUpperCase() },
)})`
: "";
🤖 Prompt for AI Agents
In apps/web/app/(ee)/app.dub.co/invoices/[invoiceId]/partner-payout-invoice.tsx
around lines 130-136, the code divides Stripe amounts by 100 for non-USD
currencies which is incorrect for currencies with 0 or 3 minor digits; instead,
determine the currency’s fraction digits (e.g. via new
Intl.NumberFormat(undefined, { style: 'currency', currency: chargeCurrency
}).resolvedOptions().maximumFractionDigits) and compute divisor = 10 **
fractionDigits, then convert the integer amount by dividing by that divisor
before passing to currencyFormatter; ensure chargeCurrency is upper-cased and
handle missing values safely.

const invoiceSummaryDetails = [
{
label: "Invoice amount",
value: currencyFormatter(invoice.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
value: currencyFormatter(invoice.amount / 100),
},
{
label: `Platform fees (${Math.round((invoice.fee / invoice.amount) * 100)}%)`,
value: `${currencyFormatter(invoice.fee / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`,
value: `${currencyFormatter(invoice.fee / 100)}`,
},
{
label: "Invoice total",
value: `${currencyFormatter(invoice.total / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}${nonUsdTransactionDisplay}`,
value: `${currencyFormatter(invoice.total / 100)}${nonUsdTransactionDisplay}`,
},
// if customer is in EU or AU, add VAT/GST reverse charge note
...(EU_CUSTOMER || AU_CUSTOMER
Expand Down Expand Up @@ -290,10 +276,7 @@ export async function PartnerPayoutInvoice({
Total
</Text>
<Text style={tw("text-neutral-800 font-medium text-[16px]")}>
{currencyFormatter(invoice.total / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(invoice.total / 100)}
</Text>
</View>
</View>
Expand Down Expand Up @@ -353,10 +336,7 @@ export async function PartnerPayoutInvoice({
)}
</Text>
<Text style={tw("w-1/6 p-3.5")}>
{currencyFormatter(payout.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(payout.amount / 100)}
</Text>
</View>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,7 @@ function PayoutDetailsSheetContent({ payout }: PayoutDetailsSheetProps) {

Amount: (
<div className="flex items-center gap-2">
<strong>
{currencyFormatter(payout.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</strong>
<strong>{currencyFormatter(payout.amount / 100)}</strong>

{INVOICE_AVAILABLE_PAYOUT_STATUSES.includes(payout.status) && (
<Tooltip content="View invoice">
Expand Down Expand Up @@ -167,11 +162,7 @@ function PayoutDetailsSheetContent({ payout }: PayoutDetailsSheetProps) {
{
id: "earnings",
header: "Earnings",
cell: ({ row }) =>
currencyFormatter(row.original.earnings / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
cell: ({ row }) => currencyFormatter(row.original.earnings / 100),
},
],
columnPinning: { right: ["earnings"] },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,7 @@ function PayoutStatsCard({
{error ? (
"-"
) : (
<>
{amount > 0
? currencyFormatter(amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
: "$0.00"}
</>
<>{amount > 0 ? currencyFormatter(amount / 100) : "$0.00"}</>
)}
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,7 @@ function AmountRowItem({
status: PayoutStatus;
minPayoutAmount: number;
}) {
const display = currencyFormatter(amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
const display = currencyFormatter(amount / 100);

if (status === PayoutStatus.pending && amount < minPayoutAmount) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,7 @@ export function EarningsCompositeChart() {
})}
</p>
<p className="text-right leading-none text-neutral-500">
{currencyFormatter((d.values.total || 0) / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter((d.values.total || 0) / 100)}
</p>
</div>
<div className="grid max-w-64 grid-cols-[minmax(0,1fr),min-content] gap-x-6 gap-y-2 px-4 py-3 text-xs">
Expand All @@ -204,10 +201,7 @@ export function EarningsCompositeChart() {
</span>
</div>
<p className="text-right text-neutral-500">
{currencyFormatter(valueAccessor(d), {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(valueAccessor(d))}
</p>
</Fragment>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,7 @@ export function EarningsTablePartner({ limit }: { limit?: number }) {
accessorKey: "amount",
cell: ({ row }) =>
row.original.amount
? currencyFormatter(row.original.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
? currencyFormatter(row.original.amount / 100)
: "-",
},
{
Expand All @@ -167,10 +164,7 @@ export function EarningsTablePartner({ limit }: { limit?: number }) {
cell: ({ row }) => {
const commission = row.original;

const earnings = currencyFormatter(commission.earnings / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
const earnings = currencyFormatter(commission.earnings / 100);

if (commission.description) {
const reason =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,7 @@ function BrandedChart({
</span>
<p className="text-right text-neutral-500">
{currency
? currencyFormatter(d.values.main, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
? currencyFormatter(d.values.main)
: nFormatter(d.values.main)}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ export function PayoutsCard({ programId }: { programId?: string }) {
>
<div className="flex flex-col">
<span className="text-xs font-medium text-neutral-800">
{currencyFormatter(payout.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
{currencyFormatter(payout.amount / 100)}
</span>
<span className="text-[0.7rem] text-neutral-500">
{formatPeriod(payout)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,7 @@ export const GET = withPartnerProfile(async ({ partner, params }) => {
label: "Payout amount",
value: (
<Text style={tw("text-neutral-800 w-2/3")}>
{currencyFormatter(payout.amount / 100, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}{" "}
{currencyFormatter(payout.amount / 100)}{" "}
<Text style={tw("text-neutral-500")}>
({payout._count.commissions}{" "}
{pluralize("commission", payout._count.commissions)})
Expand Down
4 changes: 1 addition & 3 deletions apps/web/app/api/callback/plain/partner/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,7 @@ export async function POST(req: NextRequest) {
...partnerProfile.programs.flatMap(
({ program, createdAt, totalCommissions }) => [
plainUsageSection({
usage: currencyFormatter(totalCommissions / 100, {
maximumFractionDigits: 2,
}),
usage: currencyFormatter(totalCommissions / 100),
label: program.name,
sublabel: `Partner since ${formatDate(createdAt)}`,
color: "GREEN",
Expand Down
Loading