Skip to content

Commit f68cc52

Browse files
authored
Merge pull request #20364 from mozilla/PAY-3641
feat(payments-next): Display free trial information on processing page
2 parents a60f790 + c0bd1e8 commit f68cc52

3 files changed

Lines changed: 53 additions & 19 deletions

File tree

  • apps/payments/next/app/[locale]/[offeringId]/[interval]
  • libs/payments/ui/src/lib/client/components/PurchaseDetails

apps/payments/next/app/[locale]/[offeringId]/[interval]/checkout/[cartId]/layout.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ export default async function CheckoutLayout({
8181

8282
<div className="mb-6 tablet:mt-6 tablet:min-w-[18rem] tablet:max-w-xs tablet:col-start-2 tablet:row-start-1 tablet:row-span-3">
8383
<PurchaseDetails
84-
invoice={cart.latestInvoicePreview ?? cart.upcomingInvoicePreview}
84+
invoice={
85+
cart.trialEndDate || cart.freeTrialEligibility
86+
? cart.upcomingInvoicePreview
87+
: (cart.latestInvoicePreview ?? cart.upcomingInvoicePreview)
88+
}
8589
offeringPrice={cart.offeringPrice}
8690
purchaseDetails={purchaseDetails}
8791
priceInterval={
@@ -108,14 +112,11 @@ export default async function CheckoutLayout({
108112
locale={locale}
109113
showPrices={
110114
cart.state === CartState.START ||
115+
cart.state === CartState.PROCESSING ||
111116
cart.state === CartState.SUCCESS
112117
}
113118
freeTrialEligibility={cart.freeTrialEligibility}
114-
firstChargeTax={
115-
(cart.upcomingInvoicePreview.subsequentTax ?? cart.upcomingInvoicePreview.taxAmounts)
116-
.filter((tax) => !tax.inclusive)
117-
.reduce((sum, tax) => sum + tax.amount, 0)
118-
}
119+
firstChargeAmount={cart.upcomingInvoicePreview.totalAmount}
119120
interval={cart.interval}
120121
cartState={cart.state}
121122
trialStartDate={cart.trialStartDate}

apps/payments/next/app/[locale]/[offeringId]/[interval]/upgrade/[cartId]/(mainLayout)/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export default async function UpgradeSuccessLayout({
8989
locale={locale}
9090
showPrices={
9191
cart.state === CartState.START ||
92+
cart.state === CartState.PROCESSING ||
9293
cart.state === CartState.SUCCESS
9394
}
9495
/>

libs/payments/ui/src/lib/client/components/PurchaseDetails/index.tsx

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { Localized } from '@fluent/react';
88
import Image from 'next/image';
9-
import { useState } from 'react';
9+
import { useEffect, useState } from 'react';
1010
import { InvoicePreview } from '@fxa/payments/customer';
1111
import alertCircle from '@fxa/shared/assets/images/alert-black-circle.svg';
1212
import infoLogo from '@fxa/shared/assets/images/info.svg';
@@ -32,7 +32,7 @@ type PurchaseDetailsProps = {
3232
freeTrialEligibility?: {
3333
trialLengthDays: number;
3434
} | null;
35-
firstChargeTax?: number;
35+
firstChargeAmount?: number;
3636
interval?: string;
3737
cartState?: string;
3838
trialStartDate?: number;
@@ -49,13 +49,44 @@ export function PurchaseDetails(props: PurchaseDetailsProps) {
4949
locale,
5050
showPrices,
5151
freeTrialEligibility,
52-
firstChargeTax,
52+
firstChargeAmount,
5353
interval,
5454
cartState,
5555
trialStartDate,
5656
trialEndDate,
5757
} = props;
5858
const { details, productName, subtitle, webIcon } = purchaseDetails;
59+
60+
// Cache props from START as server re-renders during PROCESSING which
61+
// may return different data as Stripe state changes
62+
const [stableInvoice, setStableInvoice] = useState(invoice);
63+
const [stableTotalPrice, setStableTotalPrice] = useState(totalPrice);
64+
const [stableFreeTrialEligibility, setStableFreeTrialEligibility] =
65+
useState(freeTrialEligibility);
66+
const [stableTrialStartDate, setStableTrialStartDate] =
67+
useState(trialStartDate);
68+
const [stableTrialEndDate, setStableTrialEndDate] = useState(trialEndDate);
69+
useEffect(() => {
70+
const isFreeTrial =
71+
!!stableTrialEndDate ||
72+
(!!stableFreeTrialEligibility &&
73+
stableFreeTrialEligibility.trialLengthDays > 0);
74+
if (cartState === 'start' || (cartState === 'success' && !isFreeTrial)) {
75+
setStableInvoice(invoice);
76+
setStableTotalPrice(totalPrice);
77+
setStableFreeTrialEligibility(freeTrialEligibility);
78+
setStableTrialStartDate(trialStartDate);
79+
setStableTrialEndDate(trialEndDate);
80+
}
81+
}, [
82+
cartState,
83+
invoice,
84+
totalPrice,
85+
freeTrialEligibility,
86+
trialStartDate,
87+
trialEndDate,
88+
]);
89+
5990
const {
6091
amountDue,
6192
creditApplied,
@@ -69,27 +100,28 @@ export function PurchaseDetails(props: PurchaseDetailsProps) {
69100
taxAmounts,
70101
totalAmount,
71102
unusedAmountTotal,
72-
} = invoice;
103+
} = stableInvoice;
73104
const exclusiveTaxRates = taxAmounts.filter(
74105
(taxAmount) => !taxAmount.inclusive
75106
);
76107
const freeTrial =
77-
!!trialEndDate ||
78-
(!!freeTrialEligibility && freeTrialEligibility.trialLengthDays > 0);
108+
!!stableTrialEndDate ||
109+
(!!stableFreeTrialEligibility &&
110+
stableFreeTrialEligibility.trialLengthDays > 0);
79111
const trialDayLength =
80-
trialStartDate && trialEndDate
81-
? Math.round((trialEndDate - trialStartDate) / 86400)
82-
: freeTrialEligibility?.trialLengthDays;
112+
stableTrialStartDate && stableTrialEndDate
113+
? Math.round((stableTrialEndDate - stableTrialStartDate) / 86400)
114+
: stableFreeTrialEligibility?.trialLengthDays;
83115
const formattedTrialEndDate = freeTrial
84116
? getLocalizedDateString(
85-
trialEndDate ??
117+
stableTrialEndDate ??
86118
Math.floor((Date.now() + (trialDayLength ?? 0) * 86400000) / 1000),
87119
false,
88120
locale
89121
)
90122
: '';
91123
const formattedFirstCharge = getLocalizedCurrencyString(
92-
offeringPrice + (firstChargeTax ?? 0),
124+
firstChargeAmount ?? offeringPrice,
93125
currency,
94126
locale
95127
);
@@ -367,9 +399,9 @@ export function PurchaseDetails(props: PurchaseDetailsProps) {
367399
>
368400
{freeTrial
369401
? getLocalizedCurrencyString(0, currency, locale)
370-
: !!unusedAmountTotal
402+
: !!unusedAmountTotal || !!creditApplied
371403
? getLocalizedCurrencyString(amountDue, currency, locale)
372-
: totalPrice}
404+
: stableTotalPrice}
373405
</p>
374406
</div>
375407

0 commit comments

Comments
 (0)