зеркало из https://github.com/mozilla/fxa.git
Merge pull request #15851 from mozilla/FXA-8405--contentfulmanager-create-manager-class-and-add-m
feat: add contentful manager and eligibility helper method
This commit is contained in:
Коммит
19e9c028b1
|
@ -9,10 +9,16 @@ const CONTENTFUL_GRAPHQL_ENVIRONMENT =
|
||||||
const config: CodegenConfig = {
|
const config: CodegenConfig = {
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
schema: `${CONTENTFUL_GRAPHQL_API_URL}/spaces/${CONTENTFUL_GRAPHQL_SPACE_ID}/environments/${CONTENTFUL_GRAPHQL_ENVIRONMENT}?access_token=${CONTENTFUL_GRAPHQL_API_KEY}`,
|
schema: `${CONTENTFUL_GRAPHQL_API_URL}/spaces/${CONTENTFUL_GRAPHQL_SPACE_ID}/environments/${CONTENTFUL_GRAPHQL_ENVIRONMENT}?access_token=${CONTENTFUL_GRAPHQL_API_KEY}`,
|
||||||
documents: ['libs/shared/contentful/src/lib/queries/*.ts'],
|
documents: [
|
||||||
|
'libs/shared/contentful/src/lib/queries/*.ts',
|
||||||
|
'libs/shared/contentful/src/lib/queries/**/*.ts',
|
||||||
|
],
|
||||||
generates: {
|
generates: {
|
||||||
'libs/shared/contentful/src/__generated__/': {
|
'libs/shared/contentful/src/__generated__/': {
|
||||||
preset: 'client',
|
preset: 'client',
|
||||||
|
config: {
|
||||||
|
avoidOptionals: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"test-unit": {
|
||||||
"executor": "@nx/jest:jest",
|
"executor": "@nx/jest:jest",
|
||||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||||
"options": {
|
"options": {
|
||||||
|
|
|
@ -19,10 +19,10 @@ const documents = {
|
||||||
types.EligibilityContentByPlanIdsDocument,
|
types.EligibilityContentByPlanIdsDocument,
|
||||||
'\n query Offering($id: String!, $locale: String!) {\n offering(id: $id, locale: $locale) {\n stripeProductId\n countries\n defaultPurchase {\n purchaseDetails {\n productName\n details\n subtitle\n webIcon\n }\n }\n }\n }\n':
|
'\n query Offering($id: String!, $locale: String!) {\n offering(id: $id, locale: $locale) {\n stripeProductId\n countries\n defaultPurchase {\n purchaseDetails {\n productName\n details\n subtitle\n webIcon\n }\n }\n }\n }\n':
|
||||||
types.OfferingDocument,
|
types.OfferingDocument,
|
||||||
'\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\n }\n }\n }\n':
|
|
||||||
types.PurchaseWithDetailsDocument,
|
|
||||||
'\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\n }\n }\n }\n':
|
'\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\n }\n }\n }\n':
|
||||||
types.PurchaseWithDetailsOfferingContentDocument,
|
types.PurchaseWithDetailsOfferingContentDocument,
|
||||||
|
'\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\n }\n }\n }\n':
|
||||||
|
types.PurchaseWithDetailsDocument,
|
||||||
'\n query ServicesWithCapabilities($skip: Int!, $limit: Int!, $locale: String!) {\n serviceCollection(skip: $skip, limit: $limit, locale: $locale) {\n items {\n oauthClientId\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n }\n }\n }\n }\n }\n':
|
'\n query ServicesWithCapabilities($skip: Int!, $limit: Int!, $locale: String!) {\n serviceCollection(skip: $skip, limit: $limit, locale: $locale) {\n items {\n oauthClientId\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n }\n }\n }\n }\n }\n':
|
||||||
types.ServicesWithCapabilitiesDocument,
|
types.ServicesWithCapabilitiesDocument,
|
||||||
};
|
};
|
||||||
|
@ -63,14 +63,14 @@ export function graphql(
|
||||||
* 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(
|
export function graphql(
|
||||||
source: '\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\n }\n }\n }\n'
|
source: '\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\n }\n }\n }\n'
|
||||||
): (typeof documents)['\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\n }\n }\n }\n'];
|
): (typeof documents)['\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\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.
|
||||||
*/
|
*/
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: '\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\n }\n }\n }\n'
|
source: '\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\n }\n }\n }\n'
|
||||||
): (typeof documents)['\n query PurchaseWithDetailsOfferingContent(\n $skip: Int!\n $limit: Int!\n $locale: String!\n $stripePlanIds: [String]!\n ) {\n purchaseCollection(\n skip: $skip\n limit: $limit\n locale: $locale\n where: { stripePlanChoices_contains_some: $stripePlanIds }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n }\n }\n }\n }\n }\n'];
|
): (typeof documents)['\n query PurchaseWithDetails($id: String!, $locale: String!) {\n purchase(id: $id, locale: $locale) {\n internalName\n description\n purchaseDetails {\n productName\n details\n webIcon\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.
|
||||||
*/
|
*/
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,5 +1,9 @@
|
||||||
export * from './lib/contentful-client';
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
export * from './lib/queries/purchase-with-details';
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
export * from './lib/queries/offering';
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
export * from './lib/errors';
|
|
||||||
|
export * from './lib/contentful.client';
|
||||||
|
export * from './lib/contentful.manager';
|
||||||
|
export * from './lib/contentful.error';
|
||||||
export * from './lib/factories';
|
export * from './lib/factories';
|
||||||
|
export * from './lib/queries/eligibility-content-by-plan-ids';
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
export const mockQuery = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue({ data: { purchaseCollection: { items: [] } } });
|
||||||
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
query: mockQuery,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
export const ContentfulClient = mock;
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import { ApolloQueryResult } from '@apollo/client';
|
import { ApolloQueryResult } from '@apollo/client';
|
||||||
import { ContentfulClient } from './contentful-client';
|
import { ContentfulClient } from './contentful.client';
|
||||||
import { offeringQuery } from './queries/offering';
|
import { offeringQuery } from './queries/offering';
|
||||||
import { OfferingQuery } from '../__generated__/graphql';
|
import { OfferingQuery } from '../__generated__/graphql';
|
||||||
import {
|
import {
|
||||||
ContentfulError,
|
ContentfulError,
|
||||||
ContentfulLinkError,
|
ContentfulLinkError,
|
||||||
ContentfulLocaleError,
|
ContentfulLocaleError,
|
||||||
} from './errors';
|
} from './contentful.error';
|
||||||
|
|
||||||
const ApolloError = jest.requireActual('@apollo/client').ApolloError;
|
const ApolloError = jest.requireActual('@apollo/client').ApolloError;
|
||||||
|
|
|
@ -15,9 +15,9 @@ import {
|
||||||
ContentfulExecutionError,
|
ContentfulExecutionError,
|
||||||
ContentfulLinkError,
|
ContentfulLinkError,
|
||||||
ContentfulLocaleError,
|
ContentfulLocaleError,
|
||||||
} from './errors';
|
} from './contentful.error';
|
||||||
import { BaseError } from '@fxa/shared/error';
|
import { BaseError } from '@fxa/shared/error';
|
||||||
import { ContentfulClientConfig } from './contentful-client.config';
|
import { ContentfulClientConfig } from './contentful.client.config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ContentfulClient {
|
export class ContentfulClient {
|
||||||
|
@ -31,7 +31,7 @@ export class ContentfulClient {
|
||||||
async query<Result, Variables>(
|
async query<Result, Variables>(
|
||||||
query: TypedDocumentNode<Result, Variables>,
|
query: TypedDocumentNode<Result, Variables>,
|
||||||
variables: Variables
|
variables: Variables
|
||||||
): Promise<ApolloQueryResult<Result> | null> {
|
): Promise<ApolloQueryResult<Result>> {
|
||||||
try {
|
try {
|
||||||
const response = await this.client.query<Result, Variables>({
|
const response = await this.client.query<Result, Variables>({
|
||||||
query,
|
query,
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* 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 { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
|
||||||
|
import { ContentfulClient } from './contentful.client';
|
||||||
|
import { ContentfulManager } from './contentful.manager';
|
||||||
|
import { EligibilityContentByPlanIdsQueryFactory } from './factories';
|
||||||
|
|
||||||
|
jest.mock('./contentful.client');
|
||||||
|
|
||||||
|
describe('ContentfulManager', () => {
|
||||||
|
let manager: ContentfulManager;
|
||||||
|
let mockClient: ContentfulClient;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
(ContentfulClient as jest.Mock).mockClear();
|
||||||
|
mockClient = new ContentfulClient({
|
||||||
|
graphqlApiKey: 'test',
|
||||||
|
graphqlApiUri: 'test',
|
||||||
|
graphqlEnvironment: 'test',
|
||||||
|
graphqlSpaceId: 'test',
|
||||||
|
});
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{ provide: ContentfulClient, useValue: mockClient },
|
||||||
|
ContentfulManager,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
manager = module.get<ContentfulManager>(ContentfulManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(manager).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getPurchaseDetailsForEligibility', () => {
|
||||||
|
it('should return empty result', async () => {
|
||||||
|
const result = await manager.getPurchaseDetailsForEligibility(['test']);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result.purchaseCollection.items).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return successfully with subgroups and offering', async () => {
|
||||||
|
const queryData = EligibilityContentByPlanIdsQueryFactory();
|
||||||
|
mockClient.query = jest.fn().mockResolvedValueOnce({ data: queryData });
|
||||||
|
const result = await manager.getPurchaseDetailsForEligibility(['test']);
|
||||||
|
const planId = result.purchaseCollection.items[0].stripePlanChoices[0];
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result.getSubgroupsForPlanId(planId)).toHaveLength(1);
|
||||||
|
expect(result.getOfferingForPlanId(planId)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* 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 { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { EligibilityContentByPlanIdsQuery } from '../__generated__/graphql';
|
||||||
|
import { ContentfulClient } from './contentful.client';
|
||||||
|
import {
|
||||||
|
eligibilityContentByPlanIdsQuery,
|
||||||
|
EligibilityContentByPlanIdsResultUtil,
|
||||||
|
} from './queries/eligibility-content-by-plan-ids';
|
||||||
|
import { DeepNonNullable } from './types';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ContentfulManager {
|
||||||
|
constructor(private client: ContentfulClient) {}
|
||||||
|
|
||||||
|
async getPurchaseDetailsForEligibility(
|
||||||
|
stripePlanIds: string[]
|
||||||
|
): Promise<EligibilityContentByPlanIdsResultUtil> {
|
||||||
|
const queryResult = await this.client.query(
|
||||||
|
eligibilityContentByPlanIdsQuery,
|
||||||
|
{
|
||||||
|
skip: 0,
|
||||||
|
limit: 100,
|
||||||
|
locale: 'en-US',
|
||||||
|
stripePlanIds,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return new EligibilityContentByPlanIdsResultUtil(
|
||||||
|
queryResult.data as DeepNonNullable<EligibilityContentByPlanIdsQuery>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,48 @@ import { faker } from '@faker-js/faker';
|
||||||
import { NetworkStatus } from '@apollo/client';
|
import { NetworkStatus } from '@apollo/client';
|
||||||
import { ApolloQueryResult } from '@apollo/client';
|
import { ApolloQueryResult } from '@apollo/client';
|
||||||
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
||||||
import { OfferingQuery } from '../__generated__/graphql';
|
import {
|
||||||
import { PurchaseWithDetailsQuery } from '../__generated__/graphql';
|
OfferingQuery,
|
||||||
|
PurchaseWithDetailsQuery,
|
||||||
|
EligibilityContentByPlanIdsQuery,
|
||||||
|
} from '../__generated__/graphql';
|
||||||
|
|
||||||
|
export const EligibilityContentByPlanIdsQueryFactory = (
|
||||||
|
override?: Partial<EligibilityContentByPlanIdsQuery>
|
||||||
|
): EligibilityContentByPlanIdsQuery => {
|
||||||
|
const stripeProductId = faker.string.sample();
|
||||||
|
return {
|
||||||
|
purchaseCollection: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
stripePlanChoices: [faker.string.sample()],
|
||||||
|
offering: {
|
||||||
|
stripeProductId,
|
||||||
|
countries: [faker.string.sample()],
|
||||||
|
linkedFrom: {
|
||||||
|
subGroupCollection: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
groupName: faker.string.sample(),
|
||||||
|
offeringCollection: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
stripeProductId,
|
||||||
|
countries: [faker.string.sample()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
...override,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const OfferingQueryFactory = (
|
export const OfferingQueryFactory = (
|
||||||
override?: Partial<OfferingQuery>
|
override?: Partial<OfferingQuery>
|
||||||
|
@ -31,6 +71,7 @@ export const PurchaseWithDetailsQueryFactory = (
|
||||||
override?: Partial<PurchaseWithDetailsQuery>
|
override?: Partial<PurchaseWithDetailsQuery>
|
||||||
): PurchaseWithDetailsQuery => ({
|
): PurchaseWithDetailsQuery => ({
|
||||||
purchase: {
|
purchase: {
|
||||||
|
internalName: faker.string.sample(),
|
||||||
description: faker.string.sample(),
|
description: faker.string.sample(),
|
||||||
purchaseDetails: {
|
purchaseDetails: {
|
||||||
productName: faker.string.sample(),
|
productName: faker.string.sample(),
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
export * from './query';
|
||||||
|
export * from './types';
|
||||||
|
export * from './util';
|
|
@ -2,7 +2,7 @@
|
||||||
* 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 { graphql } from '../../__generated__/gql';
|
import { graphql } from '../../../__generated__/gql';
|
||||||
|
|
||||||
export const eligibilityContentByPlanIdsQuery = graphql(`
|
export const eligibilityContentByPlanIdsQuery = graphql(`
|
||||||
query EligibilityContentByPlanIds(
|
query EligibilityContentByPlanIds(
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
export interface EligibilitySubgroupOfferingResult {
|
||||||
|
stripeProductId: string;
|
||||||
|
countries: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EligibilitySubgroupResult {
|
||||||
|
groupName: string;
|
||||||
|
offeringCollection: {
|
||||||
|
items: EligibilitySubgroupOfferingResult[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EligibilityOfferingResult {
|
||||||
|
stripeProductId: string;
|
||||||
|
countries: string[];
|
||||||
|
linkedFrom: {
|
||||||
|
subGroupCollection: {
|
||||||
|
items: EligibilitySubgroupResult[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EligibilityPurchaseResult {
|
||||||
|
stripePlanChoices: string[];
|
||||||
|
offering: EligibilityOfferingResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EligibilityContentByPlanIdsResult {
|
||||||
|
purchaseCollection: {
|
||||||
|
items: EligibilityPurchaseResult[];
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* 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 {
|
||||||
|
EligibilityContentByPlanIdsResult,
|
||||||
|
EligibilityOfferingResult,
|
||||||
|
EligibilitySubgroupResult,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
export class EligibilityContentByPlanIdsResultUtil {
|
||||||
|
constructor(private rawResult: EligibilityContentByPlanIdsResult) {}
|
||||||
|
|
||||||
|
getOfferingForPlanId(planId: string): EligibilityOfferingResult | undefined {
|
||||||
|
return this.rawResult.purchaseCollection.items.find((purchase) =>
|
||||||
|
purchase.stripePlanChoices.includes(planId)
|
||||||
|
)?.offering;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubgroupsForPlanId(planId: string): EligibilitySubgroupResult[] {
|
||||||
|
return (
|
||||||
|
this.rawResult.purchaseCollection.items.find((purchase) =>
|
||||||
|
purchase.stripePlanChoices.includes(planId)
|
||||||
|
)?.offering.linkedFrom.subGroupCollection.items || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get purchaseCollection() {
|
||||||
|
return this.rawResult.purchaseCollection;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export type DeepNonNullable<T> = {
|
||||||
|
[K in keyof T]: Exclude<DeepNonNullable<T[K]>, null | undefined>;
|
||||||
|
};
|
|
@ -3,7 +3,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../../../dist/out-tsc",
|
"outDir": "../../../dist/out-tsc",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"types": ["node"]
|
"types": ["jest", "node"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts"],
|
"include": ["src/**/*.ts"],
|
||||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"jest.config.ts",
|
"jest.config.ts",
|
||||||
"src/**/*.test.ts",
|
"src/**/*.test.ts",
|
||||||
"src/**/*.spec.ts",
|
"src/**/*.spec.ts",
|
||||||
"src/**/*.d.ts"
|
"src/**/*.d.ts",
|
||||||
|
"src/**/__mocks__/*.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче