66
77import { Localized } from '@fluent/react' ;
88import Image from 'next/image' ;
9- import { useState } from 'react' ;
9+ import { useEffect , useState } from 'react' ;
1010import { InvoicePreview } from '@fxa/payments/customer' ;
1111import alertCircle from '@fxa/shared/assets/images/alert-black-circle.svg' ;
1212import 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