import { isSome } from "@jet/environment"; import * as models from "../../../api/models"; import * as serverData from "../../../foundation/json-parsing/server-data"; import * as mediaDataFetching from "../../../foundation/media/data-fetching"; import * as mediaDataStructure from "../../../foundation/media/data-structure"; import { fetchData } from "../../../foundation/media/network"; import * as mediaRelationship from "../../../foundation/media/relationships"; import * as appPromotionCommon from "../../app-promotions/app-promotions-common"; import * as metricsHelpersUtil from "../../metrics/helpers/util"; import * as onDevicePersonalization from "../../personalization/on-device-personalization"; import * as placeholders from "../../placeholders/placeholders"; import { addVariantParametersToRequestForItems } from "../../product-page/product-page-variants"; import * as refresh from "../../refresh/page-refresh-controller"; import { GroupingShelfController } from "./grouping-shelf-controller"; import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common"; import { attributeAsBooleanOrFalse } from "../../../foundation/media/attributes"; import { ResponseMetadata } from "../../../foundation/network/network"; import { shelfTitleAttributePathForFeaturedContentId } from "./grouping-shelf-controller-common"; import * as mediaAttributes from "../../../foundation/media/attributes"; export class GroupingAppEventShelfController extends GroupingShelfController { // region Constructors constructor() { super("GroupingAppEventShelfController"); this.supportedFeaturedContentIds = new Set([ 519 /* groupingTypes.FeaturedContentID.AppStore_AppEventsMarker */, 518 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedAppEventsMarker */, ]); } // 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, "contents") }; } /** * 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) { var _a; if (((_a = shelfToken.recommendationsHref) === null || _a === void 0 ? void 0 : _a.length) > 0) { try { const mediaApiData = await GroupingShelfController.secondaryGroupingShelfMediaApiData(objectGraph, shelfUrl, shelfToken, parameters); const shelfResponseData = mediaDataStructure.dataFromDataContainer(objectGraph, mediaApiData); const shelfContents = this.initialShelfDataFromGroupingMediaApiData(objectGraph, shelfResponseData); shelfContents.responseTimingValues = mediaApiData[ResponseMetadata.timingValues]; const title = mediaAttributes.attributeAsString(shelfResponseData, shelfTitleAttributePathForFeaturedContentId(objectGraph, shelfToken.featuredContentId)); if (serverData.isDefinedNonNull(title) && (title === null || title === void 0 ? void 0 : title.length) > 0) { shelfContents.shelfTitle = title; } return shelfContents; } catch { return { shelfContents: [] }; } } else { const appEvents = []; const contingentItems = []; const offerItems = []; for (const remainingItem of shelfToken.remainingItems) { switch (remainingItem.type) { case "contingent-items": contingentItems.push(remainingItem); break; case "offer-items": offerItems.push(remainingItem); break; case "app-events": appEvents.push(remainingItem); break; default: break; } } const appEventsRequest = new mediaDataFetching.Request(objectGraph, appEvents); addVariantParametersToRequestForItems(objectGraph, appEventsRequest, appEvents); const contingentItemsRequest = new mediaDataFetching.Request(objectGraph, contingentItems); addVariantParametersToRequestForItems(objectGraph, contingentItemsRequest, contingentItems); const offerItemsRequest = new mediaDataFetching.Request(objectGraph, offerItems); addVariantParametersToRequestForItems(objectGraph, offerItemsRequest, offerItems); const hydrationResults = await Promise.all([ this.fetchRemainingItems(objectGraph, appEventsRequest), this.fetchRemainingItems(objectGraph, contingentItemsRequest), this.fetchRemainingItems(objectGraph, offerItemsRequest), ]); const hydratedDataMap = { ...hydrationResults[0], ...hydrationResults[1], ...hydrationResults[2] }; const shelfContents = []; for (const remainingItem of shelfToken.remainingItems) { const data = hydratedDataMap[remainingItem.id]; if (isSome(data)) { shelfContents.push(data); } } groupingShelfControllerCommon.flushRequestedItemsFromShelfToken(shelfToken, new Set([...offerItemsRequest.ids, ...contingentItemsRequest.ids, ...appEventsRequest.ids])); return { shelfContents: shelfContents }; } } async fetchRemainingItems(objectGraph, remainingItemsRequest) { const apiDataMap = {}; const addDataToMap = (data) => { for (const item of data.data) { apiDataMap[item.id] = item; } }; if (remainingItemsRequest.ids.size > 0) { groupingShelfControllerCommon.prepareGroupingShelfRequest(objectGraph, remainingItemsRequest); try { await fetchData(objectGraph, remainingItemsRequest).then((mediaApiData) => { addDataToMap(mediaApiData); }); } catch (fetchError) { objectGraph.console.error("Error fetching remaining items", remainingItemsRequest.ids); } } return apiDataMap; } /** * 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) { const shouldPersonalizeData = baseShelfToken.featuredContentId === 518 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedAppEventsMarker */; let personalizedDataResult = null; const shelfData = this.initialShelfDataFromGroupingMediaApiData(objectGraph, mediaApiData); if (shouldPersonalizeData && serverData.isDefinedNonNullNonEmpty(shelfData.shelfContents)) { personalizedDataResult = this.personalizedDataResultFromDataItems(objectGraph, shelfData.shelfContents); } const appEventShelfToken = { ...baseShelfToken, shouldPersonalizeData: shouldPersonalizeData, personalizedDataResult: personalizedDataResult, }; const hasContents = serverData.isDefinedNonNullNonEmpty(shelfData.shelfContents); const shelfPersonalizationAvailable = !attributeAsBooleanOrFalse(mediaApiData, "noPersonalizationAvailable"); if (!hasContents && shelfPersonalizationAvailable) { appEventShelfToken.recommendationsHref = mediaApiData.href; appEventShelfToken.isValidRecommendationsShelf = true; } else { appEventShelfToken.isValidRecommendationsShelf = hasContents; } return appEventShelfToken; } // endregion // region Metrics /** * Return the shelf metrics options to use for this specific shelf. Using the base options from the grouping * page controller * * @param objectGraph The App Store dependency graph * @param shelfToken The shelf shelfToken for this current shelf creation request * @param baseMetricsOptions The minimum set of metrics options for this shelf, created by the * grouping page controller */ shelfMetricsOptionsFromBaseMetricsOptions(objectGraph, shelfToken, baseMetricsOptions) { const shelfMetricsOptions = { ...baseMetricsOptions }; if (serverData.isDefinedNonNullNonEmpty(shelfToken.personalizedDataResult)) { const recoMetricsData = metricsHelpersUtil.combinedRecoMetricsDataFromMetricsData(baseMetricsOptions.recoMetricsData, shelfToken.personalizedDataResult.processingType, null); shelfMetricsOptions.recoMetricsData = recoMetricsData; } return shelfMetricsOptions; } // 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) { var _a; if (!appPromotionCommon.appEventsAreEnabled(objectGraph)) { return null; } if (!shelfToken.isValidRecommendationsShelf) { return null; } const metricsOptions = { pageInformation: shelfToken.metricsPageInformation, locationTracker: shelfToken.metricsLocationTracker, recoMetricsData: shelfToken.metricsPageInformation.recoMetricsData, }; // First personalize the data, as this may cause things to be re-ordered let sortedShelfContents = shelfData.shelfContents; // Only try to use the personalized data the first render, second renders the shelfContents has already been personalized if (serverData.isDefinedNonNullNonEmpty(shelfToken.personalizedDataResult) && shelfToken.isFirstRender) { sortedShelfContents = shelfToken.personalizedDataResult.personalizedData; } // Now find which items are hydrated, and add the rest to the token const hydratedShelfContents = []; for (const data of sortedShelfContents) { if (serverData.isNull(data.attributes) || groupingShelfControllerCommon.shouldDefer(shelfToken)) { shelfToken.isDeferring = true; shelfToken.remainingItems.push(data); continue; } hydratedShelfContents.push(data); } // Now create our shelf from the hydrated items const displayableAppEvents = appPromotionCommon.appPromotionsFromData(objectGraph, hydratedShelfContents, null, false, false, metricsOptions, false, true, shelfToken.isArcadePage, false); refresh.addNextPreferredContentRefreshDate(displayableAppEvents.nextAppEventPromotionStartDate, groupingParseContext === null || groupingParseContext === void 0 ? void 0 : groupingParseContext.refreshController); const appPromotions = displayableAppEvents.appPromotions; const shelfType = "appPromotion"; const shelf = new models.Shelf(shelfType); shelf.isHorizontal = true; shelf.title = (_a = shelfData.shelfTitle) !== null && _a !== void 0 ? _a : shelfToken.title; shelf.items = appPromotions; const willHydrateShelfLater = serverData.isNullOrEmpty(shelf.items) && shelfToken.isFirstRender; if (willHydrateShelfLater && placeholders.placeholdersEnabled(objectGraph)) { placeholders.insertPlaceholdersIntoGenericPageShelf(objectGraph, shelf, shelfToken, shelfToken.featuredContentId); } shelf.url = groupingShelfControllerCommon.createShelfTokenUrlIfNecessaryForShelf(objectGraph, shelf, shelfToken); if (serverData.isNullOrEmpty(shelf.items) && serverData.isNullOrEmpty(shelf.url)) { return shelfToken.isFirstRender ? null : GroupingAppEventShelfController.makeHiddenShelf(shelfToken); } return shelf; } // region Helpers /** * Personalizes the input list of app event data items. * @param objectGraph * @param dataItems The array of app event data items */ personalizedDataResultFromDataItems(objectGraph, dataItems) { // Collect the app IDs we are interested in const appIds = new Set(); for (const data of dataItems) { const appId = serverData.asString(data, "meta.personalizationData.appId"); if ((appId === null || appId === void 0 ? void 0 : appId.length) > 0) { appIds.add(appId); } } // Now personalize the data const personalizationDataContainer = onDevicePersonalization.personalizationDataContainerForAppIds(objectGraph, appIds); return onDevicePersonalization.personalizeDataItems(objectGraph, "groupingAppEvent", dataItems, false, personalizationDataContainer, null, null, null, true); } static makeHiddenShelf(shelfToken) { const hiddenShelf = new models.Shelf(shelfToken.shelfStyle); hiddenShelf.isHidden = true; return hiddenShelf; } } //# sourceMappingURL=grouping-app-event-shelf-controller.js.map