Skip to content

Commit

Permalink
Merge pull request #18457 from mozilla/FXA-10708
Browse files Browse the repository at this point in the history
feat(payments-next): actions response validation and dto updates
  • Loading branch information
julianpoy authored Feb 27, 2025
2 parents 6b52b86 + 3497fd4 commit 62491e6
Show file tree
Hide file tree
Showing 36 changed files with 853 additions and 223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CartEligibilityStatus } from '@fxa/shared/db/mysql/account';
import { BaseParams, buildRedirectUrl } from '@fxa/payments/ui';
import { getIpAddress } from '@fxa/payments/ui/server';
import { config } from 'apps/payments/next/config';
import type { SubplatInterval } from '@fxa/payments/customer';

export const dynamic = 'force-dynamic';

Expand All @@ -32,7 +33,7 @@ export async function GET(
let redirectToUrl: URL;
try {
const { id: cartId, eligibilityStatus } = await setupCartAction(
interval,
interval as SubplatInterval,
offeringId,
undefined,
coupon,
Expand All @@ -56,7 +57,7 @@ export async function GET(
} catch (error) {
if (error.constructor.name === 'CartInvalidPromoCodeError') {
const { id: cartId, eligibilityStatus } = await setupCartAction(
interval,
interval as SubplatInterval,
offeringId,
undefined,
undefined,
Expand Down
1 change: 1 addition & 0 deletions libs/payments/cart/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export * from './lib/cart.factories';
export * from './lib/cart.manager';
export * from './lib/cart.service';
export * from './lib/cart.utils';
export { CartInvalidStateForActionError } from './lib/cart.error';
export * from './lib/checkout.service';
export * from './lib/checkout.error';
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function stripeInvoiceToInvoicePreviewDTO(
invoice: StripeUpcomingInvoice | StripeInvoice
): InvoicePreview {
const taxAmounts = invoice.total_tax_amounts.map((amount) => ({
title: amount.tax_rate.display_name,
title: amount.tax_rate.display_name || '',
inclusive: amount.inclusive,
amount: amount.amount,
}));
Expand Down
3 changes: 2 additions & 1 deletion libs/payments/metrics/src/lib/glean/glean.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { ResultCart } from '@fxa/payments/cart';
import Stripe from 'stripe';

export const CheckoutTypes = ['with-accounts', 'without-accounts'] as const;
export type CheckoutTypesType = (typeof CheckoutTypes)[number];
Expand All @@ -13,7 +14,7 @@ export const PaymentProvidersTypePartial = [
'external_paypal',
] as const;
export type PaymentProvidersType =
| 'card'
| Stripe.PaymentMethod.Type
| 'google_iap'
| 'apple_iap'
| 'external_paypal';
Expand Down
16 changes: 6 additions & 10 deletions libs/payments/ui/src/lib/actions/checkoutCartWithPaypal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,18 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { CheckoutCartWithPaypalActionArgs } from '../nestapp/validators/CheckoutCartWithPaypalActionArgs';

export const checkoutCartWithPaypal = async (
cartId: string,
version: number,
customerData: { locale: string; displayName: string },
token?: string
) => {
await getApp().getActionsService().checkoutCartWithPaypal(
plainToClass(CheckoutCartWithPaypalActionArgs, {
cartId,
version,
customerData,
token,
})
);
await getApp().getActionsService().checkoutCartWithPaypal({
cartId,
version,
customerData,
token,
});
};
24 changes: 10 additions & 14 deletions libs/payments/ui/src/lib/actions/checkoutCartWithStripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,21 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import {
CheckoutCartWithStripeActionArgs,
CheckoutCartWithStripeActionCustomerData,
} from '../nestapp/validators/CheckoutCartWithStripeActionArgs';

export const checkoutCartWithStripe = async (
cartId: string,
version: number,
confirmationTokenId: string,
customerData: CheckoutCartWithStripeActionCustomerData
customerData: {
locale: string;
displayName: string;
}
) => {
getApp().getActionsService().checkoutCartWithStripe(
plainToClass(CheckoutCartWithStripeActionArgs, {
cartId,
version,
customerData,
confirmationTokenId,
})
);
getApp().getActionsService().checkoutCartWithStripe({
cartId,
version,
customerData,
confirmationTokenId,
});
};
10 changes: 3 additions & 7 deletions libs/payments/ui/src/lib/actions/determineCurrency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { DetermineCurrencyActionArgs } from '../nestapp/validators/DetermineCurrencyActionArgs';

export const determineCurrencyAction = async (ip: string) => {
const currency = await getApp().getActionsService().determineCurrency(
plainToClass(DetermineCurrencyActionArgs, {
ip,
})
);
const { currency } = await getApp().getActionsService().determineCurrency({
ip,
});

return currency;
};
14 changes: 5 additions & 9 deletions libs/payments/ui/src/lib/actions/fetchCMSData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,16 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { FetchCMSDataArgs } from '../nestapp/validators/FetchCMSDataArgs';

export const fetchCMSData = (
offeringId: string,
acceptLanguage?: string | null,
selectedLanguage?: string
) => {
return getApp().getActionsService().fetchCMSData(
plainToClass(FetchCMSDataArgs, {
offeringId,
acceptLanguage,
selectedLanguage,
})
);
return getApp().getActionsService().fetchCMSData({
offeringId,
acceptLanguage,
selectedLanguage,
});
};
12 changes: 4 additions & 8 deletions libs/payments/ui/src/lib/actions/finalizeCartWithError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { FinalizeCartWithErrorArgs } from '../nestapp/validators/FinalizeCartWithErrorArgs';
import { CartErrorReasonId } from '@fxa/shared/db/mysql/account/kysely-types';

export const finalizeCartWithError = async (
cartId: string,
errorReasonId: CartErrorReasonId
) => {
return await getApp().getActionsService().finalizeCartWithError(
plainToClass(FinalizeCartWithErrorArgs, {
cartId,
errorReasonId,
})
);
return await getApp().getActionsService().finalizeCartWithError({
cartId,
errorReasonId,
});
};
10 changes: 3 additions & 7 deletions libs/payments/ui/src/lib/actions/finalizeProcessingCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { GetCartActionArgs } from '../nestapp/validators/GetCartActionArgs';

export const finalizeProcessingCartAction = async (cartId: string) => {
const cart = await getApp().getActionsService().finalizeProcessingCart(
plainToClass(GetCartActionArgs, {
cartId,
})
);
const cart = await getApp().getActionsService().finalizeProcessingCart({
cartId,
});

return cart;
};
10 changes: 3 additions & 7 deletions libs/payments/ui/src/lib/actions/getCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { GetCartActionArgs } from '../nestapp/validators/GetCartActionArgs';

export const getCartAction = async (cartId: string) => {
const cart = await getApp().getActionsService().getCart(
plainToClass(GetCartActionArgs, {
cartId,
})
);
const cart = await getApp().getActionsService().getCart({
cartId,
});

return cart;
};
20 changes: 7 additions & 13 deletions libs/payments/ui/src/lib/actions/getCartOrRedirect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

'use server';

import { plainToClass } from 'class-transformer';
import { redirect } from 'next/navigation';
import { getApp } from '../nestapp/app';
import { GetCartActionArgs } from '../nestapp/validators/GetCartActionArgs';
import { getRedirect, validateCartState } from '../utils/get-cart';
import { SupportedPages } from '../utils/types';
import {
Expand All @@ -17,8 +15,8 @@ import {
FailCartDTO,
SuccessCartDTO,
CartDTO,
CartInvalidStateForActionError,
} from '@fxa/payments/cart';
import { CartInvalidStateForActionError } from 'libs/payments/cart/src/lib/cart.error';
import { VError } from 'verror';

/**
Expand Down Expand Up @@ -63,11 +61,9 @@ async function getCartOrRedirectAction(
switch (page) {
case SupportedPages.SUCCESS: {
try {
cart = await getApp().getActionsService().getSuccessCart(
plainToClass(GetCartActionArgs, {
cartId,
})
);
cart = await getApp().getActionsService().getSuccessCart({
cartId,
});
} catch (error) {
if (error instanceof CartInvalidStateForActionError) {
redirect(getRedirect(VError.info(error).state) + params);
Expand All @@ -81,11 +77,9 @@ async function getCartOrRedirectAction(
case SupportedPages.PROCESSING:
case SupportedPages.NEEDS_INPUT:
case SupportedPages.ERROR: {
cart = await getApp().getActionsService().getCart(
plainToClass(GetCartActionArgs, {
cartId,
})
);
cart = await getApp().getActionsService().getCart({
cartId,
});
break;
}
}
Expand Down
6 changes: 1 addition & 5 deletions libs/payments/ui/src/lib/actions/getNeedsInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
'use server';

import { getApp } from '../nestapp/app';
import { plainToClass } from 'class-transformer';
import { GetNeedsInputActionArgs } from '../nestapp/validators/GetNeedsInputActionArgs';

export const getNeedsInputAction = async (cartId: string) => {
const inputNeeded = getApp()
.getActionsService()
.getNeedsInput(plainToClass(GetNeedsInputActionArgs, { cartId }));
const inputNeeded = getApp().getActionsService().getNeedsInput({ cartId });

return inputNeeded;
};
12 changes: 4 additions & 8 deletions libs/payments/ui/src/lib/actions/getPayPalCheckoutToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { GetPayPalCheckoutTokenArgs } from '../nestapp/validators/GetPayPalCheckoutTokenArgs';

export const getPayPalCheckoutToken = async (currencyCode?: string | null) => {
export const getPayPalCheckoutToken = async (currencyCode: string) => {
const actionsService = getApp().getActionsService();

const token = await actionsService.getPayPalCheckoutToken(
plainToClass(GetPayPalCheckoutTokenArgs, {
currencyCode,
})
);
const { token } = await actionsService.getPayPalCheckoutToken({
currencyCode,
});

return token;
};
17 changes: 7 additions & 10 deletions libs/payments/ui/src/lib/actions/recordEmitterEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
'use server';

import { getApp } from '../nestapp/app';
import { plainToClass } from 'class-transformer';
import { RecordEmitterEventArgs } from '../nestapp/validators/RecordEmitterEvent';
import { getAdditionalRequestArgs } from '../utils/getAdditionalRequestArgs';
import { PaymentProvidersType } from '@fxa/payments/cart';
import { PaymentsEmitterEventsKeysType } from '@fxa/payments/events';
Expand Down Expand Up @@ -38,17 +36,16 @@ async function recordEmitterEventAction(
) {
const requestArgs = {
...getAdditionalRequestArgs(),
params,
// TODO: This type mismatch appears to be an actual bug -- FXA-11214
params: params as Record<string, string>,
searchParams,
};

return getApp().getActionsService().recordEmitterEvent(
plainToClass(RecordEmitterEventArgs, {
eventName,
requestArgs,
paymentProvider,
})
);
return getApp().getActionsService().recordEmitterEvent({
eventName,
requestArgs,
paymentProvider,
});
}

export { recordEmitterEventAction };
10 changes: 3 additions & 7 deletions libs/payments/ui/src/lib/actions/restartCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { RestartCartActionArgs } from '../nestapp/validators/RestartCartActionArgs';

export const restartCartAction = async (cartId: string) => {
const actionsService = getApp().getActionsService();

const cart = await actionsService.restartCart(
plainToClass(RestartCartActionArgs, {
cartId,
})
);
const cart = await actionsService.restartCart({
cartId,
});

return cart;
};
Loading

0 comments on commit 62491e6

Please sign in to comment.