@@ -9,7 +9,11 @@ import {
99 useElements ,
1010 useStripe ,
1111} from '@stripe/react-stripe-js' ;
12- import { loadStripe , type StripeElementsOptions , type Stripe } from '@stripe/stripe-js' ;
12+ import {
13+ loadStripe ,
14+ type StripeElementsOptions ,
15+ type Stripe ,
16+ } from '@stripe/stripe-js' ;
1317
1418import {
1519 currencyValues ,
@@ -57,11 +61,6 @@ function toCurrencyCode(
5761 : resolveCurrencyFromLocale ( locale ) ;
5862}
5963
60- /**
61- * IMPORTANT:
62- * - In-app navigation uses next-intl routing -> DO NOT prefix locale manually.
63- * - Stripe return_url is an external redirect -> MUST include locale exactly once.
64- */
6564const IN_APP_SHOP_BASE = '/shop' ;
6665
6766function normalizeLocale ( raw : string ) : string {
@@ -73,13 +72,21 @@ function buildInAppPath(path: string): string {
7372 return `${ IN_APP_SHOP_BASE } ${ p } ` ;
7473}
7574
76- function buildStripeReturnUrl ( params : { locale : string ; inAppPath : string } ) : string {
75+ function buildStripeReturnUrl ( params : {
76+ locale : string ;
77+ inAppPath : string ;
78+ } ) : string {
7779 const loc = normalizeLocale ( params . locale ) ;
78- const p = params . inAppPath . startsWith ( '/' ) ? params . inAppPath : `/${ params . inAppPath } ` ;
80+ const p = params . inAppPath . startsWith ( '/' )
81+ ? params . inAppPath
82+ : `/${ params . inAppPath } ` ;
7983 return new URL ( `/${ loc } ${ p } ` , window . location . origin ) . toString ( ) ;
8084}
8185
82- function nextRouteForPaymentResult ( params : { orderId : string ; status ?: string | null } ) {
86+ function nextRouteForPaymentResult ( params : {
87+ orderId : string ;
88+ status ?: string | null ;
89+ } ) {
8390 const { orderId, status } = params ;
8491 const id = encodeURIComponent ( orderId ) ;
8592
@@ -88,7 +95,11 @@ function nextRouteForPaymentResult(params: { orderId: string; status?: string |
8895
8996 if ( ! status ) return success ;
9097
91- if ( status === 'succeeded' || status === 'processing' || status === 'requires_capture' ) {
98+ if (
99+ status === 'succeeded' ||
100+ status === 'processing' ||
101+ status === 'requires_capture'
102+ ) {
92103 return success ;
93104 }
94105
@@ -99,7 +110,6 @@ function nextRouteForPaymentResult(params: { orderId: string; status?: string |
99110 return success ;
100111}
101112
102- /** Unified CTA (hero) */
103113const SHOP_HERO_CTA = cn (
104114 SHOP_CTA_BASE ,
105115 SHOP_CTA_INTERACTIVE ,
@@ -110,7 +120,6 @@ const SHOP_HERO_CTA = cn(
110120 'shadow-[var(--shop-hero-btn-shadow)] hover:shadow-[var(--shop-hero-btn-shadow-hover)]'
111121) ;
112122
113- /** Unified outline */
114123const SHOP_OUTLINE = cn (
115124 SHOP_OUTLINE_BTN_BASE ,
116125 SHOP_OUTLINE_BTN_INTERACTIVE ,
@@ -122,19 +131,22 @@ const SHOP_OUTLINE = cn(
122131function HeroCtaInner ( { children } : { children : React . ReactNode } ) {
123132 return (
124133 < >
125- { /* base gradient */ }
126134 < span
127135 className = "absolute inset-0"
128- style = { shopCtaGradient ( '--shop-hero-btn-bg' , '--shop-hero-btn-bg-hover' ) }
136+ style = { shopCtaGradient (
137+ '--shop-hero-btn-bg' ,
138+ '--shop-hero-btn-bg-hover'
139+ ) }
129140 aria-hidden = "true"
130141 />
131- { /* hover wave overlay */ }
132142 < span
133143 className = { SHOP_CTA_WAVE }
134- style = { shopCtaGradient ( '--shop-hero-btn-bg-hover' , '--shop-hero-btn-bg' ) }
144+ style = { shopCtaGradient (
145+ '--shop-hero-btn-bg-hover' ,
146+ '--shop-hero-btn-bg'
147+ ) }
135148 aria-hidden = "true"
136149 />
137- { /* glass inset */ }
138150 < span className = { SHOP_CTA_INSET } aria-hidden = "true" />
139151
140152 < span className = "relative z-10" > { children } </ span >
@@ -155,7 +167,9 @@ function StripePaymentForm({ orderId, locale }: PaymentFormProps) {
155167 setErrorMessage ( null ) ;
156168
157169 if ( ! stripe || ! elements ) {
158- setErrorMessage ( 'Payment is not ready yet. Please try again in a moment.' ) ;
170+ setErrorMessage (
171+ 'Payment is not ready yet. Please try again in a moment.'
172+ ) ;
159173 return ;
160174 }
161175
@@ -190,14 +204,20 @@ function StripePaymentForm({ orderId, locale }: PaymentFormProps) {
190204 } catch ( error ) {
191205 logError ( 'stripe_payment_confirm_failed' , error , { orderId } ) ;
192206 setErrorMessage ( 'We couldn’t confirm your payment. Please try again.' ) ;
193- router . push ( buildInAppPath ( `/checkout/error?orderId=${ encodeURIComponent ( orderId ) } ` ) ) ;
207+ router . push (
208+ buildInAppPath ( `/checkout/error?orderId=${ encodeURIComponent ( orderId ) } ` )
209+ ) ;
194210 } finally {
195211 setSubmitting ( false ) ;
196212 }
197213 }
198214
199215 return (
200- < form onSubmit = { handleSubmit } className = "space-y-4" aria-label = "Stripe payment form" >
216+ < form
217+ onSubmit = { handleSubmit }
218+ className = "space-y-4"
219+ aria-label = "Stripe payment form"
220+ >
201221 < PaymentElement />
202222
203223 < button
@@ -206,7 +226,9 @@ function StripePaymentForm({ orderId, locale }: PaymentFormProps) {
206226 className = { SHOP_HERO_CTA }
207227 aria-disabled = { ! stripe || submitting }
208228 >
209- < HeroCtaInner > { submitting ? 'Processing...' : 'Submit payment' } </ HeroCtaInner >
229+ < HeroCtaInner >
230+ { submitting ? 'Processing...' : 'Submit payment' }
231+ </ HeroCtaInner >
210232 </ button >
211233
212234 { errorMessage ? (
@@ -227,7 +249,10 @@ export default function StripePaymentClient({
227249 currency,
228250 locale,
229251} : StripePaymentClientProps ) {
230- const uiCurrency = useMemo ( ( ) => toCurrencyCode ( currency , locale ) , [ currency , locale ] ) ;
252+ const uiCurrency = useMemo (
253+ ( ) => toCurrencyCode ( currency , locale ) ,
254+ [ currency , locale ]
255+ ) ;
231256
232257 const stripePromise = useMemo ( ( ) => {
233258 if ( ! paymentsEnabled || ! publishableKey ) return null ;
@@ -244,18 +269,29 @@ export default function StripePaymentClient({
244269
245270 if ( ! paymentsEnabled ) {
246271 return (
247- < section className = "space-y-3 text-sm text-muted-foreground" aria-label = "Payments disabled" >
272+ < section
273+ className = "space-y-3 text-sm text-muted-foreground"
274+ aria-label = "Payments disabled"
275+ >
248276 < p > Payments are disabled in this environment.</ p >
249277
250- < nav className = "flex flex-col gap-3 sm:flex-row" aria-label = "Next steps" >
278+ < nav
279+ className = "flex flex-col gap-3 sm:flex-row"
280+ aria-label = "Next steps"
281+ >
251282 < Link
252- href = { buildInAppPath ( `/checkout/success?orderId=${ encodeURIComponent ( orderId ) } ` ) }
283+ href = { buildInAppPath (
284+ `/checkout/success?orderId=${ encodeURIComponent ( orderId ) } `
285+ ) }
253286 className = { cn ( SHOP_HERO_CTA , 'w-full sm:w-auto' ) }
254287 >
255288 < HeroCtaInner > Continue</ HeroCtaInner >
256289 </ Link >
257290
258- < Link href = { buildInAppPath ( '/cart' ) } className = { cn ( SHOP_OUTLINE , 'w-full sm:w-auto' ) } >
291+ < Link
292+ href = { buildInAppPath ( '/cart' ) }
293+ className = { cn ( SHOP_OUTLINE , 'w-full sm:w-auto' ) }
294+ >
259295 Back to cart
260296 </ Link >
261297 </ nav >
@@ -265,10 +301,16 @@ export default function StripePaymentClient({
265301
266302 if ( ! clientSecret || ! clientSecret . trim ( ) ) {
267303 return (
268- < section className = "space-y-3 text-sm text-muted-foreground" aria-label = "Payment initialization failed" >
304+ < section
305+ className = "space-y-3 text-sm text-muted-foreground"
306+ aria-label = "Payment initialization failed"
307+ >
269308 < p > Payment cannot be initialized. Please try again later.</ p >
270309
271- < Link href = { buildInAppPath ( '/cart' ) } className = { cn ( SHOP_OUTLINE , 'w-full sm:w-auto' ) } >
310+ < Link
311+ href = { buildInAppPath ( '/cart' ) }
312+ className = { cn ( SHOP_OUTLINE , 'w-full sm:w-auto' ) }
313+ >
272314 Return to cart
273315 </ Link >
274316 </ section >
@@ -295,7 +337,9 @@ export default function StripePaymentClient({
295337 </ span >
296338 </ div >
297339
298- < p className = "text-xs uppercase tracking-wide text-muted-foreground" > { uiCurrency } </ p >
340+ < p className = "text-xs uppercase tracking-wide text-muted-foreground" >
341+ { uiCurrency }
342+ </ p >
299343 </ div >
300344
301345 < StripePaymentForm orderId = { orderId } locale = { locale } />
0 commit comments