@openeventkit/event-site 2.0.122 → 2.0.123-beta.2

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/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "@openeventkit/event-site",
3
3
  "description": "Event Site",
4
- "version": "2.0.122",
4
+ "version": "2.0.123-beta.2",
5
5
  "author": "Tipit LLC",
6
6
  "dependencies": {
7
+ "@emotion/cache": "^11.13.1",
7
8
  "@fortawesome/fontawesome-svg-core": "^6.5.2",
8
9
  "@fortawesome/free-brands-svg-icons": "^6.5.2",
9
10
  "@fortawesome/react-fontawesome": "^0.2.2",
10
11
  "@mdx-js/react": "^3.0.1",
11
12
  "@mdx-js/runtime": "^1.6.22",
12
13
  "@mui/base": "^5.0.0-beta.40",
14
+ "@mui/icons-material": "^5.16.7",
15
+ "@mui/material": "^5.16.7",
16
+ "@mui/system": "^5.16.7",
13
17
  "@mux/mux-player-react": "^1.14.1",
14
18
  "@ncwidgets/file-relation": "^0.8.0",
15
19
  "@ncwidgets/id": "^0.8.1",
@@ -28,7 +32,7 @@
28
32
  "@vimeo/player": "^2.16.3",
29
33
  "ably": "^1.2.34",
30
34
  "assert": "^2.1.0",
31
- "attendee-to-attendee-widget": "3.1.1-beta.29",
35
+ "attendee-to-attendee-widget": "3.1.1-beta.32",
32
36
  "autoprefixer": "10.4.14",
33
37
  "awesome-bootstrap-checkbox": "^1.0.1",
34
38
  "axios": "^0.19.2",
@@ -29,23 +29,14 @@ export const setEventLastUpdate = (lastUpdate) => (dispatch) => {
29
29
 
30
30
  /**
31
31
  * @param eventId
32
- * @param checkLocal
33
32
  * @returns {(function(*, *): Promise<*>)|*}
34
33
  */
35
34
  export const getEventById = (
36
35
  eventId
37
- ) => async (dispatch, getState) => {
36
+ ) => async (dispatch) => {
38
37
 
39
38
  dispatch(startLoading());
40
- // if we have it on the reducer , provide that first
41
- let {allSchedulesState: {allEvents}} = getState();
42
- const event = allEvents.find(ev => ev.id === parseInt(eventId));
43
-
44
- if (event) {
45
- dispatch(createAction(GET_EVENT_DATA)({event}));
46
- }
47
39
 
48
- // then refresh from api
49
40
  let accessToken;
50
41
  try {
51
42
  accessToken = await getAccessToken();
@@ -0,0 +1,251 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import AvatarEditor from "react-avatar-editor";
3
+ import { Box, Typography, Slider, Modal } from "@mui/material";
4
+ import { Button, IconButton } from "../ui";
5
+ import { styled } from "@mui/system";
6
+ import {
7
+ //Close as CloseIcon,
8
+ CameraAlt as CameraAltIcon,
9
+ RotateLeft as RotateLeftIcon,
10
+ RotateRight as RotateRightIcon,
11
+ } from "@mui/icons-material";
12
+ import { create_UUID } from "@utils/uuidGenerator";
13
+
14
+ const CustomSlider = styled(Slider)(({ theme }) => ({
15
+ color: "var(--color-primary)"
16
+ }));
17
+
18
+ const AvatarEditorModal = ({
19
+ userProfile,
20
+ open,
21
+ changePicture,
22
+ handleClose
23
+ }) => {
24
+ const editorRef = useRef(null);
25
+ const fileInputRef = useRef(null);
26
+
27
+ const [image, setImage] = useState(userProfile.picture || null);
28
+ const [position, setPosition] = useState({ x: 0.5, y: 0.5 });
29
+ const [scale, setScale] = useState(1);
30
+ const [rotate, setRotate] = useState(0);
31
+ const [newImage, setNewImage] = useState(false);
32
+
33
+ useEffect(() => {
34
+ setImage(userProfile.picture);
35
+ }, [userProfile.picture]);
36
+
37
+ const handleNewImage = (e) => {
38
+ setImage(e.target.files[0]);
39
+ setNewImage(true);
40
+ };
41
+
42
+ const handleScale = (e, newValue) => {
43
+ setScale(newValue);
44
+ setNewImage(true);
45
+ };
46
+
47
+ const handlePositionChange = (newPosition) => {
48
+ setPosition(newPosition);
49
+ setNewImage(true);
50
+ };
51
+
52
+ const rotateLeft = () => {
53
+ setRotate((prev) => prev - 22.5);
54
+ setNewImage(true);
55
+ };
56
+
57
+ const rotateRight = () => {
58
+ setRotate((prev) => prev + 22.5);
59
+ setNewImage(true);
60
+ };
61
+
62
+ const handleSave = () => {
63
+ if (editorRef.current && newImage) {
64
+ const canvas = editorRef.current.getImage().toDataURL();
65
+ fetch(canvas)
66
+ .then((res) => res.blob())
67
+ .then((blob) => {
68
+ const file = new File([blob], `${create_UUID()}.png`, { type: blob.type });
69
+ changePicture(file);
70
+ });
71
+ }
72
+ };
73
+
74
+ return (
75
+ <Modal
76
+ open={open}
77
+ onClose={handleClose}
78
+ aria-labelledby="avatar-modal-title"
79
+ sx={{
80
+ display: "flex",
81
+ alignItems: "center",
82
+ justifyContent: "center"
83
+ }}
84
+ >
85
+ <Box
86
+ sx={{
87
+ width: { xs: "100%", sm: 400 },
88
+ bgcolor: "var(--color_background_light)",
89
+ color: "var(--color_text_dark)",
90
+ display: "flex",
91
+ flexDirection: "column",
92
+ position: "relative",
93
+ border: "1px solid #dbdbdb"
94
+ }}
95
+ >
96
+ <Box
97
+ sx={{
98
+ padding: "7.5px 15px",
99
+ display: "flex",
100
+ alignItems: "center",
101
+ borderBottom: "1px solid #dbdbdb"
102
+ }}
103
+ >
104
+ <Typography
105
+ id="avatar-modal-title"
106
+ component="h2"
107
+ sx={{
108
+ fontWeight: "bold",
109
+ color: "var(--color_text_dark)",
110
+ fontFamily: "var(--font_family)",
111
+ fontSize: "18px"
112
+ }}
113
+ >
114
+ Edit Profile Picture
115
+ </Typography>
116
+ <IconButton
117
+ onClick={handleClose}
118
+ sx={{
119
+ ml: "auto",
120
+ fontSize: "16px",
121
+ padding: 0
122
+ }}
123
+ >
124
+ <i className="fa fa-times" />
125
+ </IconButton>
126
+ </Box>
127
+ <Box
128
+ sx={{
129
+ padding: "20px",
130
+ textAlign: "center",
131
+ position: "relative"
132
+ }}
133
+ >
134
+ <AvatarEditor
135
+ ref={editorRef}
136
+ image={image}
137
+ width={200}
138
+ height={200}
139
+ border={50}
140
+ color={[0, 0, 0, 0.8]}
141
+ position={position}
142
+ onPositionChange={handlePositionChange}
143
+ scale={scale}
144
+ rotate={rotate}
145
+ crossOrigin={"anonymous"}
146
+ />
147
+ <IconButton
148
+ onClick={() => fileInputRef.current.click()}
149
+ sx={{
150
+ position: "absolute",
151
+ top: "79.5%",
152
+ right: "44%",
153
+ color: "#fff"
154
+ }}
155
+ >
156
+ <CameraAltIcon fontSize="inherit" />
157
+ </IconButton>
158
+ <input
159
+ ref={fileInputRef}
160
+ type="file"
161
+ accept=".jpg,.jpeg,.png"
162
+ style={{ display: "none" }}
163
+ onChange={handleNewImage}
164
+ />
165
+ </Box>
166
+ <Box
167
+ sx={{
168
+ px: "20px",
169
+ display: "flex",
170
+ flexDirection: "column",
171
+ gap: "20px"
172
+ }}
173
+ >
174
+ <Box
175
+ sx={{
176
+ display: "flex",
177
+ alignItems: "center",
178
+ gap: "20px",
179
+ justifyContent: "center"
180
+ }}
181
+ >
182
+ <Typography
183
+ sx={{
184
+ fontSize: "1.5rem",
185
+ fontFamily: "var(--font_family)"
186
+ }
187
+ }>
188
+ Zoom
189
+ </Typography>
190
+ <CustomSlider
191
+ value={scale}
192
+ min={0}
193
+ max={2}
194
+ step={0.01}
195
+ onChange={handleScale}
196
+ sx={{ flex: 1, mx: 2 }}
197
+ />
198
+ </Box>
199
+ <Box
200
+ sx={{
201
+ display: "flex",
202
+ alignItems: "center"
203
+ }}
204
+ >
205
+ <Typography
206
+ sx={{
207
+ fontSize: "1.5rem",
208
+ fontFamily: "var(--font_family)"
209
+ }}
210
+ >
211
+ Rotate
212
+ </Typography>
213
+ <Box
214
+ sx={{
215
+ display: "flex",
216
+ flex: 1,
217
+ justifyContent: "center",
218
+ gap: "20px"
219
+ }}
220
+ >
221
+ <IconButton onClick={rotateLeft}>
222
+ <RotateLeftIcon fontSize="inherit" />
223
+ </IconButton>
224
+ <IconButton onClick={rotateRight}>
225
+ <RotateRightIcon fontSize="inherit" />
226
+ </IconButton>
227
+ </Box>
228
+ </Box>
229
+ </Box>
230
+ <Box
231
+ sx={{
232
+ backgroundColor: "var(--color_background_light)",
233
+ display: "flex",
234
+ justifyContent: "space-between",
235
+ padding: "20px",
236
+ gap: "20px"
237
+ }}
238
+ >
239
+ <Button onClick={handleClose}>
240
+ Discard
241
+ </Button>
242
+ <Button onClick={handleSave} disabled={!newImage}>
243
+ Update
244
+ </Button>
245
+ </Box>
246
+ </Box>
247
+ </Modal>
248
+ );
249
+ };
250
+
251
+ export default AvatarEditorModal;
@@ -1,13 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { useMemo } from "react";
3
3
  import { connect } from "react-redux";
4
+ import { navigate } from "gatsby";
4
5
  import NavbarTemplate from "./template";
5
6
 
6
- import {
7
- updateProfile,
8
- updateProfilePicture
9
- } from "../../actions/user-actions";
10
-
11
7
  import { userHasAccessLevel, VirtualAccessLevel } from "@utils/authorizedGroups";
12
8
  import { getDefaultLocation } from "@utils/loginUtils";
13
9
 
@@ -21,11 +17,8 @@ const Navbar = ({
21
17
  summitPhase,
22
18
  summit,
23
19
  isLoggedUser,
24
- idpLoading,
25
20
  idpProfile,
26
21
  userProfile,
27
- updateProfile,
28
- updateProfilePicture,
29
22
  eventRedirect
30
23
  }) => {
31
24
 
@@ -105,20 +98,21 @@ const Navbar = ({
105
98
  passPageRestriction;
106
99
  };
107
100
 
101
+ const handleLogoClick = () => navigate(isLoggedUser ? defaultPath : "/");
102
+
103
+ const handleProfileIconClick = () => navigate("/a/profile");
104
+
108
105
  return (
109
106
  <NavbarTemplate
110
- data={navbarContent.items.filter(showItem)}
107
+ items={navbarContent.items.filter(showItem)}
111
108
  summit={summit}
109
+ logo={summit?.logo}
110
+ onLogoClick={handleLogoClick}
112
111
  isLoggedUser={isLoggedUser}
113
- idpLoading={idpLoading}
114
112
  idpProfile={idpProfile}
115
- hasVirtualBadge={hasVirtualBadge}
116
- updateProfile={updateProfile}
117
- updateProfilePicture={updateProfilePicture}
118
- defaultPath={defaultPath}
119
- logo={summit?.logo}
113
+ onProfileIconClick={handleProfileIconClick}
120
114
  />
121
- )
115
+ );
122
116
  };
123
117
 
124
118
 
@@ -129,17 +123,13 @@ const mapStateToProps = ({
129
123
  loggedUserState,
130
124
  userState
131
125
  }) => ({
132
- summitPhase: clockState.summit_phase,
133
126
  summit: summitState.summit,
127
+ summitPhase: clockState.summit_phase,
134
128
  isLoggedUser: loggedUserState.isLoggedUser,
135
129
  idpProfile: userState.idpProfile,
136
- idpLoading: userState.loadingIDP,
137
130
  userProfile: userState.userProfile,
138
131
  // TODO: move to site settings i/o marketing page settings
139
132
  eventRedirect: settingState.marketingPageSettings.eventRedirect
140
133
  });
141
134
 
142
- export default connect(mapStateToProps, {
143
- updateProfile,
144
- updateProfilePicture
145
- })(Navbar);
135
+ export default connect(mapStateToProps, {})(Navbar);
@@ -1,108 +1,88 @@
1
1
  import React, { useState } from "react";
2
-
3
2
  import Link from "../Link";
4
- import ProfilePopupComponent from "../ProfilePopupComponent";
5
3
  import LogoutButton from "../LogoutButton";
6
4
 
7
5
  import styles from "../../styles/navbar.module.scss";
8
6
 
9
7
  const NavbarTemplate = ({
10
- data,
8
+ items,
9
+ logo,
11
10
  summit,
12
11
  isLoggedUser,
13
- idpLoading,
14
12
  idpProfile,
15
- updateProfile,
16
- updateProfilePicture,
17
- defaultPath,
18
- logo
13
+ onLogoClick,
14
+ onProfileIconClick
19
15
  }) => {
20
16
  const [active, setActive] = useState(false);
21
- const [showProfile, setShowProfile] = useState(false);
22
17
 
23
- const toggleHamburger = () => {
24
- // toggle the active boolean in the state
25
- setActive(!active);
26
- };
18
+ const toggleHamburger = () => setActive(!active);
19
+
20
+ const navBarActiveClass = active ? styles.isActive : "";
21
+
22
+ const renderLogo = () => {
23
+ if (!logo && !summit?.name) return null;
24
+
25
+ const logoContent = logo ? <img src={logo} alt={summit?.name || "Logo"} /> : <h4>{summit.name}</h4>;
27
26
 
28
- const handleTogglePopup = () => {
29
- if (showProfile) {
30
- document.body.classList.remove("is-clipped");
31
- } else {
32
- document.body.classList.add("is-clipped");
33
- }
34
- setShowProfile(!showProfile);
27
+ return onLogoClick ? (
28
+ <button className={`link ${styles.navbarItem}`} onClick={onLogoClick}>
29
+ {logoContent}
30
+ </button>
31
+ ) : (
32
+ <div className={styles.navbarItem}>{logoContent}</div>
33
+ );
35
34
  };
36
35
 
37
- const navBarActiveClass = active ? styles.isActive : "";
36
+ const renderProfileIcon = () => {
37
+ if (!isLoggedUser || !idpProfile?.picture) return null;
38
38
 
39
- return (
40
- <React.Fragment>
41
- <nav
42
- className={`${styles.navbar}`}
43
- role="navigation"
44
- aria-label="main navigation"
45
- >
46
- <div className={styles.navbarBrand}>
47
- <Link
48
- to={isLoggedUser ? defaultPath : "/"}
49
- className={styles.navbarItem}
50
- >
51
- {logo && <img src={logo} alt={summit.name} />}
52
- </Link>
39
+ const profilePic = (
40
+ <img alt={idpProfile?.name} className={styles.profilePic} src={idpProfile.picture} />
41
+ );
53
42
 
54
- <button
55
- className={`link ${styles.navbarBurger} ${styles.burger} ${navBarActiveClass}`}
56
- aria-label="menu"
57
- aria-expanded="false"
58
- data-target="navbar"
59
- onClick={() => toggleHamburger()}
60
- >
61
- <span aria-hidden="true" />
62
- <span aria-hidden="true" />
63
- <span aria-hidden="true" />
64
- </button>
65
- </div>
43
+ return onProfileIconClick ? (
44
+ <div className={styles.navbarItem}>
45
+ <button className="link" onClick={onProfileIconClick}>
46
+ {profilePic}
47
+ </button>
48
+ </div>
49
+ ) : (
50
+ <div className={styles.navbarItem}>{profilePic}</div>
51
+ );
52
+ };
66
53
 
67
- <div
68
- id="navbar"
69
- className={`${styles.navbarMenu} ${navBarActiveClass}`}
54
+ return (
55
+ <nav className={styles.navbar} role="navigation" aria-label="main navigation">
56
+ <div className={styles.navbarBrand}>
57
+ {renderLogo()}
58
+ <button
59
+ className={`link ${styles.navbarBurger} ${styles.burger} ${navBarActiveClass}`}
60
+ aria-label="menu"
61
+ aria-expanded="false"
62
+ data-target="navbar"
63
+ onClick={toggleHamburger}
70
64
  >
71
- <div className={styles.navbarStart} />
72
- <div className={styles.navbarEnd}>
73
- {data.map((item, index) => (
74
- <div className={styles.navbarItem} key={index}>
75
- <Link to={item.link} className={styles.link}>
76
- <span>{item.title}</span>
77
- </Link>
78
- </div>
79
- ))}
80
- {isLoggedUser && (
81
- <div className={styles.navbarItem}>
82
- <button className="link" onClick={() => handleTogglePopup()}>
83
- <img
84
- alt="profile pic"
85
- className={styles.profilePic}
86
- src={idpProfile?.picture}
87
- />
88
- </button>
89
- {showProfile && (
90
- <ProfilePopupComponent
91
- userProfile={idpProfile}
92
- showProfile={showProfile}
93
- idpLoading={idpLoading}
94
- changePicture={updateProfilePicture}
95
- changeProfile={updateProfile}
96
- closePopup={() => handleTogglePopup()}
97
- />
98
- )}
99
- </div>
100
- )}
101
- <LogoutButton styles={styles} isLoggedUser={isLoggedUser} />
102
- </div>
65
+ <span aria-hidden="true" />
66
+ <span aria-hidden="true" />
67
+ <span aria-hidden="true" />
68
+ </button>
69
+ </div>
70
+
71
+ <div id="navbar" className={`${styles.navbarMenu} ${navBarActiveClass}`}>
72
+ <div className={styles.navbarStart} />
73
+ <div className={styles.navbarEnd}>
74
+ {items?.map((item, index) => (
75
+ <div className={styles.navbarItem} key={index}>
76
+ <Link to={item.link} className={styles.link}>
77
+ <span>{item.title}</span>
78
+ </Link>
79
+ </div>
80
+ ))}
81
+ {renderProfileIcon()}
82
+ <LogoutButton styles={styles} isLoggedUser={isLoggedUser} />
103
83
  </div>
104
- </nav>
105
- </React.Fragment>
84
+ </div>
85
+ </nav>
106
86
  );
107
87
  };
108
88
 
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {getSynchWordsVideoFrameDdFromSrc} from "../utils/videoUtils";
4
+
5
+
6
+ class SynchWordsPlayer extends React.Component {
7
+
8
+ constructor(props) {
9
+ super(props);
10
+ }
11
+
12
+ componentDidMount() {
13
+ }
14
+
15
+ componentWillUnmount() {
16
+ }
17
+
18
+ render() {
19
+ const { video, className, autoplay } = this.props;
20
+ const id = getSynchWordsVideoFrameDdFromSrc(video);
21
+ console.log(`SynchWordsPlayer::render with id ${id}`);
22
+ let allow = "encrypted-media";
23
+ if(autoplay) allow = allow +';autoplay'
24
+ return (
25
+ <div className={className}>
26
+ <iframe id={id}
27
+ src={video}
28
+ frameBorder="0"
29
+ scrolling="no"
30
+ allow={allow}
31
+ allowFullScreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen
32
+ >
33
+ </iframe>
34
+ </div>
35
+ );
36
+ }
37
+ }
38
+
39
+ SynchWordsPlayer.propTypes = {
40
+ /**
41
+ * a video URL.
42
+ */
43
+ video: PropTypes.oneOfType([
44
+ PropTypes.number,
45
+ PropTypes.string,
46
+ ]),
47
+ /**
48
+ * CSS className for the player element.
49
+ */
50
+ className: PropTypes.string,
51
+ /**
52
+ * Automatically start playback of the video. Note that this won’t work on
53
+ * some devices.
54
+ */
55
+ autoplay: PropTypes.bool,
56
+ };
57
+
58
+ export default SynchWordsPlayer;
@@ -4,7 +4,8 @@ import VideoJSPlayer from './VideoJSPlayer';
4
4
  import VimeoPlayer from "./VimeoPlayer";
5
5
  import VideoMUXPlayer from './VideoMUXPlayer';
6
6
  import styles from '../styles/video.module.scss';
7
- import { isMuxVideo, isVimeoVideo, isYouTubeVideo } from '../utils/videoUtils';
7
+ import { isMuxVideo, isVimeoVideo, isYouTubeVideo, isSynchWordsVideo } from '../utils/videoUtils';
8
+ import SynchWordsPlayer from "./SyncWordsPlayer";
8
9
 
9
10
  /**
10
11
  * @param url
@@ -48,6 +49,14 @@ const VideoComponent = ({ url, title, namespace, isLive, firstHalf, autoPlay, st
48
49
  />
49
50
  );
50
51
  };
52
+ // synch words player
53
+ if(isSynchWordsVideo(url)){
54
+ return (<SynchWordsPlayer
55
+ video={url}
56
+ autoplay={autoPlay}
57
+ className={styles.synchWordsPlayer}
58
+ />);
59
+ }
51
60
 
52
61
  const defaultVideoJsOptions = isYouTubeVideo(url) ? {
53
62
  techOrder: ["youtube"],
@@ -99,7 +108,7 @@ VideoComponent.propTypes = {
99
108
  isLive: PropTypes.bool,
100
109
  firstHalf: PropTypes.bool,
101
110
  autoPlay: PropTypes.bool,
102
- start: PropTypes.number,
111
+ start: PropTypes.number,
103
112
  tokens: PropTypes.object,
104
113
  onError: PropTypes.func,
105
114
  };
@@ -108,7 +117,7 @@ VideoComponent.defaultProps = {
108
117
  title: '',
109
118
  namespace: '',
110
119
  firstHalf: true,
111
- autoPlay: false,
120
+ autoPlay: false,
112
121
  tokens: null,
113
122
  };
114
123
 
@@ -319,6 +319,11 @@ export const TicketPopupEditDetailsForm = ({
319
319
  onBlur={formik.handleBlur}
320
320
  onChange={!!initialValues[TicketKeys.company].name ? noop : formik.handleChange}
321
321
  disabled={!!initialValues[TicketKeys.company].name}
322
+ menuPortalTarget={document.body}
323
+ menuPosition="fixed"
324
+ styles={{
325
+ menuPortal: (base) => ({ ...base, zIndex: 9999 }),
326
+ }}
322
327
  tabSelectsValue={false}
323
328
  />
324
329
  {(formik.touched[TicketKeys.company] || triedSubmitting) && formik.errors[TicketKeys.company] &&