import * as models from "../../api/models";
import * as serverData from "../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../foundation/media/attributes";
import * as mediaRelationship from "../../foundation/media/relationships";
import * as appPromotionCommon from "./app-promotions-common";
import * as offerFormatting from "../offers/offer-formatting";
import * as offers from "../offers/offers";
import * as color from "../../foundation/util/color-util";
import { isNothing, isSome } from "@jet/environment/types/optional";
import { contentAttributeAsDictionary } from "../content/attributes";
import * as content from "../content/content";
/**
* Creates a contingent offer object.
* @param data The data blob
* @param parentAppData The related parent app of this app event. If not provided will be derived from `data`.
* @param offerEnvironment The preferred environment for the offer
* @param offerStyle The preferred style of the offer
* @param baseMetricsOptions The base metrics options
* @param allowEndedEvents Whether events in the past are allowed
* @param includeLockupClickAction Whether to include the click action for the lockup
* @param isArcadePage Whether or not this is presented on the Arcade page
* @returns an ContingentOffer or null
*/
export function contingentOfferFromData(objectGraph, data, parentAppData, offerEnvironment, offerStyle, baseMetricsOptions, includeLockupClickAction, isArcadePage) {
var _a, _b, _c;
if (data.type !== "contingent-items") {
return null;
}
// Artwork
const moduleArtwork = appPromotionCommon.artworkFromPlatformData(objectGraph, data, "lockupArtwork");
if (serverData.isNull(moduleArtwork)) {
return null;
}
const isArtworkDark = color.isDarkColor(moduleArtwork.backgroundColor);
const mediaOverlayStyle = isArtworkDark ? "dark" : "light";
// Labels
const badge = mediaAttributes.attributeAsString(data, "badge");
const subtitle = mediaAttributes.attributeAsString(data, "subtitle");
const label = mediaAttributes.attributeAsString(data, "label");
const additionalInfoLabel = objectGraph.loc.string("ContingentOffer.AdditionalInfoButton.Title");
if (isNothing(badge) || isNothing(label)) {
return null;
}
// The discounted offer
const branch = mediaRelationship.relationshipData(objectGraph, data, "branch");
if (isNothing(branch) || serverData.isNullOrEmpty(serverData.asDictionary(branch, "meta.contingentItemOffer"))) {
return null;
}
const formattedText = formattedTextFromData(objectGraph, data);
if (isNothing(formattedText) || isNothing(formattedText === null || formattedText === void 0 ? void 0 : formattedText.title)) {
return null;
}
// The Apps
const resolvedBranchAppData = mediaRelationship.relationshipData(objectGraph, data, "branch-app");
const supportsStreamlinedBuy = mediaAttributes.attributeAsBooleanOrFalse(resolvedBranchAppData, "supportsStreamlinedBuy");
const offerLockup = appPromotionCommon.lockupFromData(objectGraph, data, resolvedBranchAppData, "", offerEnvironment, offerStyle, false, baseMetricsOptions, includeLockupClickAction, null, isArcadePage, true);
if (isNothing(offerLockup)) {
return null;
}
// Trunk Lockup. The app you need to be subscribed to in order to get the discounted offer
const resolvedTrunkAppData = mediaRelationship.relationshipData(objectGraph, data, "trunk-app");
let trunkAppIcon;
if (isSome(resolvedTrunkAppData) && isSome(subtitle) && (subtitle === null || subtitle === void 0 ? void 0 : subtitle.length) > 0) {
trunkAppIcon =
(_a = appPromotionCommon.artworkFromPlatformData(objectGraph, resolvedTrunkAppData, "artwork")) !== null && _a !== void 0 ? _a : appPromotionCommon.artworkFromData(objectGraph, resolvedTrunkAppData, "artwork");
}
// When displaying a first party offer the trunk artwork is in a different location
if (isSome(subtitle) && (subtitle === null || subtitle === void 0 ? void 0 : subtitle.length) > 0) {
trunkAppIcon = (_b = firstPartyTrunkLockupFromData(objectGraph, data)) !== null && _b !== void 0 ? _b : trunkAppIcon;
}
// Offer Strings
const additionalInfo = formattedAdditionalInfoFromData(objectGraph, data, branch);
const contingentOffer = new models.ContingentOffer(moduleArtwork, mediaOverlayStyle, supportsStreamlinedBuy, additionalInfoLabel, formattedText.title, subtitle !== null && subtitle !== void 0 ? subtitle : undefined, (_c = formattedText.description) !== null && _c !== void 0 ? _c : undefined, label, badge, additionalInfo, trunkAppIcon !== null && trunkAppIcon !== void 0 ? trunkAppIcon : undefined, offerLockup);
/// The raw title is used for metrics purposes
contingentOffer.title = formattedText.rawTitle;
// Detail page click action
if (serverData.isDefinedNonNull(resolvedBranchAppData)) {
contingentOffer.clickAction = appPromotionCommon.detailPageClickActionFromData(objectGraph, data, resolvedBranchAppData, contingentOffer, baseMetricsOptions, includeLockupClickAction);
}
return contingentOffer;
}
/**
* Creates the Title and description of the contingent offer out of a templated string
* @param data A data blob for the contingent-item
* @returns Creates a formatted string of the tile including the subscription price and period
*/
export function formattedTextFromData(objectGraph, data) {
var _a, _b, _c;
const branch = mediaRelationship.relationshipData(objectGraph, data, "branch");
if (isNothing(branch)) {
return undefined;
}
const regularOffer = offers.offerDataFromData(objectGraph, branch);
const discountedOffer = serverData.asDictionary(branch, "meta.contingentItemOffer");
if (serverData.isNullOrEmpty(regularOffer) || serverData.isNullOrEmpty(discountedOffer)) {
return undefined;
}
// Price Strings
// Adding \u{2060} (Word Joiner) prevents the string from breaking on the slash character
const regularPrice = (_a = formattedPrice(objectGraph, serverData.asString(regularOffer, "recurringSubscriptionPeriod"), serverData.asNumber(regularOffer, "numOfPeriods"), serverData.asString(regularOffer, "priceFormatted"))) === null || _a === void 0 ? void 0 : _a.replace("/", "/\u{2060}");
const discountedPrice = (_b = formattedPrice(objectGraph, serverData.asString(discountedOffer, "recurringSubscriptionPeriod"), serverData.asNumber(discountedOffer, "numOfPeriods"), serverData.asString(discountedOffer, "priceFormatted"))) === null || _b === void 0 ? void 0 : _b.replace("/", "/\u{2060}");
if (serverData.isNullOrEmpty(regularPrice) || serverData.isNullOrEmpty(discountedPrice)) {
return null;
}
const title = mediaAttributes.attributeAsString(data, "name");
const titleKeys = {
"@@discountedPrice@@/@@recurringSubscriptionPeriod@@": discountedPrice,
"@@regularPrice@@/@@recurringSubscriptionPeriod@@": regularPrice,
"@@discountedPricePerRecurringSubscriptionPeriod@@": discountedPrice,
"@@regularPricePerRecurringSubscriptionPeriod@@": regularPrice,
};
let titleTemplate = title !== null && title !== void 0 ? title : "";
Object.keys(titleKeys).forEach((element) => {
titleTemplate = titleTemplate.replace(element, titleKeys[element]);
});
const htmlRegex = /<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g;
const rawTitle = titleTemplate.replace(htmlRegex, "");
const formattedTitle = new models.Paragraph(titleTemplate, "text/x-apple-as3-nqml", "appPromotionTitle");
const developerDetailText = (_c = mediaAttributes.attributeAsString(data, "description.standard")) !== null && _c !== void 0 ? _c : "";
const detailTemplate = objectGraph.loc.string("ContingentOffer.Description.Format");
const descriptionKeys = {
"@@BranchName@@": mediaAttributes.attributeAsString(branch, "name"),
"@@RegularPrice@@": regularPrice,
"@@DiscountedPrice@@": discountedPrice,
};
let description = detailTemplate;
Object.keys(descriptionKeys).forEach((element) => {
description = description.replace(element, descriptionKeys[element]);
});
const formattedDescription = [description, developerDetailText].join(" ");
return {
title: formattedTitle,
rawTitle,
description: formattedDescription,
};
}
/**
* Creates a readable subscription price
* @param recurringSubscriptionPeriod The subscription recurrence in the server format. (eg P1M)
* @param price A price string in a readable format like $3.99.
* @returns A formatted string eg $3.99/month
*/
function formattedPrice(objectGraph, recurringSubscriptionPeriod, numberOfPeriods, price) {
const subscriptionRecurrence = offerFormatting.subscriptionRecurrenceForServerRecurrence(objectGraph, recurringSubscriptionPeriod, numberOfPeriods);
if (isNothing(subscriptionRecurrence) || isNothing(price)) {
return undefined;
}
return offerFormatting.priceDurationString(objectGraph, subscriptionRecurrence.type, subscriptionRecurrence.periodDuration, price);
}
/**
* Creates the additional info text of the contingent offer out of a templated string
* @param data A data blob
* @param branch A data blob containing the offer also known as the branch
* @param trunk A data blob containing the required subscription app also known as the trunk
* @returns Creates a formatted paragraph containing the contents of the additional info page.
*/
function formattedAdditionalInfoFromData(objectGraph, data, branch) {
const skuNameTitle = "" + mediaAttributes.attributeAsString(branch, "name") + "";
const skuDescription = mediaAttributes.attributeAsString(branch, "description.standard") + "
";
const termsTitle = "" + objectGraph.loc.string("ContingentOffer.Terms.Title") + "";
const terms = mediaAttributes.attributeAsString(data, "additionalTerms");
return new models.Paragraph([skuNameTitle, skuDescription, termsTitle, terms].join("
"), "text/x-apple-as3-nqml");
}
/**
* If the contingent offer has a an associated trunk use that instead of the trunk-app
* @param data The data blob
* @returns Creates a lockup to use as the TrunkLockup
*/
function firstPartyTrunkLockupFromData(objectGraph, data) {
var _a, _b;
const firstPartyTrunkData = serverData.asInterface(data, "meta.associations.trunks");
if (isNothing(firstPartyTrunkData)) {
return null;
}
const firstPartyApp = firstPartyTrunkData.data[0];
const shouldUseTrunkArtwork = (_b = (_a = firstPartyApp === null || firstPartyApp === void 0 ? void 0 : firstPartyApp.meta) === null || _a === void 0 ? void 0 : _a["useTrunkArtwork"]) !== null && _b !== void 0 ? _b : false;
if (shouldUseTrunkArtwork) {
const editorialArtwork = contentAttributeAsDictionary(objectGraph, firstPartyApp, "editorialArtwork.brandLogo");
if (isNothing(editorialArtwork)) {
return null;
}
return content.artworkFromApiArtwork(objectGraph, editorialArtwork, {
useCase: 1 /* content.ArtworkUseCase.LockupIconSmall */,
style: "roundedRect",
});
}
return null;
}
//# sourceMappingURL=contingent-offer.js.map