@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
226 lines (225 loc) • 13.5 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useContext, useMemo, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Icon from '@mui/material/Icon';
import LoadingButton from '@mui/lab/LoadingButton';
import SharesDialog from './SharesDialog';
import { styled } from '@mui/material/styles';
import { Box, Button, Divider, ListItemText, Menu, SwipeableDrawer, Tooltip, useMediaQuery, useTheme } from '@mui/material';
import MenuItem from '@mui/material/MenuItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import { MEDIA_EMBED_SC_SHARED_EVENT, MEDIA_TYPE_SHARE } from '../../../../constants/Media';
import { SCOPE_SC_UI } from '../../../../constants/Errors';
import classNames from 'classnames';
import { useSnackbar } from 'notistack';
import Skeleton from '@mui/material/Skeleton';
import { SCContributionType, SCGroupPrivacyType } from '@selfcommunity/types';
import { Endpoints, http } from '@selfcommunity/api-services';
import { copyTextToClipboard, Logger } from '@selfcommunity/utils';
import { SCPreferences, SCPreferencesContext, UserUtils, useSCContext, useSCFetchFeedObject, useSCRouting, useSCUser } from '@selfcommunity/react-core';
import { getContributionRouteName, getRouteData } from '../../../../utils/contribution';
import { FACEBOOK_SHARE, LINKEDIN_SHARE, X_SHARE } from '../../../../constants/SocialShare';
import Composer from '../../../Composer';
import { PREFIX } from '../../constants';
const messages = defineMessages({
shares: {
id: 'ui.feedObject.share.shares',
defaultMessage: 'ui.feedObject.share.shares'
},
share: {
id: 'ui.feedObject.share.share',
defaultMessage: 'ui.feedObject.share.share'
}
});
const classes = {
root: `${PREFIX}-action-share-root`,
divider: `${PREFIX}-action-share-divider`,
inline: `${PREFIX}-action-share-inline`,
button: `${PREFIX}-action-share-button`,
viewAudienceButton: `${PREFIX}-action-share-view-audience-button`
};
const Root = styled(Box, {
name: PREFIX,
slot: 'ActionShareRoot'
})(() => ({}));
export default function Share(props) {
// PROPS
const { className = null, feedObjectId = null, feedObject = null, feedObjectType = SCContributionType.POST, withAction = true, withAudience = true, inlineAction = false } = props, rest = __rest(props, ["className", "feedObjectId", "feedObject", "feedObjectType", "withAction", "withAudience", "inlineAction"]);
// STATE
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const { obj, setObj } = useSCFetchFeedObject({ id: feedObjectId, feedObject, feedObjectType });
const [isSharing, setIsSharing] = useState(false);
const [isComposerOpen, setIsComposerOpen] = useState(false);
const [composerShareProps, setComposerShareProps] = useState(null);
const [openSharesDialog, setOpenSharesDialog] = useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
// CONTEXT
const scContext = useSCContext();
const scRoutingContext = useSCRouting();
const scPreferencesContext = useContext(SCPreferencesContext);
const facebookShareEnabled = SCPreferences.ADDONS_SHARE_POST_ON_FACEBOOK_ENABLED in scPreferencesContext.preferences &&
scPreferencesContext.preferences[SCPreferences.ADDONS_SHARE_POST_ON_FACEBOOK_ENABLED].value;
const xShareEnabled = SCPreferences.ADDONS_SHARE_POST_ON_TWITTER_ENABLED in scPreferencesContext.preferences &&
scPreferencesContext.preferences[SCPreferences.ADDONS_SHARE_POST_ON_TWITTER_ENABLED].value;
const linkedinShareEnabled = SCPreferences.ADDONS_SHARE_POST_ON_LINKEDIN_ENABLED in scPreferencesContext.preferences &&
scPreferencesContext.preferences[SCPreferences.ADDONS_SHARE_POST_ON_LINKEDIN_ENABLED].value;
const scUserContext = useSCUser();
const { enqueueSnackbar } = useSnackbar();
const domain = typeof location !== 'undefined' && location.origin ? location.origin : '';
const url = domain + scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj));
const isGroupPublic = useMemo(() => feedObject.group && feedObject.group.privacy === SCGroupPrivacyType.PUBLIC, [feedObject.group]);
const showShareAction = useMemo(() => {
return !scPreferencesContext.preferences[SCPreferences.CONFIGURATIONS_POST_ONLY_STAFF_ENABLED].value || UserUtils.isStaff(scUserContext.user);
}, [scPreferencesContext, scUserContext.user]);
// INTL
const intl = useIntl();
// HANDLERS
const handleOpenShareMenu = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
/**
* Open/Close dialog shares
*/
function handleToggleSharesDialog() {
setOpenSharesDialog(!openSharesDialog);
}
/**
* Handles Composer onClose
*/
function handleComposerOnClose() {
setIsSharing(false);
setIsComposerOpen(false);
}
/**
* Handles Composer onSuccess
*/
function handleComposerOnSuccess() {
setObj(Object.assign({}, obj, { share_count: obj.share_count + 1 }));
handleComposerOnClose();
}
/**
* Performs follow/unfollow
* Post, Discussion, Status
*/
const performCreateMediaShare = useMemo(() => () => {
// Define share object id
let sharedObjectId = obj.id;
// Avoid to re-share an object with a shared_object in medias
const shareMedias = obj.medias.filter((media) => media.type === MEDIA_TYPE_SHARE);
if (shareMedias.length) {
sharedObjectId = shareMedias[0].embed.metadata.id;
}
const isMediaEvent = obj.medias.some((media) => { var _a; return ((_a = media.embed) === null || _a === void 0 ? void 0 : _a.embed_type) === MEDIA_EMBED_SC_SHARED_EVENT; });
return http
.request({
url: Endpoints.ComposerMediaCreate.url(),
method: Endpoints.ComposerMediaCreate.method,
data: {
type: MEDIA_TYPE_SHARE,
[isMediaEvent ? 'event_object' : 'shared_object']: sharedObjectId
}
})
.then((res) => {
if (res.status >= 300) {
return Promise.reject(res);
}
return Promise.resolve(res.data);
});
}, [obj]);
/**
* Performs the contribution sharing
*/
function share(inCategories) {
if (!scUserContext.user) {
scContext.settings.handleAnonymousAction();
}
else {
if (UserUtils.isBlocked(scUserContext.user)) {
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.userBlocked", defaultMessage: "ui.common.userBlocked" }), {
variant: 'warning',
autoHideDuration: 3000
});
}
else {
setIsSharing(true);
performCreateMediaShare()
.then((data) => {
setComposerShareProps(Object.assign({ medias: [data] }, (inCategories ? { categories: obj.categories } : {})));
setIsComposerOpen(true);
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
setIsSharing(false);
});
}
}
}
/**
* Get permalink
*/
function getPermalink() {
copyTextToClipboard(url).then(() => {
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.permanentLinkCopied", defaultMessage: "ui.common.permanentLinkCopied" }), {
variant: 'success',
autoHideDuration: 3000
});
});
}
/**
* Renders audience with detail dialog
* @return {JSX.Element}
*/
function renderAudience() {
const sharesCount = obj.share_count;
let audience;
if (withAudience) {
if (!obj) {
audience = (_jsx(Button, Object.assign({ variant: "text", size: "small", disabled: true, color: "inherit" }, { children: _jsx(Skeleton, { animation: "wave", height: 18, width: 50 }) })));
}
else {
audience = (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ variant: "text", size: "small", onClick: handleToggleSharesDialog, disabled: sharesCount < 1, classes: { root: classes.viewAudienceButton } }, { children: `${intl.formatMessage(messages.shares, { total: sharesCount })}` })), openSharesDialog && sharesCount > 0 && (_jsx(SharesDialog, { feedObject: obj, feedObjectType: obj.type, open: openSharesDialog, onClose: handleToggleSharesDialog }))] }));
}
}
return audience;
}
function renderShareMenuItems() {
return (_jsxs(Box, { children: [(!feedObject.group || isGroupPublic) && (_jsxs(_Fragment, { children: [showShareAction && (_jsxs(MenuItem, Object.assign({ onClick: () => share(false) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "redo" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.feedObject.share.shareNow", defaultMessage: "ui.feedObject.share.shareNow" }) })] }))), facebookShareEnabled && (_jsxs(MenuItem, Object.assign({ onClick: () => window.open(FACEBOOK_SHARE + url, 'facebook-share-dialog', 'width=626,height=436') }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "facebook" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.feedObject.share.facebook", defaultMessage: "ui.feedObject.share.facebook" }) })] }))), xShareEnabled && (_jsxs(MenuItem, Object.assign({ onClick: () => window.open(X_SHARE + url, 'x-share-dialog', 'width=626,height=436') }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "twitter" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.feedObject.share.x", defaultMessage: "ui.feedObject.share.x" }) })] }))), linkedinShareEnabled && (_jsxs(MenuItem, Object.assign({ onClick: () => window.open(LINKEDIN_SHARE + url, 'linkedin-share-dialog', 'width=626,height=436') }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "linkedin" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.feedObject.share.linkedin", defaultMessage: "ui.feedObject.share.linkedin" }) })] })))] })), _jsxs(MenuItem, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "link" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.feedObject.share.permanentLink", defaultMessage: "ui.feedObject.share.permanentLink" }), onClick: () => getPermalink() })] })] }));
}
/**
* Renders vote action if withAction==true
* @return {JSX.Element}
*/
function renderShareBtn() {
return (_jsx(React.Fragment, { children: withAction && (_jsxs(React.Fragment, { children: [!inlineAction && withAudience && _jsx(Divider, { className: classes.divider }), _jsx(Tooltip, Object.assign({ title: `${intl.formatMessage(messages.share)}` }, { children: _jsx(LoadingButton, Object.assign({ loading: isSharing, onClick: handleOpenShareMenu, className: classes.button }, { children: _jsx(Icon, { children: "share" }) })) })), Boolean(anchorEl) && (_jsx(_Fragment, { children: !isMobile ? (_jsx(Menu, Object.assign({ anchorEl: anchorEl, open: true, onClose: handleClose, onClick: handleClose, slotProps: {
paper: {
elevation: 0,
sx: {
overflow: 'visible',
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
mt: 1.5,
'&:before': {
content: '""',
display: 'block',
position: 'absolute',
top: 0,
right: 14,
width: 10,
height: 10,
bgcolor: 'background.paper',
transform: 'translateY(-50%) rotate(45deg)',
zIndex: 0
}
}
}
}, transformOrigin: { horizontal: 'right', vertical: 'top' }, anchorOrigin: { horizontal: 'right', vertical: 'bottom' } }, { children: renderShareMenuItems() }))) : (_jsx(SwipeableDrawer, Object.assign({ open: true, onClick: handleClose, onClose: handleClose, onOpen: handleOpenShareMenu, anchor: "bottom", disableSwipeToOpen: true }, { children: renderShareMenuItems() }))) })), isComposerOpen && (_jsx(Composer, { open: true, defaultValue: composerShareProps, onClose: handleComposerOnClose, onSuccess: handleComposerOnSuccess, maxWidth: "sm", fullWidth: true }))] })) }));
}
/**
* Renders share action
*/
return (_jsxs(Root, Object.assign({ className: classNames(classes.root, className, { [classes.inline]: inlineAction }) }, rest, { children: [renderAudience(), renderShareBtn()] })));
}