@maestro_io/maestro-web-sdk 5.2.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/10.maestro-web-sdk.esm.js +1 -1
- package/dist/10.maestro-web-sdk.esm.js.map +1 -1
- package/dist/11.maestro-web-sdk.esm.js +1 -1
- package/dist/11.maestro-web-sdk.esm.js.map +1 -1
- package/dist/12.maestro-web-sdk.esm.js +1 -1
- package/dist/12.maestro-web-sdk.esm.js.map +1 -1
- package/dist/13.maestro-web-sdk.esm.js +1 -1
- package/dist/13.maestro-web-sdk.esm.js.map +1 -1
- package/dist/14.maestro-web-sdk.esm.js +1 -1
- package/dist/14.maestro-web-sdk.esm.js.map +1 -1
- package/dist/15.maestro-web-sdk.esm.js +1 -1
- package/dist/15.maestro-web-sdk.esm.js.map +1 -1
- package/dist/16.maestro-web-sdk.esm.js +1 -1
- package/dist/16.maestro-web-sdk.esm.js.map +1 -1
- package/dist/17.maestro-web-sdk.esm.js +1 -1
- package/dist/17.maestro-web-sdk.esm.js.map +1 -1
- package/dist/18.maestro-web-sdk.esm.js +1 -1
- package/dist/18.maestro-web-sdk.esm.js.map +1 -1
- package/dist/19.maestro-web-sdk.esm.js +1 -1
- package/dist/19.maestro-web-sdk.esm.js.map +1 -1
- package/dist/20.maestro-web-sdk.esm.js +1 -1
- package/dist/20.maestro-web-sdk.esm.js.map +1 -1
- package/dist/21.maestro-web-sdk.esm.js +1 -1
- package/dist/21.maestro-web-sdk.esm.js.map +1 -1
- package/dist/22.maestro-web-sdk.esm.js +1 -1
- package/dist/22.maestro-web-sdk.esm.js.map +1 -1
- package/dist/23.maestro-web-sdk.esm.js +1 -1
- package/dist/23.maestro-web-sdk.esm.js.map +1 -1
- package/dist/24.maestro-web-sdk.esm.js +1 -1
- package/dist/24.maestro-web-sdk.esm.js.map +1 -1
- package/dist/25.maestro-web-sdk.esm.js +1 -1
- package/dist/25.maestro-web-sdk.esm.js.map +1 -1
- package/dist/26.maestro-web-sdk.esm.js +1 -1
- package/dist/26.maestro-web-sdk.esm.js.map +1 -1
- package/dist/27.maestro-web-sdk.esm.js +1 -1
- package/dist/27.maestro-web-sdk.esm.js.map +1 -1
- package/dist/28.maestro-web-sdk.esm.js +1 -1
- package/dist/28.maestro-web-sdk.esm.js.map +1 -1
- package/dist/29.maestro-web-sdk.esm.js +1 -1
- package/dist/29.maestro-web-sdk.esm.js.map +1 -1
- package/dist/3.maestro-web-sdk.esm.js +1 -1
- package/dist/3.maestro-web-sdk.esm.js.map +1 -1
- package/dist/30.maestro-web-sdk.esm.js +1 -1
- package/dist/30.maestro-web-sdk.esm.js.map +1 -1
- package/dist/31.maestro-web-sdk.esm.js +1 -1
- package/dist/31.maestro-web-sdk.esm.js.map +1 -1
- package/dist/32.maestro-web-sdk.esm.js +1 -1
- package/dist/32.maestro-web-sdk.esm.js.map +1 -1
- package/dist/33.maestro-web-sdk.esm.js +1 -1
- package/dist/33.maestro-web-sdk.esm.js.map +1 -1
- package/dist/34.maestro-web-sdk.esm.js +1 -1
- package/dist/34.maestro-web-sdk.esm.js.map +1 -1
- package/dist/35.maestro-web-sdk.esm.js +1 -1
- package/dist/35.maestro-web-sdk.esm.js.map +1 -1
- package/dist/36.maestro-web-sdk.esm.js +1 -1
- package/dist/36.maestro-web-sdk.esm.js.map +1 -1
- package/dist/37.maestro-web-sdk.esm.js +1 -1
- package/dist/37.maestro-web-sdk.esm.js.map +1 -1
- package/dist/38.maestro-web-sdk.esm.js +1 -1
- package/dist/38.maestro-web-sdk.esm.js.map +1 -1
- package/dist/39.maestro-web-sdk.esm.js +1 -1
- package/dist/39.maestro-web-sdk.esm.js.map +1 -1
- package/dist/6.maestro-web-sdk.esm.js +1 -1
- package/dist/7.maestro-web-sdk.esm.js +1 -1
- package/dist/8.maestro-web-sdk.esm.js +1 -1
- package/dist/8.maestro-web-sdk.esm.js.map +1 -1
- package/dist/9.maestro-web-sdk.esm.js +1 -1
- package/dist/maestro-web-sdk.esm.js +2 -2
- package/dist/maestro-web-sdk.umd.js +2 -2
- package/dist/maestro-web-sdk.umd.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/src/modules/espn/bets/services/BetsService.js +5 -5
- package/dist/src/modules/espn/fantasy/services/FantasyService.js +3 -0
- package/dist/src/modules/espn/fantasy/view/FantasyView.js +2 -1
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.FantasyPolling.d.ts +1 -1
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.FantasyPolling.js +10 -7
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.LeagueManagerPolling.d.ts +1 -1
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.LeagueManagerPolling.js +10 -7
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.TournamentPolling.d.ts +1 -1
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.TournamentPolling.js +10 -7
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.d.ts +1 -0
- package/dist/src/modules/espn/fantasy/view-model/FantasyViewModel.js +42 -32
- package/dist/src/modules/espn/shop/services/ShopService.js +1 -1
- package/dist/src/modules/espn/stats/services/StatsService.js +2 -2
- package/dist/src/modules/fox/multi-view/services/MultiViewService.d.ts +20 -15
- package/dist/src/modules/fox/multi-view/services/MultiViewService.js +6 -3
- package/dist/src/modules/fox/multi-view/types.d.ts +20 -0
- package/dist/src/modules/fox/multi-view/view/BuildYourOwn/BuildYourOwn.d.ts +7 -0
- package/dist/src/modules/fox/multi-view/view/BuildYourOwn/BuildYourOwn.js +99 -0
- package/dist/src/modules/fox/multi-view/view/BuildYourOwn/index.d.ts +2 -0
- package/dist/src/modules/fox/multi-view/view/BuildYourOwn/index.js +2 -0
- package/dist/src/modules/fox/multi-view/view/CuratedMultiview/CuratedMultiviews.js +2 -1
- package/dist/src/modules/fox/multi-view/view/FoxMultiView.js +3 -0
- package/dist/src/modules/fox/multi-view/view/components/BuildYourOwnTabs/BuildYourOwnTabs.d.ts +8 -0
- package/dist/src/modules/fox/multi-view/view/components/BuildYourOwnTabs/BuildYourOwnTabs.js +30 -0
- package/dist/src/modules/fox/multi-view/view/components/BuildYourOwnTabs/index.d.ts +2 -0
- package/dist/src/modules/fox/multi-view/view/components/BuildYourOwnTabs/index.js +2 -0
- package/dist/src/modules/fox/multi-view/view/components/CustomMultiviewStreamsCard/CustomMultiviewStreamsCard.d.ts +2 -6
- package/dist/src/modules/fox/multi-view/view/components/curated-multiview-card/CuratedMultiviewCard.js +27 -7
- package/dist/src/modules/fox/multi-view/view-model/MultiViewViewModel.d.ts +25 -4
- package/dist/src/modules/fox/multi-view/view-model/MultiViewViewModel.js +196 -15
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -25,7 +25,7 @@ class BetsService {
|
|
|
25
25
|
return this.networkManager.externalApiRequest({
|
|
26
26
|
endpoint: this.nonPersonalizedBetsEndpoint(eventID),
|
|
27
27
|
method: HttpMethod.GET,
|
|
28
|
-
params: {},
|
|
28
|
+
params: { deviceType: 'ictv' },
|
|
29
29
|
headers: {},
|
|
30
30
|
});
|
|
31
31
|
}
|
|
@@ -41,7 +41,7 @@ class BetsService {
|
|
|
41
41
|
return this.networkManager.externalApiRequest({
|
|
42
42
|
endpoint: this.personalizedBetsEndpoint(eventID),
|
|
43
43
|
method: HttpMethod.GET,
|
|
44
|
-
params: { swid },
|
|
44
|
+
params: { swid, deviceType: 'ictv' },
|
|
45
45
|
headers: { 'x-p13n-auth': jwt },
|
|
46
46
|
});
|
|
47
47
|
}
|
|
@@ -57,7 +57,7 @@ class BetsService {
|
|
|
57
57
|
return this.networkManager.externalApiRequestWithHeaders({
|
|
58
58
|
endpoint: this.personalizedBetsEndpoint(eventID),
|
|
59
59
|
method: HttpMethod.GET,
|
|
60
|
-
params: { swid },
|
|
60
|
+
params: { swid, deviceType: 'ictv' },
|
|
61
61
|
headers: { 'x-p13n-auth': jwt },
|
|
62
62
|
});
|
|
63
63
|
}
|
|
@@ -77,7 +77,7 @@ class BetsService {
|
|
|
77
77
|
endpoint: this.personalizedBetsEndpoint(eventID),
|
|
78
78
|
interval,
|
|
79
79
|
method: HttpMethod.GET,
|
|
80
|
-
params: { swid },
|
|
80
|
+
params: { swid, deviceType: 'ictv' },
|
|
81
81
|
headers: { 'x-p13n-auth': jwt },
|
|
82
82
|
onData,
|
|
83
83
|
onError,
|
|
@@ -99,7 +99,7 @@ class BetsService {
|
|
|
99
99
|
endpoint: this.personalizedBetsEndpoint(eventID),
|
|
100
100
|
interval,
|
|
101
101
|
method: HttpMethod.GET,
|
|
102
|
-
params: { swid },
|
|
102
|
+
params: { swid, deviceType: 'ictv' },
|
|
103
103
|
headers: { 'x-p13n-auth': jwt },
|
|
104
104
|
onData,
|
|
105
105
|
onError,
|
|
@@ -68,6 +68,7 @@ class FantasyService {
|
|
|
68
68
|
featureFlags: 'challengeEntries',
|
|
69
69
|
filterType: 'FANTASY_CTV',
|
|
70
70
|
platform: 'fantasyictv_bbd',
|
|
71
|
+
deviceType: 'ictv',
|
|
71
72
|
swid,
|
|
72
73
|
eventId,
|
|
73
74
|
},
|
|
@@ -85,6 +86,7 @@ class FantasyService {
|
|
|
85
86
|
params: {
|
|
86
87
|
view: 'ictv_scoreboard',
|
|
87
88
|
platform: 'fantasyictv_bbd',
|
|
89
|
+
deviceType: 'ictv',
|
|
88
90
|
proGameId,
|
|
89
91
|
teamId,
|
|
90
92
|
},
|
|
@@ -117,6 +119,7 @@ class FantasyService {
|
|
|
117
119
|
competitionId,
|
|
118
120
|
view: 'ictv_scoreboard',
|
|
119
121
|
platform: 'fantasyictv_bbd',
|
|
122
|
+
deviceType: 'ictv',
|
|
120
123
|
},
|
|
121
124
|
});
|
|
122
125
|
}
|
|
@@ -203,9 +203,10 @@ class FantasyView extends Component {
|
|
|
203
203
|
this.viewModel.cleanup();
|
|
204
204
|
}
|
|
205
205
|
render() {
|
|
206
|
+
const isError = this.state.errorState === 'tabLoadFailure';
|
|
206
207
|
return (React.createElement(ScrollableContainer, { scrollableContainerRef: this.container, containerTopOffset: this.getMaxHeaderHeight() || 40, "data-has-error": this.state.errorState !== 'none' },
|
|
207
208
|
React.createElement("div", { className: "fantasy-view", ref: this.setContainerRef },
|
|
208
|
-
this.renderItems(),
|
|
209
|
+
isError ? (React.createElement(TabLoadErrorView, { onEnterPress: this.clearTabLoadFailure, onArrowPress: this.onArrowPress })) : (this.renderItems()),
|
|
209
210
|
React.createElement("div", { className: "fantasy-bottom-padding" }))));
|
|
210
211
|
}
|
|
211
212
|
}
|
|
@@ -7,7 +7,7 @@ export default class FantasyPolling {
|
|
|
7
7
|
/**
|
|
8
8
|
* Refresh polling for fantasy data
|
|
9
9
|
*/
|
|
10
|
-
refresh(params: FantasyPollingParams, callback: (data: IFantasyResponse) => void): Promise<void>;
|
|
10
|
+
refresh(params: FantasyPollingParams, callback: (data: IFantasyResponse) => void, errorCallback: (error: Error) => void): Promise<void>;
|
|
11
11
|
/**
|
|
12
12
|
* Stop polling for fantasy data
|
|
13
13
|
*/
|
|
@@ -25,11 +25,11 @@ export default class FantasyPolling {
|
|
|
25
25
|
/**
|
|
26
26
|
* Refresh polling for fantasy data
|
|
27
27
|
*/
|
|
28
|
-
async refresh(params, callback) {
|
|
28
|
+
async refresh(params, callback, errorCallback) {
|
|
29
29
|
// First stop any existing polling
|
|
30
30
|
this.stop();
|
|
31
31
|
// Start the poll loop
|
|
32
|
-
await this.start(params, callback);
|
|
32
|
+
await this.start(params, callback, errorCallback);
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Stop polling for fantasy data
|
|
@@ -43,12 +43,15 @@ export default class FantasyPolling {
|
|
|
43
43
|
removeLastResponseHash() {
|
|
44
44
|
this.polling.lastResponseHash = null;
|
|
45
45
|
}
|
|
46
|
-
async start(params, callback) {
|
|
46
|
+
async start(params, callback, errorCallback) {
|
|
47
47
|
try {
|
|
48
48
|
this.polling.task = this.fantasyService.pollFantasy(params, this.polling.interval, (response) => {
|
|
49
|
-
this.updateInterval(params, response.headers, callback);
|
|
49
|
+
this.updateInterval(params, response.headers, callback, errorCallback);
|
|
50
50
|
this.processPolledData(response.data, callback);
|
|
51
|
-
}, (error) =>
|
|
51
|
+
}, (error) => {
|
|
52
|
+
this.handlePollingError(error, params.swid);
|
|
53
|
+
errorCallback(error);
|
|
54
|
+
});
|
|
52
55
|
}
|
|
53
56
|
catch (error) {
|
|
54
57
|
captureException(error, {
|
|
@@ -61,7 +64,7 @@ export default class FantasyPolling {
|
|
|
61
64
|
* @description Update polling interval checking either response header or panel config.
|
|
62
65
|
* Refresh polling if necessary.
|
|
63
66
|
*/
|
|
64
|
-
updateInterval(params, headers, callback) {
|
|
67
|
+
updateInterval(params, headers, callback, errorCallback) {
|
|
65
68
|
const headerInterval = this.getResponseHeaderPollingIntervalValue(headers);
|
|
66
69
|
const panelConfigInterval = this.getPanelConfigInterval();
|
|
67
70
|
const newInterval = headerInterval || panelConfigInterval; // order matters here
|
|
@@ -70,7 +73,7 @@ export default class FantasyPolling {
|
|
|
70
73
|
console.log(`[Fantasy] Updating fantasy polling interval from ${this.polling.interval}ms to ${newInterval}ms`);
|
|
71
74
|
this.polling.interval = newInterval;
|
|
72
75
|
// Restart polling with the new interval
|
|
73
|
-
this.refresh(params, callback);
|
|
76
|
+
this.refresh(params, callback, errorCallback);
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
getResponseHeaderPollingIntervalValue(headers) {
|
|
@@ -7,7 +7,7 @@ export default class LeagueManagerPolling {
|
|
|
7
7
|
/**
|
|
8
8
|
* Refresh polling for league manager data
|
|
9
9
|
*/
|
|
10
|
-
refresh(key: string, params: LeagueManagerPollingParams, callback: (data: ILeagueManagerResponse | ILeagueManagerRotoResponse) => void): void;
|
|
10
|
+
refresh(key: string, params: LeagueManagerPollingParams, callback: (data: ILeagueManagerResponse | ILeagueManagerRotoResponse) => void, errorCallback: (error: Error) => void): void;
|
|
11
11
|
/**
|
|
12
12
|
* Stop polling for fantasy data
|
|
13
13
|
*/
|
|
@@ -21,7 +21,7 @@ export default class LeagueManagerPolling {
|
|
|
21
21
|
/**
|
|
22
22
|
* Refresh polling for league manager data
|
|
23
23
|
*/
|
|
24
|
-
refresh(key, params, callback) {
|
|
24
|
+
refresh(key, params, callback, errorCallback) {
|
|
25
25
|
// First stop any existing polling
|
|
26
26
|
this.stop(key);
|
|
27
27
|
// Initialize polling state if it doesn't exist
|
|
@@ -33,7 +33,7 @@ export default class LeagueManagerPolling {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
// Start the poll loop
|
|
36
|
-
this.start(key, params, callback);
|
|
36
|
+
this.start(key, params, callback, errorCallback);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Stop polling for fantasy data
|
|
@@ -44,12 +44,15 @@ export default class LeagueManagerPolling {
|
|
|
44
44
|
this.polling[key].task = null;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
start(key, params, callback) {
|
|
47
|
+
start(key, params, callback, errorCallback) {
|
|
48
48
|
try {
|
|
49
49
|
this.polling[key].task = this.fantasyService.pollLeagueManager(params, this.polling[key].interval, (response) => {
|
|
50
|
-
this.updateInterval(key, params, callback, response.headers);
|
|
50
|
+
this.updateInterval(key, params, callback, response.headers, errorCallback);
|
|
51
51
|
this.processPolledData(key, response.data, callback);
|
|
52
|
-
}, (error) =>
|
|
52
|
+
}, (error) => {
|
|
53
|
+
this.handlePollingError(error, key, params);
|
|
54
|
+
errorCallback(error);
|
|
55
|
+
});
|
|
53
56
|
}
|
|
54
57
|
catch (error) {
|
|
55
58
|
captureException(error, {
|
|
@@ -76,7 +79,7 @@ export default class LeagueManagerPolling {
|
|
|
76
79
|
* @description Update polling interval checking either response header or panel config.
|
|
77
80
|
* Refresh polling if necessary.
|
|
78
81
|
*/
|
|
79
|
-
updateInterval(key, params, callback, headers) {
|
|
82
|
+
updateInterval(key, params, callback, headers, errorCallback) {
|
|
80
83
|
const headerInterval = this.getResponseHeaderPollingIntervalValue(headers);
|
|
81
84
|
const panelConfigInterval = this.getPanelConfigInterval();
|
|
82
85
|
const newInterval = headerInterval || panelConfigInterval; // order matters here
|
|
@@ -85,7 +88,7 @@ export default class LeagueManagerPolling {
|
|
|
85
88
|
console.log(`[Fantasy] Updating league manager polling interval from ${this.polling[key]?.interval}ms to ${newInterval}ms`);
|
|
86
89
|
this.polling[key].interval = newInterval;
|
|
87
90
|
// Restart polling with the new interval
|
|
88
|
-
this.refresh(key, params, callback);
|
|
91
|
+
this.refresh(key, params, callback, errorCallback);
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
94
|
getResponseHeaderPollingIntervalValue(headers) {
|
|
@@ -7,7 +7,7 @@ export default class TournamentPolling {
|
|
|
7
7
|
/**
|
|
8
8
|
* Refresh polling for tournament challenge data
|
|
9
9
|
*/
|
|
10
|
-
refresh(key: string, params: TournamentChallengePollingParams, callback: (data: TournamentChallenge) => void): void;
|
|
10
|
+
refresh(key: string, params: TournamentChallengePollingParams, callback: (data: TournamentChallenge) => void, errorCallback: (error: Error) => void): void;
|
|
11
11
|
/**
|
|
12
12
|
* Stop polling for tournament challenge data
|
|
13
13
|
*/
|
|
@@ -21,7 +21,7 @@ export default class TournamentPolling {
|
|
|
21
21
|
/**
|
|
22
22
|
* Refresh polling for tournament challenge data
|
|
23
23
|
*/
|
|
24
|
-
refresh(key, params, callback) {
|
|
24
|
+
refresh(key, params, callback, errorCallback) {
|
|
25
25
|
// First stop any existing polling
|
|
26
26
|
this.stop(key);
|
|
27
27
|
// Initialize polling state if it doesn't exist
|
|
@@ -33,7 +33,7 @@ export default class TournamentPolling {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
// Start the poll loop
|
|
36
|
-
this.start(key, params, callback);
|
|
36
|
+
this.start(key, params, callback, errorCallback);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Stop polling for tournament challenge data
|
|
@@ -44,12 +44,15 @@ export default class TournamentPolling {
|
|
|
44
44
|
this.polling[key].task = null;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
start(key, params, callback) {
|
|
47
|
+
start(key, params, callback, errorCallback) {
|
|
48
48
|
try {
|
|
49
49
|
this.polling[key].task = this.fantasyService.pollTournamentChallenge(params, this.polling[key].interval, (response) => {
|
|
50
|
-
this.updateInterval(key, params, callback, response.headers);
|
|
50
|
+
this.updateInterval(key, params, callback, response.headers, errorCallback);
|
|
51
51
|
this.processPolledData(key, response.data, callback);
|
|
52
|
-
}, (error) =>
|
|
52
|
+
}, (error) => {
|
|
53
|
+
this.handlePollingError(error, key, params);
|
|
54
|
+
errorCallback(error);
|
|
55
|
+
});
|
|
53
56
|
}
|
|
54
57
|
catch (error) {
|
|
55
58
|
captureException(error, {
|
|
@@ -62,7 +65,7 @@ export default class TournamentPolling {
|
|
|
62
65
|
* @description Update polling interval checking either response header or panel config.
|
|
63
66
|
* Refresh polling if necessary.
|
|
64
67
|
*/
|
|
65
|
-
updateInterval(key, params, callback, headers) {
|
|
68
|
+
updateInterval(key, params, callback, headers, errorCallback) {
|
|
66
69
|
const headerInterval = this.getResponseHeaderPollingIntervalValue(headers);
|
|
67
70
|
const panelConfigInterval = this.getPanelConfigInterval();
|
|
68
71
|
const newInterval = headerInterval || panelConfigInterval; // order matters here
|
|
@@ -71,7 +74,7 @@ export default class TournamentPolling {
|
|
|
71
74
|
console.log(`[TOURNAMENT] Updating tournament polling interval from ${this.polling[key]?.interval}ms to ${newInterval}ms`);
|
|
72
75
|
this.polling[key].interval = newInterval;
|
|
73
76
|
// Restart polling with the new interval
|
|
74
|
-
this.refresh(key, params, callback);
|
|
77
|
+
this.refresh(key, params, callback, errorCallback);
|
|
75
78
|
}
|
|
76
79
|
}
|
|
77
80
|
getResponseHeaderPollingIntervalValue(headers) {
|
|
@@ -153,32 +153,45 @@ export class FantasyViewModel {
|
|
|
153
153
|
this.trackPanelView();
|
|
154
154
|
await this.fetchData();
|
|
155
155
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
this.
|
|
162
|
-
id: 'not-logged-in',
|
|
163
|
-
type: 'notLoggedIn',
|
|
164
|
-
});
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
else if (this.fantasyItems.value.find((i) => i.type === 'notLoggedIn')) {
|
|
168
|
-
this.fantasyItems.value = [];
|
|
156
|
+
handleFetchError(error, context = 'FantasyViewModel.fetchData') {
|
|
157
|
+
captureException(error, { context });
|
|
158
|
+
console.error('[FANTASY] Error in ' + context + ':', error);
|
|
159
|
+
this.isDataLoading.value = false;
|
|
160
|
+
if (!this.hasEverSuccessfullyLoaded.value) {
|
|
161
|
+
this.errorState.value = 'tabLoadFailure';
|
|
169
162
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
163
|
+
}
|
|
164
|
+
async fetchData() {
|
|
165
|
+
try {
|
|
166
|
+
this.isDataLoading.value = true;
|
|
167
|
+
const isAuthenticated = await this.delegate.userIsAuthenticated();
|
|
168
|
+
if (!isAuthenticated) {
|
|
169
|
+
this.isDataLoading.value = false;
|
|
170
|
+
this.append({
|
|
171
|
+
id: 'not-logged-in',
|
|
172
|
+
type: 'notLoggedIn',
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
else if (this.fantasyItems.value.find((i) => i.type === 'notLoggedIn')) {
|
|
177
|
+
this.fantasyItems.value = [];
|
|
178
|
+
}
|
|
179
|
+
const swid = (await this.delegate.getUserSWID()) || '';
|
|
180
|
+
const jwt = (await this.delegate.getUserToken()) || '';
|
|
181
|
+
if (this.useMockData) {
|
|
182
|
+
await this.fetchMockData();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
await this.fantasyPolling.refresh({
|
|
187
|
+
eventId: this.eventId,
|
|
188
|
+
swid,
|
|
189
|
+
jwt,
|
|
190
|
+
}, this.processFantasy.bind(this), this.handleFetchError.bind(this));
|
|
191
|
+
}
|
|
175
192
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
eventId: this.eventId,
|
|
179
|
-
swid,
|
|
180
|
-
jwt,
|
|
181
|
-
}, this.processFantasy.bind(this));
|
|
193
|
+
catch (error) {
|
|
194
|
+
this.handleFetchError(error);
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
onEngage(type) {
|
|
@@ -269,6 +282,8 @@ export class FantasyViewModel {
|
|
|
269
282
|
this.isLoadingTc.value = false;
|
|
270
283
|
this.rebuildFantasyItems();
|
|
271
284
|
}
|
|
285
|
+
}, (error) => {
|
|
286
|
+
this.handleFetchError(error, 'FantasyViewModel.processFantasy.tournamentChallenge');
|
|
272
287
|
});
|
|
273
288
|
}
|
|
274
289
|
});
|
|
@@ -334,6 +349,8 @@ export class FantasyViewModel {
|
|
|
334
349
|
}
|
|
335
350
|
}
|
|
336
351
|
}
|
|
352
|
+
}, (error) => {
|
|
353
|
+
this.handleFetchError(error, 'FantasyViewModel.processFantasy.leagueManager');
|
|
337
354
|
});
|
|
338
355
|
}
|
|
339
356
|
// Mark successful load
|
|
@@ -344,14 +361,7 @@ export class FantasyViewModel {
|
|
|
344
361
|
this.rebuildFantasyItems();
|
|
345
362
|
}
|
|
346
363
|
catch (error) {
|
|
347
|
-
|
|
348
|
-
context: 'FantasyViewModel.processFantasy',
|
|
349
|
-
});
|
|
350
|
-
console.error('[FANTASY] Error processing fantasy data:', error);
|
|
351
|
-
this.isDataLoading.value = false;
|
|
352
|
-
if (!this.hasEverSuccessfullyLoaded.value) {
|
|
353
|
-
this.errorState.value = 'tabLoadFailure';
|
|
354
|
-
}
|
|
364
|
+
this.handleFetchError(error, 'FantasyViewModel.processFantasy');
|
|
355
365
|
}
|
|
356
366
|
}
|
|
357
367
|
parseRoto(data, preference) {
|
|
@@ -32,7 +32,7 @@ class StatsService {
|
|
|
32
32
|
return this.networkManager.externalApiRequest({
|
|
33
33
|
endpoint: this.getSyncEndpoint(timeCode),
|
|
34
34
|
method: HttpMethod.GET,
|
|
35
|
-
params: {},
|
|
35
|
+
params: { deviceType: 'ictv' },
|
|
36
36
|
headers: {},
|
|
37
37
|
});
|
|
38
38
|
}
|
|
@@ -50,7 +50,7 @@ class StatsService {
|
|
|
50
50
|
endpoint: this.getSyncEndpoint(timeCode),
|
|
51
51
|
interval,
|
|
52
52
|
method: HttpMethod.GET,
|
|
53
|
-
params: {},
|
|
53
|
+
params: { deviceType: 'ictv' },
|
|
54
54
|
headers: {},
|
|
55
55
|
onData,
|
|
56
56
|
onError,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { HttpMethod } from '@/services/NetworkManager/NetworkManager';
|
|
2
2
|
import { MultiViewLayout } from '../types';
|
|
3
3
|
export type ProductAPIData = {
|
|
4
|
-
|
|
4
|
+
url: string;
|
|
5
5
|
method: HttpMethod;
|
|
6
6
|
headers: Record<string, string>;
|
|
7
|
+
callback?: (error: ProductAPIErrorPayload) => void;
|
|
7
8
|
};
|
|
8
9
|
export type ProductAPIErrorPayload = {
|
|
9
10
|
code: number;
|
|
@@ -25,10 +26,10 @@ export type MultiViewListingResponse = {
|
|
|
25
26
|
export interface CuratedMultiviewResponse {
|
|
26
27
|
status: boolean;
|
|
27
28
|
data?: {
|
|
28
|
-
items?:
|
|
29
|
+
items?: CuratedMultiviewResponseItem[];
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
|
-
interface
|
|
32
|
+
export interface CuratedMultiviewResponseItem {
|
|
32
33
|
entity_id?: string;
|
|
33
34
|
type?: string;
|
|
34
35
|
title?: string;
|
|
@@ -37,21 +38,25 @@ interface CuratedMultiviewItem {
|
|
|
37
38
|
is_sportingevent?: boolean;
|
|
38
39
|
images?: {
|
|
39
40
|
still?: string;
|
|
41
|
+
series_list?: string;
|
|
40
42
|
};
|
|
43
|
+
location?: {
|
|
44
|
+
city?: string;
|
|
45
|
+
state?: string;
|
|
46
|
+
};
|
|
47
|
+
start_time?: string;
|
|
48
|
+
associated_listings?: Array<{
|
|
49
|
+
entity_id?: string;
|
|
50
|
+
title?: string;
|
|
51
|
+
}>;
|
|
41
52
|
multiview?: string[];
|
|
42
|
-
multiview_metadata?:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
entity_id: string;
|
|
46
|
-
type: string;
|
|
47
|
-
is_sportingevent: boolean;
|
|
48
|
-
images: Record<string, unknown>;
|
|
49
|
-
left_team: Team;
|
|
50
|
-
right_team: Team;
|
|
51
|
-
}
|
|
52
|
-
interface Team {
|
|
53
|
-
abbreviation: string;
|
|
53
|
+
multiview_metadata?: CuratedMultiviewResponseItem[];
|
|
54
|
+
left_team?: CuratedMultiviewResponseItemTeam;
|
|
55
|
+
right_team?: CuratedMultiviewResponseItemTeam;
|
|
54
56
|
}
|
|
57
|
+
type CuratedMultiviewResponseItemTeam = {
|
|
58
|
+
abbreviation?: string;
|
|
59
|
+
};
|
|
55
60
|
export declare const isProductAPIValid: (data: any) => data is ProductAPIData;
|
|
56
61
|
/**
|
|
57
62
|
* Service for handling multi-view API calls
|
|
@@ -3,11 +3,14 @@ const MULTIVIEW_BASE_URL = 'https://qa-mvlm.api.shared.digitalvideoplatform.com'
|
|
|
3
3
|
export const isProductAPIValid = (data) => {
|
|
4
4
|
if (!data || typeof data !== 'object')
|
|
5
5
|
return false;
|
|
6
|
-
return (typeof data.
|
|
6
|
+
return (typeof data.url === 'string' &&
|
|
7
|
+
data.url.length > 0 &&
|
|
7
8
|
typeof data.method === 'string' &&
|
|
9
|
+
Object.values(HttpMethod).includes(data.method) &&
|
|
8
10
|
data.headers !== null &&
|
|
9
11
|
typeof data.headers === 'object' &&
|
|
10
|
-
!Array.isArray(data.headers)
|
|
12
|
+
!Array.isArray(data.headers) &&
|
|
13
|
+
(!data.callback || typeof data.callback === 'function'));
|
|
11
14
|
};
|
|
12
15
|
/**
|
|
13
16
|
* Service for handling multi-view API calls
|
|
@@ -64,7 +67,7 @@ class MultiViewService {
|
|
|
64
67
|
return null;
|
|
65
68
|
}
|
|
66
69
|
return this.networkManager.pollExternalApiRequest({
|
|
67
|
-
endpoint: this.productAPI.
|
|
70
|
+
endpoint: this.productAPI.url,
|
|
68
71
|
interval,
|
|
69
72
|
method: this.productAPI.method,
|
|
70
73
|
headers: this.productAPI.headers,
|
|
@@ -42,6 +42,26 @@ export interface NewMultiviewPayload {
|
|
|
42
42
|
multiviewID: string;
|
|
43
43
|
childListings: NewMultiviewChildListing[];
|
|
44
44
|
}
|
|
45
|
+
export type BuildYourOwnTab = 'streams' | 'layouts';
|
|
46
|
+
/**
|
|
47
|
+
* @description Represents a single camera angle within a stream
|
|
48
|
+
*/
|
|
49
|
+
export type Camera = {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
isActive: boolean;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* @description Represents a stream with its cameras and metadata, used in Build Your Own
|
|
56
|
+
*/
|
|
57
|
+
export interface CustomMultiviewStream {
|
|
58
|
+
listing: CuratedMultiviewListing;
|
|
59
|
+
totalCameras: number;
|
|
60
|
+
activeCameraCount: number;
|
|
61
|
+
currentTime?: string;
|
|
62
|
+
location?: string;
|
|
63
|
+
cameras: Camera[];
|
|
64
|
+
}
|
|
45
65
|
/**
|
|
46
66
|
* @description Available layouts organized by stream count
|
|
47
67
|
*/
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import SDK from '@/index';
|
|
3
|
+
import BuildYourOwnTabs from '../components/BuildYourOwnTabs';
|
|
4
|
+
import LayoutSelector from '../components/LayoutSelector';
|
|
5
|
+
import CustomMultiviewStreamsCard from '../components/CustomMultiviewStreamsCard';
|
|
6
|
+
import './BuildYourOwn.styles.css';
|
|
7
|
+
const BuildYourOwn = (props) => {
|
|
8
|
+
const { streams } = props;
|
|
9
|
+
const vm = useRef(null);
|
|
10
|
+
// UI-only state
|
|
11
|
+
const [activeTab, setActiveTab] = useState('streams');
|
|
12
|
+
const [expandedStreamId, setExpandedStreamId] = useState(null);
|
|
13
|
+
const [focusedCameraIndex, setFocusedCameraIndex] = useState(0);
|
|
14
|
+
// Data from VM (subscribed via Observable)
|
|
15
|
+
const [layouts, setLayouts] = useState([]);
|
|
16
|
+
const [selectedLayoutId, setSelectedLayoutId] = useState(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const mvvm = SDK.getMaestroEventViewModel()
|
|
19
|
+
.multiViewViewModel;
|
|
20
|
+
if (!mvvm)
|
|
21
|
+
return;
|
|
22
|
+
vm.current = mvvm;
|
|
23
|
+
setLayouts(mvvm.getLayoutsObservable().value);
|
|
24
|
+
const unsubLayouts = mvvm.getLayoutsObservable().subscribe(setLayouts);
|
|
25
|
+
setSelectedLayoutId(mvvm.getSelectedLayoutId().value);
|
|
26
|
+
const unsubSelectedLayout = mvvm
|
|
27
|
+
.getSelectedLayoutId()
|
|
28
|
+
.subscribe(setSelectedLayoutId);
|
|
29
|
+
return () => {
|
|
30
|
+
unsubLayouts();
|
|
31
|
+
unsubSelectedLayout();
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
const onLayoutSelect = useCallback((layout) => {
|
|
35
|
+
vm.current?.onSelectLayout(layout.layoutId);
|
|
36
|
+
}, []);
|
|
37
|
+
const onStreamEnterPress = useCallback((streamId, cameras) => () => {
|
|
38
|
+
if (expandedStreamId === streamId) {
|
|
39
|
+
const camera = cameras[focusedCameraIndex];
|
|
40
|
+
if (camera) {
|
|
41
|
+
vm.current?.onToggleCamera(streamId, camera.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
setExpandedStreamId(streamId);
|
|
46
|
+
setFocusedCameraIndex(0);
|
|
47
|
+
}
|
|
48
|
+
}, [expandedStreamId, focusedCameraIndex]);
|
|
49
|
+
const onStreamArrowPress = useCallback((streamId, cameras) => (d) => {
|
|
50
|
+
if (d === 'left') {
|
|
51
|
+
SDK.getMaestroEventViewModel().deliverFocus();
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (expandedStreamId === streamId) {
|
|
55
|
+
if (d === 'down') {
|
|
56
|
+
if (focusedCameraIndex < cameras.length - 1) {
|
|
57
|
+
setFocusedCameraIndex((prev) => prev + 1);
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (d === 'up') {
|
|
62
|
+
if (focusedCameraIndex > 0) {
|
|
63
|
+
setFocusedCameraIndex((prev) => prev - 1);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
setExpandedStreamId(null);
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}, [expandedStreamId, focusedCameraIndex]);
|
|
72
|
+
const onStreamBackPress = useCallback((streamId) => () => {
|
|
73
|
+
if (expandedStreamId === streamId) {
|
|
74
|
+
setExpandedStreamId(null);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
SDK.getMaestroEventViewModel().navigation.setFocus('PANEL_NAVIGATION');
|
|
78
|
+
}
|
|
79
|
+
}, [expandedStreamId]);
|
|
80
|
+
const renderTabContent = () => {
|
|
81
|
+
switch (activeTab) {
|
|
82
|
+
case 'streams':
|
|
83
|
+
return (React.createElement("div", { className: "build-your-own-streams" }, streams.map((stream) => {
|
|
84
|
+
const streamId = stream.listing.id;
|
|
85
|
+
const cameras = stream.cameras || [];
|
|
86
|
+
return (React.createElement(CustomMultiviewStreamsCard, { key: streamId, focusKey: `byo-stream-${streamId}`, listing: stream.listing, totalCameras: stream.totalCameras, activeCameraCount: stream.activeCameraCount, currentTime: stream.currentTime, location: stream.location, cameras: cameras, expanded: expandedStreamId === streamId, focusedCameraIndex: expandedStreamId === streamId ? focusedCameraIndex : -1, onToggleCamera: (camera) => vm.current?.onToggleCamera(streamId, camera.id), onEnterPress: onStreamEnterPress(streamId, cameras), onArrowPress: onStreamArrowPress(streamId, cameras), onBackPress: onStreamBackPress(streamId) }));
|
|
87
|
+
})));
|
|
88
|
+
case 'layouts':
|
|
89
|
+
return (React.createElement(LayoutSelector, { layouts: layouts, selectedLayoutId: selectedLayoutId || undefined, onLayoutSelect: onLayoutSelect }));
|
|
90
|
+
default:
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return (React.createElement("div", { className: "build-your-own" },
|
|
95
|
+
React.createElement("div", { className: "build-your-own-header T10" }, "Build Your Own Multiview"),
|
|
96
|
+
React.createElement(BuildYourOwnTabs, { activeTab: activeTab, onSelectTab: setActiveTab }),
|
|
97
|
+
renderTabContent()));
|
|
98
|
+
};
|
|
99
|
+
export default BuildYourOwn;
|