From 6761f389d5a47ed206fd0d4365021c1d1a97f7e4 Mon Sep 17 00:00:00 2001 From: elizabeth-ilina Date: Thu, 23 Oct 2025 10:43:03 -0400 Subject: [PATCH] feat(payments-next): Persist 'with-accounts' or 'without-accounts' metrics throughout checkout Because: * This commit: * Initial commit - ipr --- .../next/app/api/auth/callback/fxa/route.ts | 44 +++++++++++++++++++ .../metrics/src/lib/glean/glean.types.ts | 2 +- .../glean/utils/determineCheckoutType.spec.ts | 8 +--- .../lib/glean/utils/determineCheckoutType.ts | 16 ++++++- .../lib/glean/utils/mapSubscription.spec.ts | 2 +- .../src/lib/glean/utils/mapSubscription.ts | 2 +- .../lib/client/components/Header/index.tsx | 1 + 7 files changed, 64 insertions(+), 11 deletions(-) diff --git a/apps/payments/next/app/api/auth/callback/fxa/route.ts b/apps/payments/next/app/api/auth/callback/fxa/route.ts index 3bdbbbbe861..c84b12d4dcc 100644 --- a/apps/payments/next/app/api/auth/callback/fxa/route.ts +++ b/apps/payments/next/app/api/auth/callback/fxa/route.ts @@ -8,6 +8,50 @@ export { POST } from '../../../../../auth'; export async function GET(request: NextRequest) { const requestSearchParams = request.nextUrl.searchParams; const requestErrorQuery = requestSearchParams.get('error'); + const url = new URL(request.url); + const newAccount = url.searchParams.get('newAccount'); + + if (newAccount && newAccount === 'true') { + const cookieStore = request.cookies; + const redirectUrl = + cookieStore.get('__Secure-authjs.callback-url') || + cookieStore.get('authjs.callback-url'); + + if (redirectUrl?.value) { + const updatedRedirectUrl = new URL(redirectUrl.value, request.url); + updatedRedirectUrl.searchParams.set('newAccount', 'true'); + + const rawCookieHeader = request.headers.get('cookie') ?? ''; + const cookiesMap = new Map( + rawCookieHeader + .split(';') + .map(s => s.trim()) + .filter(Boolean) + .map(cookieString => { + const idx = cookieString.indexOf('='); + const k = idx >= 0 ? cookieString.slice(0, idx).trim() : cookieString; + const v = idx >= 0 ? cookieString.slice(idx + 1).trim() : ''; + return [k, v]; + }) + ); + cookiesMap.set('authjs.callback-url', encodeURIComponent(updatedRedirectUrl.toString())); + cookiesMap.set('__Secure-authjs.callback-url', encodeURIComponent(updatedRedirectUrl.toString())); + + const newCookieHeader = Array.from(cookiesMap.entries()) + .map(([k, v]) => `${k}=${v}`) + .join('; '); + + const headers = new Headers(request.headers); + headers.set('cookie', newCookieHeader); + + const newRequest = new NextRequest(request.url, { + headers, + method: request.method, + }); + + return AuthJsGET(newRequest); + } + } // Support failure on prompt=none // If fxa prompt=none login fails because the user is not logged in diff --git a/libs/payments/metrics/src/lib/glean/glean.types.ts b/libs/payments/metrics/src/lib/glean/glean.types.ts index e25c5431aad..253d3b87c08 100644 --- a/libs/payments/metrics/src/lib/glean/glean.types.ts +++ b/libs/payments/metrics/src/lib/glean/glean.types.ts @@ -4,7 +4,7 @@ import { ResultCart } from '@fxa/payments/cart'; import Stripe from 'stripe'; -export const CheckoutTypes = ['with-accounts', 'without-accounts'] as const; +export const CheckoutTypes = ['with-accounts', 'without-accounts'] as const;// export type CheckoutTypesType = (typeof CheckoutTypes)[number]; import { SubPlatPaymentMethodType } from '@fxa/payments/customer'; diff --git a/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.spec.ts b/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.spec.ts index 93789362d67..5a06621e5d7 100644 --- a/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.spec.ts +++ b/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.spec.ts @@ -5,14 +5,10 @@ import { determineCheckoutType } from './determineCheckoutType'; describe('determineCheckoutType', () => { it('should return with-accounts if uid provided', () => { - expect(determineCheckoutType('validuid')).toEqual('with-accounts'); + expect(determineCheckoutType('true')).toEqual('without-accounts'); }); it('should return without-accounts if empty uid', () => { - expect(determineCheckoutType('')).toEqual('without-accounts'); - }); - - it('should return without-accounts if undefined uid', () => { - expect(determineCheckoutType(undefined)).toEqual('without-accounts'); + expect(determineCheckoutType('')).toEqual('with-accounts'); }); }); diff --git a/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.ts b/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.ts index f8be795e1f3..7d14dda7818 100644 --- a/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.ts +++ b/libs/payments/metrics/src/lib/glean/utils/determineCheckoutType.ts @@ -3,6 +3,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import type { CheckoutTypesType } from '../glean.types'; -export function determineCheckoutType(accountsUid?: string): CheckoutTypesType { - return accountsUid ? 'with-accounts' : 'without-accounts'; +export function determineCheckoutType(isNewAccount?: string): CheckoutTypesType { + // If isNewAccount, return without-accounts + // If !isNewAccount && isLoggedIn, return with-accounts + // If !isNewAccount && !isLoggedIn, return ''? + /*if (isNewAccount === 'true') { + console.log('new account is true') + return 'without-accounts'; + } else if (!isNewAccount || isNewAccount !== 'true' ) { + return 'with-accounts'; + } else { + return ''; ?? + } */ + + return isNewAccount === 'true' ? 'without-accounts' : 'with-accounts'; } diff --git a/libs/payments/metrics/src/lib/glean/utils/mapSubscription.spec.ts b/libs/payments/metrics/src/lib/glean/utils/mapSubscription.spec.ts index 2b6318c8c4f..4d2ac76f234 100644 --- a/libs/payments/metrics/src/lib/glean/utils/mapSubscription.spec.ts +++ b/libs/payments/metrics/src/lib/glean/utils/mapSubscription.spec.ts @@ -58,7 +58,7 @@ describe('mapSubscription', () => { cmsMetricsData: mockCmsMetricsData, }); expect(result).toEqual({ - subscription_checkout_type: 'without-accounts', + subscription_checkout_type: 'with-accounts', subscription_currency: '', subscription_error_id: '', subscription_interval: '', diff --git a/libs/payments/metrics/src/lib/glean/utils/mapSubscription.ts b/libs/payments/metrics/src/lib/glean/utils/mapSubscription.ts index 0d5534142df..b75ce71cc8f 100644 --- a/libs/payments/metrics/src/lib/glean/utils/mapSubscription.ts +++ b/libs/payments/metrics/src/lib/glean/utils/mapSubscription.ts @@ -24,7 +24,7 @@ export function mapSubscription({ }) { const mappedParams = mapParams(commonMetricsData.params); return { - subscription_checkout_type: determineCheckoutType(cartMetricsData.uid), + subscription_checkout_type: determineCheckoutType(commonMetricsData.searchParams['newAccount']), subscription_currency: normalizeGleanFalsyValues(cartMetricsData.currency), subscription_error_id: normalizeGleanFalsyValues( cartMetricsData.errorReasonId diff --git a/libs/payments/ui/src/lib/client/components/Header/index.tsx b/libs/payments/ui/src/lib/client/components/Header/index.tsx index 18f65f1df99..e3e1f155820 100644 --- a/libs/payments/ui/src/lib/client/components/Header/index.tsx +++ b/libs/payments/ui/src/lib/client/components/Header/index.tsx @@ -44,6 +44,7 @@ function buildSignOutRedirectPath( const allRemainingQueryParams = new URLSearchParams(searchParams.toString()); allRemainingQueryParams.delete('countryCode'); allRemainingQueryParams.delete('postalCode'); + allRemainingQueryParams.delete('newAccount'); const remainingQueryParams = allRemainingQueryParams.toString(); if (remainingQueryParams) {