import * as validation from "@jet/environment/json/validation"; import { isNothing, isSome } from "@jet/environment/types/optional"; import { ExternalUrlAction, TodayCard, TodayCardActionOverlay, TodayCardMediaArtwork, } from "../../../api/models"; import { isNull } from "../../../foundation/json-parsing/server-data"; import * as mediaAttributes from "../../../foundation/media/attributes"; import { relationshipCollection } from "../../../foundation/media/relationships"; import * as contentAttributes from "../../content/attributes"; import { editorialNotesFromData, notesFromData } from "../../content/content"; import { extractEditorialClientParams } from "../../editorial-pages/editorial-data-util"; import { editorialItemActionFromData, subtitleFromData } from "../../lockups/lockups"; import * as metricsHelpersImpressions from "../../metrics/helpers/impressions"; import { addMetricsEventsToVideo } from "../../metrics/helpers/media"; import { todayCardArtworkDetails } from "../artwork/today-artwork-util"; import { isCardDataOnboardingCard } from "../onboarding-cards"; import { brandedTitleArtworkForCard, cardDisplayStyleFromData, cardStyleFromJoeColors, isCardOTDIntention, relatedCardContentsContentsFromData, todayCardArtworkTitleBackingGradientForKey, todayCardEditorialDisplayOptionsFromData, todayCardMetricsOptions, } from "../today-card-util"; import { recoMetricsFromTodayItem } from "../today-parse-util"; import { TodayCardDisplayStyle } from "../today-types"; /** * If the title is not supplied for app of the day we use this */ const appOfTheDayFallbackTitle = "FEATURED APP"; /** * If the title is not supplied for game of the day we use this */ const gameOfTheDayFallbackTitle = "FEATURED GAME"; /** * Creates a TodayCard used as the base for all other TodayCards * * @param objectGraph The dependency graph for the App Store * @param data The media api data to build the card from * @param cardConfig The configuration for the card * @param context The parse context for the over all today page * @param clickOptionsModifier A function that can modify the click options for the card * @returns The newly created TodayCard, which can then be modified by other TodayCard builders */ export function createTodayBaseCard(objectGraph, data, cardConfig, context, clickOptionsModifier) { return validation.context("createTodayBaseCard", () => { const baseCard = new TodayCard(); const cardDisplayStyle = cardDisplayStyleFromData(data, cardConfig === null || cardConfig === void 0 ? void 0 : cardConfig.coercedCollectionTodayCardDisplayStyle); // Heading const heading = cardHeadingFromData(objectGraph, data, cardDisplayStyle, cardConfig); baseCard.heading = heading; // Title, title artwork const title = cardTitleFromData(objectGraph, data, cardConfig); baseCard.title = title; const shortTitle = contentAttributes.contentAttributeAsString(objectGraph, data, [ "shortEditorialNotes", "name", ]); baseCard.shortTitle = shortTitle; const cardTitleArtwork = brandedTitleArtworkForCard(objectGraph, data); baseCard.titleArtwork = cardTitleArtwork; // Description const inlineDescription = cardDescriptionFromData(objectGraph, data); baseCard.inlineDescription = inlineDescription; const metricsOptions = todayCardMetricsOptions(objectGraph, data, cardConfig, context, title); metricsOptions.adSlotOverride = context.parsedCardCount; baseCard.clickAction = cardClickAction(objectGraph, data, cardDisplayStyle, cardConfig, context, metricsOptions, clickOptionsModifier); // Configure impressions metricsHelpersImpressions.addImpressionsFieldsToTodayCard(objectGraph, baseCard, metricsOptions, heading, cardDisplayStyle, isCardDataOnboardingCard(objectGraph, data)); baseCard.editorialDisplayOptions = todayCardEditorialDisplayOptionsFromData(objectGraph, data, cardConfig); return baseCard; }); } /** * @param objectGraph The dependency graph for the App Store * @param cardDisplayStyle The display style of the card * @param data The data to get the branded single app overlay heading from * @param cardConfig The configuration for the card * @returns The heading to use on the branded single app overlay */ export function cardHeadingFromData(objectGraph, data, cardDisplayStyle, cardConfig) { var _a, _b; let heading = null; if (cardConfig === null || cardConfig === void 0 ? void 0 : cardConfig.useOTDTextStyle) { if (cardConfig.isHorizontalShelfContext) { // We don't support branded images or titles for a cards in a horizontal shelf // so want to show the "APP OF THE DAY" / "GAME OF THE DAY" text as the heading instead. heading = mediaAttributes.attributeAsString(data, "label"); } else { heading = null; } } else if (isCardOTDIntention(data, cardConfig)) { heading = (_a = mediaAttributes.attributeAsString(data, "alternateLabel")) !== null && _a !== void 0 ? _a : mediaAttributes.attributeAsString(data, "label"); if (isNull(heading) && cardDisplayStyle === TodayCardDisplayStyle.AppOfTheDay) { heading = appOfTheDayFallbackTitle; } else if (isNull(heading) && cardDisplayStyle === TodayCardDisplayStyle.GameOfTheDay) { heading = gameOfTheDayFallbackTitle; } } else { switch (cardDisplayStyle) { case TodayCardDisplayStyle.AppEventCard: const fallbackCardContents = fallbackCardContentFromData(objectGraph, data); if (isSome(fallbackCardContents)) { heading = (_b = editorialNotesFromData(objectGraph, data, "badge", true)) !== null && _b !== void 0 ? _b : mediaAttributes.attributeAsString(fallbackCardContents, "kind"); } break; default: heading = mediaAttributes.attributeAsString(data, "label"); break; } } return heading; } /** * @param objectGraph The dependency graph for the App Store * @param data The media api data used to determine the title of this card * @param cardConfig The configuration for the card * @returns The title to use for this card */ function cardTitleFromData(objectGraph, data, cardConfig) { var _a; let title = null; if (cardConfig === null || cardConfig === void 0 ? void 0 : cardConfig.useOTDTextStyle) { title = (_a = mediaAttributes.attributeAsString(data, "ofTheDayLabel")) !== null && _a !== void 0 ? _a : mediaAttributes.attributeAsString(data, "label"); // We need to replace \n characters with
tags to ensure the // newlines in APP OF THE DAY titles are maintained. The pattern must be a RegExp since string patterns // only replace the first occurrence. if (isSome(title)) { title = title.replace(/\n/g, "
"); } } if (isNothing(title)) { title = notesFromData(objectGraph, data, "name", true); } if (isNothing(title)) { // Lastly fallback to the first related content title const fallbackCardContents = fallbackCardContentFromData(objectGraph, data); title = isSome(fallbackCardContents) ? mediaAttributes.attributeAsString(fallbackCardContents, "name") : null; } return title; } /** * @param objectGraph The dependency graph for the App Store * @param data The media api data used to determine the description of this card * @returns The title to use for this card */ function cardDescriptionFromData(objectGraph, data) { var _a; const editorialClientParams = extractEditorialClientParams(objectGraph, data); const ignoreShortNotes = mediaAttributes.attributeAsBooleanOrFalse(data, "ignoreITunesShortNotes"); if (ignoreShortNotes || editorialClientParams.suppressNoteShort) { return null; } let description = notesFromData(objectGraph, data, "short", true); if (isNothing(description) && !editorialClientParams.suppressNoteTagline) { // Lastly fallback to the first related content title const fallbackCardContents = fallbackCardContentFromData(objectGraph, data); if (isSome(fallbackCardContents)) { description = (_a = notesFromData(objectGraph, fallbackCardContents, "tagline")) !== null && _a !== void 0 ? _a : subtitleFromData(objectGraph, fallbackCardContents); } } return description; } /** * * @param objectGraph The dependency graph for the App Store * @param data The media api data used to build the card * @returns */ function fallbackCardContentFromData(objectGraph, data) { const primaryContent = relationshipCollection(data, "primary-content"); if ((primaryContent === null || primaryContent === void 0 ? void 0 : primaryContent.length) === 1) { return primaryContent[0]; } // Card contents const cardContents = relatedCardContentsContentsFromData(objectGraph, data); if (cardContents.length === 1) { return cardContents[0]; } return null; } /** * @param objectGraph The dependency graph for the App Store * @param data The media api data used to build the card this action is for * @param cardDisplayStyle The display style of the card * @param cardConfig The configuration for the card * @param context The parse context for the over all today page * @param baseMetricsOptions The base metrics options for the card * @returns The click action used for tapping on the card */ function cardClickAction(objectGraph, data, cardDisplayStyle, cardConfig, context, baseMetricsOptions, clickOptionsModifier) { var _a; const clickOptions = baseMetricsOptions; const franchise = mediaAttributes.attributeAsString(data, "label"); // Metrics: JS: Add franchise/label to todayCard click events const actionDetails = { cardType: cardDisplayStyle, franchise: franchise, }; const isOnboardingCard = isCardDataOnboardingCard(objectGraph, data); if (isOnboardingCard) { actionDetails["isOnboardingCard"] = isOnboardingCard; } clickOptions["actionDetails"] = actionDetails; if (isSome(clickOptionsModifier)) { clickOptionsModifier(clickOptions); } return editorialItemActionFromData(objectGraph, data, clickOptions, (_a = cardConfig === null || cardConfig === void 0 ? void 0 : cardConfig.clientIdentifierOverride) !== null && _a !== void 0 ? _a : objectGraph.host.clientIdentifier, recoMetricsFromTodayItem(context.currentTodayItem), cardConfig); } /** * @param objectGraph The dependency graph for the App Store * @param data The media api data used to build the base card * @param baseCard The base card to add the artwork media to * @param cropCode The crop code to use for the artwork * @param context The context for the page were creating the card for * @returns Whether or not we successfully added artwork media to the base card */ export function addArtworkMediaToBaseCard(objectGraph, data, baseCard, cardConfig, context) { return validation.context("addArtworkMediaToBaseCard", () => { const ignoreEditorialArt = mediaAttributes.attributeAsBooleanOrFalse(data, "ignoreEditorialArt"); if (ignoreEditorialArt) { return false; } const mediaDetails = todayCardArtworkDetails(objectGraph, data, cardConfig); if (isNothing(mediaDetails)) { return false; } if (isSome(context)) { addMetricsEventsToVideo(objectGraph, mediaDetails === null || mediaDetails === void 0 ? void 0 : mediaDetails.videos[0], { pageInformation: context.pageInformation, locationTracker: context.locationTracker, id: data.id, }); } baseCard.media = new TodayCardMediaArtwork(mediaDetails.artworks, mediaDetails.videos, mediaDetails.artworkLayoutsWithMetrics, todayCardArtworkTitleBackingGradientForKey(objectGraph, data, cardConfig)); baseCard.style = cardStyleFromJoeColors(mediaDetails.joeColors, "bgColor"); // External URL if (baseCard.clickAction instanceof ExternalUrlAction && objectGraph.client.isiOS) { baseCard.overlay = new TodayCardActionOverlay(baseCard.clickAction); baseCard.style = "white"; } return true; }); } //# sourceMappingURL=today-base-card-builder.js.map