Skip to content

Commit 0e17ec6

Browse files
committed
guest flow changes
1 parent 4b3b755 commit 0e17ec6

File tree

2 files changed

+74
-33
lines changed

2 files changed

+74
-33
lines changed

packages/commerce-sdk-react/src/auth/index.ts

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,38 +1268,54 @@ class Auth {
12681268
* A wrapper method for commerce-sdk-isomorphic helper: authorizePasswordless.
12691269
*/
12701270
async authorizePasswordless(parameters: AuthorizePasswordlessParams) {
1271+
1272+
const slasClient = this.client
12711273
const usid = this.get('usid')
12721274
const callbackURI = parameters.callbackURI || this.passwordlessLoginCallbackURI
12731275
const finalMode = parameters.mode || (callbackURI ? 'callback' : 'sms')
12741276

1275-
const res = await (helpers as unknown as Helpers).authorizePasswordless({
1276-
slasClient: this.client,
1277-
credentials: {
1278-
clientSecret: this.clientSecret
1277+
const options = {
1278+
headers: {
1279+
Authorization: ''
12791280
},
12801281
parameters: {
1281-
...(callbackURI && {callbackURI}),
1282-
...(usid && {usid}),
1283-
userid: parameters.userid,
1284-
mode: finalMode,
12851282
...(parameters.register_customer !== undefined && {
1286-
// Helper expects camelCase 'registerCustomer'
1287-
registerCustomer:
1283+
register_customer:
12881284
typeof parameters.register_customer === 'boolean'
1289-
? Boolean(parameters.register_customer)
1285+
? String(parameters.register_customer)
12901286
: parameters.register_customer
1291-
}),
1292-
// Helper expects camelCase registration fields in parameters; it maps to body internally
1293-
...(parameters.last_name && {lastName: parameters.last_name}),
1287+
})
1288+
},
1289+
body: {
1290+
user_id: parameters.userid,
1291+
mode: finalMode,
1292+
// Include usid and site as required by SLAS
1293+
...(usid && {usid}),
1294+
channel_id: slasClient.clientConfig.parameters.siteId,
1295+
...(callbackURI && {callback_uri: callbackURI}),
1296+
...(parameters.last_name && {last_name: parameters.last_name}),
12941297
...(parameters.email && {email: parameters.email}),
1295-
...(parameters.first_name && {firstName: parameters.first_name}),
1296-
...(parameters.phone_number && {phoneNumber: parameters.phone_number})
1298+
...(parameters.first_name && {first_name: parameters.first_name}),
1299+
...(parameters.phone_number && {phone_number: parameters.phone_number})
12971300
}
1298-
} as any)
1299-
if (res && res.status && res.status !== 200) {
1300-
const errorData = await res.json()
1301-
throw new Error(`${res.status} ${String(errorData.message)}`)
1301+
} as {
1302+
headers?: {[key: string]: string}
1303+
parameters?: Record<string, string>
1304+
body: ShopperLoginTypes.authorizePasswordlessCustomerBodyType & helpers.CustomRequestBody
13021305
}
1306+
1307+
// Use Basic auth header when using private client
1308+
if (this.clientSecret) {
1309+
options.headers = options.headers || {}
1310+
options.headers.Authorization = `Basic ${stringToBase64(
1311+
`${slasClient.clientConfig.parameters.clientId}:${this.clientSecret}`
1312+
)}`
1313+
} else {
1314+
// If not using private client, avoid sending Authorization header
1315+
delete options.headers
1316+
}
1317+
1318+
const res = await slasClient.authorizePasswordlessCustomer(options)
13031319
return res
13041320
}
13051321

packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-payment.jsx

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const Payment = ({
9191
const loginPasswordless = useAuthHelper(AuthHelpers.LoginPasswordlessUser)
9292
const {isOpen: isOtpOpen, onOpen: onOtpOpen, onClose: onOtpClose} = useDisclosure()
9393
const otpDismissedRef = useRef(false)
94+
const activeBasketIdRef = useRef(null)
9495
const passwordlessConfigCallback = getConfig().app.login?.passwordless?.callbackURI
9596
const callbackURL = isAbsoluteURL(passwordlessConfigCallback)
9697
? passwordlessConfigCallback
@@ -185,15 +186,35 @@ const Payment = ({
185186
// Allow auth storage to settle before SCAPI calls
186187
await auth.refreshAccessToken()
187188

188-
await recoverBasketAfterAuth({
189+
// Immediately mark OTP completed and close modal to prevent a brief re-open on remounts
190+
otpDismissedRef.current = true
191+
setEnableUserRegistration?.(false)
192+
onOtpClose()
193+
194+
const newBasketId = await recoverBasketAfterAuth({
189195
preLoginItems: basket?.productItems || [],
190-
shipmentSnapshot: basket?.shipments?.[0] || null,
196+
shipment: basket?.shipments?.[0] || null,
191197
doMerge: true
192198
})
193-
otpDismissedRef.current = true
199+
if (newBasketId) {
200+
activeBasketIdRef.current = newBasketId
201+
}
194202
// Ensure save-for-future is selected after successful registration
195203
setShouldSavePaymentMethod(true)
196204

205+
// If user typed a new card and nothing is applied yet, apply it to the new basket id
206+
try {
207+
const values = paymentMethodForm?.getValues?.()
208+
const hasEnteredCard = values?.number && values?.holder && values?.expiry
209+
const hasApplied = (currentBasketQuery?.data?.paymentInstruments?.length || 0) > 0
210+
if (hasEnteredCard && !hasApplied && newBasketId) {
211+
await onPaymentSubmit(values, newBasketId)
212+
await currentBasketQuery.refetch()
213+
}
214+
} catch (_e) {
215+
// best-effort; user can still place order manually
216+
}
217+
197218
showToast({
198219
variant: 'subtle',
199220
title: `${formatMessage(
@@ -214,7 +235,7 @@ const Payment = ({
214235
isClosable: true
215236
})
216237

217-
onOtpClose()
238+
// modal already closed right after auth
218239
} catch (error) {
219240
let message = formatMessage(API_ERROR_MESSAGE)
220241
if (error.response) {
@@ -235,8 +256,9 @@ const Payment = ({
235256
const handleSendEmailOtp = async (email) => {
236257
try {
237258
await authorizePasswordlessLogin.mutateAsync({
259+
// Pass fields at top-level. The helper maps to query/body correctly.
238260
userid: email,
239-
callbackURI: `${callbackURL}?mode=otp_email`,
261+
callbackURI: callbackURL,
240262
register_customer: true,
241263
last_name: email,
242264
email: email
@@ -300,7 +322,7 @@ const Payment = ({
300322
// eslint-disable-next-line @typescript-eslint/no-unused-vars
301323
const {removePromoCode, ...promoCodeProps} = usePromoCode()
302324

303-
const onPaymentSubmit = async (formValue) => {
325+
const onPaymentSubmit = async (formValue, forcedBasketId) => {
304326
// The form gives us the expiration date as `MM/YY` - so we need to split it into
305327
// month and year to submit them as individual fields.
306328
const [expirationMonth, expirationYear] = formValue.expiry.split('/')
@@ -322,7 +344,7 @@ const Payment = ({
322344
}
323345

324346
return addPaymentInstrumentToBasket({
325-
parameters: {basketId: basket?.basketId},
347+
parameters: {basketId: forcedBasketId || activeBasketIdRef.current || basket?.basketId},
326348
body: paymentInstrument
327349
})
328350
}
@@ -338,15 +360,18 @@ const Payment = ({
338360
const isRegistered = customer?.isRegistered
339361
const hasSaved = customer?.paymentInstruments?.length > 0
340362
const alreadyApplied = (basket?.paymentInstruments?.length || 0) > 0
341-
if (!isRegistered || !hasSaved || alreadyApplied) return
363+
// If the shopper is currently typing a new card, skip auto-apply of saved
364+
const entered = paymentMethodForm?.getValues?.()
365+
const hasEnteredCard = entered?.number && entered?.holder && entered?.expiry
366+
if (!isRegistered || !hasSaved || alreadyApplied || hasEnteredCard) return
342367
autoAppliedRef.current = true
343368
const preferred =
344369
customer.paymentInstruments.find((pi) => pi.default === true) ||
345370
customer.paymentInstruments[0]
346371
try {
347372
setIsApplyingSavedPayment(true)
348373
await addPaymentInstrumentToBasket({
349-
parameters: {basketId: basket?.basketId},
374+
parameters: {basketId: activeBasketIdRef.current || basket?.basketId},
350375
body: {
351376
paymentMethodId: 'CREDIT_CARD',
352377
customerPaymentInstrumentId: preferred.paymentInstrumentId
@@ -394,7 +419,7 @@ const Payment = ({
394419
} else {
395420
setIsApplyingSavedPayment(true)
396421
await addPaymentInstrumentToBasket({
397-
parameters: {basketId: basket?.basketId},
422+
parameters: {basketId: activeBasketIdRef.current || basket?.basketId},
398423
body: {
399424
paymentMethodId: 'CREDIT_CARD',
400425
customerPaymentInstrumentId: paymentInstrumentId
@@ -423,15 +448,15 @@ const Payment = ({
423448
const {addressId, creationDate, lastModified, preferred, ...address} = billingAddress
424449
return await updateBillingAddressForBasket({
425450
body: address,
426-
parameters: {basketId: basket.basketId}
451+
parameters: {basketId: activeBasketIdRef.current || basket.basketId}
427452
})
428453
}
429454

430455
const onPaymentRemoval = async () => {
431456
try {
432457
await removePaymentInstrumentFromBasket({
433458
parameters: {
434-
basketId: basket.basketId,
459+
basketId: activeBasketIdRef.current || basket.basketId,
435460
paymentInstrumentId: appliedPayment.paymentInstrumentId
436461
}
437462
})
@@ -445,7 +470,7 @@ const Payment = ({
445470
const onSubmit = paymentMethodForm.handleSubmit(async (paymentFormValues) => {
446471
try {
447472
if (!appliedPayment) {
448-
await onPaymentSubmit(paymentFormValues)
473+
await onPaymentSubmit(paymentFormValues, activeBasketIdRef.current)
449474
}
450475

451476
// Update billing address

0 commit comments

Comments
 (0)