@openeventkit/event-site 2.0.125-beta.2 → 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 +7 -3
- package/src/components/AttendeeToAttendeeWidgetComponent.js +41 -5
- package/src/components/AvatarEditorModal/index.js +250 -0
- package/src/components/Navbar/index.js +12 -22
- package/src/components/Navbar/template.js +64 -84
- package/src/components/ui/Button/index.js +41 -0
- package/src/components/ui/IconButton/index.js +32 -0
- package/src/components/ui/index.js +7 -0
- package/src/content/site-settings/index.json +1 -50
- package/src/content/sponsors.json +1 -1
- package/src/styles/colors.scss +0 -6
- package/src/styles/full-profile.module.scss +3 -0
- package/src/templates/full-profile-page.js +73 -24
- package/src/utils/videoUtils.js +1 -1
- package/src/components/ProfilePopupComponent.js +0 -369
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from 'react'
|
|
2
|
-
import AvatarEditor from 'react-avatar-editor'
|
|
3
|
-
import AjaxLoader from "openstack-uicore-foundation/lib/components/ajaxloader";
|
|
4
|
-
import { create_UUID } from '../utils/uuidGenerator'
|
|
5
|
-
import Link from "./Link";
|
|
6
|
-
|
|
7
|
-
import styles from '../styles/profile.module.scss'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const ProfilePopupComponent = ({ userProfile, idpLoading, closePopup, showProfile, changePicture, changeProfile, fromFullProfile }) => {
|
|
11
|
-
|
|
12
|
-
const editorRef = useRef(null);
|
|
13
|
-
const modalHeaderRef = useRef(null)
|
|
14
|
-
const modalRef = useRef(null)
|
|
15
|
-
const fileInput = useRef(null)
|
|
16
|
-
|
|
17
|
-
const [firstName, setFirstName] = useState("");
|
|
18
|
-
const [lastName, setLastName] = useState("");
|
|
19
|
-
const [company, setCompany] = useState("");
|
|
20
|
-
const [bio, setBio] = useState('');
|
|
21
|
-
const [jobTitle, setJobTitle] = useState('');
|
|
22
|
-
const [github, setGithub] = useState('');
|
|
23
|
-
const [irc, setIRC] = useState('');
|
|
24
|
-
const [linkedin, setLinkedin] = useState('');
|
|
25
|
-
const [twitter, setTwitter] = useState('');
|
|
26
|
-
|
|
27
|
-
const [image, setImage] = useState(null);
|
|
28
|
-
const [newImage, setNewImage] = useState(false);
|
|
29
|
-
const [position, setPosition] = useState({ x: 0.5, y: 0.5 });
|
|
30
|
-
const [scale, setScale] = useState(1);
|
|
31
|
-
const [rotate, setRotate] = useState(0);
|
|
32
|
-
const width = 200;
|
|
33
|
-
const height = 200;
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
setFirstName(userProfile.given_name || '');
|
|
37
|
-
setLastName(userProfile.family_name || '');
|
|
38
|
-
setCompany(userProfile.company || '');
|
|
39
|
-
setBio(userProfile.bio || '');
|
|
40
|
-
setJobTitle(userProfile.job_title || '');
|
|
41
|
-
setImage(userProfile.picture || '');
|
|
42
|
-
setGithub(userProfile.github_user || '');
|
|
43
|
-
setIRC(userProfile.irc || '');
|
|
44
|
-
setLinkedin(userProfile.linked_in_profile || '');
|
|
45
|
-
setTwitter(userProfile.twitter_name || '');
|
|
46
|
-
|
|
47
|
-
return () => {
|
|
48
|
-
setFirstName('');
|
|
49
|
-
setLastName('');
|
|
50
|
-
setCompany('');
|
|
51
|
-
setBio('');
|
|
52
|
-
setJobTitle('');
|
|
53
|
-
setGithub('');
|
|
54
|
-
setIRC('');
|
|
55
|
-
setLinkedin('');
|
|
56
|
-
setTwitter('');
|
|
57
|
-
};
|
|
58
|
-
}, [
|
|
59
|
-
userProfile.given_name,
|
|
60
|
-
userProfile.family_name,
|
|
61
|
-
userProfile.company,
|
|
62
|
-
userProfile.picture,
|
|
63
|
-
userProfile.bio,
|
|
64
|
-
userProfile.job_title,
|
|
65
|
-
userProfile.github,
|
|
66
|
-
userProfile.irc,
|
|
67
|
-
userProfile.linkedin,
|
|
68
|
-
userProfile.twitter_name
|
|
69
|
-
]);
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
if (modalHeaderRef) {
|
|
73
|
-
window.setTimeout(function () {
|
|
74
|
-
modalHeaderRef.current.focus();
|
|
75
|
-
}, 0);
|
|
76
|
-
}
|
|
77
|
-
}, [modalHeaderRef])
|
|
78
|
-
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
window.addEventListener('keydown', handleUserKeyPress);
|
|
81
|
-
|
|
82
|
-
return () => {
|
|
83
|
-
window.removeEventListener('keydown', handleUserKeyPress);
|
|
84
|
-
};
|
|
85
|
-
}, []);
|
|
86
|
-
|
|
87
|
-
const handleUserKeyPress = (e) => {
|
|
88
|
-
const focusable = modalRef.current.querySelectorAll('button, input, a, textarea, select, [tabindex]:not([tabindex="-1"])');
|
|
89
|
-
const firstFocusable = focusable[0];
|
|
90
|
-
const lastFocusable = focusable[focusable.length - 1];
|
|
91
|
-
const KEYCODE_TAB = 9;
|
|
92
|
-
const KEYCODE_ESC = 27;
|
|
93
|
-
const isTabPressed = (e.key === 'Tab' || e.keyCode === KEYCODE_TAB);
|
|
94
|
-
const isEscapePressed = (e.key === 'Escape' || e.keyCode === KEYCODE_ESC);
|
|
95
|
-
|
|
96
|
-
if (isEscapePressed) {
|
|
97
|
-
closePopup();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!isTabPressed) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if ( e.shiftKey ) /* shift + tab */ {
|
|
105
|
-
if (document.activeElement === firstFocusable) {
|
|
106
|
-
lastFocusable.focus();
|
|
107
|
-
e.preventDefault();
|
|
108
|
-
}
|
|
109
|
-
} else /* tab */ {
|
|
110
|
-
if (document.activeElement === lastFocusable) {
|
|
111
|
-
firstFocusable.focus();
|
|
112
|
-
e.preventDefault();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const handleNewImage = (e) => {
|
|
119
|
-
setImage(e.target.files[0]);
|
|
120
|
-
setNewImage(true);
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const urltoFile = (url, filename, mimeType) => {
|
|
124
|
-
mimeType = mimeType || (url.match(/^data:([^;]+);/) || '')[1];
|
|
125
|
-
filename = filename || create_UUID();
|
|
126
|
-
return (fetch(url)
|
|
127
|
-
.then(function (res) { return res.arrayBuffer(); })
|
|
128
|
-
.then(function (buf) { return new File([buf], filename, { type: mimeType }); })
|
|
129
|
-
);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const handleScale = (e) => {
|
|
133
|
-
const scale = parseFloat(e.target.value);
|
|
134
|
-
setScale(scale);
|
|
135
|
-
setNewImage(true);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const handlePositionChange = (position) => {
|
|
139
|
-
setPosition(position);
|
|
140
|
-
setNewImage(true);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const rotateLeft = (e) => {
|
|
144
|
-
e.preventDefault();
|
|
145
|
-
setRotate(rotate - 90);
|
|
146
|
-
setNewImage(true);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const rotateRight = (e) => {
|
|
150
|
-
e.preventDefault();
|
|
151
|
-
setRotate(rotate + 90);
|
|
152
|
-
setNewImage(true);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
const onClickSave = () => {
|
|
156
|
-
if (editorRef.current && newImage) {
|
|
157
|
-
const canvas = editorRef.current?.getImage()?.toDataURL();
|
|
158
|
-
if(canvas) {
|
|
159
|
-
urltoFile(canvas, image.name)
|
|
160
|
-
.then(file => changePicture(file));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (userProfile.given_name !== firstName ||
|
|
164
|
-
userProfile.family_name !== lastName ||
|
|
165
|
-
userProfile.company !== company ||
|
|
166
|
-
userProfile.bio !== bio ||
|
|
167
|
-
userProfile.job_title !== jobTitle ||
|
|
168
|
-
userProfile.github_user !== github ||
|
|
169
|
-
userProfile.irc !== irc ||
|
|
170
|
-
userProfile.linked_in_profile !== linkedin ||
|
|
171
|
-
userProfile.twitter_name != twitter) {
|
|
172
|
-
const newProfile = {
|
|
173
|
-
first_name: firstName,
|
|
174
|
-
last_name: lastName,
|
|
175
|
-
company: company,
|
|
176
|
-
bio: bio,
|
|
177
|
-
job_title: jobTitle,
|
|
178
|
-
github_user: github,
|
|
179
|
-
irc: irc,
|
|
180
|
-
linked_in_profile: linkedin,
|
|
181
|
-
twitter_name: twitter,
|
|
182
|
-
};
|
|
183
|
-
changeProfile(newProfile);
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
return (
|
|
188
|
-
<div className={`${styles.modal} ${showProfile ? styles.isActive : ''}`} ref={modalRef}>
|
|
189
|
-
<div className={`${styles.modalCard} ${styles.profilePopup}`}>
|
|
190
|
-
<AjaxLoader relative={true} color={'#ffffff'} show={idpLoading} size={120} />
|
|
191
|
-
<header className={`${styles.modalCardHead}`}>
|
|
192
|
-
<h2 className={`${styles.modalCardTitle}`} tabIndex='-1' ref={modalHeaderRef}>Edit profile</h2>
|
|
193
|
-
<button className="link" onClick={() => closePopup()}>
|
|
194
|
-
<i className={`${styles.closeIcon} fa fa-times icon`} />
|
|
195
|
-
</button>
|
|
196
|
-
</header>
|
|
197
|
-
<section className={`${styles.modalCardBody}`}>
|
|
198
|
-
<div className={styles.modalCardPicture}>
|
|
199
|
-
<div className={styles.title}>Profile picture</div>
|
|
200
|
-
<div className={styles.picture}>
|
|
201
|
-
<AvatarEditor
|
|
202
|
-
ref={editorRef}
|
|
203
|
-
image={image}
|
|
204
|
-
width={width}
|
|
205
|
-
height={height}
|
|
206
|
-
border={50}
|
|
207
|
-
color={[0, 0, 0, 0.8]} // RGBA
|
|
208
|
-
position={position}
|
|
209
|
-
onPositionChange={handlePositionChange}
|
|
210
|
-
scale={scale}
|
|
211
|
-
borderRadius={5}
|
|
212
|
-
rotate={parseFloat(rotate)}
|
|
213
|
-
/>
|
|
214
|
-
<div className={styles.imageUpload} tabIndex="0" onKeyPress={() => {fileInput.current.click()}}>
|
|
215
|
-
<label htmlFor="file-input" >
|
|
216
|
-
<i className={`${styles.pictureIcon} fa fa-2x fa-camera icon is-large`} />
|
|
217
|
-
</label>
|
|
218
|
-
<input ref={fileInput} name="newImage" id="file-input" type="file" accept=".jpg,.jpeg,.png" onChange={handleNewImage} />
|
|
219
|
-
</div>
|
|
220
|
-
<div>
|
|
221
|
-
<div className={`columns ${styles.inputRow}`}>
|
|
222
|
-
<span id="zoomLabel" className='column is-one-quarter'>Zoom:</span>
|
|
223
|
-
<div className='column is-two-thirds'>
|
|
224
|
-
<input
|
|
225
|
-
name="scale"
|
|
226
|
-
type="range"
|
|
227
|
-
aria-labelledby='zoomLabel'
|
|
228
|
-
max="2"
|
|
229
|
-
onChange={(e) => handleScale(e)}
|
|
230
|
-
step="0.01"
|
|
231
|
-
defaultValue="1"
|
|
232
|
-
/>
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
<div className={`columns ${styles.inputRow}`}>
|
|
236
|
-
<div className='column is-one-quarter'>Rotate:</div>
|
|
237
|
-
<div className='column is-two-thirds'>
|
|
238
|
-
<button className={`button is-large ${styles.button}`} onClick={rotateLeft}>
|
|
239
|
-
<i className={`fa fa-undo icon is-large`} />Left
|
|
240
|
-
</button>
|
|
241
|
-
<button className={`button is-large ${styles.button}`} onClick={rotateRight}>
|
|
242
|
-
<i className={`fa fa-undo icon is-large`} />Right
|
|
243
|
-
</button>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
{!fromFullProfile &&
|
|
251
|
-
<div className={styles.modalCardForm}>
|
|
252
|
-
<div className={styles.title}>Profile Info</div>
|
|
253
|
-
<div className={styles.form}>
|
|
254
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
255
|
-
<div className='column is-one-quarter'>First Name</div>
|
|
256
|
-
<div className='column is-two-thirds'>
|
|
257
|
-
<input
|
|
258
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
259
|
-
type="text"
|
|
260
|
-
placeholder="First Name"
|
|
261
|
-
onChange={e => setFirstName(e.target.value)}
|
|
262
|
-
value={firstName} />
|
|
263
|
-
</div>
|
|
264
|
-
</div>
|
|
265
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
266
|
-
<div className='column is-one-quarter'>Last Name</div>
|
|
267
|
-
<div className='column is-two-thirds'>
|
|
268
|
-
<input
|
|
269
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
270
|
-
type="text"
|
|
271
|
-
placeholder="Last Name"
|
|
272
|
-
onChange={e => setLastName(e.target.value)}
|
|
273
|
-
value={lastName} />
|
|
274
|
-
</div>
|
|
275
|
-
</div>
|
|
276
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
277
|
-
<div className='column is-one-quarter'>Company</div>
|
|
278
|
-
<div className='column is-two-thirds'>
|
|
279
|
-
<input
|
|
280
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
281
|
-
type="text"
|
|
282
|
-
placeholder="Company"
|
|
283
|
-
onChange={e => setCompany(e.target.value)}
|
|
284
|
-
value={company}
|
|
285
|
-
/>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
289
|
-
<div className='column is-one-quarter'>Bio</div>
|
|
290
|
-
<div className='column is-two-thirds'>
|
|
291
|
-
<textarea
|
|
292
|
-
className={`textarea ${styles.textarea}`}
|
|
293
|
-
placeholder=''
|
|
294
|
-
rows="6"
|
|
295
|
-
onChange={e => setBio(e.target.value)}
|
|
296
|
-
value={bio}
|
|
297
|
-
>
|
|
298
|
-
</textarea>
|
|
299
|
-
</div>
|
|
300
|
-
</div>
|
|
301
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
302
|
-
<div className='column is-one-quarter'>Job Title</div>
|
|
303
|
-
<div className='column is-two-thirds'>
|
|
304
|
-
<input
|
|
305
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
306
|
-
type="text"
|
|
307
|
-
placeholder="Job Title"
|
|
308
|
-
onChange={e => setJobTitle(e.target.value)}
|
|
309
|
-
value={jobTitle} />
|
|
310
|
-
</div>
|
|
311
|
-
</div>
|
|
312
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
313
|
-
<div className='column is-one-quarter'>Github</div>
|
|
314
|
-
<div className='column is-two-thirds'>
|
|
315
|
-
<input
|
|
316
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
317
|
-
type="text"
|
|
318
|
-
placeholder="Github"
|
|
319
|
-
onChange={e => setGithub(e.target.value)}
|
|
320
|
-
value={github} />
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
323
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
324
|
-
<div className='column is-one-quarter'>IRC</div>
|
|
325
|
-
<div className='column is-two-thirds'>
|
|
326
|
-
<input
|
|
327
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
328
|
-
type="text"
|
|
329
|
-
placeholder="IRC"
|
|
330
|
-
onChange={e => setIRC(e.target.value)}
|
|
331
|
-
value={irc} />
|
|
332
|
-
</div>
|
|
333
|
-
</div>
|
|
334
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
335
|
-
<div className='column is-one-quarter'>LinkedIn</div>
|
|
336
|
-
<div className='column is-two-thirds'>
|
|
337
|
-
<input
|
|
338
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
339
|
-
type="text"
|
|
340
|
-
placeholder="LinkedIn"
|
|
341
|
-
onChange={e => setLinkedin(e.target.value)}
|
|
342
|
-
value={linkedin} />
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
<div className={`columns is-mobile ${styles.inputRow}`}>
|
|
346
|
-
<div className='column is-one-quarter'>X</div>
|
|
347
|
-
<div className='column is-two-thirds'>
|
|
348
|
-
<input
|
|
349
|
-
className={`${styles.input} ${styles.isMedium}`}
|
|
350
|
-
type="text"
|
|
351
|
-
placeholder="Twitter/X"
|
|
352
|
-
onChange={e => setTwitter(e.target.value)}
|
|
353
|
-
value={twitter} />
|
|
354
|
-
</div>
|
|
355
|
-
</div>
|
|
356
|
-
</div>
|
|
357
|
-
</div>
|
|
358
|
-
}
|
|
359
|
-
</section>
|
|
360
|
-
<footer className={`${styles.modalCardFoot}`}>
|
|
361
|
-
<button onClick={() => closePopup()} className="button is-large">Discard</button>
|
|
362
|
-
<button onClick={() => onClickSave()} className="button is-large">Update</button>
|
|
363
|
-
</footer>
|
|
364
|
-
</div>
|
|
365
|
-
</div>
|
|
366
|
-
)
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
export default ProfilePopupComponent
|