diff --git a/packages/fxa-payments-server/.storybook/components/MockApp.tsx b/packages/fxa-payments-server/.storybook/components/MockApp.tsx index d855cf2036..f4cc9e019c 100644 --- a/packages/fxa-payments-server/.storybook/components/MockApp.tsx +++ b/packages/fxa-payments-server/.storybook/components/MockApp.tsx @@ -24,6 +24,9 @@ type MockAppProps = { export const defaultAppContextValue: AppContextType = { config: { ...config, + featureFlags: { + usePaypalUIByDefault: true, + }, productRedirectURLs: { product_8675309: 'https://example.com/product', }, diff --git a/packages/fxa-payments-server/src/components/PaymentConfirmation/index.tsx b/packages/fxa-payments-server/src/components/PaymentConfirmation/index.tsx index 039e753d24..2f06caaa20 100644 --- a/packages/fxa-payments-server/src/components/PaymentConfirmation/index.tsx +++ b/packages/fxa-payments-server/src/components/PaymentConfirmation/index.tsx @@ -6,10 +6,7 @@ import { Plan, Profile, Customer } from '../../store/types'; import { PaymentProviderDetails } from '../PaymentProviderDetails'; import SubscriptionTitle from '../SubscriptionTitle'; import { TermsAndPrivacy } from '../TermsAndPrivacy'; -import { - PaypalPaymentLegalBlurb, - StripePaymentLegalBlurb, -} from '../PaymentLegalBlurb'; +import PaymentLegalBlurb from '../PaymentLegalBlurb'; import circledCheckbox from './images/circled-confirm.svg'; @@ -135,8 +132,7 @@ export const PaymentConfirmation = ({ Continue to download - {Provider.isPaypal(payment_provider) && } - {Provider.isStripe(payment_provider) && } + diff --git a/packages/fxa-payments-server/src/components/PaymentForm/index.stories.tsx b/packages/fxa-payments-server/src/components/PaymentForm/index.stories.tsx index 9ea643f194..57a9cdb875 100644 --- a/packages/fxa-payments-server/src/components/PaymentForm/index.stories.tsx +++ b/packages/fxa-payments-server/src/components/PaymentForm/index.stories.tsx @@ -56,7 +56,7 @@ const PLAN = { 'https://www.mozilla.org/fr/privacy/websites/', }, }; -const CUSTOMER = { +const CUSTOMER: Customer = { billing_name: 'Foo Barson', payment_provider: 'stripe', payment_type: 'credit', diff --git a/packages/fxa-payments-server/src/components/PaymentForm/index.tsx b/packages/fxa-payments-server/src/components/PaymentForm/index.tsx index b31a1770dd..c3725f9743 100644 --- a/packages/fxa-payments-server/src/components/PaymentForm/index.tsx +++ b/packages/fxa-payments-server/src/components/PaymentForm/index.tsx @@ -39,6 +39,7 @@ import { Plan, Customer } from '../../store/types'; import { productDetailsFromPlan } from 'fxa-shared/subscriptions/metadata'; import './index.scss'; +import * as PaymentProvider from '../../lib/PaymentProvider'; export type PaymentSubmitResult = { stripe: Stripe; @@ -82,8 +83,10 @@ export const PaymentForm = ({ onChange: onChangeProp, submitNonce, }: BasePaymentFormProps) => { - const hasExistingCard = - customer && customer.last4 && customer.subscriptions.length > 0; + const isExistingStripeCustomer = + customer && + PaymentProvider.isStripe(customer?.payment_provider) && + customer.subscriptions.length > 0; const stripe = useStripe(); const elements = useElements(); @@ -121,7 +124,7 @@ export const PaymentForm = ({ const { name } = validator.getValues(); const card = elements.getElement(CardElement); /* istanbul ignore next - card should exist unless there was an external stripe loading error, handled above */ - if (hasExistingCard || card) { + if (isExistingStripeCustomer || card) { onSubmitForParent({ stripe, elements, @@ -157,7 +160,7 @@ export const PaymentForm = ({ navigatorLanguages )); } - const paymentSource = hasExistingCard ? ( + const paymentSource = isExistingStripeCustomer ? (
Stripe privacy policy.'; } -export const PaypalPaymentLegalBlurb = () => ( +const PaypalPaymentLegalBlurb = () => (

Mozilla uses Paypal for secure payment processing.

@@ -38,7 +40,7 @@ export const PaypalPaymentLegalBlurb = () => (
); -export const StripePaymentLegalBlurb = () => ( +const StripePaymentLegalBlurb = () => (

Mozilla uses Stripe for secure payment processing.

@@ -61,7 +63,7 @@ export const StripePaymentLegalBlurb = () => (
); -export const PaymentLegalBlurb = () => ( +const DefaultPaymentLegalBlurb = () => (

Mozilla uses Stripe and Paypal for secure payment processing.

@@ -91,4 +93,17 @@ export const PaymentLegalBlurb = () => (
); +export type PaymentLegalBlurbProps = { + provider: PaymentProvider.ProviderType | undefined; +}; + +export const PaymentLegalBlurb = ({ provider }: PaymentLegalBlurbProps) => { + return ( + (PaymentProvider.isPaypal(provider) && ) || + (PaymentProvider.isStripe(provider) && ) || ( + + ) + ); +}; + export default PaymentLegalBlurb; diff --git a/packages/fxa-payments-server/src/components/PaymentProcessing/index.tsx b/packages/fxa-payments-server/src/components/PaymentProcessing/index.tsx index 5448d449b6..0e082e7a15 100644 --- a/packages/fxa-payments-server/src/components/PaymentProcessing/index.tsx +++ b/packages/fxa-payments-server/src/components/PaymentProcessing/index.tsx @@ -1,18 +1,15 @@ import React from 'react'; import { Localized } from '@fluent/react'; -import * as Provider from '../../lib/PaymentProvider'; import { LoadingSpinner } from '../LoadingSpinner'; import SubscriptionTitle from '../SubscriptionTitle'; -import { - PaypalPaymentLegalBlurb, - StripePaymentLegalBlurb, -} from '../PaymentLegalBlurb'; +import PaymentLegalBlurb from '../PaymentLegalBlurb'; +import { ProviderType } from 'fxa-payments-server/src/lib/PaymentProvider'; import './index.scss'; export type PaymentProcessingProps = { - provider: 'stripe' | 'paypal'; + provider?: ProviderType; className?: string; }; @@ -35,8 +32,7 @@ export const PaymentProcessing = ({
- {Provider.isPaypal(provider) && } - {Provider.isStripe(provider) && } +
diff --git a/packages/fxa-payments-server/src/lib/PaymentProvider.ts b/packages/fxa-payments-server/src/lib/PaymentProvider.ts index 8e5de79af7..29a2aa8173 100644 --- a/packages/fxa-payments-server/src/lib/PaymentProvider.ts +++ b/packages/fxa-payments-server/src/lib/PaymentProvider.ts @@ -2,10 +2,16 @@ * 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/. */ -export function isStripe(provider: string | undefined) { +export type ProviderType = 'paypal' | 'stripe' | 'not_chosen'; + +export function isStripe(provider: ProviderType | undefined): boolean { return provider === 'stripe'; } -export function isPaypal(provider: string | undefined) { +export function isPaypal(provider: ProviderType | undefined): boolean { return provider === 'paypal'; } + +export function isNotChosen(provider: ProviderType | undefined): boolean { + return provider === 'not_chosen' || provider === undefined; +} diff --git a/packages/fxa-payments-server/src/lib/test-utils.tsx b/packages/fxa-payments-server/src/lib/test-utils.tsx index 2001e7d27c..3ee987ecc9 100644 --- a/packages/fxa-payments-server/src/lib/test-utils.tsx +++ b/packages/fxa-payments-server/src/lib/test-utils.tsx @@ -513,6 +513,7 @@ export const MOCK_ACTIVE_SUBSCRIPTIONS_AFTER_SUBSCRIPTION = [ export const MOCK_CUSTOMER = { billing_name: 'Jane Doe', payment_type: 'card', + payment_provider: 'stripe', brand: 'Visa', last4: '8675', exp_month: '8', diff --git a/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.stories.tsx b/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.stories.tsx index e81f6b565d..1e16c974b5 100644 --- a/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.stories.tsx +++ b/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.stories.tsx @@ -11,7 +11,7 @@ import { linkTo } from '@storybook/addon-links'; import MockApp, { defaultAppContextValue, } from '../../../../.storybook/components/MockApp'; -import { CUSTOMER, PROFILE, PLAN } from '../../../lib/mock-data'; +import { CUSTOMER, PROFILE, PLAN, NEW_CUSTOMER } from '../../../lib/mock-data'; import { APIError } from '../../../lib/apiClient'; import { PickPartial } from '../../../lib/types'; import { SignInLayout } from '../../../components/AppLayout'; @@ -178,7 +178,7 @@ function init() { const Subject = ({ isMobile = false, - customer = CUSTOMER, + customer = NEW_CUSTOMER, profile = PROFILE, selectedPlan = PLAN, apiClientOverrides = defaultApiClientOverrides, diff --git a/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.test.tsx b/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.test.tsx index 2d926dabfd..2bbf08a5a4 100644 --- a/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.test.tsx +++ b/packages/fxa-payments-server/src/routes/Product/SubscriptionCreate/index.test.tsx @@ -12,7 +12,13 @@ import { import '@testing-library/jest-dom/extend-expect'; import { PaymentMethod, PaymentIntent } from '@stripe/stripe-js'; import { SignInLayout } from '../../../components/AppLayout'; -import { CUSTOMER, PROFILE, PLAN, NEW_CUSTOMER } from '../../../lib/mock-data'; +import { + CUSTOMER, + PROFILE, + PLAN, + NEW_CUSTOMER, + PAYPAL_CUSTOMER, +} from '../../../lib/mock-data'; import { PickPartial } from '../../../lib/types'; import { @@ -191,7 +197,7 @@ describe('routes/ProductV2/SubscriptionCreate', () => { ); }); - it('renders as expected with PayPal UI enabled and an existing customer', async () => { + it('renders as expected with PayPal UI enabled and an existing Stripe customer', async () => { const { queryByTestId } = screen; updateConfig({ featureFlags: { @@ -209,6 +215,35 @@ describe('routes/ProductV2/SubscriptionCreate', () => { waitForExpect(() => expect(queryByTestId('paypal-button')).not.toBeInTheDocument() ); + waitForExpect(() => + expect(queryByTestId('paymentForm')).toBeInTheDocument() + ); + }); + + it('renders as expected with PayPal UI enabled and an existing PayPal customer', async () => { + const { queryByTestId } = screen; + updateConfig({ + featureFlags: { + usePaypalUIByDefault: true, + }, + }); + const MockedButtonBase = ({}: ButtonBaseProps) => { + return