From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Tue, 4 Nov 2025 05:03:50 +0800 Subject: init commit --- .../tmp/src/common/app-promotions/offer-item.js | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 node_modules/@jet-app/app-store/tmp/src/common/app-promotions/offer-item.js (limited to 'node_modules/@jet-app/app-store/tmp/src/common/app-promotions/offer-item.js') diff --git a/node_modules/@jet-app/app-store/tmp/src/common/app-promotions/offer-item.js b/node_modules/@jet-app/app-store/tmp/src/common/app-promotions/offer-item.js new file mode 100644 index 0000000..989ab6d --- /dev/null +++ b/node_modules/@jet-app/app-store/tmp/src/common/app-promotions/offer-item.js @@ -0,0 +1,206 @@ +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 dateUtil from "../../foundation/util/date-util"; +import { isNothing, isSome } from "@jet/environment/types/optional"; +import * as offerFormatting from "../offers/offer-formatting"; +import * as offers from "../offers/offers"; +import * as content from "../content/content"; +import * as contentArtwork from "../content/artwork/artwork"; +/** + * Creates an offer item object. + * @param offerItemData 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 Offer Item or null + */ +export function offerItemFromData(objectGraph, offerItemData, parentAppData, offerEnvironment, offerStyle, baseMetricsOptions, includeLockupClickAction, isArcadePage) { + var _a, _b, _c, _d, _e, _f; + if (offerItemData.type !== "offer-items") { + return null; + } + const kind = mediaAttributes.attributeAsString(offerItemData, "kind"); + if (kind !== "resubscription" && kind !== "winback") { + // Only resubscriptions are supported + return null; + } + const isArtworkDark = false; + const mediaOverlayStyle = isArtworkDark ? "dark" : "light"; + // The Offers + const discountedIAP = mediaRelationship.relationshipData(objectGraph, offerItemData, "salables"); + if (isNothing(discountedIAP)) { + return null; + } + const discountedOffer = serverData.asDictionary(discountedIAP, "meta.discountOffer"); + const regularOffer = offers.offerDataFromData(objectGraph, discountedIAP); + if (isNothing(discountedOffer)) { + return null; + } + const resolvedParentApp = (_a = parentAppData !== null && parentAppData !== void 0 ? parentAppData : mediaRelationship.relationshipData(objectGraph, offerItemData, "app")) !== null && _a !== void 0 ? _a : mediaRelationship.relationshipData(objectGraph, discountedIAP, "app"); + const supportsStreamlinedBuy = mediaAttributes.attributeAsBooleanOrFalse(resolvedParentApp, "supportsStreamlinedBuy"); + // Offer Validity + const endDateString = mediaAttributes.attributeAsString(offerItemData, "redemptionExpirationDate"); + if (isNothing(endDateString) || !isOfferValid(endDateString)) { + return null; + } + const endDate = new Date(endDateString); + let formattedExpiryDateShortString = formattedExpiryDate(objectGraph, endDate); + if (isNothing(formattedExpiryDateShortString)) { + formattedExpiryDateShortString = objectGraph.loc.string("OfferItems.Available.Now"); + } + // IAP Artwork + let iapArtwork = content.iconFromData(objectGraph, discountedIAP, { + useCase: 3 /* content.ArtworkUseCase.LockupIconLarge */, + withJoeColorPlaceholder: true, + overrideTextColorKey: "textColor4", + }); + /// A fallback artwork for rare cases where no artwork is found. + /// This should not happen in production + if (serverData.isNullOrEmpty(iapArtwork)) { + const blackColor = { + type: "rgb", + red: 0.0 / 255, + green: 0.0 / 255, + blue: 0.0 / 255, + alpha: 1, + }; + iapArtwork = contentArtwork.createArtworkForResource(objectGraph, "systemimage://questionmark.circle", 200, 200, blackColor); + iapArtwork.style = "iap"; + } + const subscriptionRecurrence = offerFormatting.subscriptionRecurrenceForServerRecurrence(objectGraph, serverData.asString(discountedOffer, "recurringSubscriptionPeriod"), serverData.asNumber(discountedOffer, "numOfPeriods")); + const discountDuration = isSome(subscriptionRecurrence) + ? offerFormatting.durationCountString(objectGraph, subscriptionRecurrence.type, subscriptionRecurrence.periodDuration * subscriptionRecurrence.periodCount) + : undefined; + // Price Strings + // Adding \u{2060} (Word Joiner) prevents the string from breaking on the slash character + const regularPrice = (_b = formattedPrice(objectGraph, serverData.asString(regularOffer, "recurringSubscriptionPeriod"), serverData.asNumber(regularOffer, "numOfPeriods"), serverData.asString(regularOffer, "priceFormatted"))) === null || _b === void 0 ? void 0 : _b.replace("/", "/\u{2060}"); + const discountedPrice = (_c = formattedPrice(objectGraph, serverData.asString(discountedOffer, "recurringSubscriptionPeriod"), serverData.asNumber(discountedOffer, "numOfPeriods"), serverData.asString(discountedOffer, "priceFormatted"))) === null || _c === void 0 ? void 0 : _c.replace("/", "/\u{2060}"); + /// A string map of the templated string in an offer + /// Fallback to the templated string if the string does not exist + const redemptionDateFormat = objectGraph.loc.string("OfferItems.FormattedDate.RedemptionDate.DateFormat"); + const templateKeyMap = { + "@@redemptionDate@@": objectGraph.loc.formatDate(redemptionDateFormat, endDate), + "@@skuName@@": (_d = mediaAttributes.attributeAsString(discountedIAP, "name")) !== null && _d !== void 0 ? _d : "@@skuName@@", + "@@discountedPrice@@": discountedPrice !== null && discountedPrice !== void 0 ? discountedPrice : "@@discountedPrice@@", + "@@regularPricePerDuration@@": regularPrice !== null && regularPrice !== void 0 ? regularPrice : "@@regularPricePerDuration@@", + "@@discountDuration@@": discountDuration !== null && discountDuration !== void 0 ? discountDuration : "@@discountDuration@@", + "@@payUpfrontPrice@@": (_e = serverData.asString(discountedOffer, "priceFormatted")) !== null && _e !== void 0 ? _e : "@@payUpfrontPrice@@", + }; + // Labels + const badge = mediaAttributes.attributeAsString(offerItemData, "badge"); + if (isNothing(badge)) { + return null; + } + const title = appPromotionCommon.replacingTemplatedKeys(mediaAttributes.attributeAsString(offerItemData, "title"), templateKeyMap); + const formattedTitle = new models.Paragraph(title, "text/x-apple-as3-nqml", "appPromotionTitle"); + const subtitle = appPromotionCommon.replacingTemplatedKeys(mediaAttributes.attributeAsString(offerItemData, "subtitle"), templateKeyMap); + const description = appPromotionCommon.replacingTemplatedKeys((_f = mediaAttributes.attributeAsString(offerItemData, "details")) !== null && _f !== void 0 ? _f : "", templateKeyMap); + // Offer Lockup + let offerLockup; + if (serverData.isDefinedNonNull(resolvedParentApp)) { + offerLockup = appPromotionCommon.lockupFromData(objectGraph, offerItemData, resolvedParentApp, "", offerEnvironment, offerStyle, false, baseMetricsOptions, includeLockupClickAction, null, isArcadePage, true); + } + if (isNothing(offerLockup)) { + return null; + } + const offerItem = new models.OfferItem(null, null, mediaOverlayStyle, supportsStreamlinedBuy, formattedTitle, formattedExpiryDateShortString, subtitle, description, badge, endDate, iapArtwork, offerLockup); + offerItem.title = title; + // Detail page click action + if (serverData.isDefinedNonNull(resolvedParentApp)) { + offerItem.clickAction = appPromotionCommon.detailPageClickActionFromData(objectGraph, offerItemData, resolvedParentApp, offerItem, baseMetricsOptions, includeLockupClickAction); + } + return offerItem; +} +/** + * Creates a readable subscription price + * @param recurringSubscriptionPeriod The subscription recurrence in the server format. (eg P1M) + * @param numberOfPeriods The number of periods the subscription recurs for. + * @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 null; + } + return offerFormatting.priceDurationString(objectGraph, subscriptionRecurrence === null || subscriptionRecurrence === void 0 ? void 0 : subscriptionRecurrence.type, subscriptionRecurrence === null || subscriptionRecurrence === void 0 ? void 0 : subscriptionRecurrence.periodDuration, price); +} +/** + * Checks the validity of a app promotion based on end date + * @param endDateString A string representation of the end date + * @returns bool of if the offer is valid or not + */ +function isOfferValid(endDateString) { + if (isNothing(endDateString) || serverData.isNullOrEmpty(endDateString)) { + return false; + } + const endDate = new Date(endDateString); + if (serverData.isNull(endDate)) { + return false; + } + const todayDate = new Date(); + const hasEventEnded = endDate.getTime() <= todayDate.getTime(); + if (hasEventEnded) { + return false; + } + return true; +} +/** + * Creates the availability label for a app promotion + * @param startDate The start date + * @param endDate The end date + * @returns string of the format the date should be shown + */ +function formattedExpiryDate(objectGraph, endDate) { + if (isNothing(endDate)) { + return null; + } + const endMidnight = dateUtil.convertLocalDateToLocalMidnight(endDate); + const currentDate = new Date(); + const daysLeft = dateUtil.numberOfDaysBetween(currentDate, endMidnight); + if (isNothing(daysLeft)) { + return null; + } + const isSameDate = dateUtil.areLocalDatesSameDay(currentDate, endDate); + if (daysLeft > 90) { + return objectGraph.loc.string("OfferItems.Available.Now"); + } + // Event ends 5+ days from now + // Example: EXPIRES DEC 31 + if (daysLeft > 5) { + const expiryDateFormat = currentDate.getFullYear() !== endDate.getFullYear() + ? objectGraph.loc.string("OfferItems.FormattedDate.NextYear.DateFormat") + : objectGraph.loc.string("OfferItems.FormattedDate.FiveDaysOrMore.DateFormat"); + const expiryDateString = objectGraph.loc.uppercased(objectGraph.loc.formatDate(expiryDateFormat, endDate)); + if (isNothing(expiryDateString)) { + return null; + } + return objectGraph.loc + .string("OfferItems.FormattedDate.FiveDaysOrMore.Title") + .replace("@@date@@", expiryDateString); + } + // Event ends 2-5 days from now + // Example: EXPIRES IN 3 Days + if (daysLeft > 1) { + const fiveDaysPriorDateFormat = objectGraph.loc + .string("OfferItems.FormattedDate.FiveDaysOrLess.Title") + .replace("@@count@@", objectGraph.loc.formattedCount(daysLeft)); + return fiveDaysPriorDateFormat; + } + // Event ends 1 day from now + // Example: EXPIRES TOMORROW + if (daysLeft === 1 && !isSameDate) { + return objectGraph.loc.string("OfferItems.FormattedDate.Tomorrow.Title"); + } + // Event ends 1 day from now + // Example: EXPIRES TONIGHT + return objectGraph.loc.string("OfferItems.FormattedDate.Today.Title"); +} +//# sourceMappingURL=offer-item.js.map \ No newline at end of file -- cgit v1.2.3