From fb0d284f799214af3b3f2437c6eb8e1be4f92ed1 Mon Sep 17 00:00:00 2001
From: Christiaan Scheermeijer
Date: Mon, 1 Jul 2024 12:37:26 +0200
Subject: [PATCH] refactor(payment): align integration flows
---
.../src/controllers/AccountController.ts | 6 +-
.../src/controllers/CheckoutController.ts | 15 +-
.../src/services/WatchHistoryService.ts | 25 ++-
.../cleeng/CleengCheckoutService.ts | 23 ++-
.../integrations/jwp/JWPAccountService.ts | 2 +-
.../integrations/jwp/JWPCheckoutService.ts | 54 +++++-
.../jwp/JWPSubscriptionService.ts | 12 +-
packages/common/types/checkout.ts | 11 +-
.../hooks-react/src/useSubscriptionChange.ts | 38 -----
.../OfferSwitch/OfferSwitch.module.scss | 62 -------
.../components/OfferSwitch/OfferSwitch.tsx | 55 ------
.../src/components/Payment/Payment.test.tsx | 11 --
.../src/components/Payment/Payment.tsx | 158 +++---------------
.../PaymentContainer/PaymentContainer.tsx | 25 +--
.../User/__snapshots__/User.test.tsx.snap | 10 --
15 files changed, 133 insertions(+), 374 deletions(-)
delete mode 100644 packages/hooks-react/src/useSubscriptionChange.ts
delete mode 100644 packages/ui-react/src/components/OfferSwitch/OfferSwitch.module.scss
delete mode 100644 packages/ui-react/src/components/OfferSwitch/OfferSwitch.tsx
diff --git a/packages/common/src/controllers/AccountController.ts b/packages/common/src/controllers/AccountController.ts
index 5c876c941..6f48e3b68 100644
--- a/packages/common/src/controllers/AccountController.ts
+++ b/packages/common/src/controllers/AccountController.ts
@@ -427,13 +427,11 @@ export default class AccountController {
// resolve and fetch the pending offer after upgrade/downgrade
try {
if (activeSubscription?.pendingSwitchId) {
- assertModuleMethod(this.checkoutService.getOffer, 'getOffer is not available in checkout service');
assertModuleMethod(this.checkoutService.getSubscriptionSwitch, 'getSubscriptionSwitch is not available in checkout service');
- const switchOffer = await this.checkoutService.getSubscriptionSwitch({ switchId: activeSubscription.pendingSwitchId });
- const offerResponse = await this.checkoutService.getOffer({ offerId: switchOffer.responseData.toOfferId });
+ const switchOffer = await this.checkoutService.getSubscriptionSwitch({ subscription: activeSubscription });
- pendingOffer = offerResponse.responseData;
+ pendingOffer = switchOffer.responseData;
}
} catch (error: unknown) {
logDev('Failed to fetch the pending offer', error);
diff --git a/packages/common/src/controllers/CheckoutController.ts b/packages/common/src/controllers/CheckoutController.ts
index 3695e4af9..c09c30932 100644
--- a/packages/common/src/controllers/CheckoutController.ts
+++ b/packages/common/src/controllers/CheckoutController.ts
@@ -53,8 +53,7 @@ export default class CheckoutController {
}
if (!useCheckoutStore.getState().switchSubscriptionOffers.length) {
- const subscriptionSwitches = await this.getSubscriptionSwitches();
- const switchSubscriptionOffers = subscriptionSwitches ? await this.getOffers({ offerIds: subscriptionSwitches }) : [];
+ const switchSubscriptionOffers = await this.getSubscriptionSwitches();
useCheckoutStore.setState({ switchSubscriptionOffers });
}
};
@@ -238,24 +237,20 @@ export default class CheckoutController {
};
};
- getSubscriptionSwitches = async (): Promise => {
+ getSubscriptionSwitches = async (): Promise => {
const { getAccountInfo } = useAccountStore.getState();
const { customerId } = getAccountInfo();
const { subscription } = useAccountStore.getState();
- if (!subscription || !this.checkoutService.getSubscriptionSwitches) return null;
-
- assertModuleMethod(this.checkoutService.getOffer, 'getOffer is not available in checkout service');
+ if (!subscription || !this.checkoutService.getSubscriptionSwitches) return [];
const response = await this.checkoutService.getSubscriptionSwitches({
customerId: customerId,
offerId: subscription.offerId,
});
- if (!response.responseData.available.length) return null;
-
- return response.responseData.available.map(({ toOfferId }) => toOfferId);
+ return response.responseData;
};
switchSubscription = async () => {
@@ -271,9 +266,9 @@ export default class CheckoutController {
const switchDirection: 'upgrade' | 'downgrade' = determineSwitchDirection(subscription);
const switchSubscriptionPayload = {
+ subscription,
toOfferId: selectedOffer.offerId,
customerId: customerId,
- offerId: subscription.offerId,
switchDirection: switchDirection,
};
diff --git a/packages/common/src/services/WatchHistoryService.ts b/packages/common/src/services/WatchHistoryService.ts
index 62e4408ac..e33dc1269 100644
--- a/packages/common/src/services/WatchHistoryService.ts
+++ b/packages/common/src/services/WatchHistoryService.ts
@@ -1,5 +1,5 @@
import { inject, injectable } from 'inversify';
-import { array, number, object, string } from 'yup';
+import { number, object, string } from 'yup';
import type { PlaylistItem } from '../../types/playlist';
import type { SerializedWatchHistoryItem, WatchHistoryItem } from '../../types/watchHistory';
@@ -13,12 +13,10 @@ import ApiService from './ApiService';
import StorageService from './StorageService';
import AccountService from './integrations/AccountService';
-const schema = array(
- object().shape({
- mediaid: string(),
- progress: number(),
- }),
-);
+const schema = object().shape({
+ mediaid: string(),
+ progress: number(),
+});
@injectable()
export default class WatchHistoryService {
@@ -63,8 +61,17 @@ export default class WatchHistoryService {
};
private validateWatchHistory(history: unknown) {
- if (history && schema.validateSync(history)) {
- return history as SerializedWatchHistoryItem[];
+ if (Array.isArray(history)) {
+ const validatedHistory = history.filter((item) => {
+ try {
+ return schema.validateSync(item);
+ } catch (error: unknown) {
+ logDev('Failed to validated watch history item', error);
+ return false;
+ }
+ });
+
+ return validatedHistory as SerializedWatchHistoryItem[];
}
return [];
diff --git a/packages/common/src/services/integrations/cleeng/CleengCheckoutService.ts b/packages/common/src/services/integrations/cleeng/CleengCheckoutService.ts
index 6aa89be0e..0a87af9c5 100644
--- a/packages/common/src/services/integrations/cleeng/CleengCheckoutService.ts
+++ b/packages/common/src/services/integrations/cleeng/CleengCheckoutService.ts
@@ -16,6 +16,8 @@ import type {
GetPaymentMethods,
GetSubscriptionSwitch,
GetSubscriptionSwitches,
+ GetSubscriptionSwitchesResponse,
+ GetSubscriptionSwitchResponse,
PaymentWithoutDetails,
PaymentWithPayPal,
SwitchSubscription,
@@ -128,16 +130,31 @@ export default class CleengCheckoutService extends CheckoutService {
};
getSubscriptionSwitches: GetSubscriptionSwitches = async (payload) => {
- return this.cleengService.get(`/customers/${payload.customerId}/subscription_switches/${payload.offerId}/availability`, { authenticate: true });
+ const response = await this.cleengService.get>(
+ `/customers/${payload.customerId}/subscription_switches/${payload.offerId}/availability`,
+ { authenticate: true },
+ );
+
+ const subscriptionSwitches = await this.getOffers({ offerIds: response.responseData.available.map((switchOffer) => switchOffer.toOfferId) });
+
+ return {
+ responseData: subscriptionSwitches,
+ errors: [],
+ };
};
getSubscriptionSwitch: GetSubscriptionSwitch = async (payload) => {
- return this.cleengService.get(`/subscription_switches/${payload.switchId}`, { authenticate: true });
+ const response = await this.cleengService.get>(
+ `/subscription_switches/${payload.subscription.pendingSwitchId}`,
+ { authenticate: true },
+ );
+
+ return this.getOffer({ offerId: response.responseData.toOfferId });
};
switchSubscription: SwitchSubscription = async (payload) => {
return this.cleengService.post(
- `/customers/${payload.customerId}/subscription_switches/${payload.offerId}`,
+ `/customers/${payload.customerId}/subscription_switches/${payload.subscription.offerId}`,
JSON.stringify({ toOfferId: payload.toOfferId, switchDirection: payload.switchDirection }),
{ authenticate: true },
);
diff --git a/packages/common/src/services/integrations/jwp/JWPAccountService.ts b/packages/common/src/services/integrations/jwp/JWPAccountService.ts
index 5daba8d5e..c3e949e41 100644
--- a/packages/common/src/services/integrations/jwp/JWPAccountService.ts
+++ b/packages/common/src/services/integrations/jwp/JWPAccountService.ts
@@ -61,7 +61,7 @@ export default class JWPAccountService extends AccountService {
canUpdateEmail: false,
canSupportEmptyFullName: false,
canChangePasswordWithOldPassword: true,
- canRenewSubscription: false,
+ canRenewSubscription: true,
canExportAccountData: true,
canUpdatePaymentMethod: false,
canShowReceipts: true,
diff --git a/packages/common/src/services/integrations/jwp/JWPCheckoutService.ts b/packages/common/src/services/integrations/jwp/JWPCheckoutService.ts
index c22c678ed..d8d02c1a2 100644
--- a/packages/common/src/services/integrations/jwp/JWPCheckoutService.ts
+++ b/packages/common/src/services/integrations/jwp/JWPCheckoutService.ts
@@ -1,5 +1,5 @@
import InPlayer, { type AccessFee, type MerchantPaymentMethod } from '@inplayer-org/inplayer.js';
-import { injectable } from 'inversify';
+import { inject, injectable, named } from 'inversify';
import { isSVODOffer } from '../../../utils/offers';
import type {
@@ -10,6 +10,8 @@ import type {
GetEntitlementsResponse,
GetOffers,
GetPaymentMethods,
+ GetSubscriptionSwitch,
+ GetSubscriptionSwitches,
Offer,
Order,
Payment,
@@ -17,11 +19,13 @@ import type {
PaymentWithAdyen,
PaymentWithoutDetails,
PaymentWithPayPal,
+ SwitchSubscription,
UpdateOrder,
} from '../../../../types/checkout';
import CheckoutService from '../CheckoutService';
import type { ServiceResponse } from '../../../../types/service';
import { isCommonError } from '../../../utils/api';
+import AccountService from '../AccountService';
@injectable()
export default class JWPCheckoutService extends CheckoutService {
@@ -85,7 +89,6 @@ export default class JWPCheckoutService extends CheckoutService {
active: true,
period: offer.access_type.period === 'month' && offer.access_type.quantity === 12 ? 'year' : offer.access_type.period,
freePeriods: offer.trial_period ? 1 : 0,
- planSwitchEnabled: offer.item.plan_switch_enabled ?? false,
} as Offer;
};
@@ -109,6 +112,10 @@ export default class JWPCheckoutService extends CheckoutService {
} as Order;
};
+ constructor(@inject(AccountService) @named('JWP') private readonly accountService: AccountService) {
+ super();
+ }
+
createOrder: CreateOrder = async (payload) => {
return {
errors: [],
@@ -276,13 +283,50 @@ export default class JWPCheckoutService extends CheckoutService {
}
};
- getSubscriptionSwitches = undefined;
+ getSubscriptionSwitches: GetSubscriptionSwitches = async (payload) => {
+ const { data } = await InPlayer.Asset.getAssetAccessFees(this.parseOfferId(payload.offerId));
+
+ const subscriptionSwitches = data?.filter((accessFee) => accessFee.item.plan_switch_enabled).map((accessFee) => this.formatOffer(accessFee)) || [];
+
+ return { responseData: subscriptionSwitches, errors: [] };
+ };
getOrder = undefined;
- switchSubscription = undefined;
+ switchSubscription: SwitchSubscription = async (payload) => {
+ const { subscription, toOfferId } = payload;
+ const accessFeeId = parseInt(toOfferId.split('_')[1]);
+
+ try {
+ const response = await InPlayer.Subscription.changeSubscriptionPlan({
+ access_fee_id: accessFeeId,
+ inplayer_token: String(subscription.subscriptionId),
+ });
+
+ await this.accountService.updateCustomer({
+ metadata: {
+ [`${subscription.subscriptionId}_pending_downgrade`]: toOfferId,
+ },
+ });
+
+ return {
+ errors: [],
+ responseData: response.data.message,
+ };
+ } catch {
+ throw new Error('Failed to change subscription');
+ }
+ };
+
+ getSubscriptionSwitch: GetSubscriptionSwitch = async ({ subscription }) => {
+ if (subscription.pendingSwitchId) {
+ const offers = await this.getOffers({ offerIds: [subscription.offerId] });
- getSubscriptionSwitch = undefined;
+ return { responseData: offers.find((offer) => offer.offerId === subscription.pendingSwitchId) || null, errors: [] };
+ }
+
+ return { responseData: null, errors: [] };
+ };
createAdyenPaymentSession = undefined;
diff --git a/packages/common/src/services/integrations/jwp/JWPSubscriptionService.ts b/packages/common/src/services/integrations/jwp/JWPSubscriptionService.ts
index 6d42b457e..41dff124c 100644
--- a/packages/common/src/services/integrations/jwp/JWPSubscriptionService.ts
+++ b/packages/common/src/services/integrations/jwp/JWPSubscriptionService.ts
@@ -100,7 +100,7 @@ export default class JWPSubscriptionService extends SubscriptionService {
};
};
- private formatActiveSubscription = (subscription: SubscriptionDetails, expiresAt: number) => {
+ private formatActiveSubscription = (subscription: SubscriptionDetails, expiresAt: number, pendingSwitchId: string | null) => {
let status = '';
switch (subscription.action_type) {
case 'free-trial':
@@ -134,7 +134,7 @@ export default class JWPSubscriptionService extends SubscriptionService {
period: subscription.access_type?.period,
totalPrice: subscription.charged_amount,
unsubscribeUrl: subscription.unsubscribe_url,
- pendingSwitchId: null,
+ pendingSwitchId: pendingSwitchId,
} as Subscription;
};
@@ -159,6 +159,7 @@ export default class JWPSubscriptionService extends SubscriptionService {
getActiveSubscription: GetActiveSubscription = async () => {
const assetId = this.accountService.assetId;
+ const { data: customer } = await InPlayer.Account.getAccountInfo();
if (assetId === null) throw new Error("Couldn't fetch active subscription, there is no assetId configured");
@@ -167,10 +168,13 @@ export default class JWPSubscriptionService extends SubscriptionService {
if (hasAccess) {
const { data } = await InPlayer.Subscription.getSubscriptions();
- const activeSubscription = data.collection.find((subscription: SubscriptionDetails) => subscription.item_id === assetId);
+ const activeSubscription = data.collection.find((subscription: SubscriptionDetails) => subscription.item_id === assetId) as
+ | SubscriptionDetails
+ | undefined;
+ const pendingSwitchId = (customer.metadata?.[`${activeSubscription?.subscription_id}_pending_downgrade`] as string) || null;
if (activeSubscription) {
- return this.formatActiveSubscription(activeSubscription, hasAccess?.data?.expires_at);
+ return this.formatActiveSubscription(activeSubscription, hasAccess?.data?.expires_at, pendingSwitchId);
}
return this.formatGrantedSubscription(hasAccess.data);
diff --git a/packages/common/types/checkout.ts b/packages/common/types/checkout.ts
index 89210f117..8d1983b0d 100644
--- a/packages/common/types/checkout.ts
+++ b/packages/common/types/checkout.ts
@@ -1,5 +1,5 @@
import type { PayloadWithIPOverride } from './account';
-import type { PaymentDetail } from './subscription';
+import type { PaymentDetail, Subscription } from './subscription';
import type { EmptyEnvironmentServiceRequest, EnvironmentServiceRequest, PromiseRequest } from './service';
export type Offer = {
@@ -41,7 +41,6 @@ export type Offer = {
contentExternalId: number | null;
contentExternalData: string | null;
contentAgeRestriction: string | null;
- planSwitchEnabled?: boolean;
};
export type OfferType = 'svod' | 'tvod';
@@ -188,7 +187,7 @@ export type GetSubscriptionSwitchesResponse = {
};
export type GetSubscriptionSwitchPayload = {
- switchId: string;
+ subscription: Subscription;
};
export type GetSubscriptionSwitchResponse = {
@@ -206,7 +205,7 @@ export type GetSubscriptionSwitchResponse = {
export type SwitchSubscriptionPayload = {
customerId: string;
- offerId: string;
+ subscription: Subscription;
toOfferId: string;
switchDirection: string;
};
@@ -372,8 +371,8 @@ export type GetPaymentMethods = EmptyEnvironmentServiceRequest;
export type PaymentWithAdyen = EnvironmentServiceRequest;
export type PaymentWithPayPal = EnvironmentServiceRequest;
-export type GetSubscriptionSwitches = EnvironmentServiceRequest;
-export type GetSubscriptionSwitch = EnvironmentServiceRequest;
+export type GetSubscriptionSwitches = EnvironmentServiceRequest;
+export type GetSubscriptionSwitch = EnvironmentServiceRequest;
export type SwitchSubscription = EnvironmentServiceRequest;
export type GetEntitlements = EnvironmentServiceRequest;
export type GetAdyenPaymentSession = EnvironmentServiceRequest;
diff --git a/packages/hooks-react/src/useSubscriptionChange.ts b/packages/hooks-react/src/useSubscriptionChange.ts
deleted file mode 100644
index 772397ef4..000000000
--- a/packages/hooks-react/src/useSubscriptionChange.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useMutation } from 'react-query';
-import type { Customer } from '@jwp/ott-common/types/account';
-import { getModule } from '@jwp/ott-common/src/modules/container';
-import { useAccountStore } from '@jwp/ott-common/src/stores/AccountStore';
-import AccountController from '@jwp/ott-common/src/controllers/AccountController';
-import CheckoutController from '@jwp/ott-common/src/controllers/CheckoutController';
-
-export const useSubscriptionChange = (
- isUpgradeOffer: boolean,
- selectedOfferId: string | null,
- customer: Customer | null,
- activeSubscriptionId: string | number | undefined,
-) => {
- const accountController = getModule(AccountController);
- const checkoutController = getModule(CheckoutController);
-
- const updateSubscriptionMetadata = useMutation(accountController.updateUser, {
- onSuccess: () => {
- useAccountStore.setState({
- loading: false,
- });
- },
- });
-
- return useMutation(checkoutController.changeSubscription, {
- onSuccess: () => {
- if (!isUpgradeOffer && selectedOfferId) {
- updateSubscriptionMetadata.mutate({
- firstName: customer?.firstName || '',
- lastName: customer?.lastName || '',
- metadata: {
- [`${activeSubscriptionId}_pending_downgrade`]: selectedOfferId,
- },
- });
- }
- },
- });
-};
diff --git a/packages/ui-react/src/components/OfferSwitch/OfferSwitch.module.scss b/packages/ui-react/src/components/OfferSwitch/OfferSwitch.module.scss
deleted file mode 100644
index 43326e202..000000000
--- a/packages/ui-react/src/components/OfferSwitch/OfferSwitch.module.scss
+++ /dev/null
@@ -1,62 +0,0 @@
-@use '@jwp/ott-ui-react/src/styles/variables';
-@use '@jwp/ott-ui-react/src/styles/theme';
-
-.offerSwitchContainer {
- display: flex;
- align-items: center;
- width: 100%;
- height: auto;
- padding: 16px;
- gap: 25px;
- color: variables.$gray-white;
- background-color: theme.$panel-bg;
- border-radius: 4px;
-}
-
-.activeOfferSwitchContainer {
- color: variables.$gray-darker;
- background-color: variables.$white;
-}
-
-.offerSwitchInfoContainer {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- height: 100%;
- gap: 4px;
- font-weight: 600;
-}
-
-.offerSwitchPlanContainer {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- gap: 2px;
-}
-
-.currentPlanHeading {
- color: variables.$gray;
- font-size: 10px;
-}
-
-.activeCurrentPlanHeading {
- color: variables.$gray;
-}
-
-.nextBillingDate {
- color: variables.$gray;
- font-weight: 400;
- font-size: 12px;
-}
-
-.price {
- margin-left: auto;
- font-size: 20px;
- line-height: variables.$base-line-height;
-}
-
-.paymentFrequency {
- font-size: 12px;
-}
diff --git a/packages/ui-react/src/components/OfferSwitch/OfferSwitch.tsx b/packages/ui-react/src/components/OfferSwitch/OfferSwitch.tsx
deleted file mode 100644
index 3ced92a6e..000000000
--- a/packages/ui-react/src/components/OfferSwitch/OfferSwitch.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import classNames from 'classnames';
-import { useTranslation } from 'react-i18next';
-import type { Offer } from '@jwp/ott-common/types/checkout';
-import { formatLocalizedDate, formatPrice } from '@jwp/ott-common/src/utils/formatting';
-
-import Checkbox from '../form-fields/Checkbox/Checkbox';
-
-import styles from './OfferSwitch.module.scss';
-
-type OfferSwitchProps = {
- isCurrentOffer: boolean;
- pendingDowngradeOfferId: string;
- offer: Offer;
- selected: boolean;
- onChange: (offerId: string) => void;
- expiresAt: number | undefined;
-};
-
-const OfferSwitch = ({ isCurrentOffer, pendingDowngradeOfferId, offer, selected, onChange, expiresAt }: OfferSwitchProps) => {
- const { t, i18n } = useTranslation(['user', 'account']);
- const { customerPriceInclTax, customerCurrency, period } = offer;
-
- const isPendingDowngrade = pendingDowngradeOfferId === offer.offerId;
-
- return (
-
-
onChange(offer.offerId)} />
-
- {(isCurrentOffer || isPendingDowngrade) && (
-
- {isCurrentOffer && t('user:payment.current_plan').toUpperCase()}
- {isPendingDowngrade && t('user:payment.pending_downgrade').toUpperCase()}
-
- )}
-
-
{t(`user:payment.${period === 'month' ? 'monthly' : 'annual'}_subscription`)}
- {(isCurrentOffer || isPendingDowngrade) && expiresAt && (
-
- {isCurrentOffer &&
- !pendingDowngradeOfferId &&
- t('user:payment.next_billing_date_on', { date: formatLocalizedDate(new Date(expiresAt * 1000), i18n.language) })}
- {isPendingDowngrade && t('user:payment.downgrade_on', { date: formatLocalizedDate(new Date(expiresAt * 1000), i18n.language) })}
-
- )}
-
-
-
- {formatPrice(customerPriceInclTax, customerCurrency, undefined)}
- /{t(`account:periods.${period}_one`)}
-
-
- );
-};
-
-export default OfferSwitch;
diff --git a/packages/ui-react/src/components/Payment/Payment.test.tsx b/packages/ui-react/src/components/Payment/Payment.test.tsx
index a4847043d..c5ad4f0f3 100644
--- a/packages/ui-react/src/components/Payment/Payment.test.tsx
+++ b/packages/ui-react/src/components/Payment/Payment.test.tsx
@@ -27,17 +27,6 @@ describe('', () => {
onShowReceiptClick={vi.fn()}
onUpgradeSubscriptionClick={vi.fn()}
onShowAllTransactionsClick={vi.fn()}
- changeSubscriptionPlan={{
- isLoading: false,
- isSuccess: false,
- isError: false,
- reset: vi.fn(),
- }}
- onChangePlanClick={vi.fn()}
- selectedOfferId={null}
- setSelectedOfferId={vi.fn()}
- isUpgradeOffer={undefined}
- setIsUpgradeOffer={vi.fn()}
isExternalPaymentProvider={false}
/>,
);
diff --git a/packages/ui-react/src/components/Payment/Payment.tsx b/packages/ui-react/src/components/Payment/Payment.tsx
index 538e78509..dd8b9bc7c 100644
--- a/packages/ui-react/src/components/Payment/Payment.tsx
+++ b/packages/ui-react/src/components/Payment/Payment.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router-dom';
import type { AccessModel } from '@jwp/ott-common/types/config';
@@ -14,10 +14,8 @@ import useOpaqueId from '@jwp/ott-hooks-react/src/useOpaqueId';
import classNames from 'classnames';
import IconButton from '../IconButton/IconButton';
-import Alert from '../Alert/Alert';
import Button from '../Button/Button';
import LoadingOverlay from '../LoadingOverlay/LoadingOverlay';
-import OfferSwitch from '../OfferSwitch/OfferSwitch';
import TextField from '../form-fields/TextField/TextField';
import Icon from '../Icon/Icon';
import Link from '../Link/Link';
@@ -45,19 +43,6 @@ type Props = {
canUpdatePaymentMethod: boolean;
canRenewSubscription?: boolean;
canShowReceipts?: boolean;
- offers?: Offer[];
- pendingDowngradeOfferId?: string;
- changeSubscriptionPlan: {
- isLoading: boolean;
- isError: boolean;
- isSuccess: boolean;
- reset: () => void;
- };
- onChangePlanClick: () => void;
- selectedOfferId: string | null;
- setSelectedOfferId: (offerId: string | null) => void;
- isUpgradeOffer: boolean | undefined;
- setIsUpgradeOffer: (isUpgradeOffer: boolean | undefined) => void;
isExternalPaymentProvider: boolean;
paymentProvider?: string;
paymentProviderLink?: string;
@@ -81,14 +66,6 @@ const Payment = ({
canUpdatePaymentMethod,
onUpgradeSubscriptionClick,
offerSwitchesAvailable,
- offers = [],
- pendingDowngradeOfferId = '',
- changeSubscriptionPlan,
- onChangePlanClick,
- selectedOfferId,
- setSelectedOfferId,
- isUpgradeOffer,
- setIsUpgradeOffer,
isExternalPaymentProvider,
paymentProvider,
paymentProviderLink,
@@ -105,27 +82,6 @@ const Payment = ({
const breakpoint = useBreakpoint();
const isMobile = breakpoint === Breakpoint.xs;
- const [isChangingOffer, setIsChangingOffer] = useState(false);
-
- useEffect(() => {
- if (!isChangingOffer) {
- setSelectedOfferId(activeSubscription?.accessFeeId ?? null);
- }
- }, [activeSubscription, isChangingOffer, setSelectedOfferId]);
-
- useEffect(() => {
- setIsChangingOffer(false);
- }, [activeSubscription?.status, activeSubscription?.pendingSwitchId]);
-
- useEffect(() => {
- if (selectedOfferId && offers) {
- setIsUpgradeOffer(
- (offers.find((offer) => offer.offerId === selectedOfferId)?.customerPriceInclTax ?? 0) >
- (offers.find((offer) => offer.offerId === activeSubscription?.accessFeeId)?.customerPriceInclTax ?? 0),
- );
- }
- }, [selectedOfferId, offers, activeSubscription, setIsUpgradeOffer]);
-
function onCompleteSubscriptionClick() {
navigate(modalURLFromLocation(location, 'choose-offer'));
}
@@ -159,58 +115,39 @@ const Payment = ({
}
}
- const showChangeSubscriptionButton = (!isExternalPaymentProvider && offerSwitchesAvailable) || (!isChangingOffer && !canRenewSubscription);
+ const showChangeSubscriptionButton = !isExternalPaymentProvider && offerSwitchesAvailable;
return (
<>
- {
- changeSubscriptionPlan.reset();
- setIsChangingOffer(false);
- }}
- />
{t('nav.payments')}
{accessModel === ACCESS_MODEL.SVOD && (
-
{isChangingOffer ? t('user:payment.change_plan') : t('user:payment.subscription_details')}
+ {t('user:payment.subscription_details')}
{activeSubscription ? (
- {!isChangingOffer && (
-
-
- {getTitle(activeSubscription.period)}
- {activeSubscription.status === 'active' && !isGrantedSubscription && !pendingDowngradeOfferId
- ? t('user:payment.next_billing_date_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) })
- : t('user:payment.subscription_expires_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) })}
- {(pendingOffer || pendingDowngradeOfferId) && activeSubscription.status !== 'cancelled' && (
-
- {t('user:payment.pending_offer_switch', {
- title: getTitle(pendingOffer?.period || offers.find((offer) => offer.offerId === pendingDowngradeOfferId)?.period || 'month'),
- })}
-
- )}
-
- {!isGrantedSubscription && (
-
- {formatPrice(activeSubscription.nextPaymentPrice, activeSubscription.nextPaymentCurrency, customer.country)}
- /{t(`account:periods.${activeSubscription.period}`)}
-
+
+
+ {getTitle(activeSubscription.period)}
+ {activeSubscription.status === 'active' && !isGrantedSubscription
+ ? t('user:payment.next_billing_date_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) })
+ : t('user:payment.subscription_expires_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) })}
+ {pendingOffer && activeSubscription.status !== 'cancelled' && (
+
+ {t('user:payment.pending_offer_switch', {
+ title: getTitle(pendingOffer?.period),
+ })}
+
)}
-
- )}
+
+ {!isGrantedSubscription && (
+
+ {formatPrice(activeSubscription.nextPaymentPrice, activeSubscription.nextPaymentCurrency, customer.country)}
+ /{t(`account:periods.${activeSubscription.period}`)}
+
+ )}
+
{isExternalPaymentProvider ? (
{t('account:external_payment.explanation', { paymentProvider })}{' '}
@@ -223,24 +160,15 @@ const Payment = ({
)}
- {isChangingOffer && (
-
- {offers
- .filter((o) => o.planSwitchEnabled)
- .map((offer) => (
-
setSelectedOfferId(offerId)}
- expiresAt={activeSubscription?.expiresAt}
- />
- ))}
-
-
- setIsChangingOffer(false)} variant="text" />
- {activeSubscription?.status !== 'cancelled' && (
-
- )}
-
-
- )}
)}
diff --git a/packages/ui-react/src/containers/PaymentContainer/PaymentContainer.tsx b/packages/ui-react/src/containers/PaymentContainer/PaymentContainer.tsx
index 2aaeb2b87..fe7f794f3 100644
--- a/packages/ui-react/src/containers/PaymentContainer/PaymentContainer.tsx
+++ b/packages/ui-react/src/containers/PaymentContainer/PaymentContainer.tsx
@@ -6,7 +6,6 @@ import { useAccountStore } from '@jwp/ott-common/src/stores/AccountStore';
import { useConfigStore } from '@jwp/ott-common/src/stores/ConfigStore';
import AccountController from '@jwp/ott-common/src/controllers/AccountController';
import useOffers from '@jwp/ott-hooks-react/src/useOffers';
-import { useSubscriptionChange } from '@jwp/ott-hooks-react/src/useSubscriptionChange';
import styles from '../../pages/User/User.module.scss';
import LoadingOverlay from '../../components/LoadingOverlay/LoadingOverlay';
@@ -59,12 +58,10 @@ const PaymentContainer = () => {
const { accessModel } = useConfigStore(({ accessModel }) => ({ accessModel }), shallow);
const { user: customer, subscription: activeSubscription, transactions, activePayment, pendingOffer, loading } = useAccountStore();
const { canUpdatePaymentMethod, canShowReceipts, canRenewSubscription } = accountController.getFeatures();
- const { subscriptionOffers, switchSubscriptionOffers } = useOffers();
+ const { switchSubscriptionOffers } = useOffers();
const [showAllTransactions, setShowAllTransactions] = useState(false);
const [isLoadingReceipt, setIsLoadingReceipt] = useState(false);
- const [selectedOfferId, setSelectedOfferId] = useState(activeSubscription?.accessFeeId ?? null);
- const [isUpgradeOffer, setIsUpgradeOffer] = useState(undefined);
const location = useLocation();
@@ -85,22 +82,10 @@ const PaymentContainer = () => {
setIsLoadingReceipt(false);
};
- const changeSubscriptionPlan = useSubscriptionChange(isUpgradeOffer ?? false, selectedOfferId, customer, activeSubscription?.subscriptionId);
-
- const onChangePlanClick = async () => {
- if (selectedOfferId && activeSubscription?.subscriptionId) {
- changeSubscriptionPlan.mutate({
- accessFeeId: selectedOfferId.slice(1),
- subscriptionId: `${activeSubscription.subscriptionId}`,
- });
- }
- };
-
if (!customer) {
return ;
}
- const pendingDowngradeOfferId = (customer.metadata?.[`${activeSubscription?.subscriptionId}_pending_downgrade`] as string) || '';
const isExternalPaymentProvider = !!activeSubscription && EXTERNAL_PAYMENT_METHODS.includes(activeSubscription.paymentMethod);
const paymentProvider = activeSubscription?.paymentMethod.split(' ')[0] || 'unknown';
const paymentProviderLink = STORE_LINKS[paymentProvider.toLowerCase()];
@@ -124,14 +109,6 @@ const PaymentContainer = () => {
offerSwitchesAvailable={switchSubscriptionOffers.length > 0}
canShowReceipts={canShowReceipts}
onShowReceiptClick={handleShowReceiptClick}
- offers={subscriptionOffers}
- pendingDowngradeOfferId={pendingDowngradeOfferId}
- changeSubscriptionPlan={changeSubscriptionPlan}
- onChangePlanClick={onChangePlanClick}
- selectedOfferId={selectedOfferId}
- setSelectedOfferId={(offerId: string | null) => setSelectedOfferId(offerId)}
- isUpgradeOffer={isUpgradeOffer}
- setIsUpgradeOffer={(isUpgradeOffer: boolean | undefined) => setIsUpgradeOffer(isUpgradeOffer)}
isExternalPaymentProvider={isExternalPaymentProvider}
paymentProvider={paymentProvider}
paymentProviderLink={paymentProviderLink}
diff --git a/packages/ui-react/src/pages/User/__snapshots__/User.test.tsx.snap b/packages/ui-react/src/pages/User/__snapshots__/User.test.tsx.snap
index c6c0ec92b..fb0b843c0 100644
--- a/packages/ui-react/src/pages/User/__snapshots__/User.test.tsx.snap
+++ b/packages/ui-react/src/pages/User/__snapshots__/User.test.tsx.snap
@@ -689,16 +689,6 @@ exports[`User Component tests > Payments Page 1`] = `
-
-
- user:payment.change_subscription
-
-