polish(payments-next): Adjust styling and server action for terms

Because:

* A few code style and css-style tweaks were needed as a follow to the terms page release

This commit:

* addresses some of the outcomes from style conversations

Closes #N/A
This commit is contained in:
Davey Alvarez
2025-12-03 13:01:17 -08:00
parent 0ab32c016b
commit 8494d581d3
15 changed files with 239 additions and 126 deletions

View File

@@ -2,9 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { Breadcrumbs, Header } from '@fxa/payments/ui'; import { Header } from '@fxa/payments/ui';
import { auth } from 'apps/payments/next/auth'; import { auth } from 'apps/payments/next/auth';
import { config } from 'apps/payments/next/config';
export const dynamic = 'force-dynamic'; export const dynamic = 'force-dynamic';
@@ -16,19 +15,13 @@ export default async function ChurnLayout({
const session = await auth(); const session = await auth();
return ( return (
<div className="min-h-[calc(100vh_-_4rem)] bg-white tablet:bg-grey-10 flex flex-col justify-start"> <>
<Header <Header
auth={{ auth={{
user: session?.user, user: session?.user,
}} }}
/> />
<Breadcrumbs <>{children}</>
contentServerUrl={config.contentServerUrl} </>
paymentsNextUrl={config.paymentsNextHostedUrl}
/>
<div className="flex flex-col tablet:pt-20 items-center flex-1">
<div className="flex justify-center max-w-lg">{children}</div>
</div>
</div>
); );
} }

View File

@@ -1,3 +1,7 @@
loyalty-discount-terms-heading = Terms and Restrictions loyalty-discount-terms-heading = Terms and restrictions
loyalty-discount-terms-support = Contact Support loyalty-discount-terms-support = Contact Support
loyalty-discount-terms-support-aria = Contact Support # $productName (String) - The name of the product to create subscription, e.g. Mozilla VPN
loyalty-discount-terms-contact-support-product-aria = Contact Support for { $productName }
not-found-page-title-terms = Page not found
not-found-page-description-terms = The page youre looking for does not exist.
not-found-page-button-terms-manage-subscriptions = Manage subscriptions

View File

@@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 { headers } from 'next/headers';
import { PageNotFound } from '@fxa/payments/ui';
import { getApp } from '@fxa/payments/ui/server';
export enum PaymentsPage {
Subscriptions = 'subscriptions',
}
export default function NotFound() {
const acceptLanguage = headers().get('accept-language');
const l10n = getApp().getL10n(acceptLanguage);
return (
<PageNotFound
header={l10n.getString('not-found-page-title-terms', 'Page not found')}
description={l10n.getString(
'not-found-page-description-terms',
'The page youre looking for does not exist.'
)}
button={l10n.getString(
'not-found-page-button-terms-manage-subscriptions',
'Manage subscriptions'
)}
paymentsPage={PaymentsPage.Subscriptions}
/>
);
}

View File

@@ -8,7 +8,7 @@ import { getApp } from '@fxa/payments/ui/server';
import { headers } from 'next/headers'; import { headers } from 'next/headers';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
import { SubplatInterval } from '@fxa/payments/customer'; import { SubplatInterval } from '@fxa/payments/customer';
import { BaseButton, ButtonVariant } from '@fxa/payments/ui'; import { notFound } from 'next/navigation';
export default async function ChurnTerms({ export default async function ChurnTerms({
params, params,
@@ -37,45 +37,61 @@ export default async function ChurnTerms({
selectedLanguage: locale, selectedLanguage: locale,
}); });
const content = churnIntervention.churnInterventions.at(0);
if (
!content ||
!content.termsHeading ||
!Array.isArray(content.termsDetails) ||
content.termsDetails.length === 0
) {
notFound();
}
return ( return (
<div className="flex flex-col tablet:bg-white p-8 tablet:rounded-lg tablet:shadow-lg"> <section
<h1 className="font-bold text-lg my-1"> className="flex tablet:items-center justify-center min-h-[calc(100vh_-_4rem)] tablet:min-h-[calc(100vh_-_5rem)]"
{l10n.getString( aria-labelledby="loyalty-discount-terms"
'loyalty-discount-terms-heading', >
'Terms and Restrictions' <div className="max-w-xl flex flex-col p-6 pt-10 tablet:bg-white tablet:border tablet:border-grey-200 tablet:opacity-100 tablet:p-8 tablet:rounded-xl tablet:shadow-[0_0px_10px_rgba(0,0,0,0.08)]">
)} <h1
</h1> id="loyalty-discount-terms"
<h1 className="font-bold text-lg my-1"> className="font-semibold text-xl leading-8"
{`${churnIntervention.churnInterventions[0].termsHeading}`}
</h1>
<ul className="list-disc ml-5 my-2 marker:text-xs text-sm font-light [&_li]:leading-5">
{churnIntervention.churnInterventions[0].termsDetails.map(
(term, index) => (
<li key={index}>{term}</li>
)
)}
</ul>
<div className="flex justify-start">
<LinkExternal
href={`${churnIntervention.churnInterventions[0].supportUrl}${searchParamsString}`}
aria-label={l10n.getString(
'loyalty-discount-terms-support-aria',
'Contact Support'
)}
> >
<BaseButton {l10n.getString(
variant={ButtonVariant.SubscriptionManagementSecondary} 'loyalty-discount-terms-heading',
className="w-40 mt-4" 'Terms and restrictions'
)}
</h1>
<h2 className="font-semibold text-xl leading-8">
{`${content.termsHeading}`}
</h2>
<div className="mt-3 mx-6 mb-6 tablet:mx-10">
<ul className="font-light leading-6 list-disc marker:text-sm marker:leading-normal">
{content.termsDetails.map((term, index) => (
<li key={index}>{term}</li>
))}
</ul>
</div>
<div className="flex">
<LinkExternal
className="border box-border font-header rounded text-center py-2 px-5 border-grey-200 w-auto bg-grey-10 font-semibold hover:bg-grey-50 text-grey-700"
href={`${content.supportUrl}${searchParamsString}`}
aria-label={l10n.getString(
'loyalty-discount-terms-contact-support-product-aria',
{
productName: content.productName,
},
`Contact support for ${content.productName}`
)}
> >
<span> {l10n.getString(
{l10n.getString( 'loyalty-discount-terms-support',
'loyalty-discount-terms-support', 'Contact Support'
'Contact Support' )}
)} </LinkExternal>
</span> </div>
</BaseButton>
</LinkExternal>
</div> </div>
</div> </section>
); );
} }

View File

@@ -0,0 +1,26 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 { BaseError } from '@fxa/shared/error';
/**
* ChurnInterventionError is not intended for direct use, except for type-checking errors.
* When throwing a new ChurnInterventionError, create a unique extension of the class.
*/
export class ChurnInterventionError extends BaseError {
constructor(message: string, info: Record<string, any>, cause?: Error) {
super(message, { info, cause });
this.name = 'ChurnInterventionError';
}
}
export class ChurnInterventionProductIdentifierMissingError extends ChurnInterventionError {
constructor() {
super(
'Either stripeProductId or offeringApiIdentifier must be provided',
{}
);
this.name = 'ChurnInterventionProductIdentifierMissingError';
}
}

View File

@@ -5,13 +5,14 @@
import { Inject, Injectable, Logger, type LoggerService } from '@nestjs/common'; import { Inject, Injectable, Logger, type LoggerService } from '@nestjs/common';
import { ChurnInterventionManager } from '@fxa/payments/cart'; import { ChurnInterventionManager } from '@fxa/payments/cart';
import { import {
ChurnInterventionByProductIdResultUtil,
ProductConfigurationManager, ProductConfigurationManager,
} from '@fxa/shared/cms'; } from '@fxa/shared/cms';
import { SubscriptionManagementService } from './subscriptionManagement.service'; import { SubscriptionManagementService } from './subscriptionManagement.service';
import { import { StatsDService } from '@fxa/shared/metrics/statsd';
StatsDService,
} from '@fxa/shared/metrics/statsd';
import { StatsD } from 'hot-shots'; import { StatsD } from 'hot-shots';
import { SubplatInterval } from '@fxa/payments/customer';
import { ChurnInterventionProductIdentifierMissingError } from './churn-intervention.error';
@Injectable() @Injectable()
export class ChurnInterventionService { export class ChurnInterventionService {
@@ -20,10 +21,9 @@ export class ChurnInterventionService {
private churnInterventionManager: ChurnInterventionManager, private churnInterventionManager: ChurnInterventionManager,
private subscriptionManagementService: SubscriptionManagementService, private subscriptionManagementService: SubscriptionManagementService,
@Inject(StatsDService) private statsd: StatsD, @Inject(StatsDService) private statsd: StatsD,
@Inject(Logger) private log: LoggerService, @Inject(Logger) private log: LoggerService
) {} ) {}
async getChurnInterventionForCustomerId( async getChurnInterventionForCustomerId(
customerId: string, customerId: string,
churnInterventionId: string churnInterventionId: string
@@ -34,11 +34,47 @@ export class ChurnInterventionService {
); );
} }
async getChurnInterventionForProduct(
interval: SubplatInterval,
churnType: 'cancel' | 'stay_subscribed',
stripeProductId?: string,
offeringApiIdentifier?: string,
acceptLanguage?: string,
selectedLanguage?: string
) {
let util: ChurnInterventionByProductIdResultUtil;
if (stripeProductId) {
util = await this.productConfigurationManager.getChurnIntervention(
interval,
churnType,
stripeProductId,
null,
acceptLanguage,
selectedLanguage
);
} else if (offeringApiIdentifier) {
util = await this.productConfigurationManager.getChurnIntervention(
interval,
churnType,
null,
offeringApiIdentifier,
acceptLanguage,
selectedLanguage
);
} else {
throw new ChurnInterventionProductIdentifierMissingError();
}
return {
churnInterventions: util.getTransformedChurnInterventionByProductId(),
};
}
async determineStaySubscribedEligibility( async determineStaySubscribedEligibility(
uid: string, uid: string,
subscriptionId: string, subscriptionId: string,
acceptLanguage?: string | null, acceptLanguage?: string | null,
selectedLanguage?: string, selectedLanguage?: string
) { ) {
try { try {
const cmsChurnResult = const cmsChurnResult =
@@ -49,7 +85,8 @@ export class ChurnInterventionService {
selectedLanguage selectedLanguage
); );
const cmsChurnInterventionEntries = cmsChurnResult.getTransformedChurnInterventionByProductId(); const cmsChurnInterventionEntries =
cmsChurnResult.getTransformedChurnInterventionByProductId();
if (!cmsChurnInterventionEntries.length) { if (!cmsChurnInterventionEntries.length) {
this.statsd.increment('stay_subscribed_eligibility', { this.statsd.increment('stay_subscribed_eligibility', {
eligibility: 'ineligible', eligibility: 'ineligible',
@@ -59,16 +96,20 @@ export class ChurnInterventionService {
isEligible: false, isEligible: false,
reason: 'no_churn_intervention_found', reason: 'no_churn_intervention_found',
cmsChurnInterventionEntry: null, cmsChurnInterventionEntry: null,
} };
} }
const cmsChurnInterventionEntry = cmsChurnInterventionEntries[0]; const cmsChurnInterventionEntry = cmsChurnInterventionEntries[0];
const redemptionCount = await this.churnInterventionManager.getRedemptionCountForUid( const redemptionCount =
uid, await this.churnInterventionManager.getRedemptionCountForUid(
cmsChurnInterventionEntry.churnInterventionId uid,
); cmsChurnInterventionEntry.churnInterventionId
);
if (cmsChurnInterventionEntry.redemptionLimit && redemptionCount >= cmsChurnInterventionEntry.redemptionLimit) { if (
cmsChurnInterventionEntry.redemptionLimit &&
redemptionCount >= cmsChurnInterventionEntry.redemptionLimit
) {
this.statsd.increment('stay_subscribed_eligibility', { this.statsd.increment('stay_subscribed_eligibility', {
eligibility: 'ineligible', eligibility: 'ineligible',
reason: 'discount_already_applied', reason: 'discount_already_applied',
@@ -77,13 +118,14 @@ export class ChurnInterventionService {
isEligible: false, isEligible: false,
reason: 'discount_already_applied', reason: 'discount_already_applied',
cmsChurnInterventionEntry: null, cmsChurnInterventionEntry: null,
} };
} }
const subscriptionStatus = await this.subscriptionManagementService.getSubscriptionStatus( const subscriptionStatus =
uid, await this.subscriptionManagementService.getSubscriptionStatus(
subscriptionId uid,
); subscriptionId
);
if (!subscriptionStatus.active) { if (!subscriptionStatus.active) {
this.statsd.increment('stay_subscribed_eligibility', { this.statsd.increment('stay_subscribed_eligibility', {
eligibility: 'ineligible', eligibility: 'ineligible',
@@ -93,7 +135,7 @@ export class ChurnInterventionService {
isEligible: false, isEligible: false,
reason: 'subscription_not_active', reason: 'subscription_not_active',
cmsChurnInterventionEntry: null, cmsChurnInterventionEntry: null,
} };
} }
if (!subscriptionStatus.cancelAtPeriodEnd) { if (!subscriptionStatus.cancelAtPeriodEnd) {
this.statsd.increment('stay_subscribed_eligibility', { this.statsd.increment('stay_subscribed_eligibility', {
@@ -114,14 +156,14 @@ export class ChurnInterventionService {
isEligible: true, isEligible: true,
reason: 'eligible', reason: 'eligible',
cmsChurnInterventionEntry, cmsChurnInterventionEntry,
} };
} catch (error) { } catch (error) {
this.log.error(error); this.log.error(error);
return { return {
isEligible: false, isEligible: false,
reason: 'general_error', reason: 'general_error',
cmsChurnInterventionEntry: null, cmsChurnInterventionEntry: null,
} };
} }
} }
@@ -129,7 +171,7 @@ export class ChurnInterventionService {
uid: string, uid: string,
subscriptionId: string, subscriptionId: string,
acceptLanguage?: string | null, acceptLanguage?: string | null,
selectedLanguage?: string, selectedLanguage?: string
) { ) {
const eligibilityResult = await this.determineStaySubscribedEligibility( const eligibilityResult = await this.determineStaySubscribedEligibility(
uid, uid,
@@ -138,7 +180,10 @@ export class ChurnInterventionService {
selectedLanguage selectedLanguage
); );
if (!eligibilityResult.isEligible || !eligibilityResult.cmsChurnInterventionEntry) { if (
!eligibilityResult.isEligible ||
!eligibilityResult.cmsChurnInterventionEntry
) {
return { return {
redeemed: false, redeemed: false,
reason: eligibilityResult.reason, reason: eligibilityResult.reason,
@@ -148,18 +193,26 @@ export class ChurnInterventionService {
} }
try { try {
const updatedSubscription = await this.subscriptionManagementService.applyStripeCouponToSubscription({ const updatedSubscription =
uid, await this.subscriptionManagementService.applyStripeCouponToSubscription(
subscriptionId, {
stripeCouponId: eligibilityResult.cmsChurnInterventionEntry.stripeCouponId, uid,
setCancelAtPeriodEnd: true, subscriptionId,
}); stripeCouponId:
if (!updatedSubscription || updatedSubscription.cancel_at_period_end !== true) { eligibilityResult.cmsChurnInterventionEntry.stripeCouponId,
setCancelAtPeriodEnd: true,
}
);
if (
!updatedSubscription ||
updatedSubscription.cancel_at_period_end !== true
) {
return { return {
redeemed: false, redeemed: false,
reason: 'stripe_subscription_update_failed', reason: 'stripe_subscription_update_failed',
updatedChurnInterventionEntryData: null, updatedChurnInterventionEntryData: null,
cmsChurnInterventionEntry: eligibilityResult.cmsChurnInterventionEntry, cmsChurnInterventionEntry:
eligibilityResult.cmsChurnInterventionEntry,
}; };
} }

View File

@@ -14,13 +14,15 @@ import {
} from '@fxa/payments/cart'; } from '@fxa/payments/cart';
import { ContentServerManager } from '@fxa/payments/content-server'; import { ContentServerManager } from '@fxa/payments/content-server';
import { CurrencyManager } from '@fxa/payments/currency'; import { CurrencyManager } from '@fxa/payments/currency';
import { SubscriptionManagementService, ChurnInterventionService } from '@fxa/payments/management'; import {
SubscriptionManagementService,
ChurnInterventionService,
} from '@fxa/payments/management';
import { import {
CheckoutTokenManager, CheckoutTokenManager,
PaypalBillingAgreementManager, PaypalBillingAgreementManager,
} from '@fxa/payments/paypal'; } from '@fxa/payments/paypal';
import { import {
ChurnInterventionByProductIdResultUtil,
ProductConfigError, ProductConfigError,
ProductConfigurationManager, ProductConfigurationManager,
} from '@fxa/shared/cms'; } from '@fxa/shared/cms';
@@ -279,15 +281,12 @@ export class NextJSActionsService {
args.uid, args.uid,
args.subscriptionId, args.subscriptionId,
args.acceptLanguage, args.acceptLanguage,
args.selectedLanguage, args.selectedLanguage
); );
} }
@SanitizeExceptions() @SanitizeExceptions()
@NextIOValidator( @NextIOValidator(RedeemChurnCouponActionArgs, RedeemChurnCouponActionResult)
RedeemChurnCouponActionArgs,
RedeemChurnCouponActionResult
)
@WithTypeCachableAsyncLocalStorage() @WithTypeCachableAsyncLocalStorage()
@CaptureTimingWithStatsD() @CaptureTimingWithStatsD()
async redeemChurnCoupon(args: { async redeemChurnCoupon(args: {
@@ -300,7 +299,7 @@ export class NextJSActionsService {
args.uid, args.uid,
args.subscriptionId, args.subscriptionId,
args.acceptLanguage, args.acceptLanguage,
args.selectedLanguage, args.selectedLanguage
); );
} }
@@ -903,36 +902,13 @@ export class NextJSActionsService {
acceptLanguage?: string; acceptLanguage?: string;
selectedLanguage?: string; selectedLanguage?: string;
}) { }) {
let util: ChurnInterventionByProductIdResultUtil; return await this.churnInterventionService.getChurnInterventionForProduct(
if (args.stripeProductId) { args.interval,
util = await this.productConfigurationManager.getChurnIntervention( args.churnType,
args.interval, args.stripeProductId,
args.churnType, args.offeringApiIdentifier,
args.stripeProductId, args.acceptLanguage,
null, args.selectedLanguage
args.acceptLanguage, );
args.selectedLanguage
);
} else if (args.offeringApiIdentifier) {
util = await this.productConfigurationManager.getChurnIntervention(
args.interval,
args.churnType,
null,
args.offeringApiIdentifier,
args.acceptLanguage,
args.selectedLanguage
);
} else {
throw new Error(
'Either stripeProductId or offeringApiIdentifier must be provided'
);
}
const churnInterventions =
util.getTransformedChurnInterventionByProductId();
return {
churnInterventions,
};
} }
} }

View File

@@ -16,7 +16,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
type Documents = { type Documents = {
"\n query CancelInterstitialOffer(\n $offeringApiIdentifier: String!\n $currentInterval: String!\n $upgradeInterval: String!\n $locale: String!\n ) {\n cancelInterstitialOffers(\n filters: {\n offeringApiIdentifier: { eq: $offeringApiIdentifier }\n currentInterval: { eq: $currentInterval }\n upgradeInterval: { eq: $upgradeInterval }\n }\n ) {\n offeringApiIdentifier\n currentInterval\n upgradeInterval\n advertisedSavings\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n localizations(filters: { locale: { eq: $locale } }) {\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n }\n offering {\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n }\n }\n }\n": typeof types.CancelInterstitialOfferDocument, "\n query CancelInterstitialOffer(\n $offeringApiIdentifier: String!\n $currentInterval: String!\n $upgradeInterval: String!\n $locale: String!\n ) {\n cancelInterstitialOffers(\n filters: {\n offeringApiIdentifier: { eq: $offeringApiIdentifier }\n currentInterval: { eq: $currentInterval }\n upgradeInterval: { eq: $upgradeInterval }\n }\n ) {\n offeringApiIdentifier\n currentInterval\n upgradeInterval\n advertisedSavings\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n localizations(filters: { locale: { eq: $locale } }) {\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n }\n offering {\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n }\n }\n }\n": typeof types.CancelInterstitialOfferDocument,
"\n query CapabilityServiceByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n capabilities {\n slug\n services {\n oauthClientId\n }\n }\n }\n }\n }\n": typeof types.CapabilityServiceByPlanIdsDocument, "\n query CapabilityServiceByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n capabilities {\n slug\n services {\n oauthClientId\n }\n }\n }\n }\n }\n": typeof types.CapabilityServiceByPlanIdsDocument,
"\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n": typeof types.ChurnInterventionByProductIdDocument, "\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n": typeof types.ChurnInterventionByProductIdDocument,
"\n query EligibilityContentByOffering($apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n }\n }\n }\n": typeof types.EligibilityContentByOfferingDocument, "\n query EligibilityContentByOffering($apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n }\n }\n }\n": typeof types.EligibilityContentByOfferingDocument,
"\n query EligibilityContentByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n }\n }\n }\n }\n }\n": typeof types.EligibilityContentByPlanIdsDocument, "\n query EligibilityContentByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n }\n }\n }\n }\n }\n": typeof types.EligibilityContentByPlanIdsDocument,
"\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": typeof types.IapOfferingsByStoreIDsDocument, "\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": typeof types.IapOfferingsByStoreIDsDocument,
@@ -31,7 +31,7 @@ type Documents = {
const documents: Documents = { const documents: Documents = {
"\n query CancelInterstitialOffer(\n $offeringApiIdentifier: String!\n $currentInterval: String!\n $upgradeInterval: String!\n $locale: String!\n ) {\n cancelInterstitialOffers(\n filters: {\n offeringApiIdentifier: { eq: $offeringApiIdentifier }\n currentInterval: { eq: $currentInterval }\n upgradeInterval: { eq: $upgradeInterval }\n }\n ) {\n offeringApiIdentifier\n currentInterval\n upgradeInterval\n advertisedSavings\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n localizations(filters: { locale: { eq: $locale } }) {\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n }\n offering {\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n }\n }\n }\n": types.CancelInterstitialOfferDocument, "\n query CancelInterstitialOffer(\n $offeringApiIdentifier: String!\n $currentInterval: String!\n $upgradeInterval: String!\n $locale: String!\n ) {\n cancelInterstitialOffers(\n filters: {\n offeringApiIdentifier: { eq: $offeringApiIdentifier }\n currentInterval: { eq: $currentInterval }\n upgradeInterval: { eq: $upgradeInterval }\n }\n ) {\n offeringApiIdentifier\n currentInterval\n upgradeInterval\n advertisedSavings\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n localizations(filters: { locale: { eq: $locale } }) {\n ctaMessage\n modalHeading1\n modalHeading2\n modalMessage\n productPageUrl\n upgradeButtonLabel\n upgradeButtonUrl\n }\n offering {\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n }\n }\n }\n": types.CancelInterstitialOfferDocument,
"\n query CapabilityServiceByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n capabilities {\n slug\n services {\n oauthClientId\n }\n }\n }\n }\n }\n": types.CapabilityServiceByPlanIdsDocument, "\n query CapabilityServiceByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n capabilities {\n slug\n services {\n oauthClientId\n }\n }\n }\n }\n }\n": types.CapabilityServiceByPlanIdsDocument,
"\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n": types.ChurnInterventionByProductIdDocument, "\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n": types.ChurnInterventionByProductIdDocument,
"\n query EligibilityContentByOffering($apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n }\n }\n }\n": types.EligibilityContentByOfferingDocument, "\n query EligibilityContentByOffering($apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n }\n }\n }\n": types.EligibilityContentByOfferingDocument,
"\n query EligibilityContentByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n }\n }\n }\n }\n }\n": types.EligibilityContentByPlanIdsDocument, "\n query EligibilityContentByPlanIds($stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 200 }\n ) {\n stripePlanChoices {\n stripePlanChoice\n }\n offering {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n subGroups {\n groupName\n offerings {\n apiIdentifier\n stripeProductId\n stripeLegacyPlans(pagination: { limit: 200 }) {\n stripeLegacyPlan\n }\n countries\n }\n }\n }\n }\n }\n": types.EligibilityContentByPlanIdsDocument,
"\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": types.IapOfferingsByStoreIDsDocument, "\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": types.IapOfferingsByStoreIDsDocument,
@@ -69,7 +69,7 @@ export function graphql(source: "\n query CapabilityServiceByPlanIds($stripePla
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n"): (typeof documents)["\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n"]; export function graphql(source: "\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n"): (typeof documents)["\n query ChurnInterventionByProductId(\n $offeringApiIdentifier: String\n $stripeProductId: String\n $interval: String!\n $locale: String!\n $churnType: String!\n ) {\n offerings(\n filters: {\n or: [\n { stripeProductId: { eq: $stripeProductId } }\n { apiIdentifier: { eq: $offeringApiIdentifier } }\n ]\n }\n pagination: { limit: 200 }\n ) {\n defaultPurchase {\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n commonContent {\n supportUrl\n }\n churnInterventions(\n filters: { interval: { eq: $interval }, churnType: { eq: $churnType } }\n pagination: { limit: 200 }\n ) {\n localizations(filters: { locale: { eq: $locale } }) {\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n churnInterventionId\n churnType\n redemptionLimit\n stripeCouponId\n interval\n discountAmount\n ctaMessage\n modalHeading\n modalMessage\n productPageUrl\n termsHeading\n termsDetails\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

File diff suppressed because one or more lines are too long

View File

@@ -40,9 +40,11 @@ export const ChurnInterventionByProductIdOfferingsResultFactory = (
): ChurnInterventionByProductIdOfferingResult => ({ ): ChurnInterventionByProductIdOfferingResult => ({
defaultPurchase: { defaultPurchase: {
purchaseDetails: { purchaseDetails: {
productName: faker.string.sample(),
webIcon: faker.image.urlLoremFlickr(), webIcon: faker.image.urlLoremFlickr(),
localizations: [ localizations: [
{ {
productName: faker.string.sample(),
webIcon: faker.image.urlLoremFlickr(), webIcon: faker.image.urlLoremFlickr(),
}, },
], ],
@@ -77,6 +79,7 @@ export const ChurnInterventionByProductIdRawResultFactory = (
export const ChurnInterventionByProductIdResultFactory = ( export const ChurnInterventionByProductIdResultFactory = (
override?: Partial<ChurnInterventionByProductIdResult> override?: Partial<ChurnInterventionByProductIdResult>
): ChurnInterventionByProductIdResult => ({ ): ChurnInterventionByProductIdResult => ({
productName: faker.string.sample(),
webIcon: faker.image.urlLoremFlickr(), webIcon: faker.image.urlLoremFlickr(),
churnInterventionId: faker.string.uuid(), churnInterventionId: faker.string.uuid(),
churnType: faker.helpers.enumValue(Enum_Churnintervention_Churntype), churnType: faker.helpers.enumValue(Enum_Churnintervention_Churntype),

View File

@@ -23,8 +23,10 @@ export const churnInterventionByProductIdQuery = graphql(`
) { ) {
defaultPurchase { defaultPurchase {
purchaseDetails { purchaseDetails {
productName
webIcon webIcon
localizations(filters: { locale: { eq: $locale } }) { localizations(filters: { locale: { eq: $locale } }) {
productName
webIcon webIcon
} }
} }

View File

@@ -25,8 +25,9 @@ export interface ChurnInterventionByProductIdChurnInterventionsResult {
export interface ChurnInterventionByProductIdOfferingResult { export interface ChurnInterventionByProductIdOfferingResult {
defaultPurchase: { defaultPurchase: {
purchaseDetails: { purchaseDetails: {
productName: string;
webIcon: string; webIcon: string;
localizations: { webIcon: string }[]; localizations: { productName: string; webIcon: string }[];
}; };
}; };
commonContent: { commonContent: {
@@ -42,6 +43,7 @@ export interface ChurnInterventionByProductIdRawResult {
} }
export interface ChurnInterventionByProductIdResult { export interface ChurnInterventionByProductIdResult {
productName: string;
webIcon: string; webIcon: string;
churnInterventionId: string; churnInterventionId: string;
churnType: Enum_Churnintervention_Churntype; churnType: Enum_Churnintervention_Churntype;

View File

@@ -36,6 +36,7 @@ describe('ChurnInterventionByProductIdResultUtil', () => {
it('should transform churn intervention by offering', () => { it('should transform churn intervention by offering', () => {
const transformed = util.getTransformedChurnInterventionByProductId()[0]; const transformed = util.getTransformedChurnInterventionByProductId()[0];
expect(transformed).toBeDefined(); expect(transformed).toBeDefined();
expect(transformed?.productName).toBeDefined();
expect(transformed?.webIcon).toBeDefined(); expect(transformed?.webIcon).toBeDefined();
expect(transformed?.supportUrl).toBeDefined(); expect(transformed?.supportUrl).toBeDefined();
expect(transformed?.churnInterventionId).toBeDefined(); expect(transformed?.churnInterventionId).toBeDefined();

View File

@@ -30,6 +30,10 @@ export class ChurnInterventionByProductIdResultUtil {
defaultPurchase.purchaseDetails.localizations.length > 0 defaultPurchase.purchaseDetails.localizations.length > 0
? defaultPurchase.purchaseDetails.localizations[0].webIcon ? defaultPurchase.purchaseDetails.localizations[0].webIcon
: defaultPurchase.purchaseDetails.webIcon, : defaultPurchase.purchaseDetails.webIcon,
productName:
defaultPurchase.purchaseDetails.localizations.length > 0
? defaultPurchase.purchaseDetails.localizations[0].productName
: defaultPurchase.purchaseDetails.productName,
supportUrl: commonContent.supportUrl, supportUrl: commonContent.supportUrl,
ctaMessage: ctaMessage:
churnIntervention.localizations.at(0)?.ctaMessage ?? churnIntervention.localizations.at(0)?.ctaMessage ??

View File

@@ -15,6 +15,7 @@ interface LinkExternalProps {
rel?: 'noopener noreferrer' | 'author'; rel?: 'noopener noreferrer' | 'author';
tabIndex?: number; tabIndex?: number;
onClick?: () => void; onClick?: () => void;
'aria-label'?: string;
} }
export const LinkExternal = ({ export const LinkExternal = ({
@@ -26,6 +27,7 @@ export const LinkExternal = ({
rel = 'noopener noreferrer', rel = 'noopener noreferrer',
tabIndex, tabIndex,
onClick, onClick,
'aria-label': ariaLabel,
}: LinkExternalProps) => ( }: LinkExternalProps) => (
<a <a
data-testid={testid} data-testid={testid}
@@ -37,6 +39,7 @@ export const LinkExternal = ({
rel, rel,
tabIndex, tabIndex,
onClick, onClick,
'aria-label': ariaLabel,
}} }}
> >
{children} {children}