import * as models from "../../../api/models"; import * as serverData from "../../../foundation/json-parsing/server-data"; import * as mediaAttributes from "../../../foundation/media/attributes"; import * as mediaDataStructure from "../../../foundation/media/data-structure"; import * as mediaRelationship from "../../../foundation/media/relationships"; import * as color from "../../../foundation/util/color-util"; import * as flowPreview from "../../content/flow-preview"; import * as metricsHelpersClicks from "../../metrics/helpers/clicks"; import * as metricsHelpersImpressions from "../../metrics/helpers/impressions"; import * as metricsHelpersLocation from "../../metrics/helpers/location"; import * as metricsHelpersUtil from "../../metrics/helpers/util"; import * as onDevicePersonalization from "../../personalization/on-device-personalization"; import { GroupingShelfController } from "./grouping-shelf-controller"; import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common"; export class GroupingEditorialCardShelfController extends GroupingShelfController { // region Constructors constructor() { super("GroupingEditorialCardShelfController"); this.supportedFeaturedContentIds = new Set([ 415 /* groupingTypes.FeaturedContentID.AppStore_HeroList */, 416 /* groupingTypes.FeaturedContentID.AppStore_Hero */, 501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */, 417 /* groupingTypes.FeaturedContentID.AppStore_CustomHero */, 258 /* groupingTypes.FeaturedContentID.Sundance_Flowcase */, ]); } // endregion // region Shelf Creation Prerequisites /** * For a given mediaApiData extract the actual shelfContents array needed to render this shelf * * @param mediaApiData The outer shelfContents object containing the shelf contents */ initialShelfDataFromGroupingMediaApiData(objectGraph, mediaApiData) { return { shelfContents: mediaRelationship.relationshipCollection(mediaApiData, "children") }; } /** * For a given url that this controller handles, we should return a promise that will result in the `ShelfData` * needed to render this shelf * * @param objectGraph The App Store dependency graph * @param shelfUrl The url that this controller handled on a secondary fetch * @param parameters The extracted parameters from the shelf url */ async secondaryShelfDataForShelfUrl(objectGraph, shelfUrl, shelfToken, parameters) { return await GroupingShelfController.secondaryGroupingShelfDataForShelfUrl(objectGraph, shelfUrl, shelfToken, parameters); } /** * For a given mediaApiData create an updated shelf token that contains all the additional data for this specific shelf type * * @param objectGraph The App Store dependency graph * @param baseShelfToken The base grouping shelf token created by the grouping-controller * @param mediaApiData The outer data object containing the FC properties and data * @param groupingParseContext The parse context for the grouping page so far */ shelfTokenFromBaseTokenAndMediaApiData(objectGraph, mediaApiData, baseShelfToken, groupingParseContext) { return baseShelfToken; } // endregion // region Shelf Creation /** * * @param objectGraph The App Store dependency graph * @param shelfToken The shelf shelfToken for this current shelf creation request * @param shelfData The media api shelfContents array for this shelf * @param groupingParseContext The parse context used to generate the grouping page on the initial page load, * this will be missing when this controller renders a secondary or incomplete shelf fetch. */ _createShelf(objectGraph, shelfToken, shelfData, groupingParseContext) { const shelf = new models.Shelf("editorialCard"); shelf.isHorizontal = true; const personalizationDataContainer = this.personalizationDataContainerForEditorialCardItemsDataArray(objectGraph, shelfData.shelfContents); const items = []; for (const data of shelfData.shelfContents) { const card = GroupingEditorialCardShelfController.makeEditorialCard(objectGraph, data, personalizationDataContainer, groupingParseContext, shelfToken); if (serverData.isNullOrEmpty(card) || !card.isValid()) { continue; } items.push(card); metricsHelpersLocation.nextPosition(shelfToken.metricsLocationTracker); } // We don't need this in our incomplete shelf URL, so we'll preemptively remove it. delete shelfToken.maxItemCount; if (objectGraph.client.isVision) { shelf.presentationHints = { ...shelf.presentationHints, showSupplementaryText: true }; } shelf.items = items; shelf.url = groupingShelfControllerCommon.createShelfTokenUrlIfNecessaryForShelf(objectGraph, shelf, shelfToken); return shelf; } static makeEditorialCard(objectGraph, itemData, personalizationDataContainer, groupingParseContext, shelfToken) { var _a, _b, _c; const metricsOptions = { targetType: "hero", pageInformation: shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.metricsPageInformation, locationTracker: shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.metricsLocationTracker, recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(itemData), id: itemData.id, idType: "editorial_id", }; const featuredContentId = mediaAttributes.attributeAsNumber(itemData, "editorialElementKind"); const shouldPersonalizeContent = featuredContentId === 501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */; const metadata = groupingShelfControllerCommon.metadataForFCData(objectGraph, itemData, shelfToken, shouldPersonalizeContent, personalizationDataContainer, metricsOptions, groupingParseContext, () => { shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.remainingItems.push(itemData); }); if (!metadata) { return null; } const hasContentId = ((_b = (_a = metadata.content) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.length) > 0; if (hasContentId) { metricsOptions.id = metadata.content.id; metricsOptions.idType = "its_id"; metricsOptions.adamId = metadata.content.id; } const card = new models.EditorialCard(); // Set caption let caption = mediaAttributes.attributeAsString(itemData, "designBadge"); if (!caption) { caption = metadata.caption; } card.caption = caption; // Set title let title = mediaAttributes.attributeAsString(itemData, "title"); if (!title) { title = metadata.title; } card.title = title; // Set subtitle let subtitle = groupingShelfControllerCommon.unescapeHtmlString(mediaAttributes.attributeAsString(itemData, "designTag")); if (!subtitle) { subtitle = metadata.subtitle; } card.subtitle = subtitle; // Setup Artwork const artworkOptions = { useCase: 19 /* content.ArtworkUseCase.GroupingHero */, withJoeColorPlaceholder: true, }; if (metadata.artwork && (shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.featuredContentId) !== 258 /* groupingTypes.FeaturedContentID.Sundance_Flowcase */) { let artworkDict = serverData.asDictionary(metadata.artwork, "subscriptionHero"); if (serverData.isNull(artworkDict) && serverData.isDefinedNonNull(metadata.appEvent)) { artworkDict = serverData.asDictionary(metadata.artwork, "eventCard"); } card.artwork = groupingShelfControllerCommon.groupingArtworkFromApiArtwork(objectGraph, artworkDict, artworkOptions); } else { card.artwork = groupingShelfControllerCommon.artworkFromFC(objectGraph, itemData, 416, 204, artworkOptions); } // Set action card.clickAction = metadata.action; // App event formatted dates if (serverData.isDefinedNonNull(metadata.appEvent)) { card.appEventFormattedDates = metadata.appEvent.formattedDates; } // Lockup card.lockup = metadata.lockup; // Overlay style if (serverData.isDefinedNonNull(card.artwork) && serverData.isDefinedNonNull(card.artwork.backgroundColor)) { const isArtworkDark = color.isDarkColor(card.artwork.backgroundColor); card.mediaOverlayStyle = isArtworkDark ? "dark" : "light"; if (serverData.isDefinedNonNull(card.lockup) && serverData.isDefinedNonNull(card.lockup.offerDisplayProperties) && objectGraph.host.isiOS) { const offerEnvironment = isArtworkDark ? "dark" : "light"; card.lockup.offerDisplayProperties = card.lockup.offerDisplayProperties.newOfferDisplayPropertiesChangingAppearance(false, "transparent", offerEnvironment); } } // Set adamId card.adamId = serverData.asString(metadata.content, "id"); // Set flow preview actions const contentData = mediaRelationship.relationshipData(objectGraph, itemData, "contents"); if (serverData.isDefinedNonNull(contentData)) { const metricsClickOptions = metricsHelpersClicks.clickOptionsForLockup(objectGraph, contentData, metricsOptions); metricsClickOptions.targetType = metricsOptions.targetType; card.flowPreviewActionsConfiguration = flowPreview.flowPreviewActionsConfigurationForProductFromData(objectGraph, itemData, false, shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.clientIdentifierOverride, card.clickAction, metricsOptions, metricsClickOptions); } // Configure impressions const impressionOptions = metricsHelpersImpressions.impressionOptions(objectGraph, (_c = metadata.content) !== null && _c !== void 0 ? _c : itemData, metadata.title, metricsOptions); if (serverData.isDefinedNonNull(metadata.onDevicePersonalizationDataProcessingType)) { const recoMetricsData = metricsHelpersUtil.combinedRecoMetricsDataFromMetricsData(impressionOptions.recoMetricsData, metadata.onDevicePersonalizationDataProcessingType, null); impressionOptions.recoMetricsData = recoMetricsData; } if (serverData.isDefinedNonNull(metadata.appEvent)) { impressionOptions.inAppEventId = metadata.appEvent.appEventId; if (serverData.isDefinedNonNull(metadata.appEvent.lockup)) { impressionOptions.relatedSubjectIds = [metadata.appEvent.lockup.adamId]; } } if (serverData.isDefinedNonNull(shelfToken)) { metricsHelpersImpressions.addImpressionFields(objectGraph, card, impressionOptions); } return card; } // region Helpers /** * Iterates through all the editorial cards data, and creates a set of personalization data that is targetted only to these cards. * * @param objectGraph * @param dataArray The input array of editorial card data items * @returns Any relevant OnDevicePersonalizaionData */ personalizationDataContainerForEditorialCardItemsDataArray(objectGraph, dataArray) { var _a, _b; if (!onDevicePersonalization.isPersonalizationAvailable(objectGraph)) { return null; } // First iterate through and extract any relevant App IDs from meta.personalizationData for each card's contents. const appIds = new Set(); for (const data of dataArray) { const featuredContentId = mediaAttributes.attributeAsNumber(data, "editorialElementKind"); const shouldPersonalizeContent = featuredContentId === 501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */; const isLinkNode = ((_a = serverData.asString(data, "url")) === null || _a === void 0 ? void 0 : _a.length) > 0; const containsLinkNode = ((_b = mediaAttributes.attributeAsString(data, "link.url")) === null || _b === void 0 ? void 0 : _b.length) > 0; const isContentNode = mediaRelationship.hasRelationship(data, "contents", false); if (shouldPersonalizeContent && !isLinkNode && !containsLinkNode && isContentNode) { const contentDataItems = mediaRelationship.relationshipCollection(data, "contents"); for (const contentData of contentDataItems) { const appId = serverData.asString(contentData, "meta.personalizationData.appId"); if ((appId === null || appId === void 0 ? void 0 : appId.length) > 0) { appIds.add(appId); } } } } return onDevicePersonalization.personalizationDataContainerForAppIds(objectGraph, appIds); } } //# sourceMappingURL=grouping-editorial-card-shelf-controller.js.map