Skip to content

Commit fd61e80

Browse files
committed
Move error to server component
1 parent e0b88c9 commit fd61e80

File tree

8 files changed

+119
-67
lines changed

8 files changed

+119
-67
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { headers } from 'next/headers';
6+
import { notFound, redirect } from 'next/navigation';
7+
8+
import { SubscriptionParams } from '@fxa/payments/ui';
9+
import { determineStaySubscribedEligibilityAction } from '@fxa/payments/ui/actions';
10+
import { ChurnError } from '@fxa/payments/ui/server';
11+
import { auth } from 'apps/payments/next/auth';
12+
import { config } from 'apps/payments/next/config';
13+
14+
export default async function LoyaltyDiscountStaySubscribedErrorPage({
15+
params,
16+
searchParams,
17+
}: {
18+
params: SubscriptionParams;
19+
searchParams: Record<string, string> | undefined;
20+
}) {
21+
const { locale, subscriptionId } = params;
22+
const acceptLanguage = headers().get('accept-language');
23+
24+
const session = await auth();
25+
if (!session?.user?.id) {
26+
const redirectToUrl = new URL(
27+
`${config.paymentsNextHostedUrl}/${locale}/subscriptions/landing`
28+
);
29+
redirectToUrl.search = new URLSearchParams(searchParams).toString();
30+
redirect(redirectToUrl.href);
31+
}
32+
33+
const uid = session.user.id;
34+
35+
const pageContent = await determineStaySubscribedEligibilityAction(
36+
uid,
37+
subscriptionId,
38+
acceptLanguage
39+
);
40+
41+
if (!pageContent) {
42+
notFound();
43+
}
44+
45+
const { cmsOfferingContent, reason } = pageContent;
46+
47+
if (!cmsOfferingContent) {
48+
notFound();
49+
}
50+
51+
const staySubscribedContent = pageContent.staySubscribedContent;
52+
53+
if (staySubscribedContent.flowType !== 'stay_subscribed') {
54+
notFound();
55+
}
56+
57+
return (
58+
<ChurnError
59+
cmsOfferingContent={cmsOfferingContent}
60+
locale={locale}
61+
reason={reason}
62+
pageContent={staySubscribedContent}
63+
subscriptionId={subscriptionId}
64+
/>
65+
);
66+
}

apps/payments/next/app/[locale]/subscriptions/[subscriptionId]/loyalty-discount/stay-subscribed/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default async function LoyaltyDiscountStaySubscribedPage({
5858

5959
if (isErrorReason) {
6060
redirect(
61-
`/${locale}/subscriptions/${subscriptionId}/loyalty-discount/error`
61+
`/${locale}/subscriptions/${subscriptionId}/loyalty-discount/stay-subscribed/error`
6262
);
6363
}
6464

libs/payments/customer/src/lib/subscription.manager.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ describe('SubscriptionManager', () => {
433433
{
434434
discounts: [{ coupon: mockCouponId }],
435435
cancel_at_period_end: false,
436+
metadata: {
437+
cancelled_for_customer_at: '',
438+
},
436439
}
437440
);
438441
expect(result).toEqual(mockUpdatedResponse);
@@ -469,7 +472,10 @@ describe('SubscriptionManager', () => {
469472
mockSubscription.id,
470473
{
471474
discounts: [{ coupon: mockCouponId }],
472-
cancel_at_period_end: true,
475+
cancel_at_period_end: false,
476+
metadata: {
477+
cancelled_for_customer_at: '',
478+
},
473479
}
474480
);
475481
expect(result).toEqual(mockUpdatedResponse);

libs/payments/management/src/lib/churn-intervention.service.spec.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,11 @@ describe('ChurnInterventionService', () => {
7878
{
7979
provide: ChurnInterventionManager,
8080
useValue: {
81-
getEntry: jest.fn(),
81+
getOrCreateEntry: jest.fn(),
8282
getRedemptionCountForUid: jest.fn(),
8383
updateEntry: jest.fn(),
8484
},
8585
},
86-
{
87-
provide: SubscriptionManager,
88-
useValue: {
89-
getSubscriptionStatus: jest.fn(),
90-
applyStripeCouponToSubscription: jest.fn(),
91-
},
92-
},
9386
{
9487
provide: ProductConfigurationManager,
9588
useValue: {

libs/payments/management/src/lib/subscriptionManagement.service.spec.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ describe('SubscriptionManagementService', () => {
192192
provide: ChurnInterventionService,
193193
useValue: {
194194
determineStaySubscribedEligibility: jest.fn(),
195-
}
196-
}
195+
},
196+
},
197197
],
198198
}).compile();
199199

@@ -313,7 +313,8 @@ describe('SubscriptionManagementService', () => {
313313
const mockPaymentMethod = StripeResponseFactory(
314314
StripePaymentMethodFactory({})
315315
);
316-
const mockStaySubscribedCmsChurnEntry = ChurnInterventionByProductIdResultFactory();
316+
const mockStaySubscribedCmsChurnEntry =
317+
ChurnInterventionByProductIdResultFactory();
317318
const mockSubscriptionContent = SubscriptionContentFactory();
318319
const mockPaymentMethodInformation = {
319320
type: SubPlatPaymentMethodType.Card,
@@ -404,6 +405,7 @@ describe('SubscriptionManagementService', () => {
404405
isEligible: true,
405406
reason: 'eligible',
406407
cmsChurnInterventionEntry: mockStaySubscribedCmsChurnEntry,
408+
cmsOfferingContent: null,
407409
});
408410

409411
const result =
@@ -1527,7 +1529,7 @@ describe('SubscriptionManagementService', () => {
15271529
await expect(
15281530
subscriptionManagementService.setDefaultStripePaymentDetails(
15291531
mockAccountCustomer.uid,
1530-
'pm_12345',
1532+
'pm_12345'
15311533
)
15321534
).rejects.toBeInstanceOf(SetDefaultPaymentAccountCustomerMissingStripeId);
15331535
});

apps/payments/next/app/[locale]/subscriptions/[subscriptionId]/loyalty-discount/error/en.ftl renamed to libs/payments/ui/src/lib/server/components/ChurnError/en.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## LoyaltyDiscountErrorPage
1+
## Churn flow - Error page
22

33
churn-error-page-title-discount-already-applied = Discount code already applied
44
# $productName (String) - The name of the product associated with the subscription.

apps/payments/next/app/[locale]/subscriptions/[subscriptionId]/loyalty-discount/error/page.tsx renamed to libs/payments/ui/src/lib/server/components/ChurnError/index.tsx

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,44 @@
55
import { headers } from 'next/headers';
66
import Image from 'next/image';
77
import Link from 'next/link';
8-
import { notFound, redirect } from 'next/navigation';
98

109
import {
1110
getNextChargeChurnContent,
12-
SubscriptionParams,
11+
SubPlatPaymentMethodType,
1312
} from '@fxa/payments/ui';
14-
import { determineStaySubscribedEligibilityAction } from '@fxa/payments/ui/actions';
15-
import { getApp } from '@fxa/payments/ui/server';
1613
import { LinkExternal } from '@fxa/shared/react';
17-
import { auth } from 'apps/payments/next/auth';
18-
import { config } from 'apps/payments/next/config';
14+
import { getApp } from '@fxa/payments/ui/server';
1915

20-
export default async function LoyaltyDiscountErrorPage({
21-
params,
22-
searchParams,
23-
}: {
24-
params: SubscriptionParams;
25-
searchParams: Record<string, string> | undefined;
26-
}) {
27-
const { locale, subscriptionId } = params;
16+
type ChurnErrorProps = {
17+
cmsOfferingContent: any;
18+
locale: string;
19+
reason: string;
20+
pageContent: {
21+
flowType: 'cancel' | 'stay_subscribed';
22+
active: boolean;
23+
cancelAtPeriodEnd: boolean;
24+
currency: string;
25+
currentPeriodEnd: number;
26+
defaultPaymentMethodType?: SubPlatPaymentMethodType;
27+
last4?: string;
28+
nextInvoiceTax?: number;
29+
nextInvoiceTotal?: number;
30+
productName: string;
31+
webIcon: string;
32+
};
33+
subscriptionId: string;
34+
};
35+
36+
export async function ChurnError({
37+
cmsOfferingContent,
38+
locale,
39+
reason,
40+
pageContent,
41+
subscriptionId,
42+
}: ChurnErrorProps) {
2843
const acceptLanguage = headers().get('accept-language');
2944
const l10n = getApp().getL10n(acceptLanguage);
3045

31-
const session = await auth();
32-
if (!session?.user?.id) {
33-
const redirectToUrl = new URL(
34-
`${config.paymentsNextHostedUrl}/${locale}/subscriptions/landing`
35-
);
36-
redirectToUrl.search = new URLSearchParams(searchParams).toString();
37-
redirect(redirectToUrl.href);
38-
}
39-
40-
const uid = session.user.id;
41-
42-
const pageContent = await determineStaySubscribedEligibilityAction(
43-
uid,
44-
subscriptionId,
45-
acceptLanguage
46-
);
47-
48-
if (!pageContent) {
49-
notFound();
50-
}
51-
52-
const { cmsOfferingContent, reason, staySubscribedContent } = pageContent;
53-
54-
if (!cmsOfferingContent) {
55-
notFound();
56-
}
57-
5846
const { productName, successActionButtonUrl, supportUrl, webIcon } =
5947
cmsOfferingContent;
6048

@@ -148,23 +136,19 @@ export default async function LoyaltyDiscountErrorPage({
148136
</section>
149137
);
150138
case 'subscription_still_active':
151-
if (
152-
!staySubscribedContent ||
153-
staySubscribedContent.flowType !== 'stay_subscribed'
154-
) {
139+
if (!pageContent) {
155140
// Re-render as general error section below
156141
break;
157142
}
158143

159144
const nextChargeChurnContent = getNextChargeChurnContent({
160-
currency: staySubscribedContent.currency,
161-
currentPeriodEnd: staySubscribedContent.currentPeriodEnd,
145+
currency: pageContent.currency,
146+
currentPeriodEnd: pageContent.currentPeriodEnd,
162147
locale,
163-
defaultPaymentMethodType:
164-
staySubscribedContent.defaultPaymentMethodType,
165-
last4: staySubscribedContent.last4,
166-
nextInvoiceTotal: staySubscribedContent.nextInvoiceTotal,
167-
nextInvoiceTax: staySubscribedContent.nextInvoiceTax,
148+
defaultPaymentMethodType: pageContent.defaultPaymentMethodType,
149+
last4: pageContent.last4,
150+
nextInvoiceTotal: pageContent.nextInvoiceTotal,
151+
nextInvoiceTax: pageContent.nextInvoiceTax,
168152
});
169153

170154
return (

libs/payments/ui/src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
export * from './lib/nestapp/app';
77
export * from './lib/nestapp/config';
88
export * from './lib/config.utils';
9+
export * from './lib/server/components/ChurnError';
910
export * from './lib/server/components/PriceInterval';
1011
export * from './lib/server/components/SignedIn';
1112
export * from './lib/server/components/SubscriptionTitle';

0 commit comments

Comments
 (0)