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
|
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 color from "../../../foundation/util/color-util";
import * as flowPreview from "../../content/flow-preview";
import * as metricsHelpersClicks from "../../metrics/helpers/clicks";
import * as metricsHelpersImpressions from "../../metrics/helpers/impressions";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import * as metricsHelpersUtil from "../../metrics/helpers/util";
import * as onDevicePersonalization from "../../personalization/on-device-personalization";
import { GroupingShelfController } from "./grouping-shelf-controller";
import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common";
export class GroupingEditorialCardShelfController extends GroupingShelfController {
// region Constructors
constructor() {
super("GroupingEditorialCardShelfController");
this.supportedFeaturedContentIds = new Set([
415 /* groupingTypes.FeaturedContentID.AppStore_HeroList */,
416 /* groupingTypes.FeaturedContentID.AppStore_Hero */,
501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */,
417 /* groupingTypes.FeaturedContentID.AppStore_CustomHero */,
258 /* groupingTypes.FeaturedContentID.Sundance_Flowcase */,
]);
}
// 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);
}
/**
* 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) {
return baseShelfToken;
}
// 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 shelf = new models.Shelf("editorialCard");
shelf.isHorizontal = true;
const personalizationDataContainer = this.personalizationDataContainerForEditorialCardItemsDataArray(objectGraph, shelfData.shelfContents);
const items = [];
for (const data of shelfData.shelfContents) {
const card = GroupingEditorialCardShelfController.makeEditorialCard(objectGraph, data, personalizationDataContainer, groupingParseContext, shelfToken);
if (serverData.isNullOrEmpty(card) || !card.isValid()) {
continue;
}
items.push(card);
metricsHelpersLocation.nextPosition(shelfToken.metricsLocationTracker);
}
// We don't need this in our incomplete shelf URL, so we'll preemptively remove it.
delete shelfToken.maxItemCount;
if (objectGraph.client.isVision) {
shelf.presentationHints = { ...shelf.presentationHints, showSupplementaryText: true };
}
shelf.items = items;
shelf.url = groupingShelfControllerCommon.createShelfTokenUrlIfNecessaryForShelf(objectGraph, shelf, shelfToken);
return shelf;
}
static makeEditorialCard(objectGraph, itemData, personalizationDataContainer, groupingParseContext, shelfToken) {
var _a, _b, _c;
const metricsOptions = {
targetType: "hero",
pageInformation: shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.metricsPageInformation,
locationTracker: shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.metricsLocationTracker,
recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(itemData),
id: itemData.id,
idType: "editorial_id",
};
const featuredContentId = mediaAttributes.attributeAsNumber(itemData, "editorialElementKind");
const shouldPersonalizeContent = featuredContentId === 501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */;
const metadata = groupingShelfControllerCommon.metadataForFCData(objectGraph, itemData, shelfToken, shouldPersonalizeContent, personalizationDataContainer, metricsOptions, groupingParseContext, () => {
shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.remainingItems.push(itemData);
});
if (!metadata) {
return null;
}
const hasContentId = ((_b = (_a = metadata.content) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.length) > 0;
if (hasContentId) {
metricsOptions.id = metadata.content.id;
metricsOptions.idType = "its_id";
metricsOptions.adamId = metadata.content.id;
}
const card = new models.EditorialCard();
// Set caption
let caption = mediaAttributes.attributeAsString(itemData, "designBadge");
if (!caption) {
caption = metadata.caption;
}
card.caption = caption;
// Set title
let title = mediaAttributes.attributeAsString(itemData, "title");
if (!title) {
title = metadata.title;
}
card.title = title;
// Set subtitle
let subtitle = groupingShelfControllerCommon.unescapeHtmlString(mediaAttributes.attributeAsString(itemData, "designTag"));
if (!subtitle) {
subtitle = metadata.subtitle;
}
card.subtitle = subtitle;
// Setup Artwork
const artworkOptions = {
useCase: 19 /* content.ArtworkUseCase.GroupingHero */,
withJoeColorPlaceholder: true,
};
if (metadata.artwork && (shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.featuredContentId) !== 258 /* groupingTypes.FeaturedContentID.Sundance_Flowcase */) {
let artworkDict = serverData.asDictionary(metadata.artwork, "subscriptionHero");
if (serverData.isNull(artworkDict) && serverData.isDefinedNonNull(metadata.appEvent)) {
artworkDict = serverData.asDictionary(metadata.artwork, "eventCard");
}
card.artwork = groupingShelfControllerCommon.groupingArtworkFromApiArtwork(objectGraph, artworkDict, artworkOptions);
}
else {
card.artwork = groupingShelfControllerCommon.artworkFromFC(objectGraph, itemData, 416, 204, artworkOptions);
}
// Set action
card.clickAction = metadata.action;
// App event formatted dates
if (serverData.isDefinedNonNull(metadata.appEvent)) {
card.appEventFormattedDates = metadata.appEvent.formattedDates;
}
// Lockup
card.lockup = metadata.lockup;
// Overlay style
if (serverData.isDefinedNonNull(card.artwork) && serverData.isDefinedNonNull(card.artwork.backgroundColor)) {
const isArtworkDark = color.isDarkColor(card.artwork.backgroundColor);
card.mediaOverlayStyle = isArtworkDark ? "dark" : "light";
if (serverData.isDefinedNonNull(card.lockup) &&
serverData.isDefinedNonNull(card.lockup.offerDisplayProperties) &&
objectGraph.host.isiOS) {
const offerEnvironment = isArtworkDark ? "dark" : "light";
card.lockup.offerDisplayProperties =
card.lockup.offerDisplayProperties.newOfferDisplayPropertiesChangingAppearance(false, "transparent", offerEnvironment);
}
}
// Set adamId
card.adamId = serverData.asString(metadata.content, "id");
// Set flow preview actions
const contentData = mediaRelationship.relationshipData(objectGraph, itemData, "contents");
if (serverData.isDefinedNonNull(contentData)) {
const metricsClickOptions = metricsHelpersClicks.clickOptionsForLockup(objectGraph, contentData, metricsOptions);
metricsClickOptions.targetType = metricsOptions.targetType;
card.flowPreviewActionsConfiguration = flowPreview.flowPreviewActionsConfigurationForProductFromData(objectGraph, itemData, false, shelfToken === null || shelfToken === void 0 ? void 0 : shelfToken.clientIdentifierOverride, card.clickAction, metricsOptions, metricsClickOptions);
}
// Configure impressions
const impressionOptions = metricsHelpersImpressions.impressionOptions(objectGraph, (_c = metadata.content) !== null && _c !== void 0 ? _c : itemData, metadata.title, metricsOptions);
if (serverData.isDefinedNonNull(metadata.onDevicePersonalizationDataProcessingType)) {
const recoMetricsData = metricsHelpersUtil.combinedRecoMetricsDataFromMetricsData(impressionOptions.recoMetricsData, metadata.onDevicePersonalizationDataProcessingType, null);
impressionOptions.recoMetricsData = recoMetricsData;
}
if (serverData.isDefinedNonNull(metadata.appEvent)) {
impressionOptions.inAppEventId = metadata.appEvent.appEventId;
if (serverData.isDefinedNonNull(metadata.appEvent.lockup)) {
impressionOptions.relatedSubjectIds = [metadata.appEvent.lockup.adamId];
}
}
if (serverData.isDefinedNonNull(shelfToken)) {
metricsHelpersImpressions.addImpressionFields(objectGraph, card, impressionOptions);
}
return card;
}
// region Helpers
/**
* Iterates through all the editorial cards data, and creates a set of personalization data that is targetted only to these cards.
*
* @param objectGraph
* @param dataArray The input array of editorial card data items
* @returns Any relevant OnDevicePersonalizaionData
*/
personalizationDataContainerForEditorialCardItemsDataArray(objectGraph, dataArray) {
var _a, _b;
if (!onDevicePersonalization.isPersonalizationAvailable(objectGraph)) {
return null;
}
// First iterate through and extract any relevant App IDs from meta.personalizationData for each card's contents.
const appIds = new Set();
for (const data of dataArray) {
const featuredContentId = mediaAttributes.attributeAsNumber(data, "editorialElementKind");
const shouldPersonalizeContent = featuredContentId === 501 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedHeroMarker */;
const isLinkNode = ((_a = serverData.asString(data, "url")) === null || _a === void 0 ? void 0 : _a.length) > 0;
const containsLinkNode = ((_b = mediaAttributes.attributeAsString(data, "link.url")) === null || _b === void 0 ? void 0 : _b.length) > 0;
const isContentNode = mediaRelationship.hasRelationship(data, "contents", false);
if (shouldPersonalizeContent && !isLinkNode && !containsLinkNode && isContentNode) {
const contentDataItems = mediaRelationship.relationshipCollection(data, "contents");
for (const contentData of contentDataItems) {
const appId = serverData.asString(contentData, "meta.personalizationData.appId");
if ((appId === null || appId === void 0 ? void 0 : appId.length) > 0) {
appIds.add(appId);
}
}
}
}
return onDevicePersonalization.personalizationDataContainerForAppIds(objectGraph, appIds);
}
}
//# sourceMappingURL=grouping-editorial-card-shelf-controller.js.map
|