@@ -6,9 +6,8 @@ import { getOrderSummary } from '@/lib/services/orders';
66import { OrderNotFoundError } from '@/lib/services/errors' ;
77import { orderIdParamSchema } from '@/lib/validation/shop' ;
88import { getStripeEnv } from '@/lib/env/stripe' ;
9- import { createPaymentIntent , retrievePaymentIntent } from '@/lib/psp/stripe' ;
10- import { setOrderPaymentIntent } from '@/lib/services/orders' ;
119import { logError } from '@/lib/logging' ;
10+ import { ensureStripePaymentIntentForOrder } from '@/lib/services/orders/payment-attempts' ;
1211
1312export const dynamic = 'force-dynamic' ;
1413export const revalidate = 0 ;
@@ -90,6 +89,7 @@ export default async function PaymentPage(props: PaymentPageProps) {
9089 const clearCart = shouldClearCart ( searchParams ) ;
9190 const cc = clearCart ? '&clearCart=1' : '' ;
9291 const { locale } = params ;
92+ const shopBase = `/${ locale } /shop` ;
9393
9494 const orderId = getOrderId ( params ) ;
9595
@@ -101,13 +101,13 @@ export default async function PaymentPage(props: PaymentPageProps) {
101101 >
102102 < nav className = "mt-6 flex justify-center gap-3" aria-label = "Next steps" >
103103 < Link
104- href = "/shop/ cart"
104+ href = { ` ${ shopBase } / cart` }
105105 className = "inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-semibold uppercase tracking-wide text-foreground hover:bg-secondary"
106106 >
107107 Go to cart
108108 </ Link >
109109 < Link
110- href = "/shop/ products"
110+ href = { ` ${ shopBase } / products` }
111111 className = "inline-flex items-center justify-center rounded-md bg-accent px-4 py-2 text-sm font-semibold uppercase tracking-wide text-accent-foreground hover:bg-accent/90"
112112 >
113113 Continue shopping
@@ -133,13 +133,13 @@ export default async function PaymentPage(props: PaymentPageProps) {
133133 aria-label = "Next steps"
134134 >
135135 < Link
136- href = "/shop/ cart"
136+ href = { ` ${ shopBase } / cart` }
137137 className = "inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-semibold uppercase tracking-wide text-foreground hover:bg-secondary"
138138 >
139139 Go to cart
140140 </ Link >
141141 < Link
142- href = "/shop/ products"
142+ href = { ` ${ shopBase } / products` }
143143 className = "inline-flex items-center justify-center rounded-md bg-accent px-4 py-2 text-sm font-semibold uppercase tracking-wide text-accent-foreground hover:bg-accent/90"
144144 >
145145 Continue shopping
@@ -163,50 +163,28 @@ export default async function PaymentPage(props: PaymentPageProps) {
163163 let clientSecret = resolveClientSecret ( searchParams ) ;
164164 const publishableKey = paymentsEnabled ? stripeEnv . publishableKey : null ;
165165
166- // Ensure we have a clientSecret even when URL doesn't include ?clientSecret=...
167- // Source of truth for payment finality is webhook; this only initializes Elements.
168166 if (
169167 paymentsEnabled &&
170168 publishableKey &&
171169 ( ! clientSecret || ! clientSecret . trim ( ) )
172170 ) {
173171 const existingPi = order . paymentIntentId ?. trim ( ) ?? '' ;
174- let phase :
175- | 'retrievePaymentIntent'
176- | 'createPaymentIntent'
177- | 'setOrderPaymentIntent'
178- | 'unknown' = 'unknown' ;
172+ let phase : 'ensureStripePaymentIntentForOrder' | 'unknown' = 'unknown' ;
179173
180174 try {
181- if ( existingPi ) {
182- phase = 'retrievePaymentIntent' ;
183- const retrieved = await retrievePaymentIntent ( existingPi ) ;
184- clientSecret = retrieved . clientSecret ;
185- } else {
186- phase = 'createPaymentIntent' ;
187- const created = await createPaymentIntent ( {
188- amount : order . totalAmountMinor ,
189- currency : order . currency ,
190- orderId : order . id ,
191- idempotencyKey : `pi:${ order . id } ` ,
192- } ) ;
193-
194- phase = 'setOrderPaymentIntent' ;
195- await setOrderPaymentIntent ( {
196- orderId : order . id ,
197- paymentIntentId : created . paymentIntentId ,
198- } ) ;
175+ phase = 'ensureStripePaymentIntentForOrder' ;
176+ const ensured = await ensureStripePaymentIntentForOrder ( {
177+ orderId : order . id ,
178+ existingPaymentIntentId : existingPi || null ,
179+ } ) ;
199180
200- clientSecret = created . clientSecret ;
201- }
181+ clientSecret = ensured . clientSecret ;
202182 } catch ( error ) {
203183 logError ( 'payment_page_failed' , error , {
204184 orderId : order . id ,
205185 existingPi,
206186 phase,
207187 } ) ;
208-
209- // Leave clientSecret empty -> UI shows "Payment cannot be initialized"
210188 }
211189 }
212190
@@ -223,13 +201,13 @@ export default async function PaymentPage(props: PaymentPageProps) {
223201 aria-label = "Next steps"
224202 >
225203 < Link
226- href = { `/shop /checkout/success?orderId=${ order . id } ${ cc } ` }
204+ href = { `${ shopBase } /checkout/success?orderId=${ order . id } ${ cc } ` }
227205 className = "inline-flex items-center justify-center rounded-md bg-accent px-4 py-2 text-sm font-semibold uppercase tracking-wide text-accent-foreground hover:bg-accent/90"
228206 >
229207 View confirmation
230208 </ Link >
231209 < Link
232- href = "/shop/ products"
210+ href = { ` ${ shopBase } / products` }
233211 className = "inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-semibold uppercase tracking-wide text-foreground hover:bg-secondary"
234212 >
235213 Continue shopping
0 commit comments