@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
203 lines (197 loc) • 9.97 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useContext, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
import { Alert, Box, Button, Divider, ListItemIcon, Menu, MenuItem, Popover, SwipeableDrawer, Typography, useMediaQuery, useTheme } from '@mui/material';
import { Endpoints, http } from '@selfcommunity/api-services';
import { SCUserContext } from '@selfcommunity/react-core';
import Icon from '@mui/material/Icon';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import ConfirmDialog from '../../shared/ConfirmDialog/ConfirmDialog';
import classNames from 'classnames';
import CircularProgress from '@mui/material/CircularProgress';
import { useThemeProps } from '@mui/system';
import { SCOPE_SC_UI } from '../../constants/Errors';
import { Logger } from '@selfcommunity/utils';
import { PREFIX } from './constants';
const classes = {
root: `${PREFIX}-root`,
helpPopover: `${PREFIX}-help-popover`,
addMenuItem: `${PREFIX}-add-menuItem`,
delMenuItem: `${PREFIX}-del-menuItem`
};
const Root = styled(Box, {
name: PREFIX,
slot: 'Root'
})(() => ({}));
const messages = defineMessages({
imageMaxSize: {
id: 'ui.changeCover.button.change.alertMaxSize',
defaultMessage: 'ui.changeCover.button.change.alertMaxSize'
},
errorLoadImage: {
id: 'ui.changeCover.button.change.alertErrorImage',
defaultMessage: 'ui.changeCover.button.change.alertErrorImage'
}
});
/**
* > API documentation for the Community-JS Change Cover component. Learn about the available props and the CSS API.
*
*
* This component renders a button that allows users to edit their profile cover and a popover that specifies format and sizes allowed.
* Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/ChangeCover)
#### Import
```jsx
import {ChangeCover} from '@selfcommunity/react-ui';
```
#### Component Name
The name `SCChangeCoverButton` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCChangeCoverButton-root|Styles applied to the root element.|
|helpPopover|.SCChangeCoverButton-help-popover|Styles applied to the help popover element.|
|addMenuItem|.SCChangeCoverButton-add-menuItem|Styles applied to the add menu element.|
|delMenuItem|.SCChangeCoverButton-del-menuItem|Styles applied to the del menu element.|
* @param inProps
*/
export default function ChangeCover(inProps) {
//PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { onChange, autoHide, className } = props, rest = __rest(props, ["onChange", "autoHide", "className"]);
//CONTEXT
const scUserContext = useContext(SCUserContext);
//STATE
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
let fileInput = useRef(null);
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const [anchorElPopover, setAnchorElPopover] = React.useState(null);
const [openDeleteCoverDialog, setOpenDeleteCoverDialog] = useState(false);
const [isDeletingCover, setIsDeletingCover] = useState(false);
const [loading, setLoading] = useState(false);
const [alert, setAlert] = useState(null);
// INTL
const intl = useIntl();
// HANDLERS
const handleOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const hasCover = scUserContext.user && scUserContext.user.cover !== null;
const handleClickHelpButton = (event) => {
setAnchorElPopover(event.currentTarget);
};
const handleCloseHelpPopover = () => {
setAnchorElPopover(null);
};
const isOpen = Boolean(anchorElPopover);
// Anonymous
if (!scUserContext.user) {
return null;
}
/**
* Handles file upload
* @param event
*/
const handleUpload = (event) => {
var _a;
const maxSize = 5 * 1024 * 1024;
if (((_a = event.target.files[0]) === null || _a === void 0 ? void 0 : _a.size) <= maxSize) {
fileInput = event.target.files[0];
handleSave();
}
else {
setAlert(intl.formatMessage(messages.imageMaxSize));
setAnchorEl(null);
}
};
/**
* Handles deletion of a specific cover
*/
function deleteCover() {
setIsDeletingCover(true);
handleSave(true);
}
/**
* Handles cover saving after upload and delete actions
*/
function handleSave(performDelete = false) {
setLoading(true);
const formData = new FormData();
if (!performDelete) {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
formData.append('cover', fileInput);
}
else {
formData.append('cover', '');
}
http
.request({
url: Endpoints.UserPatch.url({ id: scUserContext.user['id'] }),
method: Endpoints.UserPatch.method,
headers: {
'Content-Type': 'multipart/form-data'
},
data: formData
})
.then((res) => {
scUserContext.updateUser({ cover: res.data.cover });
onChange && onChange(res.data.cover);
setAnchorEl(null);
setLoading(false);
if (performDelete) {
setIsDeletingCover(false);
setOpenDeleteCoverDialog(false);
}
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
setLoading(false);
setAlert(intl.formatMessage(messages.errorLoadImage));
});
}
/**
* Renders change cover menu items
*/
function renderMenuItems() {
return (_jsx(Box, { children: loading ? (_jsx(MenuItem, Object.assign({ sx: { justifyContent: 'center' } }, { children: _jsx(CircularProgress, { size: 15 }) }))) : (_jsxs(_Fragment, { children: [_jsx("input", { type: "file", onChange: handleUpload, ref: fileInput, hidden: true, accept: ".gif,.png,.jpg,.jpeg" }), _jsxs(MenuItem, Object.assign({ disabled: loading, onClick: () => fileInput.current.click(), className: classes.addMenuItem }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "add_circle_outline" }) }), _jsx(FormattedMessage, { id: "ui.changeCover.button.upload", defaultMessage: "ui.changeCover.button.upload" })] })), hasCover && (_jsxs(MenuItem, Object.assign({ className: classes.delMenuItem, onClick: () => setOpenDeleteCoverDialog(true) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "delete" }) }), _jsx(FormattedMessage, { id: "ui.changeCover.button.delete", defaultMessage: "ui.changeCover.button.delete" })] })))] })) }));
}
/**
* Renders change cover menu
*/
const cc = (_jsxs(React.Fragment, { children: [_jsx(Button, Object.assign({ size: "small", variant: "contained", disabled: loading, onClick: handleOpen }, rest, { children: _jsx(Icon, { children: "photo_camera" }) })), open && (_jsx(_Fragment, { children: isMobile ? (_jsx(SwipeableDrawer, Object.assign({ open: true, onClose: handleClose, onOpen: handleOpen, anchor: "bottom", disableSwipeToOpen: true }, { children: renderMenuItems() }))) : (_jsx(Menu, Object.assign({ anchorEl: anchorEl, open: true, onClose: handleClose }, { children: renderMenuItems() }))) })), !isMobile && (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ className: classes.helpPopover, variant: "contained", onClick: handleClickHelpButton }, { children: _jsx(Icon, { children: "help_outline" }) })), isOpen && (_jsx(Popover, Object.assign({ open: isOpen, anchorEl: anchorElPopover, onClose: handleCloseHelpPopover, anchorOrigin: {
vertical: 'bottom',
horizontal: 'right'
} }, { children: _jsxs(Box, Object.assign({ sx: { p: '10px' } }, { children: [_jsx(Typography, Object.assign({ component: "h3" }, { children: _jsx(FormattedMessage, { id: "ui.changeCover.button.uploadA", defaultMessage: "ui.changeCover.button.uploadA" }) })), _jsx(Divider, {}), _jsx(Typography, Object.assign({ component: "span" }, { children: _jsx(FormattedMessage, { id: "ui.changeCover.info", defaultMessage: "ui.changeCover.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 })
} }) }))] })) })))] })), openDeleteCoverDialog && (_jsx(ConfirmDialog, { open: openDeleteCoverDialog, title: _jsx(FormattedMessage, { id: "ui.changeCover.dialog.msg", defaultMessage: "ui.changeCover.dialog.msg" }), onConfirm: deleteCover, isUpdating: isDeletingCover, onClose: () => {
setOpenDeleteCoverDialog(false);
setAnchorEl(null);
} }))] }));
/**
* If there is an error
*/
if (alert) {
return (_jsx(Alert, Object.assign({ color: "error", onClose: () => setAlert(null) }, { children: alert })));
}
/**
* Renders root object (if not hidden by autoHide prop)
*/
if (!autoHide) {
return (_jsx(Root, Object.assign({}, rest, { className: classNames(classes.root, className) }, { children: cc })));
}
return null;
}