@openeventkit/event-site 2.0.125-beta.1 → 2.0.125

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.125-beta.1",
4
+ "version": "2.0.125",
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",
@@ -21,14 +25,14 @@
21
25
  "@sentry/integrations": "^7.39.0",
22
26
  "@sentry/react": "^7.39.0",
23
27
  "@sentry/webpack-plugin": "^1.20.0",
24
- "@supabase/supabase-js": "^1.35.6",
28
+ "@supabase/supabase-js": "2.45.1",
25
29
  "@types/googlemaps": "^3.39.9",
26
30
  "@types/markerclustererplus": "^2.1.33",
27
31
  "@types/react": "^16.9.42",
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.0",
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",
@@ -59,7 +59,13 @@ const AttendeesWidgetComponent = ({ user, event, chatSettings }) => {
59
59
  linked_in_profile,
60
60
  twitter_name,
61
61
  wechat_user,
62
- public_profile_show_fullname } = idpProfile || {};
62
+ public_profile_show_fullname,
63
+ public_profile_show_email,
64
+ public_profile_allow_chat_with_me,
65
+ public_profile_show_photo,
66
+ public_profile_show_social_media_info,
67
+ public_profile_show_bio
68
+ } = idpProfile || {};
63
69
 
64
70
  useEffect(() => {
65
71
  if (!user || !userProfile || !idpProfile) return;
@@ -127,6 +133,12 @@ const AttendeesWidgetComponent = ({ user, event, chatSettings }) => {
127
133
  .flatMap((st) => st.badge.features)
128
134
  .filter((v, i, a) => a.map((item) => item.id).indexOf(v.id) === i),
129
135
  bio: bio,
136
+ showEmail: public_profile_show_email === true,
137
+ allowChatWithMe: public_profile_allow_chat_with_me === true,
138
+ showFullName: public_profile_show_fullname === true,
139
+ showProfilePic: public_profile_show_photo === true,
140
+ showSocialInfo: public_profile_show_social_media_info === true,
141
+ showBio: public_profile_show_bio === true,
130
142
  hasPermission: (permission) => {
131
143
  const isAdmin = groups &&
132
144
  groups.map((g) => g.slug).filter((g) => adminGroups.includes(g))
@@ -186,6 +198,20 @@ const mapState = ({ settingState }) => ({
186
198
  export const AttendeesWidget = connect(mapState)(AttendeesWidgetComponent);
187
199
 
188
200
  const AccessTracker = ({ user, isLoggedUser, summitPhase, chatSettings }) => {
201
+ const chatProps = {
202
+ streamApiKey: getEnvVariable(STREAM_IO_API_KEY),
203
+ apiBaseUrl: getEnvVariable(IDP_BASE_URL),
204
+ chatApiBaseUrl: getEnvVariable(CHAT_API_BASE_URL),
205
+ onAuthError: (err, res) => console.log(err),
206
+ openDir: "left",
207
+ activity: null,
208
+ getAccessToken: async () => {
209
+ const accessToken = await getAccessToken();
210
+ //console.log("AttendeesList->getAccessToken", accessToken);
211
+ return accessToken;
212
+ },
213
+ };
214
+
189
215
  const trackerRef = useRef();
190
216
 
191
217
  const handleLogout = useCallback(() => {
@@ -237,11 +263,15 @@ const AccessTracker = ({ user, isLoggedUser, summitPhase, chatSettings }) => {
237
263
  wechat_user,
238
264
  public_profile_show_fullname,
239
265
  public_profile_show_email,
240
- public_profile_allow_chat_with_me
266
+ public_profile_allow_chat_with_me,
267
+ public_profile_show_photo,
268
+ public_profile_show_social_media_info,
269
+ public_profile_show_bio
241
270
  } = user.idpProfile;
242
271
 
243
272
  const widgetProps = {
244
273
  user: {
274
+ id: sub,
245
275
  idpUserId: sub,
246
276
  fullName: public_profile_show_fullname ? `${given_name} ${family_name}` : `${given_name}`,
247
277
  email: email,
@@ -260,11 +290,17 @@ const AccessTracker = ({ user, isLoggedUser, summitPhase, chatSettings }) => {
260
290
  .flatMap((st) => st.badge.features)
261
291
  .filter((v, i, a) => a.map((item) => item.id).indexOf(v.id) === i),
262
292
  bio: bio,
263
- showEmail: public_profile_show_email,
264
- allowChatWithMe: public_profile_allow_chat_with_me ?? true
293
+ showEmail: public_profile_show_email === true,
294
+ allowChatWithMe: public_profile_allow_chat_with_me === true,
295
+ showFullName: public_profile_show_fullname === true,
296
+ showProfilePic: public_profile_show_photo === true,
297
+ showSocialInfo: public_profile_show_social_media_info === true,
298
+ showBio: public_profile_show_bio === true
265
299
  },
266
300
  summitId: parseInt(getEnvVariable(SUMMIT_ID)),
267
- ...sbAuthProps,
301
+ keepAliveEnabled: true,
302
+ ...chatProps,
303
+ ...sbAuthProps
268
304
  };
269
305
 
270
306
  if (!chatSettings.enabled) return null;
@@ -0,0 +1,250 @@
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
+ />
146
+ <IconButton
147
+ onClick={() => fileInputRef.current.click()}
148
+ sx={{
149
+ position: "absolute",
150
+ top: "79.5%",
151
+ right: "44%",
152
+ color: "#fff"
153
+ }}
154
+ >
155
+ <CameraAltIcon fontSize="inherit" />
156
+ </IconButton>
157
+ <input
158
+ ref={fileInputRef}
159
+ type="file"
160
+ accept=".jpg,.jpeg,.png"
161
+ style={{ display: "none" }}
162
+ onChange={handleNewImage}
163
+ />
164
+ </Box>
165
+ <Box
166
+ sx={{
167
+ px: "20px",
168
+ display: "flex",
169
+ flexDirection: "column",
170
+ gap: "20px"
171
+ }}
172
+ >
173
+ <Box
174
+ sx={{
175
+ display: "flex",
176
+ alignItems: "center",
177
+ gap: "20px",
178
+ justifyContent: "center"
179
+ }}
180
+ >
181
+ <Typography
182
+ sx={{
183
+ fontSize: "1.5rem",
184
+ fontFamily: "var(--font_family)"
185
+ }
186
+ }>
187
+ Zoom
188
+ </Typography>
189
+ <CustomSlider
190
+ value={scale}
191
+ min={0}
192
+ max={2}
193
+ step={0.01}
194
+ onChange={handleScale}
195
+ sx={{ flex: 1, mx: 2 }}
196
+ />
197
+ </Box>
198
+ <Box
199
+ sx={{
200
+ display: "flex",
201
+ alignItems: "center"
202
+ }}
203
+ >
204
+ <Typography
205
+ sx={{
206
+ fontSize: "1.5rem",
207
+ fontFamily: "var(--font_family)"
208
+ }}
209
+ >
210
+ Rotate
211
+ </Typography>
212
+ <Box
213
+ sx={{
214
+ display: "flex",
215
+ flex: 1,
216
+ justifyContent: "center",
217
+ gap: "20px"
218
+ }}
219
+ >
220
+ <IconButton onClick={rotateLeft}>
221
+ <RotateLeftIcon fontSize="inherit" />
222
+ </IconButton>
223
+ <IconButton onClick={rotateRight}>
224
+ <RotateRightIcon fontSize="inherit" />
225
+ </IconButton>
226
+ </Box>
227
+ </Box>
228
+ </Box>
229
+ <Box
230
+ sx={{
231
+ backgroundColor: "var(--color_background_light)",
232
+ display: "flex",
233
+ justifyContent: "space-between",
234
+ padding: "20px",
235
+ gap: "20px"
236
+ }}
237
+ >
238
+ <Button onClick={handleClose}>
239
+ Discard
240
+ </Button>
241
+ <Button onClick={handleSave} disabled={!newImage}>
242
+ Update
243
+ </Button>
244
+ </Box>
245
+ </Box>
246
+ </Modal>
247
+ );
248
+ };
249
+
250
+ 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,41 @@
1
+ import * as React from "react";
2
+ import { Button as BaseButton } from "@mui/base";
3
+ import { styled } from "@mui/system";
4
+
5
+ const StyledButton = styled(BaseButton)({
6
+ width: "100%",
7
+ height: "5.5rem",
8
+ color: "var(--color_input_text_color)",
9
+ backgroundColor: "var(--color_input_background_color)",
10
+ borderColor: "var(--color_input_border_color)",
11
+ borderStyle: "solid",
12
+ borderWidth: 1,
13
+ borderRadius: 4,
14
+ fontSize: "1.5rem",
15
+ fontFamily: "var(--font_family)",
16
+ justifyContent: "center",
17
+ textAlign: "center",
18
+ whiteSpace: "nowrap",
19
+ padding: "calc(0.5em - 1px) 1em",
20
+ display: "inline-flex",
21
+ alignItems: "center",
22
+ lineHeight: 1.5,
23
+ ":disabled": {
24
+ opacity: 0.65
25
+ }
26
+ });
27
+
28
+ const Button = ({
29
+ children,
30
+ ...rest
31
+ }) => {
32
+ return (
33
+ <StyledButton
34
+ {...rest}
35
+ >
36
+ {children}
37
+ </StyledButton>
38
+ );
39
+ };
40
+
41
+ export default Button;