feat(contentful): add planIdsToClientCapabilities to capability manager

Because:

* We want to fetch the list of capabilities for the given plan ids.

This commit:

* Adds planIdsToClientCapabilities method to the capability manager.

Closes FXA-8240
This commit is contained in:
Meghan Sardesai 2023-11-04 17:48:04 -04:00
Родитель d9ec27c859
Коммит c8a059e468
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 9A46BEBC2E8A3934
13 изменённых файлов: 543 добавлений и 1834 удалений

Просмотреть файл

@ -27,4 +27,41 @@ export class CapabilityManager {
),
}));
}
/**
* Fetch the list of capabilities for the given price ids.
*
* Returns Record<string, string[]>
* Keys are clientIds
* Values are capabilitySlugs[]
*/
async planIdsToClientCapabilities(
subscribedPrices: string[]
): Promise<Record<string, string[]>> {
const purchaseDetails =
await this.contentfulManager.getPurchaseDetailsForCapabilityServiceByPlanIds(
[...subscribedPrices]
);
const result: Record<string, string[]> = {};
for (const subscribedPrice of subscribedPrices) {
const capabilityOffering =
purchaseDetails.capabilityOfferingForPlanId(subscribedPrice);
if (!capabilityOffering) continue;
for (const capabilityCollection of capabilityOffering
.capabilitiesCollection.items) {
for (const capability of capabilityCollection.servicesCollection
.items) {
result[capability.oauthClientId] ||= [];
result[capability.oauthClientId].push(capabilityCollection.slug);
}
}
}
return result;
}
}

Просмотреть файл

@ -1,14 +1,12 @@
import {
ResultOf,
DocumentTypeDecoration,
TypedDocumentNode,
} from '@graphql-typed-document-node/core';
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
import { FragmentDefinitionNode } from 'graphql';
import { Incremental } from './graphql';
export type FragmentType<
TDocumentType extends DocumentTypeDecoration<any, any>
> = TDocumentType extends DocumentTypeDecoration<infer TType, any>
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
infer TType,
any
>
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
@ -24,10 +22,7 @@ export function useFragment<TType>(
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType:
| FragmentType<DocumentTypeDecoration<TType, any>>
| null
| undefined
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
@ -37,22 +32,16 @@ export function useFragment<TType>(
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType:
| ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
| null
| undefined
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType:
| FragmentType<DocumentTypeDecoration<TType, any>>
| ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
| null
| undefined
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}
export function makeFragmentData<
F extends DocumentTypeDecoration<any, any>,
FT extends ResultOf<F>
@ -62,24 +51,16 @@ export function makeFragmentData<
export function isFragmentReady<TQuery, TFrag>(
queryNode: DocumentTypeDecoration<TQuery, any>,
fragmentNode: TypedDocumentNode<TFrag>,
data:
| FragmentType<TypedDocumentNode<Incremental<TFrag>, any>>
| null
| undefined
data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
): data is FragmentType<typeof fragmentNode> {
const deferredFields = (
queryNode as {
__meta__?: { deferredFields: Record<string, (keyof TFrag)[]> };
}
).__meta__?.deferredFields;
const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
?.deferredFields;
if (!deferredFields) return true;
const fragDef = fragmentNode.definitions[0] as
| FragmentDefinitionNode
| undefined;
const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
const fragName = fragDef?.name?.value;
const fields = (fragName && deferredFields[fragName]) || [];
return fields.length > 0 && fields.every((field) => data && field in data);
return fields.length > 0 && fields.every(field => data && field in data);
}

45
libs/shared/contentful/src/__generated__/gql.ts сгенерированный
Просмотреть файл

@ -13,18 +13,12 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
'\n query CapabilityServiceByPriceIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\n }\n }\n }\n }\n }\n':
types.CapabilityServiceByPriceIdsDocument,
'\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\n }\n }\n }\n }\n }\n':
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':
types.OfferingDocument,
'\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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\n }\n }\n }\n':
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':
types.ServicesWithCapabilitiesDocument,
"\n query CapabilityServiceByPlanIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CapabilityServiceByPlanIdsDocument,
"\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": 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": types.OfferingDocument,
"\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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\n }\n }\n }\n": 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": types.ServicesWithCapabilitiesDocument,
};
/**
@ -44,43 +38,30 @@ export function graphql(source: string): unknown;
/**
* 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 CapabilityServiceByPriceIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\n }\n }\n }\n }\n }\n'
): (typeof documents)['\n query CapabilityServiceByPriceIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\n }\n }\n }\n }\n }\n'];
export function graphql(source: "\n query CapabilityServiceByPlanIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query CapabilityServiceByPlanIds(\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 offering {\n capabilitiesCollection(skip: $skip, limit: $limit) {\n items {\n slug\n servicesCollection(skip: $skip, limit: $limit) {\n items {\n oauthClientId\n }\n }\n }\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.
*/
export function graphql(
source: '\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\n }\n }\n }\n }\n }\n'
): (typeof documents)['\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\n }\n }\n }\n }\n }\n'];
export function graphql(source: "\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query EligibilityContentByPlanIds(\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 offering {\n stripeProductId\n countries\n linkedFrom {\n subGroupCollection(skip: $skip, limit: $limit) {\n items {\n groupName\n offeringCollection(skip: $skip, limit: $limit) {\n items {\n stripeProductId\n countries\n }\n }\n }\n }\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.
*/
export function graphql(
source: '\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'
): (typeof documents)['\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'];
export function graphql(source: "\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"): (typeof documents)["\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"];
/**
* 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 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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\n }\n }\n }\n'];
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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\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: {\n OR: [\n { stripePlanChoices_contains_some: $stripePlanIds }\n { offering: { stripeLegacyPlans_contains_some: $stripePlanIds } }\n ]\n }\n ) {\n items {\n stripePlanChoices\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n }\n offering {\n stripeProductId\n stripeLegacyPlans\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\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.
*/
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'
): (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'];
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"): (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.
*/
export function graphql(
source: '\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'
): (typeof documents)['\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'];
export function graphql(source: "\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"): (typeof documents)["\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"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};
}
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> =
TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;

2063
libs/shared/contentful/src/__generated__/graphql.ts сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

4
libs/shared/contentful/src/__generated__/index.ts сгенерированный
Просмотреть файл

@ -1,2 +1,2 @@
export * from './fragment-masking';
export * from './gql';
export * from "./fragment-masking";
export * from "./gql";

Просмотреть файл

@ -7,5 +7,6 @@ export * from './lib/contentful.client.config';
export * from './lib/contentful.error';
export * from './lib/contentful.manager';
export * from './lib/factories';
export * from './lib/queries/capability-service-by-plan-ids';
export * from './lib/queries/eligibility-content-by-plan-ids';
export * from './lib/queries/services-with-capabilities';

Просмотреть файл

@ -8,8 +8,14 @@ import {
EligibilityContentByPlanIdsQuery,
PurchaseWithDetailsOfferingContentQuery,
ServicesWithCapabilitiesQuery,
CapabilityServiceByPlanIdsQuery,
} from '../__generated__/graphql';
import { ContentfulClient } from './contentful.client';
import {
capabilityServiceByPlanIdsQuery,
CapabilityServiceByPlanIdsResultUtil,
} from './queries/capability-service-by-plan-ids';
import {
EligibilityContentByPlanIdsResultUtil,
eligibilityContentByPlanIdsQuery,
@ -28,6 +34,24 @@ import { DeepNonNullable } from './types';
export class ContentfulManager {
constructor(private client: ContentfulClient) {}
async getPurchaseDetailsForCapabilityServiceByPlanIds(
stripePlanIds: string[]
): Promise<CapabilityServiceByPlanIdsResultUtil> {
const queryResult = await this.client.query(
capabilityServiceByPlanIdsQuery,
{
skip: 0,
limit: 100,
locale: 'en',
stripePlanIds,
}
);
return new CapabilityServiceByPlanIdsResultUtil(
queryResult.data as DeepNonNullable<CapabilityServiceByPlanIdsQuery>
);
}
async getPurchaseDetailsForEligibility(
stripePlanIds: string[]
): Promise<EligibilityContentByPlanIdsResultUtil> {

Просмотреть файл

@ -0,0 +1,58 @@
/* 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 { faker } from '@faker-js/faker';
import { CapabilityServiceByPlanIdsQuery } from '../../../__generated__/graphql';
import {
CapabilityPurchaseResult,
CapabilityOfferingResult,
CapabilityCapabilitiesResult,
CapabilityServicesResult,
} from '.';
export const CapabilityServiceByPlanIdsQueryFactory = (
override?: Partial<CapabilityServiceByPlanIdsQuery>
): CapabilityServiceByPlanIdsQuery => {
return {
purchaseCollection: {
items: [CapabilityPurchaseResultFactory()],
},
...override,
};
};
export const CapabilityPurchaseResultFactory = (
override?: Partial<CapabilityPurchaseResult>
): CapabilityPurchaseResult => ({
stripePlanChoices: [faker.string.sample()],
offering: CapabilityOfferingResultFactory(),
...override,
});
export const CapabilityOfferingResultFactory = (
override?: Partial<CapabilityOfferingResult>
): CapabilityOfferingResult => ({
capabilitiesCollection: {
items: [CapabilityCapabilitiesResultFactory()],
},
...override,
});
export const CapabilityCapabilitiesResultFactory = (
override?: Partial<CapabilityCapabilitiesResult>
): CapabilityCapabilitiesResult => ({
slug: faker.string.sample(),
servicesCollection: {
items: [CapabilityServicesResultFactory()],
},
...override,
});
export const CapabilityServicesResultFactory = (
override?: Partial<CapabilityServicesResult>
): CapabilityServicesResult => ({
oauthClientId: faker.string.sample(),
...override,
});

Просмотреть файл

@ -0,0 +1,8 @@
/* 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 './factories';
export * from './query';
export * from './types';
export * from './util';

Просмотреть файл

@ -2,10 +2,10 @@
* 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 { graphql } from '../../__generated__/gql';
import { graphql } from '../../../__generated__/gql';
export const capabilityServiceByPlanIdsQuery = graphql(`
query CapabilityServiceByPriceIds(
query CapabilityServiceByPlanIds(
$skip: Int!
$limit: Int!
$locale: String!

Просмотреть файл

@ -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/. */
export interface CapabilityServicesResult {
oauthClientId: string;
}
export interface CapabilityCapabilitiesResult {
slug: string;
servicesCollection: {
items: CapabilityServicesResult[];
};
}
export interface CapabilityOfferingResult {
capabilitiesCollection: {
items: CapabilityCapabilitiesResult[];
};
}
export interface CapabilityPurchaseResult {
stripePlanChoices: string[];
offering: CapabilityOfferingResult;
}
export interface CapabilityServiceByPlanIdsResult {
purchaseCollection: {
items: CapabilityPurchaseResult[];
};
}

Просмотреть файл

@ -0,0 +1,22 @@
/* 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 { CapabilityServiceByPlanIdsQueryFactory } from './factories';
import { CapabilityServiceByPlanIdsResult } from './types';
import { CapabilityServiceByPlanIdsResultUtil } from './util';
describe('CapabilityServiceByPlanIdsResultUtil', () => {
it('should create a util from response', () => {
const result = CapabilityServiceByPlanIdsQueryFactory();
const planId = result.purchaseCollection?.items[0]?.stripePlanChoices?.[0];
const util = new CapabilityServiceByPlanIdsResultUtil(
result as CapabilityServiceByPlanIdsResult
);
expect(util).toBeDefined();
expect(
util.capabilityOfferingForPlanId(planId ?? '')?.capabilitiesCollection
).toBeDefined();
expect(util.purchaseCollection.items.length).toBe(1);
});
});

Просмотреть файл

@ -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 {
CapabilityServiceByPlanIdsResult,
CapabilityOfferingResult,
CapabilityPurchaseResult,
} from './types';
export class CapabilityServiceByPlanIdsResultUtil {
private purchaseByPlanId: Record<string, CapabilityPurchaseResult> = {};
constructor(private rawResult: CapabilityServiceByPlanIdsResult) {
for (const purchase of rawResult.purchaseCollection.items) {
for (const planId of purchase.stripePlanChoices) {
this.purchaseByPlanId[planId] = purchase;
}
}
}
capabilityOfferingForPlanId(
planId: string
): CapabilityOfferingResult | undefined {
return this.purchaseByPlanId[planId]?.offering;
}
get purchaseCollection() {
return this.rawResult.purchaseCollection;
}
}