@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
213 lines (212 loc) • 10.4 kB
JavaScript
import { __awaiter, __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useContext, useMemo, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
import { FormattedMessage } from 'react-intl';
import Popper from '@mui/material/Popper';
import Icon from '@mui/material/Icon';
import { useSnackbar } from 'notistack';
import classNames from 'classnames';
import { Box, ClickAwayListener, Grow, IconButton, ListItemIcon, ListItemText, MenuItem, MenuList, Paper, SwipeableDrawer, useMediaQuery, useTheme } from '@mui/material';
import { LiveStreamApiClient } from '@selfcommunity/api-services';
import { SCContext, SCUserContext } from '@selfcommunity/react-core';
import { BAN_ROOM_USER, REMOVE_ROOM_USER } from './constants';
import ConfirmDialog from '../../../shared/ConfirmDialog/ConfirmDialog';
import { useEnsureParticipant } from '@livekit/components-react';
import { useLiveStream } from './LiveStreamProvider';
import { Logger } from '@selfcommunity/utils';
import { SCOPE_SC_UI } from '../../../constants/Errors';
const PREFIX = 'SCParticipantTileActionsMenu';
const classes = {
root: `${PREFIX}-root`,
button: `${PREFIX}-button`,
popperRoot: `${PREFIX}-popper-root`,
paper: `${PREFIX}-paper`,
item: `${PREFIX}-item`,
itemText: `${PREFIX}-item-text`,
subItem: `${PREFIX}-sub-item`,
subItemText: `${PREFIX}-sub-item-text`,
footerSubItems: `${PREFIX}-footer-sub-items`,
selectedIcon: `${PREFIX}-selected-icon`,
sectionBadge: `${PREFIX}-section-badge`,
sectionWithSelectionIcon: `${PREFIX}-section-with-selection-icon`,
visibilityIcons: `${PREFIX}-visibility-icons`
};
const PopperRoot = styled(Popper, {
name: PREFIX,
slot: 'Root',
overridesResolver: (props, styles) => styles.popperRoot
})(() => ({
'& .SCParticipantTileActionsMenu-paper': {
borderRadius: 5
}
}));
const Root = styled(Box, {
name: PREFIX,
slot: 'Root',
overridesResolver: (props, styles) => styles.root
})(({ theme }) => ({
display: 'inline-block',
'& button': {
color: theme.palette.common.white
}
}));
export default function ContributionActionsMenu(props) {
// PROPS
const { className, participant, onRemoveParticipant, onBanParticipant, PopperProps = {} } = props, rest = __rest(props, ["className", "participant", "onRemoveParticipant", "onBanParticipant", "PopperProps"]);
// CONTEXT
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const scContext = useContext(SCContext);
const scUserContext = useContext(SCUserContext);
const { enqueueSnackbar } = useSnackbar();
const p = useEnsureParticipant(participant);
const { liveStream } = useLiveStream();
// GENERAL POPPER STATE
const [open, setOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
// CONFIRM ACTION DIALOG STATE
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
const [currentAction, setCurrentAction] = useState(null);
const [currentActionLoading, setCurrentActionLoading] = useState(null);
// CONST
let popperRef = useRef(null);
/**
* Handles open popup
*/
function handleOpen() {
if (scUserContext.user) {
setOpen(true);
}
else {
scContext.settings.handleAnonymousAction();
}
}
/**
* Closes popup
*/
function handleClose() {
if (popperRef.current && popperRef.current.contains(event.target)) {
return;
}
setOpen(false);
if (rest.onClose) {
rest.onClose();
}
}
/**
* Perform ban participant
*/
const performRemoveOrBanParticipant = useMemo(() => (ban = false) => __awaiter(this, void 0, void 0, function* () {
const res = yield LiveStreamApiClient.removeParticipant(liveStream.id, { participant_id: p.identity, ban });
if (res.status >= 300) {
return Promise.reject(res);
}
return yield Promise.resolve(res.data);
}), [p]);
/**
* Handle action
*/
function handleAction(action) {
if ([REMOVE_ROOM_USER, BAN_ROOM_USER].indexOf(action) > -1) {
setCurrentAction(action);
setOpenConfirmDialog(true);
handleClose();
}
}
/**
* Perform additional operations at the end of single action
*/
function performPostConfirmAction(success) {
if (success) {
setCurrentActionLoading(null);
setCurrentAction(null);
setOpenConfirmDialog(false);
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.contributionActionMenu.actionSuccess", defaultMessage: "ui.contributionActionMenu.actionSuccess" }), {
variant: 'success',
autoHideDuration: 3000
});
}
else {
setCurrentActionLoading(null);
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.contributionActionMenu.actionError", defaultMessage: "ui.contributionActionMenu.actionError" }), {
variant: 'error',
autoHideDuration: 3000
});
}
}
/**
* Delete a contribution
*/
function handleConfirmedAction() {
if (p && !isLoading && !currentActionLoading) {
if (currentAction === REMOVE_ROOM_USER) {
setCurrentActionLoading(REMOVE_ROOM_USER);
performRemoveOrBanParticipant()
.then(() => {
onRemoveParticipant && onRemoveParticipant(p);
performPostConfirmAction(true);
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
performPostConfirmAction(false);
});
}
else if (currentAction === BAN_ROOM_USER) {
setCurrentActionLoading(BAN_ROOM_USER);
performRemoveOrBanParticipant(true)
.then(() => {
onBanParticipant && onBanParticipant(p);
performPostConfirmAction(true);
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
performPostConfirmAction(false);
});
}
}
}
/**
* Can authenticated ban a user in a room
*/
const canRemoveOrBanUser = useMemo(() => () => {
return (scUserContext.user &&
liveStream &&
p &&
p.identity &&
liveStream.host.id === scUserContext.user.id &&
scUserContext.user.id.toString() !== p.identity);
}, [scUserContext, liveStream, p]);
/**
* Renders section general
*/
function renderGeneralSection() {
return (_jsx(Box, { children: canRemoveOrBanUser() && (_jsxs(_Fragment, { children: [_jsxs(MenuItem, Object.assign({ className: classes.subItem, disabled: currentActionLoading === REMOVE_ROOM_USER, onClick: () => handleAction(REMOVE_ROOM_USER) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "person" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.liveStreamRoom.participantTileActions.removeRoomUser", defaultMessage: "ui.liveStreamRoom.participantTileActions.removeRoomUser" }), classes: { root: classes.itemText } })] })), _jsxs(MenuItem, Object.assign({ className: classes.subItem, disabled: currentActionLoading === BAN_ROOM_USER, onClick: () => handleAction(BAN_ROOM_USER) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "error" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.liveStreamRoom.participantTileActions.banRoomUser", defaultMessage: "ui.liveStreamRoom.participantTileActions.banRoomUser" }), classes: { root: classes.itemText } })] }))] })) }));
}
/**
* Renders contribution menu content
*/
function renderContent() {
return (_jsx(Box, { children: _jsx(MenuList, { children: renderGeneralSection() }) }));
}
/**
* Renders component only if the logged user has actions available
*/
if (!canRemoveOrBanUser()) {
return null;
}
/**
* Renders component
*/
return (_jsxs(Root, Object.assign({ className: classNames(classes.root, className) }, { children: [_jsx(IconButton, Object.assign({ ref: (ref) => {
popperRef.current = ref;
}, "aria-haspopup": "true", onClick: handleOpen, className: classes.button, size: "small" }, { children: _jsx(Icon, { children: "expand_more" }) })), open && (_jsx(_Fragment, { children: isMobile ? (_jsx(SwipeableDrawer, Object.assign({ open: true, onClose: handleClose, onOpen: handleOpen, anchor: "bottom", disableSwipeToOpen: true }, { children: renderContent() }))) : (_jsx(PopperRoot, Object.assign({ open: true, anchorEl: popperRef.current, role: undefined, transition: true, className: classes.popperRoot }, PopperProps, { placement: "right" }, { children: ({ TransitionProps, placement }) => (_jsx(Grow, Object.assign({}, TransitionProps, { style: { transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' } }, { children: _jsx(Paper, Object.assign({ variant: 'outlined', className: classes.paper }, { children: _jsx(ClickAwayListener, Object.assign({ onClickAway: handleClose }, { children: renderContent() })) })) }))) }))) })), openConfirmDialog && (_jsx(ConfirmDialog, Object.assign({ open: openConfirmDialog }, (currentAction === REMOVE_ROOM_USER
? {
content: (_jsx(FormattedMessage, { id: "ui.liveStreamRoom.participantTileActions.removeRoomUser", defaultMessage: "ui.liveStreamRoom.participantTileActions.removeRoomUser" }))
}
: currentAction === BAN_ROOM_USER
? {
content: (_jsx(FormattedMessage, { id: "ui.liveStreamRoom.participantTileActions.banRoomUser", defaultMessage: "ui.liveStreamRoom.participantTileActions.banRoomUser" }))
}
: {}), { onConfirm: handleConfirmedAction, isUpdating: Boolean(currentActionLoading), onClose: () => setOpenConfirmDialog(false) })))] })));
}