@openeventkit/event-site 2.0.58 → 2.0.60
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/gatsby-ssr.js +3 -1
- package/package.json +2 -1
- package/src/actions/event-actions-definitions.js +2 -1
- package/src/actions/event-actions.js +47 -3
- package/src/actions/user-actions.js +2 -2
- package/src/components/VideoComponent.js +35 -51
- package/src/components/VideoMUXPlayer.js +67 -0
- package/src/content/site-settings/index.json +1 -1
- package/src/content/sponsors.json +1 -1
- package/src/reducers/event-reducer.js +9 -3
- package/src/routes/WithBadgeRoute.js +18 -5
- package/src/templates/event-page.js +39 -24
- package/src/utils/customErrorHandler.js +14 -0
- package/src/utils/videoUtils.js +23 -0
package/gatsby-ssr.js
CHANGED
|
@@ -31,4 +31,6 @@ global.window.matchMedia = () => ({
|
|
|
31
31
|
addListener: () => {},
|
|
32
32
|
removeListener: () => {}
|
|
33
33
|
});
|
|
34
|
-
global.
|
|
34
|
+
global.window.window.requestAnimationFrame = () => {};
|
|
35
|
+
global.window.window.cancelAnimationFrame = () => {};
|
|
36
|
+
global.XMLHttpRequest = XMLHttpRequest;
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openeventkit/event-site",
|
|
3
3
|
"description": "Event Site",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.60",
|
|
5
5
|
"author": "Tipit LLC",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@mui/base": "^5.0.0-alpha.114",
|
|
8
|
+
"@mux/mux-player-react": "^1.14.1",
|
|
8
9
|
"@ncwidgets/file-relation": "^0.8.0",
|
|
9
10
|
"@ncwidgets/id": "^0.8.1",
|
|
10
11
|
"@react-pdf/renderer": "^3.1.12",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const GET_EVENT_DATA = 'GET_EVENT_DATA';
|
|
2
2
|
export const GET_EVENT_DATA_ERROR = 'GET_EVENT_DATA_ERROR';
|
|
3
3
|
export const SET_EVENT_LAST_UPDATE = 'SET_EVENT_LAST_UPDATE';
|
|
4
|
-
export const RELOAD_EVENT_STATE = 'RELOAD_EVENT_STATE';
|
|
4
|
+
export const RELOAD_EVENT_STATE = 'RELOAD_EVENT_STATE';
|
|
5
|
+
export const GET_EVENT_TOKENS='GET_EVENT_TOKENS';
|
|
@@ -12,7 +12,12 @@ import {
|
|
|
12
12
|
import { customErrorHandler } from '../utils/customErrorHandler';
|
|
13
13
|
|
|
14
14
|
import {LOGOUT_USER} from "openstack-uicore-foundation/lib/security/actions";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
GET_EVENT_DATA,
|
|
17
|
+
GET_EVENT_DATA_ERROR,
|
|
18
|
+
GET_EVENT_TOKENS,
|
|
19
|
+
SET_EVENT_LAST_UPDATE,
|
|
20
|
+
} from './event-actions-definitions';
|
|
16
21
|
|
|
17
22
|
export const handleResetReducers = () => (dispatch) => {
|
|
18
23
|
dispatch(createAction(LOGOUT_USER)({}));
|
|
@@ -23,7 +28,6 @@ export const setEventLastUpdate = (lastUpdate) => (dispatch) => {
|
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
|
-
*
|
|
27
31
|
* @param eventId
|
|
28
32
|
* @param checkLocal
|
|
29
33
|
* @returns {(function(*, *): Promise<*>)|*}
|
|
@@ -75,4 +79,44 @@ export const getEventById = (
|
|
|
75
79
|
clearAccessToken();
|
|
76
80
|
return (e);
|
|
77
81
|
});
|
|
78
|
-
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param eventId
|
|
86
|
+
* @param checkLocal
|
|
87
|
+
* @returns {(function(*, *): Promise<*>)|*}
|
|
88
|
+
*/
|
|
89
|
+
export const getEventTokensById = (
|
|
90
|
+
eventId
|
|
91
|
+
) => async (dispatch, getState) => {
|
|
92
|
+
|
|
93
|
+
// then refresh from api
|
|
94
|
+
|
|
95
|
+
let accessToken;
|
|
96
|
+
try {
|
|
97
|
+
accessToken = await getAccessToken();
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.log('getAccessToken error: ', e);
|
|
100
|
+
return Promise.reject();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let params = {
|
|
104
|
+
access_token: accessToken
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return getRequest(
|
|
108
|
+
null,
|
|
109
|
+
createAction(GET_EVENT_TOKENS),
|
|
110
|
+
`${window.SUMMIT_API_BASE_URL}/api/v1/summits/${window.SUMMIT_ID}/events/${eventId}/published/tokens`,
|
|
111
|
+
customErrorHandler,
|
|
112
|
+
{},
|
|
113
|
+
true)
|
|
114
|
+
(params)(dispatch).then((payload) => {
|
|
115
|
+
return payload
|
|
116
|
+
}).catch(e => {
|
|
117
|
+
dispatch(createAction(GET_EVENT_DATA_ERROR)(e));
|
|
118
|
+
console.log('ERROR: ', e);
|
|
119
|
+
clearAccessToken();
|
|
120
|
+
return (e);
|
|
121
|
+
});
|
|
122
|
+
};
|
|
@@ -20,7 +20,7 @@ import QuestionsSet from 'openstack-uicore-foundation/lib/utils/questions-set'
|
|
|
20
20
|
import Swal from 'sweetalert2';
|
|
21
21
|
import axios from "axios";
|
|
22
22
|
import { navigate } from 'gatsby';
|
|
23
|
-
import { customErrorHandler, customBadgeHandler } from '../utils/customErrorHandler';
|
|
23
|
+
import { customErrorHandler, customBadgeHandler, voidErrorHandler } from '../utils/customErrorHandler';
|
|
24
24
|
import { getEnvVariable, SUMMIT_API_BASE_URL, SUMMIT_ID } from "../utils/envVariables";
|
|
25
25
|
|
|
26
26
|
export const GET_DISQUS_SSO = 'GET_DISQUS_SSO';
|
|
@@ -570,7 +570,7 @@ export const doVirtualCheckIn = (attendee) => async (dispatch, getState) => {
|
|
|
570
570
|
createAction(UPDATE_EXTRA_QUESTIONS),
|
|
571
571
|
`${window.API_BASE_URL}/api/v1/summits/${attendee.summit_id}/attendees/${attendee.id}/virtual-check-in`,
|
|
572
572
|
{},
|
|
573
|
-
|
|
573
|
+
voidErrorHandler
|
|
574
574
|
)(params)(dispatch).catch((e) => {
|
|
575
575
|
console.log('ERROR: ', e);
|
|
576
576
|
clearAccessToken();
|
|
@@ -3,29 +3,26 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
|
|
4
4
|
import VideoJSPlayer from './VideoJSPlayer';
|
|
5
5
|
import VimeoPlayer from "./VimeoPlayer";
|
|
6
|
-
|
|
6
|
+
import VideoMUXPlayer from './VideoMUXPlayer';
|
|
7
7
|
import styles from '../styles/video.module.scss';
|
|
8
|
+
import { isMuxVideo, isVimeoVideo, isYouTubeVideo } from '../utils/videoUtils';
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
-
let isLiveVideo = null;
|
|
11
|
-
url.match(/.m3u8/) ? isLiveVideo = true : isLiveVideo = false;
|
|
12
|
-
return isLiveVideo;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const checkVimeoVideo = (url) => {
|
|
16
|
-
// this is get from vimeo dash board
|
|
17
|
-
return url.match(/https:\/\/(www\.)?(player\.)?vimeo.com\/(.*)/);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function checkYouTubeVideo(url) {
|
|
21
|
-
return url.match(/^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/);
|
|
22
|
-
}
|
|
10
|
+
const VideoComponent = ({ url, title, namespace, isLive, firstHalf, autoPlay, start, tokens }) => {
|
|
23
11
|
|
|
24
|
-
const VideoComponent = ({ url, title, namespace, firstHalf, autoPlay, start }) => {
|
|
25
|
-
console.log({ url, title, namespace, firstHalf, autoPlay, start });
|
|
26
12
|
if (url) {
|
|
13
|
+
// using mux player
|
|
14
|
+
if(isMuxVideo(url)) {
|
|
15
|
+
const muxOptions = {
|
|
16
|
+
muted: !!autoPlay,
|
|
17
|
+
startTime: start,
|
|
18
|
+
};
|
|
19
|
+
return (
|
|
20
|
+
<VideoMUXPlayer isLive={isLive ? "live" : "on-demand"} autoPlay={autoPlay}
|
|
21
|
+
title={title} namespace={namespace} videoSrc={url} tokens={tokens} {...muxOptions} />
|
|
22
|
+
);
|
|
23
|
+
}
|
|
27
24
|
// vimeo player
|
|
28
|
-
if (
|
|
25
|
+
if (isVimeoVideo(url)) {
|
|
29
26
|
return (
|
|
30
27
|
<VimeoPlayer
|
|
31
28
|
video={url}
|
|
@@ -35,31 +32,8 @@ const VideoComponent = ({ url, title, namespace, firstHalf, autoPlay, start }) =
|
|
|
35
32
|
/>
|
|
36
33
|
);
|
|
37
34
|
};
|
|
38
|
-
// default mux live
|
|
39
|
-
if (checkLiveVideo(url)) {
|
|
40
|
-
const videoJsOptions = {
|
|
41
|
-
autoplay: autoPlay,
|
|
42
|
-
/*
|
|
43
|
-
TIP: If you want to use autoplay and improve the chances of it working, use the muted attribute
|
|
44
|
-
(or the muted option, with Video.js).
|
|
45
|
-
@see https://blog.videojs.com/autoplay-best-practices-with-video-js/
|
|
46
|
-
*/
|
|
47
|
-
muted: !!autoPlay,
|
|
48
|
-
controls: true,
|
|
49
|
-
fluid: true,
|
|
50
|
-
playsInline: true,
|
|
51
|
-
start: start,
|
|
52
|
-
sources: [{
|
|
53
|
-
src: url,
|
|
54
|
-
type: 'application/x-mpegURL'
|
|
55
|
-
}],
|
|
56
|
-
};
|
|
57
|
-
return (
|
|
58
|
-
<VideoJSPlayer title={title} namespace={namespace} firstHalf={firstHalf} {...videoJsOptions} />
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
35
|
|
|
62
|
-
const
|
|
36
|
+
const defaultVideoJsOptions = isYouTubeVideo(url) ? {
|
|
63
37
|
techOrder: ["youtube"],
|
|
64
38
|
sources: [{
|
|
65
39
|
type: "video/youtube",
|
|
@@ -70,12 +44,6 @@ const VideoComponent = ({ url, title, namespace, firstHalf, autoPlay, start }) =
|
|
|
70
44
|
iv_load_policy: 1
|
|
71
45
|
},
|
|
72
46
|
}: {
|
|
73
|
-
sources: [{
|
|
74
|
-
src: url
|
|
75
|
-
}],
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const videoJsOptions = {
|
|
79
47
|
autoplay: autoPlay,
|
|
80
48
|
/*
|
|
81
49
|
TIP: If you want to use autoplay and improve the chances of it working, use the muted attribute
|
|
@@ -86,11 +54,23 @@ const VideoComponent = ({ url, title, namespace, firstHalf, autoPlay, start }) =
|
|
|
86
54
|
controls: true,
|
|
87
55
|
fluid: true,
|
|
88
56
|
playsInline: true,
|
|
89
|
-
|
|
57
|
+
start: isLive ? start : null,
|
|
58
|
+
sources: isLive ?
|
|
59
|
+
[{
|
|
60
|
+
src: url,
|
|
61
|
+
type: 'application/x-mpegURL'
|
|
62
|
+
}]
|
|
63
|
+
:
|
|
64
|
+
[{
|
|
65
|
+
src: url
|
|
66
|
+
}]
|
|
67
|
+
,
|
|
90
68
|
};
|
|
91
69
|
|
|
70
|
+
const firstHalfProp = isLive ? {firstHalf: firstHalf} : {}
|
|
71
|
+
|
|
92
72
|
return (
|
|
93
|
-
<VideoJSPlayer title={title} namespace={namespace} {...
|
|
73
|
+
<VideoJSPlayer title={title} namespace={namespace} {...firstHalfProp} {...defaultVideoJsOptions} />
|
|
94
74
|
);
|
|
95
75
|
}
|
|
96
76
|
return (<span className="no-video">No video URL Provided</span>);
|
|
@@ -100,15 +80,19 @@ VideoComponent.propTypes = {
|
|
|
100
80
|
url: PropTypes.string.isRequired,
|
|
101
81
|
title: PropTypes.string,
|
|
102
82
|
namespace: PropTypes.string,
|
|
83
|
+
isLive: PropTypes.bool,
|
|
103
84
|
firstHalf: PropTypes.bool,
|
|
104
85
|
autoPlay: PropTypes.bool,
|
|
86
|
+
start: PropTypes.number,
|
|
87
|
+
tokens: PropTypes.object
|
|
105
88
|
};
|
|
106
89
|
|
|
107
90
|
VideoComponent.defaultProps = {
|
|
108
91
|
title: '',
|
|
109
92
|
namespace: '',
|
|
110
93
|
firstHalf: true,
|
|
111
|
-
autoPlay: false,
|
|
94
|
+
autoPlay: false,
|
|
95
|
+
tokens: null,
|
|
112
96
|
};
|
|
113
97
|
|
|
114
98
|
export default VideoComponent;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useState, useRef } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { getEnvVariable, MUX_ENV_KEY } from '../utils/envVariables'
|
|
4
|
+
import { getMUXPlaybackId } from '../utils/videoUtils';
|
|
5
|
+
import Swal from 'sweetalert2';
|
|
6
|
+
// lazy load bc otherwise SSR breaks
|
|
7
|
+
// @see https://www.gatsbyjs.com/docs/using-client-side-only-packages/
|
|
8
|
+
const MuxPlayer = React.lazy(() => import('@mux/mux-player-react'));
|
|
9
|
+
|
|
10
|
+
const VideoMUXPlayer = ({ title, namespace, videoSrc, streamType, tokens, autoPlay, ...muxOptions }) => {
|
|
11
|
+
|
|
12
|
+
const playerRef = useRef(null);
|
|
13
|
+
const [isPlaying, setIsPlaying] = useState(autoPlay);
|
|
14
|
+
|
|
15
|
+
const handleVideoEnded = () => {
|
|
16
|
+
if (streamType === "live") {
|
|
17
|
+
setIsPlaying(false);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const secureProps = tokens ? { tokens: {
|
|
22
|
+
playback: tokens?.playback_token,
|
|
23
|
+
thumbnail: tokens?.thumbnail_token,
|
|
24
|
+
storyboard: tokens?.storyboard_token,
|
|
25
|
+
}} : {}
|
|
26
|
+
|
|
27
|
+
const isSSR = typeof window === "undefined"
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
{!isSSR && (
|
|
31
|
+
<React.Suspense fallback={<></>}>
|
|
32
|
+
<MuxPlayer
|
|
33
|
+
ref={playerRef}
|
|
34
|
+
streamType={streamType}
|
|
35
|
+
envKey={getEnvVariable(MUX_ENV_KEY)}
|
|
36
|
+
playbackId={getMUXPlaybackId(videoSrc)}
|
|
37
|
+
onError={(err) => {
|
|
38
|
+
Swal.fire('Error', 'This video stream will begin momentarily. Please standby.', "warning");
|
|
39
|
+
console.log(err);
|
|
40
|
+
}}
|
|
41
|
+
onEnded={handleVideoEnded}
|
|
42
|
+
autoPlay={isPlaying}
|
|
43
|
+
metadata={{
|
|
44
|
+
video_title: {title},
|
|
45
|
+
sub_property_id: {namespace},
|
|
46
|
+
}}
|
|
47
|
+
style={{aspectRatio: 16 / 9}}
|
|
48
|
+
{...secureProps}
|
|
49
|
+
{...muxOptions}
|
|
50
|
+
/>
|
|
51
|
+
</React.Suspense>
|
|
52
|
+
)}
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
VideoMUXPlayer.propTypes = {
|
|
59
|
+
videoSrc: PropTypes.string.isRequired,
|
|
60
|
+
title: PropTypes.string,
|
|
61
|
+
namespace: PropTypes.string,
|
|
62
|
+
streamType: PropTypes.oneOfType(["live", "on-demand"]),
|
|
63
|
+
autoPlay: PropTypes.bool,
|
|
64
|
+
tokens: PropTypes.object
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default VideoMUXPlayer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"widgets":{"chat":{"enabled":
|
|
1
|
+
{"widgets":{"chat":{"enabled":true,"showQA":false,"showHelp":false,"defaultScope":"page"},"schedule":{"allowClick":true}},"favicons":{"favicon180":"/img/favicon.png","favicon32":"/img/favicon.png","favicon16":"/img/favicon.png"},"staticJsonFilesBuildTime":[{"file":"src/data/summit.json","build_time":1694051984256},{"file":"src/data/events.json","build_time":1694051986915},{"file":"src/data/events.idx.json","build_time":1694051986920},{"file":"src/data/speakers.json","build_time":1694051987917},{"file":"src/data/speakers.idx.json","build_time":1694051987917},{"file":"src/content/sponsors.json","build_time":1694051991031},{"file":"src/data/voteable-presentations.json","build_time":1694051992928}],"lastBuild":1694051992929}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"id":228,"created":1691602669,"last_edited":1691602669,"order":1,"summit_id":49,"is_published":
|
|
1
|
+
[{"id":228,"created":1691602669,"last_edited":1691602669,"order":1,"summit_id":49,"is_published":true,"side_image":null,"header_image":null,"header_image_mobile":null,"carousel_advertise_image":null,"marquee":"","intro":"","external_link":"","video_link":"","chat_link":"","featured_event_id":0,"header_image_alt_text":"","side_image_alt_text":"","header_image_mobile_alt_text":"","carousel_advertise_image_alt_text":"","show_logo_in_event_page":true,"members":[90654,90670],"company":{"id":3,"created":1580138376,"last_edited":1580138376,"name":"Tipit , LLC","url":null,"display_on_site":false,"featured":false,"city":null,"state":null,"country":null,"description":null,"industry":null,"contributions":null,"contact_email":null,"member_level":"None","admin_email":null,"overview":null,"products":null,"commitment":null,"commitment_author":null,"logo":null,"big_logo":null,"color":"#f0f0ee","sponsorships":[616],"project_sponsorships":[]},"sponsorship":{"id":2048,"widget_title":"","lobby_template":null,"expo_hall_template":null,"sponsor_page_template":null,"event_page_template":null,"sponsor_page_use_disqus_widget":false,"sponsor_page_use_live_event_widget":false,"sponsor_page_use_schedule_widget":false,"sponsor_page_use_banner_widget":false,"badge_image":null,"badge_image_alt_text":"","summit_id":49,"order":1,"should_display_on_expo_hall_page":false,"should_display_on_lobby_page":false,"type":{"id":3,"created":1579890943,"last_edited":1579890943,"name":"Gold","label":"not sure??","order":3,"size":"Medium"}},"ads":[],"materials":[],"social_networks":[{"id":2,"created":1694011600,"last_edited":1694011600,"sponsor_id":228,"link":"https://twhitter.com","icon_css_class":"new-icon","is_enabled":true}]}]
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { START_LOADING, STOP_LOADING } from "openstack-uicore-foundation/lib/utils/actions";
|
|
2
2
|
import { LOGOUT_USER } from "openstack-uicore-foundation/lib/security/actions";
|
|
3
|
-
import {GET_EVENT_DATA, GET_EVENT_DATA_ERROR, RELOAD_EVENT_STATE, SET_EVENT_LAST_UPDATE} from "../actions/event-actions-definitions";
|
|
3
|
+
import {GET_EVENT_DATA, GET_EVENT_DATA_ERROR, RELOAD_EVENT_STATE, SET_EVENT_LAST_UPDATE, GET_EVENT_TOKENS} from "../actions/event-actions-definitions";
|
|
4
4
|
import {RESET_STATE} from "../actions/base-actions-definitions";
|
|
5
5
|
|
|
6
6
|
const DEFAULT_STATE = {
|
|
7
7
|
loading: false,
|
|
8
8
|
event: null,
|
|
9
|
-
lastUpdate: null
|
|
9
|
+
lastUpdate: null,
|
|
10
|
+
tokens:null,
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
const eventReducer = (state = DEFAULT_STATE, action) => {
|
|
@@ -25,11 +26,12 @@ const eventReducer = (state = DEFAULT_STATE, action) => {
|
|
|
25
26
|
return { ...state, loading: true };
|
|
26
27
|
case STOP_LOADING:
|
|
27
28
|
return { ...state, loading: false };
|
|
28
|
-
case GET_EVENT_DATA:
|
|
29
|
+
case GET_EVENT_DATA: {
|
|
29
30
|
const event = payload?.response ?? payload.event;
|
|
30
31
|
// check if we need to update the current event or do we need to just use the new one
|
|
31
32
|
const updatedEvent = event.id === state?.event?.id ? {...state, ...event} : event;
|
|
32
33
|
return { ...state, loading: false, event: updatedEvent };
|
|
34
|
+
}
|
|
33
35
|
case GET_EVENT_DATA_ERROR: {
|
|
34
36
|
return { ...state, loading: false, event: null }
|
|
35
37
|
}
|
|
@@ -37,6 +39,10 @@ const eventReducer = (state = DEFAULT_STATE, action) => {
|
|
|
37
39
|
case RELOAD_EVENT_STATE:{
|
|
38
40
|
return {...state, loading:false, event: payload};
|
|
39
41
|
}
|
|
42
|
+
case GET_EVENT_TOKENS:{
|
|
43
|
+
const { tokens } = payload.response
|
|
44
|
+
return {...state, tokens: tokens};
|
|
45
|
+
}
|
|
40
46
|
default:
|
|
41
47
|
return state;
|
|
42
48
|
}
|
|
@@ -2,9 +2,11 @@ import React, {useEffect} from "react";
|
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
import { isAuthorizedBadge } from "../utils/authorizedGroups";
|
|
4
4
|
import HeroComponent from "../components/HeroComponent";
|
|
5
|
-
import {getEventById} from "../actions/event-actions";
|
|
5
|
+
import {getEventById, getEventTokensById} from "../actions/event-actions";
|
|
6
|
+
import { isMuxVideo } from "../utils/videoUtils";
|
|
7
|
+
import {navigate} from "gatsby";
|
|
6
8
|
|
|
7
|
-
const WithBadgeRoute = ({ children, location, eventId, event, loading, userProfile, hasTicket, isAuthorized, getEventById }) => {
|
|
9
|
+
const WithBadgeRoute = ({ children, location, eventId, event, loading, userProfile, hasTicket, isAuthorized, getEventById, getEventTokensById }) => {
|
|
8
10
|
// if user is Authorized then bypass the badge checking
|
|
9
11
|
const hasBadgeForEvent = isAuthorized || (eventId && userProfile && isAuthorizedBadge(event, userProfile.summit_tickets));
|
|
10
12
|
const userIsAuthz = hasTicket || isAuthorized;
|
|
@@ -21,9 +23,20 @@ const WithBadgeRoute = ({ children, location, eventId, event, loading, userProfi
|
|
|
21
23
|
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
if (event === null || parseInt(eventId) !== parseInt(event.id)) {
|
|
24
|
-
getEventById(eventId)
|
|
26
|
+
getEventById(eventId).then((res) => {
|
|
27
|
+
const { response, err } = res;
|
|
28
|
+
// check error
|
|
29
|
+
if(err && err?.status === 404){
|
|
30
|
+
navigate('/a/schedule');
|
|
31
|
+
}
|
|
32
|
+
if(response && response?.stream_is_secure && isMuxVideo(response?.streaming_url)){
|
|
33
|
+
getEventTokensById(eventId)
|
|
34
|
+
}
|
|
35
|
+
}).catch(err => {
|
|
36
|
+
console.log(err);
|
|
37
|
+
});
|
|
25
38
|
}
|
|
26
|
-
}, [eventId, getEventById, event]);
|
|
39
|
+
}, [eventId, getEventById, event, getEventTokensById]);
|
|
27
40
|
|
|
28
41
|
if (loading || needsToLoadEvent) {
|
|
29
42
|
return <HeroComponent title="Loading event" />;
|
|
@@ -44,4 +57,4 @@ const mapStateToProps = ({ userState, eventState }) => ({
|
|
|
44
57
|
loading: eventState.loading,
|
|
45
58
|
});
|
|
46
59
|
|
|
47
|
-
export default connect(mapStateToProps, {getEventById})(WithBadgeRoute);
|
|
60
|
+
export default connect(mapStateToProps, {getEventById, getEventTokensById})(WithBadgeRoute);
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
-
import {navigate} from "gatsby";
|
|
4
3
|
import {connect} from "react-redux";
|
|
5
4
|
import { isEqual } from "lodash";
|
|
6
5
|
import Layout from "../components/Layout";
|
|
7
|
-
//import EventHeroComponent from "../components/EventHeroComponent";
|
|
8
6
|
import DisqusComponent from "../components/DisqusComponent";
|
|
9
7
|
import AdvertiseComponent from "../components/AdvertiseComponent";
|
|
10
8
|
import Etherpad from "../components/Etherpad";
|
|
@@ -21,9 +19,10 @@ import AccessTracker, {AttendeesWidget} from "../components/AttendeeToAttendeeWi
|
|
|
21
19
|
import AttendanceTrackerComponent from "../components/AttendanceTrackerComponent";
|
|
22
20
|
import EventFeedbackComponent from "../components/EventFeedbackComponent"
|
|
23
21
|
import {PHASES} from "../utils/phasesUtils";
|
|
24
|
-
import { getEventById } from "../actions/event-actions";
|
|
22
|
+
import { getEventById, getEventTokensById } from "../actions/event-actions";
|
|
25
23
|
import URI from "urijs";
|
|
26
24
|
import useMarketingSettings, { MARKETING_SETTINGS_KEYS } from "@utils/useMarketingSettings";
|
|
25
|
+
import { checkMuxTokens, isMuxVideo } from "../utils/videoUtils";
|
|
27
26
|
/**
|
|
28
27
|
* @type {EventPageTemplate}
|
|
29
28
|
*/
|
|
@@ -31,21 +30,14 @@ export const EventPageTemplate = class extends React.Component {
|
|
|
31
30
|
|
|
32
31
|
constructor(props) {
|
|
33
32
|
super(props);
|
|
34
|
-
this.onEventChange = this.onEventChange.bind(this);
|
|
35
33
|
this.canRenderVideo = this.canRenderVideo.bind(this);
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
onEventChange(ev) {
|
|
39
|
-
const {eventId} = this.props;
|
|
40
|
-
if (parseInt(eventId) !== parseInt(ev.id)) {
|
|
41
|
-
navigate(`/a/event/${ev.id}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
36
|
shouldComponentUpdate(nextProps, nextState) {
|
|
46
|
-
const {eventId, event, eventsPhases, lastDataSync} = this.props;
|
|
37
|
+
const {eventId, event, eventTokens, eventsPhases, lastDataSync} = this.props;
|
|
47
38
|
if (eventId !== nextProps.eventId) return true;
|
|
48
39
|
if (!isEqual(event, nextProps.event)) return true;
|
|
40
|
+
if (!isEqual(eventTokens, nextProps.eventTokens)) return true;
|
|
49
41
|
// a synch did happened!
|
|
50
42
|
if(lastDataSync !== nextProps.lastDataSync) return true;
|
|
51
43
|
// compare current event phase with next one
|
|
@@ -67,20 +59,28 @@ export const EventPageTemplate = class extends React.Component {
|
|
|
67
59
|
const {eventId: prevEventId} = prevProps;
|
|
68
60
|
// event id could come as param at uri
|
|
69
61
|
if (parseInt(eventId) !== parseInt(prevEventId) || parseInt(event?.id) !== parseInt(eventId)) {
|
|
70
|
-
this.props.getEventById(eventId)
|
|
62
|
+
this.props.getEventById(eventId).then((res) => {
|
|
63
|
+
const { response } = res;
|
|
64
|
+
if(response && response?.stream_is_secure && isMuxVideo(response?.streaming_url)) // todo check
|
|
65
|
+
this.props.getEventTokensById(eventId)
|
|
66
|
+
});
|
|
71
67
|
}
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
componentDidMount() {
|
|
75
71
|
const {eventId, event } = this.props;
|
|
76
72
|
if (parseInt(event?.id) !== parseInt(eventId)) {
|
|
77
|
-
this.props.getEventById(eventId)
|
|
73
|
+
this.props.getEventById(eventId).then((res) => {
|
|
74
|
+
const { response } = res;
|
|
75
|
+
if(response && response?.stream_is_secure && isMuxVideo(response?.streaming_url)) // todo check stream url is mux
|
|
76
|
+
this.props.getEventTokensById(eventId)
|
|
77
|
+
});
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
render() {
|
|
82
82
|
|
|
83
|
-
const {event, user, loading, nowUtc, summit, eventsPhases, eventId, lastDataSync, activityCtaText} = this.props;
|
|
83
|
+
const {event, eventTokens, user, loading, nowUtc, summit, eventsPhases, eventId, lastDataSync, activityCtaText} = this.props;
|
|
84
84
|
// get current event phase
|
|
85
85
|
const currentPhaseInfo = eventsPhases.find((e) => parseInt(e.id) === parseInt(eventId));
|
|
86
86
|
const currentPhase = currentPhaseInfo?.phase;
|
|
@@ -100,21 +100,26 @@ export const EventPageTemplate = class extends React.Component {
|
|
|
100
100
|
return <HeroComponent title="Event not found" redirectTo="/a/schedule"/>;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
if(isMuxVideo(event?.streaming_url) && event?.stream_is_secure && ! checkMuxTokens(eventTokens)){
|
|
104
|
+
return <HeroComponent title="Loading secure event"/>;
|
|
105
|
+
}
|
|
106
|
+
|
|
103
107
|
return (
|
|
104
108
|
<React.Fragment>
|
|
105
|
-
{/* <EventHeroComponent /> */}
|
|
106
109
|
<section className="section px-0 py-0">
|
|
107
110
|
<div className="columns is-gapless">
|
|
108
111
|
{this.canRenderVideo(currentPhase) ? (
|
|
109
112
|
<div className="column is-three-quarters px-0 py-0">
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
<VideoComponent
|
|
114
|
+
url={event.streaming_url}
|
|
115
|
+
tokens={eventTokens}
|
|
116
|
+
isLive={event.streaming_type === "LIVE"}
|
|
117
|
+
title={event.title}
|
|
118
|
+
namespace={summit.name}
|
|
119
|
+
firstHalf={firstHalf}
|
|
120
|
+
autoPlay={autoPlay}
|
|
121
|
+
start={startTime}
|
|
122
|
+
/>
|
|
118
123
|
{event.meeting_url && <VideoBanner event={event} ctaText={activityCtaText} />}
|
|
119
124
|
</div>
|
|
120
125
|
) : (
|
|
@@ -211,11 +216,13 @@ const EventPage = ({
|
|
|
211
216
|
location,
|
|
212
217
|
loading,
|
|
213
218
|
event,
|
|
219
|
+
eventTokens,
|
|
214
220
|
eventId,
|
|
215
221
|
user,
|
|
216
222
|
eventsPhases,
|
|
217
223
|
nowUtc,
|
|
218
224
|
getEventById,
|
|
225
|
+
getEventTokensById,
|
|
219
226
|
lastUpdate,
|
|
220
227
|
lastDataSync
|
|
221
228
|
}) => {
|
|
@@ -235,6 +242,7 @@ const EventPage = ({
|
|
|
235
242
|
<EventPageTemplate
|
|
236
243
|
summit={summit}
|
|
237
244
|
event={event}
|
|
245
|
+
eventTokens={eventTokens}
|
|
238
246
|
eventId={eventId}
|
|
239
247
|
loading={loading}
|
|
240
248
|
user={user}
|
|
@@ -242,6 +250,7 @@ const EventPage = ({
|
|
|
242
250
|
nowUtc={nowUtc}
|
|
243
251
|
location={location}
|
|
244
252
|
getEventById={getEventById}
|
|
253
|
+
getEventTokensById={getEventTokensById}
|
|
245
254
|
lastUpdate={lastUpdate}
|
|
246
255
|
activityCtaText={activityCtaText}
|
|
247
256
|
lastDataSync={lastDataSync}
|
|
@@ -253,21 +262,25 @@ const EventPage = ({
|
|
|
253
262
|
EventPage.propTypes = {
|
|
254
263
|
loading: PropTypes.bool,
|
|
255
264
|
event: PropTypes.object,
|
|
265
|
+
eventTokens: PropTypes.object,
|
|
256
266
|
lastUpdate: PropTypes.object,
|
|
257
267
|
eventId: PropTypes.string,
|
|
258
268
|
user: PropTypes.object,
|
|
259
269
|
eventsPhases: PropTypes.array,
|
|
260
270
|
getEventById: PropTypes.func,
|
|
271
|
+
getEventTokensById: PropTypes.func,
|
|
261
272
|
};
|
|
262
273
|
|
|
263
274
|
EventPageTemplate.propTypes = {
|
|
264
275
|
event: PropTypes.object,
|
|
276
|
+
eventTokens: PropTypes.object,
|
|
265
277
|
lastUpdate: PropTypes.object,
|
|
266
278
|
loading: PropTypes.bool,
|
|
267
279
|
eventId: PropTypes.string,
|
|
268
280
|
user: PropTypes.object,
|
|
269
281
|
eventsPhases: PropTypes.array,
|
|
270
282
|
getEventById: PropTypes.func,
|
|
283
|
+
getEventTokensById: PropTypes.func,
|
|
271
284
|
activityCtaText: PropTypes.string,
|
|
272
285
|
};
|
|
273
286
|
|
|
@@ -280,6 +293,7 @@ const mapStateToProps = ({
|
|
|
280
293
|
}) => ({
|
|
281
294
|
loading: eventState.loading,
|
|
282
295
|
event: eventState.event,
|
|
296
|
+
eventTokens: eventState.tokens,
|
|
283
297
|
user: userState,
|
|
284
298
|
summit: summitState.summit,
|
|
285
299
|
eventsPhases: clockState.events_phases,
|
|
@@ -290,4 +304,5 @@ const mapStateToProps = ({
|
|
|
290
304
|
|
|
291
305
|
export default connect(mapStateToProps, {
|
|
292
306
|
getEventById,
|
|
307
|
+
getEventTokensById,
|
|
293
308
|
})(EventPage);
|
|
@@ -25,6 +25,20 @@ export const customErrorHandler = (err, res) => (dispatch, state) => {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export const voidErrorHandler = (err, res) => (dispatch, state) => {
|
|
29
|
+
let code = err.status;
|
|
30
|
+
dispatch(stopLoading());
|
|
31
|
+
let msg = '';
|
|
32
|
+
switch (code) {
|
|
33
|
+
case 401:
|
|
34
|
+
console.log('authErrorHandler 401 - re login');
|
|
35
|
+
expiredToken(err);
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
export const customBadgeHandler = (err, res) => (dispatch, state) => {
|
|
29
43
|
let code = err.status;
|
|
30
44
|
dispatch(stopLoading());
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const IS_MUX_VIDEO_REGEX = /https:\/\/stream.mux.com\/(.*).m3u8/;
|
|
2
|
+
|
|
3
|
+
export const getMUXPlaybackId = (url) => {
|
|
4
|
+
const fileMatch = url.match(IS_MUX_VIDEO_REGEX);
|
|
5
|
+
return fileMatch ? fileMatch[1] : null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const checkMuxTokens = (tokens) => {
|
|
9
|
+
return tokens && tokens.playback_token && tokens.thumbnail_token && tokens.storyboard_token;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const isVimeoVideo = (url) => {
|
|
13
|
+
// this is get from vimeo dash board
|
|
14
|
+
return url.match(/https:\/\/(www\.)?(player\.)?vimeo.com\/(.*)/);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const isYouTubeVideo = (url) => {
|
|
18
|
+
return url.match(/^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const isMuxVideo = (url) => {
|
|
22
|
+
return url.match(IS_MUX_VIDEO_REGEX)
|
|
23
|
+
}
|