@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
191 lines (190 loc) • 9.84 kB
JavaScript
import { __awaiter, __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useContext, useEffect, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import { Alert, Box, IconButton, ImageList, ImageListItem, ImageListItemBar } from '@mui/material';
import Icon from '@mui/material/Icon';
import { Endpoints, UserService } from '@selfcommunity/api-services';
import { SCContext, SCUserContext } from '@selfcommunity/react-core';
import { FormattedMessage } from 'react-intl';
import BaseDialog from '../../../shared/BaseDialog';
import ConfirmDialog from '../../../shared/ConfirmDialog/ConfirmDialog';
import classNames from 'classnames';
import CircularProgress from '@mui/material/CircularProgress';
import { scroll } from 'seamless-scroll-polyfill';
import { SCOPE_SC_UI } from '../../../constants/Errors';
import { Logger } from '@selfcommunity/utils';
import { PREFIX } from '../constants';
const classes = {
dialogRoot: `${PREFIX}-dialog-root`,
upload: `${PREFIX}-upload`,
imagesList: `${PREFIX}-images-list`,
imageItem: `${PREFIX}-image-item`,
primary: `${PREFIX}-primary`
};
const Root = styled(BaseDialog, {
name: PREFIX,
slot: 'DialogRoot'
})(() => ({}));
export default function ChangePictureDialog(props) {
//PROPS
const { open, onChange, onClose, className } = props, rest = __rest(props, ["open", "onChange", "onClose", "className"]);
//CONTEXT
const scUserContext = useContext(SCUserContext);
const scContext = useContext(SCContext);
//STATE
const [file, setFile] = useState(scUserContext.user['avatar']);
const [error, setError] = useState(false);
const [alert, setAlert] = useState(false);
const [primary, setPrimary] = useState(null);
const [avatars, setAvatars] = useState([]);
const [deleteAvatarId, setDeleteAvatarId] = useState(null);
let fileInput = useRef(null);
const [openDeleteAvatarDialog, setOpenDeleteAvatarDialog] = useState(false);
const [isDeletingAvatar, setIsDeletingAvatar] = useState(false);
const [loading, setLoading] = useState(false);
/**
* Handles open confirm delete avatar dialog
* @param id
*/
function handleOpen(id) {
setOpenDeleteAvatarDialog(true);
setDeleteAvatarId(id);
}
/**
* Handles avatar upload
* @param event
*/
function handleUpload(event) {
var _a;
const maxSize = 3 * 1024 * 1024;
if (event && ((_a = event.target.files[0]) === null || _a === void 0 ? void 0 : _a.size) <= maxSize) {
fileInput = event.target.files[0];
setFile(URL.createObjectURL(fileInput));
handleSave();
}
else {
setAlert(true);
}
}
/**
* Performs save avatar after upload
*/
function handleSave() {
setLoading(true);
const formData = new FormData();
formData.append('avatar', fileInput);
UserService.addUserAvatar(formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then((data) => {
setAvatars((prev) => [...prev, data]);
selectPrimaryAvatar(data);
setLoading(false);
scrollToEndListAvatars();
setError(false);
})
.catch((error) => {
setError(true);
setLoading(false);
Logger.error(SCOPE_SC_UI, error);
});
}
/**
* Handle scroll to the last item added in the list of avatars
*/
function scrollToEndListAvatars() {
setTimeout(() => {
const element = document.getElementById(`avatarsList`);
if (element) {
scroll(element, { top: element.scrollHeight, behavior: 'smooth' });
}
}, 200);
}
/**
* Fetches the list of avatars
*/
const fetchUserAvatars = (next = Endpoints.GetAvatars.url({})) => __awaiter(this, void 0, void 0, function* () {
const data = yield UserService.getUserAvatars({ url: next });
return data.next ? data.results.concat(yield fetchUserAvatars(data.next)) : data.results;
});
/**
* Gets the primary avatar from a list of avatars
* @param data
*/
function getPrimaryAvatar(data) {
return data.find((a) => a.primary === true);
}
/**
* Selects primary avatar
* Only if another avatar is selected (primary !== avatar.id)
* @param avatar
*/
function selectPrimaryAvatar(avatar) {
if (avatar.id !== primary) {
UserService.setUserPrimaryAvatar(avatar.id, { headers: { Authorization: `Bearer ${scContext.settings.session.authToken.accessToken}` } })
.then(() => {
scUserContext.updateUser({ avatar: avatar.avatar });
setPrimary(avatar.id);
onChange && onChange(avatar);
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
});
}
}
/**
* Handles deletion of a specific avatar
*/
function deleteAvatar() {
setIsDeletingAvatar(true);
UserService.removeUserAvatar(deleteAvatarId, { headers: { Authorization: `Bearer ${scContext.settings.session.authToken.accessToken}` } })
.then(() => {
const _avatars = avatars.filter((a) => a.id !== deleteAvatarId);
setAvatars(_avatars);
setIsDeletingAvatar(false);
setOpenDeleteAvatarDialog(false);
if (primary === deleteAvatarId) {
if (_avatars.length > 0) {
selectPrimaryAvatar(_avatars[_avatars.length - 1]);
}
else {
// if there are no more avatars set auto generated image
onChange && onChange(null);
}
}
})
.catch((error) => {
setOpenDeleteAvatarDialog(false);
Logger.error(SCOPE_SC_UI, error);
});
}
/**
* On mount, fetches the list of scUser's avatars
*/
useEffect(() => {
fetchUserAvatars()
.then((data) => {
const primary = getPrimaryAvatar(data);
if (data && data.length) {
setAvatars(data);
setPrimary(primary.id);
setFile(primary.avatar);
}
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
});
}, []);
/**
* Renders root object
*/
return (_jsxs(Root, Object.assign({ className: classNames(classes.dialogRoot, className), title: _jsx(FormattedMessage, { defaultMessage: "ui.changePicture.title", id: "ui.changePicture.title" }), onClose: onClose, open: open }, rest, { children: [_jsxs(Box, Object.assign({ className: classes.upload }, { children: [alert ? (_jsx(Alert, Object.assign({ color: "error", onClose: () => setAlert(false) }, { children: _jsx(FormattedMessage, { id: "ui.changePicture.button.upload.alert", defaultMessage: "ui.changePicture.button.upload.alert" }) }))) : (_jsxs(_Fragment, { children: [_jsx("input", { type: "file", onChange: handleUpload, ref: fileInput, hidden: true, accept: ".gif,.png,.jpg,.jpeg" }), _jsx(Button, Object.assign({ disabled: loading || isDeletingAvatar, variant: "outlined", onClick: () => fileInput.current.click(), color: error ? 'error' : 'primary', startIcon: loading ? null : _jsx(Icon, { children: "folder_open" }) }, { children: loading ? (_jsx(CircularProgress, { size: 15 })) : (_jsx(_Fragment, { children: error ? (_jsx(FormattedMessage, { id: "ui.changePicture.button.upload.error", defaultMessage: "ui.changePicture.button.upload.error" })) : (_jsx(FormattedMessage, { id: "ui.changePicture.button.upload", defaultMessage: "ui.changePicture.button.upload" })) })) }))] })), _jsx(Typography, Object.assign({ component: "span", fontSize: "small", color: "text.secondary", gutterBottom: true }, { children: _jsx(FormattedMessage, { id: "ui.changePicture.info", defaultMessage: "ui.changePicture.info", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
li: (chunks) => _jsx("li", { children: chunks }),
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
ul: (chunks) => _jsx("ul", { children: chunks })
} }) }))] })), _jsx(ImageList, Object.assign({ cols: 3, rowHeight: 'auto', id: "avatarsList", classes: { root: classes.imagesList } }, { children: avatars.map((avatar) => (_jsx(Box, Object.assign({ className: classes.imageItem }, { children: _jsxs(ImageListItem, Object.assign({ className: primary === avatar.id ? classes.primary : '', onClick: () => selectPrimaryAvatar(avatar) }, { children: [_jsx("img", { src: avatar.avatar, loading: "lazy", alt: 'img' }), _jsx(ImageListItemBar, { position: "top", actionIcon: _jsx(IconButton, Object.assign({ onClick: () => handleOpen(avatar.id), size: "small" }, { children: _jsx(Icon, { children: "delete" }) })) })] }), avatar.id) }), avatar.id))) })), openDeleteAvatarDialog && (_jsx(ConfirmDialog, { open: openDeleteAvatarDialog, title: _jsx(FormattedMessage, { id: "ui.changePicture.dialog.msg", defaultMessage: "ui.changePicture.dialog.msg" }), btnConfirm: _jsx(FormattedMessage, { id: "ui.changePicture.dialog.confirm", defaultMessage: "ui.changePicture.dialog.confirm" }), onConfirm: deleteAvatar, isUpdating: isDeletingAvatar, onClose: () => setOpenDeleteAvatarDialog(false) }))] })));
}