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 content from "../../content/content"; import * as flowPreview from "../../content/flow-preview"; import * as lockupsEditorialContext from "../../lockups/editorial-context"; import * as metricsHelpersClicks from "../../metrics/helpers/clicks"; import * as metricsHelpersImpressions from "../../metrics/helpers/impressions"; import * as metricsHelpersLocation from "../../metrics/helpers/location"; import * as placeholders from "../../placeholders/placeholders"; import { GroupingShelfController } from "./grouping-shelf-controller"; import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common"; import * as metricsLocation from "../../../common/metrics/helpers/location"; import { defaultLayoutSize } from "../../../foundation/media/data-fetching"; import * as color from "../../../foundation/util/color-util"; import { isSome } from "@jet/environment"; export class GroupingBrickShelfController extends GroupingShelfController { // region Constructors constructor() { super("GroupingBrickShelfController"); this.supportedFeaturedContentIds = new Set([ 421 /* groupingTypes.FeaturedContentID.AppStore_BrickRow */, 422 /* groupingTypes.FeaturedContentID.AppStore_Brick */, 423 /* groupingTypes.FeaturedContentID.AppStore_CustomBrick */, 261 /* groupingTypes.FeaturedContentID.Sundance_BrickRow */, ]); } // 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).then((shelfData) => { return { shelfContents: groupingShelfControllerCommon.mergeContentDataIntoEditorialData(shelfData.shelfContents, mediaRelationship.relationshipCollection(shelfToken.featuredContentData, "children")), }; }); } /** * 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) { // If suppress text is not provided, default to hiding. let suppressText = mediaAttributes.attributeAsBoolean(mediaApiData, "suppressText"); if (serverData.isNull(suppressText)) { suppressText = true; } const brickShelfToken = { ...baseShelfToken, showSupplementaryText: !suppressText, }; brickShelfToken.clientIdentifierOverride = lockupsEditorialContext.clientIdentifierForEditorialContextInData(objectGraph, mediaApiData); return brickShelfToken; } // 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 items = []; const remainingBricks = []; // Data where metadata was missing. const displayStyle = serverData.asString(shelfToken.featuredContentData.attributes, "displayStyle"); const isCategoryBrick = displayStyle === "small"; let shelf; if (isCategoryBrick) { // i.e. category bricks shelf shelf = new models.Shelf("categoryBrick"); const layoutSize = serverData.asNumber(shelfToken.featuredContentData.attributes, "layoutStyle.layoutSize"); shelf.rowsPerColumn = layoutSize !== null && layoutSize !== void 0 ? layoutSize : defaultLayoutSize(objectGraph); metricsLocation.currentLocation(shelfToken.metricsLocationTracker).name = "Browse Categories"; } else { // i.e. "medium", also the default bricks shelf shelf = new models.Shelf("brick"); } shelf.isHorizontal = true; for (const brickData of shelfData.shelfContents) { const brickModel = GroupingBrickShelfController.createBrick(objectGraph, brickData, isCategoryBrick, shelfToken.metricsPageInformation, shelfToken.metricsLocationTracker, shelfToken, groupingParseContext); if (!brickModel) { remainingBricks.push(brickData); continue; } items.push(brickModel); metricsHelpersLocation.nextPosition(shelfToken.metricsLocationTracker); } if (serverData.isDefinedNonNull(shelfToken.presentationHints)) { shelf.presentationHints = shelfToken.presentationHints; } if (serverData.isDefinedNonNull(shelfToken.showSupplementaryText)) { shelf.presentationHints = { ...shelf.presentationHints, showSupplementaryText: shelfToken.showSupplementaryText, }; } // We don't need this in our incomplete shelf URL, so we'll preemptively remove it. delete shelfToken.maxItemCount; // Override `featuredContentData` to only have remaining bricks that must be fetched. if (serverData.isDefinedNonNull(serverData.traverse(shelfToken.featuredContentData, "relationships.children.data"))) { shelfToken.featuredContentData.relationships["children"].data = remainingBricks; } // Set metadata shelf.title = shelfToken.title; shelf.subtitle = shelfToken.subtitle; if (isCategoryBrick) { const displayCount = serverData.asNumber(shelfToken.featuredContentData.attributes, "displayCount"); shelf.items = items.slice(0, displayCount !== null && displayCount !== void 0 ? displayCount : items.length); } else { shelf.items = items; } // See all const hasSeeAll = serverData.asBooleanOrFalse(shelfToken.featuredContentData.attributes, "hasSeeAll"); if (isCategoryBrick && hasSeeAll && !objectGraph.client.isWeb) { // Setup shelf const seeAllShelf = new models.Shelf("categoryBrick"); seeAllShelf.items = this.sortCategories(objectGraph, items); seeAllShelf.presentationHints = { isSeeAllContext: true }; // Setup Page const seeAllPage = new models.GenericPage([seeAllShelf]); seeAllPage.title = shelfToken.title; // Setup action const seeAllAction = new models.FlowAction("page"); seeAllAction.title = objectGraph.loc.string("ACTION_SEE_ALL"); seeAllAction.pageData = seeAllPage; // Connect action shelf.seeAllAction = seeAllAction; // Metrics metricsHelpersClicks.addClickEventToSeeAllAction(objectGraph, seeAllAction, null, { pageInformation: shelfToken.metricsPageInformation, locationTracker: shelfToken.metricsLocationTracker, }); } // If no items should we display placeholders for this shelf? const willHydrateShelfLater = shelf && serverData.isNullOrEmpty(shelf.items) && shelfToken.isFirstRender; if (willHydrateShelfLater && placeholders.placeholdersEnabled(objectGraph)) { placeholders.insertPlaceholdersIntoGenericPageShelf(objectGraph, shelf, shelfToken, shelfToken.featuredContentId); } if (!willHydrateShelfLater && GroupingBrickShelfController.shouldDisplayChooseYourFavoritesBrick(objectGraph, shelfToken, isCategoryBrick, groupingParseContext)) { const brickModel = GroupingBrickShelfController.createChooseYourFavoritesBrick(objectGraph, shelfToken.metricsPageInformation, shelfToken.metricsLocationTracker); shelf.items.splice(0, 0, brickModel); } shelfToken.presentationHints = shelf.presentationHints; shelf.url = groupingShelfControllerCommon.createShelfTokenUrlIfNecessaryForShelf(objectGraph, shelf, shelfToken); return shelf; } // region Static Helpers // Whether to display Choose Your Favorites brick. // It will return TRUE when: // - This is an Arcade page // - This is a Category brick // - Feature flag is enabled // - The user is subscribed or trial enrolled static shouldDisplayChooseYourFavoritesBrick(objectGraph, shelfToken, isCategoryBrick, groupingParseContext) { return (shelfToken.isArcadePage && isCategoryBrick && objectGraph.featureFlags.isEnabled("arcade_choose_your_favorites_brick_Future") && isSome(groupingParseContext === null || groupingParseContext === void 0 ? void 0 : groupingParseContext.additionalShelfParameters) && ((groupingParseContext === null || groupingParseContext === void 0 ? void 0 : groupingParseContext.additionalShelfParameters.isSubscribed) === "true" || (groupingParseContext === null || groupingParseContext === void 0 ? void 0 : groupingParseContext.additionalShelfParameters.isTrialEnrolled) === "true")); } static createBrick(objectGraph, brickData, searchCategoryBricks, metricsPageInformation, metricsLocationTracker, shelfToken, groupingParseContext) { const metricsOptions = { targetType: searchCategoryBricks ? "tile" : "brick", pageInformation: metricsPageInformation, locationTracker: metricsLocationTracker, recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(brickData), }; const metadata = groupingShelfControllerCommon.metadataForFCData(objectGraph, brickData, shelfToken, false, null, metricsOptions, groupingParseContext); if (!metadata) { return null; } const brickModel = new models.Brick(); // Setup Artwork const artworkOptions = { useCase: 18 /* content.ArtworkUseCase.GroupingBrick */, }; if (searchCategoryBricks) { const artworks = content.searchChartOrCategoryArtworkFromData(objectGraph, metadata.content, content.SearchChartOrCategoryBrickUseCase.categoryBreakout, models.GenericSearchPageShelfDisplayStyleDensity.Density1); brickModel.artworks = artworks; } else if (metadata.artwork && (shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.featuredContentId) !== 261 /* groupingTypes.FeaturedContentID.Sundance_BrickRow */) { let artworkDict = serverData.asDictionary(metadata.artwork, "subscriptionHero"); if (!artworkDict) { artworkDict = serverData.asDictionary(metadata.artwork, "originalFlowcaseBrick"); } const artwork = groupingShelfControllerCommon.groupingArtworkFromApiArtwork(objectGraph, artworkDict, artworkOptions); brickModel.artworks = [artwork]; } else { const artwork = groupingShelfControllerCommon.artworkFromFC(objectGraph, brickData, 1060, 520, artworkOptions); brickModel.artworks = [artwork]; } brickModel.accessibilityLabel = metadata.title; // Set supplementary text. brickModel.shortEditorialDescription = metadata.title; // Set action brickModel.clickAction = metadata.action; // Set personalization const brickFeaturedContentId = mediaAttributes.attributeAsNumber(brickData, "editorialElementKind"); if (brickFeaturedContentId === 435 /* groupingTypes.FeaturedContentID.AppStore_MSOBrickMarker */) { brickModel.personalizationStyle = "mso"; } // Set flow preview actions const contentData = mediaRelationship.relationshipData(objectGraph, brickData, "contents"); if (serverData.isDefinedNonNull(contentData)) { const metricsClickOptions = metricsHelpersClicks.clickOptionsForLockup(objectGraph, contentData, metricsOptions); brickModel.flowPreviewActionsConfiguration = flowPreview.flowPreviewActionsConfigurationForProductFromData(objectGraph, brickData, true, shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.clientIdentifierOverride, brickModel.clickAction, metricsOptions, metricsClickOptions); } // Configure impressions const impressionOptions = metricsHelpersImpressions.impressionOptions(objectGraph, brickData, metadata.title, metricsOptions); metricsHelpersImpressions.addImpressionFields(objectGraph, brickModel, impressionOptions); // Safe area brickModel.artworkSafeArea = models.ChartOrCategorySafeArea.defaultTileArtworkSafeArea; brickModel.textSafeArea = models.ChartOrCategorySafeArea.defaultTileTextSafeArea; if (!brickModel.isValid()) { return null; } return brickModel; } /// Creates and returns Choose Your Favorites brick. static createChooseYourFavoritesBrick(objectGraph, metricsPageInformation, metricsLocationTracker) { const brickModel = new models.Brick(); // Artwork const artwork = new models.Artwork("", 1060, 520, [], color.fromHex("efac78")); brickModel.artworks = [artwork]; // Labels const title = objectGraph.loc.string("ARCADE_CHOOSE_YOUR_FAVORITES_BRICK_TITLE"); brickModel.accessibilityLabel = title; brickModel.shortEditorialDescription = title; // Action const flowAction = new models.FlowAction("arcadeDownloadPackCategories"); flowAction.presentationContext = "presentModalFormSheet"; flowAction.pageData = "unknown"; brickModel.clickAction = flowAction; // Impressions const metricsOptions = { targetType: "brick", pageInformation: metricsPageInformation, locationTracker: metricsLocationTracker, recoMetricsData: null, }; const impressionOptions = metricsHelpersImpressions.impressionOptionsForArcadeChooseYourFavoritesBrick(metricsOptions); metricsHelpersImpressions.addImpressionFields(objectGraph, brickModel, impressionOptions); // Safe area brickModel.artworkSafeArea = models.ChartOrCategorySafeArea.defaultTileArtworkSafeArea; brickModel.textSafeArea = models.ChartOrCategorySafeArea.defaultTileTextSafeArea; return brickModel; } // 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 }; const displayStyle = serverData.asString(shelfToken.featuredContentData.attributes, "displayStyle"); // If this is a Category Bricks shelf, configure metrics title accordingly. if (displayStyle === "small") { shelfMetricsOptions.title = "Browse Categories"; } return shelfMetricsOptions; } // endregion // region Sort sortCategories(objectGraph, categories) { return categories.sort((category1, category2) => { try { return category1.shortEditorialDescription.localeCompare(category2.shortEditorialDescription, objectGraph.loc.safeIdentifier, { usage: "sort", }); } catch (e) { return 0; } }); } } //# sourceMappingURL=grouping-brick-shelf-controller.js.map