From 09f7225eb717a3547a07e506ea795f3bbb0a96c9 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Mon, 13 Sep 2021 12:27:55 +0530 Subject: [PATCH] Added progress spinner in ImageUplaod (#91) --- public/res/svg/avatar-clip.svg | 3 - .../molecules/image-upload/ImageUpload.jsx | 75 ++++++++++++------- .../molecules/image-upload/ImageUpload.scss | 60 +++++++++++---- .../profile-editor/ProfileEditor.jsx | 23 ++++-- .../profile-editor/ProfileEditor.scss | 6 +- src/app/organisms/settings/Settings.jsx | 2 +- 6 files changed, 115 insertions(+), 54 deletions(-) delete mode 100644 public/res/svg/avatar-clip.svg diff --git a/public/res/svg/avatar-clip.svg b/public/res/svg/avatar-clip.svg deleted file mode 100644 index ffaa1a2f..00000000 --- a/public/res/svg/avatar-clip.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/app/molecules/image-upload/ImageUpload.jsx b/src/app/molecules/image-upload/ImageUpload.jsx index 992d5bca..da794892 100644 --- a/src/app/molecules/image-upload/ImageUpload.jsx +++ b/src/app/molecules/image-upload/ImageUpload.jsx @@ -1,48 +1,73 @@ -import React, { useRef } from 'react'; +import React, { useState, useRef } from 'react'; import PropTypes from 'prop-types'; +import './ImageUpload.scss'; import initMatrix from '../../../client/initMatrix'; -import SettingsIC from '../../../../public/res/ic/outlined/settings.svg'; +import Text from '../../atoms/text/Text'; import Avatar from '../../atoms/avatar/Avatar'; - -import RawIcon from '../../atoms/system-icons/RawIcon'; -import './ImageUpload.scss'; +import Spinner from '../../atoms/spinner/Spinner'; function ImageUpload({ - text, bgColor, imageSrc, onUpload, + text, bgColor, imageSrc, onUpload, onRequestRemove, }) { + const [uploadPromise, setUploadPromise] = useState(null); const uploadImageRef = useRef(null); - // Uploads image and passes resulting URI to onUpload function provided in component props. - function uploadImage(e) { + async function uploadImage(e) { const file = e.target.files.item(0); - if (file !== null) { // TODO Add upload progress spinner - initMatrix.matrixClient.uploadContent(file, { onlyContentUri: false }).then((res) => { - if (res.content_uri !== null) { - onUpload({ content_uri: res.content_uri }); - } - }, (err) => { - console.log(err); // TODO Replace with alert banner. - }); + if (file === null) return; + try { + const uPromise = initMatrix.matrixClient.uploadContent(file, { onlyContentUri: false }); + setUploadPromise(uPromise); + + const res = await uPromise; + if (typeof res?.content_uri === 'string') onUpload(res.content_uri); + setUploadPromise(null); + } catch { + setUploadPromise(null); } + uploadImageRef.current.value = null; + } + + function cancelUpload() { + initMatrix.matrixClient.cancelUpload(uploadPromise); + setUploadPromise(null); + uploadImageRef.current.value = null; } return ( - + { (typeof imageSrc === 'string' || uploadPromise !== null) && ( + + )} - + ); } @@ -50,14 +75,14 @@ ImageUpload.defaultProps = { text: null, bgColor: 'transparent', imageSrc: null, - onUpload: null, }; ImageUpload.propTypes = { text: PropTypes.string, bgColor: PropTypes.string, imageSrc: PropTypes.string, - onUpload: PropTypes.func, + onUpload: PropTypes.func.isRequired, + onRequestRemove: PropTypes.func.isRequired, }; export default ImageUpload; diff --git a/src/app/molecules/image-upload/ImageUpload.scss b/src/app/molecules/image-upload/ImageUpload.scss index dbf2bace..9e0f312f 100644 --- a/src/app/molecules/image-upload/ImageUpload.scss +++ b/src/app/molecules/image-upload/ImageUpload.scss @@ -1,20 +1,50 @@ +.img-upload__wrapper { + display: flex; + flex-direction: column; + align-items: center; +} + .img-upload { display: flex; - flex-direction: row-reverse; - width: 80px; - height: 80px; -} - -.img-upload:hover { cursor: pointer; -} + position: relative; -.img-upload__mask { - mask: url('../../../../public/res/svg/avatar-clip.svg'); - -webkit-mask: url('../../../../public/res/svg/avatar-clip.svg'); -} + &__process { + width: 100%; + height: 100%; + border-radius: var(--bo-radius); + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, .6); + + position: absolute; + left: 0; + right: 0; + z-index: 1; + & .text { + text-transform: uppercase; + font-weight: 600; + color: white; + } + &--stopped { + display: none; + } + & .donut-spinner { + border-color: rgb(255, 255, 255, .3); + border-left-color: white; + } + } + &:hover .img-upload__process--stopped { + display: flex; + } -.img-upload__icon { - z-index: 1; - position: absolute; -} \ No newline at end of file + + &__btn-cancel { + margin-top: var(--sp-extra-tight); + cursor: pointer; + & .text { + color: var(--tc-danger-normal) + } + } +} diff --git a/src/app/organisms/profile-editor/ProfileEditor.jsx b/src/app/organisms/profile-editor/ProfileEditor.jsx index 61cd896d..9dd308a4 100644 --- a/src/app/organisms/profile-editor/ProfileEditor.jsx +++ b/src/app/organisms/profile-editor/ProfileEditor.jsx @@ -18,15 +18,22 @@ function ProfileEditor({ const mx = initMatrix.matrixClient; const displayNameRef = useRef(null); const bgColor = colorMXID(userId); - const [imageSrc, updateImgSrc] = useState(mx.mxcUrlToHttp(mx.getUser(mx.getUserId()).avatarUrl)); + const [avatarSrc, setAvatarSrc] = useState(mx.mxcUrlToHttp(mx.getUser(mx.getUserId()).avatarUrl, 80, 80, 'crop') || null); const [disabled, setDisabled] = useState(true); let username = mx.getUser(mx.getUserId()).displayName; // Sets avatar URL and updates the avatar component in profile editor to reflect new upload - function handleUpload(e) { - mx.setAvatarUrl(e.content_uri); - updateImgSrc(mx.mxcUrlToHttp(e.content_uri)); + function handleAvatarUpload(url) { + if (url === null) { + if (confirm('Are you sure you want to remove avatar?')) { + mx.setAvatarUrl(''); + setAvatarSrc(null); + } + return; + } + mx.setAvatarUrl(url); + setAvatarSrc(mx.mxcUrlToHttp(url, 80, 80, 'crop')); } function saveDisplayName() { @@ -44,7 +51,13 @@ function ProfileEditor({ return (
- + handleAvatarUpload(null)} + />
Display name of  diff --git a/src/app/organisms/profile-editor/ProfileEditor.scss b/src/app/organisms/profile-editor/ProfileEditor.scss index 015b920f..882f0792 100644 --- a/src/app/organisms/profile-editor/ProfileEditor.scss +++ b/src/app/organisms/profile-editor/ProfileEditor.scss @@ -3,14 +3,10 @@ align-items: end; } -.img-upload { - margin-right: var(--sp-normal) -} - .profile-editor__input-container { display: flex; flex-direction: column; - margin-right: var(--sp-normal); + margin: 0 var(--sp-normal); width: 100%; max-width: 400px; } diff --git a/src/app/organisms/settings/Settings.jsx b/src/app/organisms/settings/Settings.jsx index f97c942c..b20364c6 100644 --- a/src/app/organisms/settings/Settings.jsx +++ b/src/app/organisms/settings/Settings.jsx @@ -30,7 +30,7 @@ function GeneralSection() { return (
)}