UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

213 lines (212 loc) • 10.4 kB
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) })))] }))); }