summaryrefslogtreecommitdiff
path: root/node_modules/@jet-app/app-store/tmp/src/common/app-promotions/app-event.js
blob: 94eb7fec93c244e91913f057ae16671192ff8b97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
import { isNothing, isSome } from "@jet/environment";
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 color from "../../foundation/util/color-util";
import * as dateUtil from "../../foundation/util/date-util";
import * as appPromotionCommon from "./app-promotions-common";
/**
 * Creates an app event object or a Date, if the event should not yet be shown, from the given data.
 * @param data The data blob
 * @param parentAppData The related parent app of this app event. If not provided will be derived from `data`.
 * @param hideLockupWhenNotInstalled Whether to hide the lockup chin when the app is installed
 * @param includeClickAction Whether to generate a click action for the app event
 * @param offerEnvironment The preferred environment for the offer
 * @param offerStyle The preferred style of the offer
 * @param includeCrossLinkTitles Whether the cross link titles will be displayed when the app is installed
 * @param allowMissingParentApp Whether to still create the app event if the parent app is missing
 * @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
 * @param allowUnpublishedAppEventPreviews Whether or not to allow app event previews
 * @returns an AppEvent, or a Date if the event's `promotionStartDate` is in the future.
 */
export function appEventOrPromotionStartDateFromData(objectGraph, data, parentAppData, hideLockupWhenNotInstalled, includeClickAction, offerEnvironment, offerStyle, includeCrossLinkTitles, baseMetricsOptions, allowEndedEvents, includeLockupClickAction, editorialKind, isArcadePage, allowUnpublishedAppEventPreviews) {
    var _a, _b, _c;
    if (data.type !== "app-events") {
        return null;
    }
    const promotionStartDateString = mediaAttributes.attributeAsString(data, "promotionStartDate");
    if (isNothing(promotionStartDateString) || promotionStartDateString.length === 0) {
        return null;
    }
    const promotionStartDate = new Date(promotionStartDateString);
    if (isNothing(promotionStartDate)) {
        return null;
    }
    const todayDate = new Date();
    const isFutureDate = promotionStartDate.getTime() > todayDate.getTime();
    if (isFutureDate && !allowUnpublishedAppEventPreviews) {
        return promotionStartDate;
    }
    // Artwork / video
    const moduleArtwork = appPromotionCommon.artworkFromData(objectGraph, data, "lockupArtwork");
    const moduleVideo = appPromotionCommon.videoFromData(objectGraph, data, "lockupVideo", false, false);
    if (isNothing(moduleArtwork) && serverData.isNullOrEmpty(moduleVideo)) {
        return null;
    }
    const selectedArtwork = (_a = moduleVideo === null || moduleVideo === void 0 ? void 0 : moduleVideo.preview) !== null && _a !== void 0 ? _a : moduleArtwork;
    const isArtworkDark = color.isDarkColor(selectedArtwork === null || selectedArtwork === void 0 ? void 0 : selectedArtwork.backgroundColor);
    const mediaOverlayStyle = isArtworkDark ? "dark" : "light";
    const includeBorderInDarkMode = color.isDarkColor(selectedArtwork === null || selectedArtwork === void 0 ? void 0 : selectedArtwork.backgroundColor, 10);
    // Other required fields
    const title = mediaAttributes.attributeAsString(data, "name");
    let kind = mediaAttributes.attributeAsString(data, "kind");
    if (serverData.isDefinedNonNullNonEmpty(editorialKind)) {
        kind = editorialKind;
    }
    const startDateString = mediaAttributes.attributeAsString(data, "startDate");
    if (isNothing(title) ||
        title.length === 0 ||
        isNothing(kind) ||
        kind.length === 0 ||
        isNothing(startDateString) ||
        startDateString.length === 0) {
        return null;
    }
    const startDate = new Date(startDateString);
    if (isNothing(startDate)) {
        return null;
    }
    // Description
    const detail = (_b = mediaAttributes.attributeAsString(data, "description.standard")) !== null && _b !== void 0 ? _b : "";
    // Lockup
    const resolvedParentAppData = parentAppData !== null && parentAppData !== void 0 ? parentAppData : mediaRelationship.relationshipData(objectGraph, data, "app");
    let lockup = null;
    if (isSome(resolvedParentAppData)) {
        lockup = appPromotionCommon.lockupFromData(objectGraph, data, resolvedParentAppData, title, offerEnvironment, offerStyle, includeCrossLinkTitles, baseMetricsOptions, includeLockupClickAction, null, isArcadePage, true);
    }
    if (isNothing(lockup)) {
        objectGraph.console.warn(`Parent app for event ${data.id} is missing, returning null.`);
        return null;
    }
    // Requirements
    const requirements = mediaAttributes.attributeAsString(data, "requirement");
    // Supplementary optional fields
    const subtitle = mediaAttributes.attributeAsString(data, "subtitle");
    const endDateString = mediaAttributes.attributeAsString(data, "endDate");
    let endDate;
    if (isSome(endDateString) && endDateString.length > 0) {
        endDate = new Date(endDateString);
    }
    const hasEventEnded = endDate !== undefined && endDate.getTime() <= todayDate.getTime();
    if (hasEventEnded && !allowEndedEvents) {
        return null;
    }
    // Formatted dates
    const badgeKindString = (_c = mediaAttributes.attributeAsString(data, "badgeKind")) !== null && _c !== void 0 ? _c : undefined;
    const badgeKind = badgeKindFromString(badgeKindString, startDate, endDate);
    const formattedDates = formattedDatesWithKind(objectGraph, badgeKind, startDate, endDate);
    const appEvent = new models.AppEvent(data.id, moduleArtwork !== null && moduleArtwork !== void 0 ? moduleArtwork : undefined, moduleVideo !== null && moduleVideo !== void 0 ? moduleVideo : undefined, title, subtitle !== null && subtitle !== void 0 ? subtitle : undefined, detail, startDate, endDate, badgeKind, kind, requirements !== null && requirements !== void 0 ? requirements : undefined, lockup, hideLockupWhenNotInstalled, formattedDates, mediaOverlayStyle, includeBorderInDarkMode);
    // Notifications
    if (serverData.isDefinedNonNull(resolvedParentAppData)) {
        const clickOptions = {
            ...baseMetricsOptions,
            id: resolvedParentAppData.id,
            inAppEventId: data.id,
            relatedSubjectIds: [resolvedParentAppData.id],
        };
        appEvent.notificationConfig = appPromotionCommon.notificationConfigFromData(objectGraph, data, appEvent, clickOptions, true);
    }
    // Click action
    if (includeClickAction && serverData.isDefinedNonNull(resolvedParentAppData)) {
        appEvent.clickAction = appPromotionCommon.detailPageClickActionFromData(objectGraph, data, resolvedParentAppData, appEvent, baseMetricsOptions, includeLockupClickAction);
    }
    return appEvent;
}
/**
 * Determines the badge kind from the given string.
 * @param badgeKindString The raw badge kind string
 * @param startDate The start date of the app event
 * @param endDate  The end date of the app event, if any
 * @returns An AppEventBadgeKind
 */
export function badgeKindFromString(badgeKindString, startDate, endDate) {
    let badgeKind = (badgeKindString !== null && badgeKindString !== void 0 ? badgeKindString : models.AppEventBadgeKind.live);
    if (badgeKind === models.AppEventBadgeKind.live && serverData.isDefinedNonNull(endDate)) {
        // If the event is longer than 6 hours, override with "happening now" so that
        // the blinking red live dot is less prevalent.
        const difference = endDate.getTime() - startDate.getTime();
        const sixHoursDifference = 1000 * 60 * 60 * 6;
        if (difference > sixHoursDifference) {
            badgeKind = models.AppEventBadgeKind.happening;
        }
    }
    return badgeKind;
}
/**
 * Generates a list of all the possible date variants for a given app event. The native
 * client will look at this list and determine which variant to display, based
 * on the current time. The reason for sending down all variants is that the client will
 * continue to update the display as time progresses, so it's feasible that the client will
 * cross over from date variant to the next (eg. TOMORROW 12:00 PM -> TODAY 12:00 PM).
 * @param badgeKind The kind of badge used
 * @param startDate The start date of the app event
 * @param endDate The end date of the app event, if any
 */
export function formattedDatesWithKind(objectGraph, badgeKind, startDate, endDate) {
    const formattedDates = [];
    const startMidnight = dateUtil.convertLocalDateToLocalMidnight(startDate);
    if (isNothing(startMidnight)) {
        // This is only possible if `startDate` is "nothing", which means we can't proceed to create formatted dates anyway.
        return [];
    }
    // Event starts 7+ days from now
    // Example: JAN 15
    const introductionDateFormat = objectGraph.loc.string("AppEvents.FormattedDate.SevenDaysOrMore.DateFormat");
    const introductionText = objectGraph.loc.uppercased(objectGraph.loc.formatDate(introductionDateFormat, startDate));
    const introductionFormattedDate = new models.AppEventFormattedDate(false, undefined, introductionText !== null && introductionText !== void 0 ? introductionText : undefined, undefined, undefined);
    formattedDates.push(introductionFormattedDate);
    // Event starts 2-6 days from now
    // Example: FRI 12:00 PM
    const sixDaysPrior = new Date(startMidnight);
    sixDaysPrior.setDate(sixDaysPrior.getDate() - 6);
    const sixDaysPriorDateFormat = objectGraph.loc.string("AppEvents.FormattedDate.SixDaysOrLess.DateFormat");
    const sixDaysPriorText = objectGraph.loc.formatDate(sixDaysPriorDateFormat, startDate);
    const sixDaysPriorTextUppercased = objectGraph.loc.uppercased(sixDaysPriorText);
    const sixDaysPriorFormattedDate = new models.AppEventFormattedDate(false, sixDaysPrior, sixDaysPriorTextUppercased !== null && sixDaysPriorTextUppercased !== void 0 ? sixDaysPriorTextUppercased : undefined, undefined, undefined);
    formattedDates.push(sixDaysPriorFormattedDate);
    // Event starts tomorrow
    // Example: TOMORROW 12:00 PM
    const oneDayPrior = new Date(startMidnight);
    oneDayPrior.setDate(oneDayPrior.getDate() - 1);
    const tomorrowSentence = objectGraph.loc.string("AppEvents.FormattedDate.Tomorrow");
    const tomorrowText = objectGraph.loc.formatDateInSentence(tomorrowSentence, "j:mm", startDate);
    const tomorrowTextUppercased = objectGraph.loc.uppercased(tomorrowText);
    const tomorrowFormattedDate = new models.AppEventFormattedDate(false, oneDayPrior, tomorrowTextUppercased !== null && tomorrowTextUppercased !== void 0 ? tomorrowTextUppercased : undefined, undefined, undefined);
    formattedDates.push(tomorrowFormattedDate);
    // Event starts today
    // If the event starts within 1 hour of midnight, we don't need to show this case
    // as it will be superceded by the 1 hour countdown
    // Example: TODAY 12:00 PM, TONIGHT 7:00 PM
    if (startDate.getHours() > 1 || (startDate.getHours() === 1 && startDate.getMinutes() > 0)) {
        let todaySentence;
        if (startDate.getHours() >= 19) {
            todaySentence = objectGraph.loc.string("AppEvents.FormattedDate.Tonight");
        }
        else {
            todaySentence = objectGraph.loc.string("AppEvents.FormattedDate.Today");
        }
        const todayText = objectGraph.loc.formatDateInSentence(todaySentence, "j:mm", startDate);
        const todayTextUppercased = objectGraph.loc.uppercased(todayText);
        const todayFormattedDate = new models.AppEventFormattedDate(false, startMidnight !== null && startMidnight !== void 0 ? startMidnight : undefined, todayTextUppercased !== null && todayTextUppercased !== void 0 ? todayTextUppercased : undefined, undefined, undefined);
        formattedDates.push(todayFormattedDate);
    }
    // Event is starting in 1 hour or less
    // Example: STARTS IN 59 MIN / AVAILABLE IN 59 MIN
    const oneHourPrior = new Date(startDate);
    oneHourPrior.setHours(oneHourPrior.getHours() - 1);
    let countdownStringKey;
    switch (badgeKind) {
        case models.AppEventBadgeKind.available:
            countdownStringKey = "AppEvents.FormattedDate.AvailableIn.MinutesCountdown";
            break;
        case models.AppEventBadgeKind.happening:
        case models.AppEventBadgeKind.live:
        default:
            countdownStringKey = "AppEvents.FormattedDate.StartsIn.MinutesCountdown";
            break;
    }
    const oneHourPriorFormattedDate = new models.AppEventFormattedDate(false, oneHourPrior, undefined, startDate, countdownStringKey);
    formattedDates.push(oneHourPriorFormattedDate);
    // Event is happening now
    // Example: LIVE, HAPPENING NOW, NOW AVAILABLE
    let liveText;
    let showLiveIndicator;
    switch (badgeKind) {
        case models.AppEventBadgeKind.available:
            liveText = objectGraph.loc.string("AppEvents.FormattedDate.NowAvailable");
            showLiveIndicator = false;
            break;
        case models.AppEventBadgeKind.happening:
            liveText = objectGraph.loc.string("AppEvents.FormattedDate.HappeningNow");
            showLiveIndicator = false;
            break;
        case models.AppEventBadgeKind.live:
        default:
            liveText = objectGraph.loc.string("AppEvents.FormattedDate.Live");
            showLiveIndicator = true;
            break;
    }
    const liveFormattedDate = new models.AppEventFormattedDate(showLiveIndicator, startDate, liveText, undefined, undefined);
    formattedDates.push(liveFormattedDate);
    // Event has ended
    // Example: EVENT ENDED
    if (endDate !== null) {
        const eventEndedFormattedDate = new models.AppEventFormattedDate(false, endDate, objectGraph.loc.string("AppEvents.FormattedDate.EventEnded"), undefined, undefined);
        formattedDates.push(eventEndedFormattedDate);
    }
    return formattedDates;
}
//# sourceMappingURL=app-event.js.map