UNPKG

@selfcommunity/react-ui

Version:

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

320 lines (311 loc) • 20.2 kB
import { __rest } from "tslib"; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { useMemo, useState } from 'react'; import { styled } from '@mui/material/styles'; import CardContent from '@mui/material/CardContent'; import CommentNotification from './Comment'; import UserFollowNotification from './UserFollow'; import UndeletedForNotification from './UndeletedFor'; import DeletedForNotification from './DeletedFor'; import UserConnectionNotification from './UserConnection'; import PrivateMessageNotification from './PrivateMessage'; import UserBlockedNotification from './UserBlocked'; import MentionNotification from './Mention'; import CollapsedForNotification from './CollapsedFor'; import KindlyNoticeForNotification from './KindlyNoticeFor'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import KindlyNoticeFlagNotification from './KindlyNoticeFlag'; import VoteUpNotification from './VoteUp'; import EventNotification from './Event/Event'; import LiveStreamNotification from './LiveStream/LiveStream'; import Icon from '@mui/material/Icon'; import { SCOPE_SC_UI } from '../../constants/Errors'; import { getContribution, getContributionRouteName, getContributionSnippet, getRouteData } from '../../utils/contribution'; import ContributionFollowNotification from './ContributionFollow'; import { Avatar, CardHeader, Collapse, ListItemButton, ListItemText, Tooltip } from '@mui/material'; import IncubatorApprovedNotification from './IncubatorApproved'; import { Endpoints, http } from '@selfcommunity/api-services'; import { Link, SCRoutes, useSCRouting } from '@selfcommunity/react-core'; import ContributionNotification from './Contribution'; import classNames from 'classnames'; import LoadingButton from '@mui/lab/LoadingButton'; import Widget from '../Widget'; import { useThemeProps } from '@mui/system'; import { Logger } from '@selfcommunity/utils'; import { SCNotificationTypologyType } from '@selfcommunity/types'; import UserDeletedSnackBar from '../../shared/UserDeletedSnackBar'; import UserAvatar from '../../shared/UserAvatar'; import { PREFIX } from './constants'; import GroupNotification from './Group'; const messages = defineMessages({ receivePrivateMessage: { id: 'ui.notification.receivePrivateMessage', defaultMessage: 'ui.notification.receivePrivateMessage' } }); const classes = { root: `${PREFIX}-root`, header: `${PREFIX}-header`, avatar: `${PREFIX}-avatar`, title: `${PREFIX}-title`, image: `${PREFIX}-image`, username: `${PREFIX}-username`, content: `${PREFIX}-content`, unCollapsed: `${PREFIX}-uncollapsed`, collapsed: `${PREFIX}-collapsed`, stopButton: `${PREFIX}-stop-button`, showOtherAggregated: `${PREFIX}-show-other-aggregated` }; const Root = styled(Widget, { name: PREFIX, slot: 'Root' })(() => ({})); /** * > API documentation for the Community-JS UserNotification component. Learn about the available props and the CSS API. #### Import ```jsx import {UserNotification} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCNotification` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCNotification-root|Styles applied to the root element.| |content|.SCNotification-notification-wrap|Styles applied to the element wrap.| |header|.SCNotification-notification-wrap|Styles applied to the notification header.| |title|.SCNotification-title|Styles applied to the title element in the notification header.| |image|.SCNotification-image|Styles applied to the image element in the notification header.| |username|.SCNotification-username|Styles applied to the user element in the notification header.| |content|.SCNotification-notification-content|Styles applied to the notification content.| |unCollapsed|.SCNotification-notification-wrap|Styles applied to the uncollapsed elements.| |collapsed|.SCNotification-notification-wrap|Styles applied to the collapsed elements.| |stopButton|.SCNotification-stop-notification-button|Styles applied to the stop notification button.| |showOtherAggregated|.SCNotification-show-other-aggregated|Styles applied to the show other aggregated element.| * @param inProps */ export default function UserNotification(inProps) { // PROPS const props = useThemeProps({ props: inProps, name: PREFIX }); const { id = `notification_${props.notificationObject.sid}`, className, notificationObject, handleCustomNotification, showMaxAggregated = 2, collapsedOtherAggregated = true, onStateChange, onHeightChange } = props, rest = __rest(props, ["id", "className", "notificationObject", "handleCustomNotification", "showMaxAggregated", "collapsedOtherAggregated", "onStateChange", "onHeightChange"]); // ROUTING const scRoutingContext = useSCRouting(); // STATE const [obj, setObj] = useState(notificationObject); const [loadingSuspendNotification, setLoadingSuspendNotification] = useState(false); const [openOtherAggregated, setOpenOtherAggregated] = useState(!collapsedOtherAggregated); const [openAlert, setOpenAlert] = useState(false); //INTL const intl = useIntl(); /** * Notify changes to Feed if the FeedObject is contained in the feed */ const notifyFeedChanges = useMemo(() => (state) => { if (onStateChange && state) { onStateChange(state); } onHeightChange && onHeightChange(); }, [onStateChange, onHeightChange]); /** * Performs notification suspension */ const performSuspendNotification = useMemo(() => (obj) => { return http .request({ url: Endpoints.UserSuspendContributionNotification.url({ type: obj.type, id: obj.id }), method: Endpoints.UserSuspendContributionNotification.method }) .then((res) => { if (res.status >= 300) { return Promise.reject(res); } return Promise.resolve(res.data); }); }, [obj]); /** * Handles stop notification for contribution * @param contribution */ function handleStopContentNotification(contribution) { setLoadingSuspendNotification(true); performSuspendNotification(contribution) .then((data) => { const newObj = obj; newObj[contribution.type].suspended = !newObj[contribution.type].suspended; setObj(newObj); setLoadingSuspendNotification(false); }) .catch((error) => { Logger.error(SCOPE_SC_UI, error); }); } /** * Handles vote * @param index */ const handleVote = (index) => { return (contribution) => { const newObj = Object.assign({}, notificationObject); const _notification = Object.assign({}, newObj.aggregated[index]); _notification[contribution.type] = contribution; newObj.aggregated[index] = _notification; setObj(newObj); }; }; /** * Open/close other aggregated activities * The layout change -> call onStateChange */ function setStateAggregated() { const _openOtherAggregated = !openOtherAggregated; notifyFeedChanges({ collapsedOtherAggregated: _openOtherAggregated }); setOpenOtherAggregated(_openOtherAggregated); } /** * Render: * - discussion/post/status summary if notification include contribute * - user header for private message */ function renderNotificationHeader() { /** * Private messages header */ if (notificationObject.aggregated && notificationObject.aggregated[0].type === SCNotificationTypologyType.PRIVATE_MESSAGE) { let messageNotification = notificationObject.aggregated[0]; return (_jsx(CardHeader, { className: classes.header, avatar: _jsx(Link, Object.assign({}, (!messageNotification.message.sender.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, messageNotification.message.sender) }), { onClick: messageNotification.message.sender.deleted ? () => setOpenAlert(true) : null }, { children: _jsx(UserAvatar, Object.assign({ hide: !messageNotification.message.sender.community_badge, smaller: true }, { children: _jsx(Avatar, { className: classes.avatar, alt: messageNotification.message.sender.username, variant: "circular", src: messageNotification.message.sender.avatar }) })) })), titleTypographyProps: { className: classes.title, variant: 'subtitle1' }, title: _jsxs(_Fragment, { children: [_jsx(Link, Object.assign({}, (!messageNotification.message.sender.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, messageNotification.message.sender) }), { onClick: messageNotification.message.sender.deleted ? () => setOpenAlert(true) : null, className: classes.username }, { children: messageNotification.message.sender.username })), ' ', intl.formatMessage(messages.receivePrivateMessage, { total: notificationObject.aggregated.length, b: (...chunks) => _jsx("strong", { children: chunks }) })] }) })); } /** * Group notifications header */ if (notificationObject.aggregated && (notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_INVITED_TO_JOIN_GROUP || notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_GROUP || notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_ADDED_TO_GROUP || notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_GROUP)) { let groupNotification = notificationObject.aggregated[0]; return (_jsx(CardHeader, { className: classes.header, avatar: _jsx(Link, Object.assign({}, (!groupNotification.user.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, groupNotification.user) }), { onClick: groupNotification.user.deleted ? () => setOpenAlert(true) : null }, { children: _jsx(UserAvatar, Object.assign({ hide: !groupNotification.user.community_badge, smaller: true }, { children: _jsx(Avatar, { className: classes.avatar, alt: groupNotification.user.username, variant: "circular", src: groupNotification.user.avatar }) })) })), titleTypographyProps: { className: classes.title, variant: 'subtitle1' }, title: _jsxs(_Fragment, { children: [_jsx(Link, Object.assign({}, (!groupNotification.user.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, groupNotification.user) }), { onClick: groupNotification.user.deleted ? () => setOpenAlert(true) : null, className: classes.username }, { children: groupNotification.user.username })), ' ', _jsx(FormattedMessage, { id: `ui.notification.${notificationObject.aggregated[0].type}`, defaultMessage: `ui.notification.${notificationObject.aggregated[0].type}`, values: { group: groupNotification.group.name, link: (...chunks) => (_jsx(Link, Object.assign({ to: notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_GROUP || notificationObject.aggregated[0].type === SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_GROUP ? scRoutingContext.url(SCRoutes.GROUP_MEMBERS_ROUTE_NAME, groupNotification.group) : scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, groupNotification.group) }, { children: chunks }))) } })] }) })); } /** * Comment, NestedComment, Follow Contribution header */ if (notificationObject.aggregated && (notificationObject.aggregated[0].type === SCNotificationTypologyType.COMMENT || notificationObject.aggregated[0].type === SCNotificationTypologyType.NESTED_COMMENT || notificationObject.aggregated[0].type === SCNotificationTypologyType.FOLLOW || notificationObject.aggregated[0].type === SCNotificationTypologyType.MENTION || notificationObject.aggregated[0].type === SCNotificationTypologyType.VOTE_UP || notificationObject.aggregated[0].type === SCNotificationTypologyType.CONTRIBUTION)) { const contribution = getContribution(notificationObject); return (_jsx(CardHeader, { className: classes.header, titleTypographyProps: { className: classes.title, variant: 'subtitle1' }, title: _jsx(Link, Object.assign({ to: scRoutingContext.url(getContributionRouteName(contribution), getRouteData(notificationObject[contribution.type])) }, { children: getContributionSnippet(contribution) })), action: contribution && (_jsx(Tooltip, Object.assign({ title: contribution.suspended ? (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspended', defaultMessage: 'ui.notification.notificationSuspended' })) : (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspend', defaultMessage: 'ui.notification.notificationSuspend' })) }, { children: _jsx(LoadingButton, Object.assign({ variant: "text", size: "small", loading: loadingSuspendNotification, color: 'inherit', classes: { root: classes.stopButton }, onClick: () => handleStopContentNotification(contribution) }, { children: contribution.suspended ? _jsx(Icon, Object.assign({ color: 'primary' }, { children: "notifications_off" })) : _jsx(Icon, Object.assign({ color: 'inherit' }, { children: "notifications_active" })) })) }))) })); } return null; } /** * Render every single notification in aggregated group * @param n * @param i */ function renderAggregatedItem(n, i) { if (n.type === SCNotificationTypologyType.COMMENT || n.type === SCNotificationTypologyType.NESTED_COMMENT) { return _jsx(CommentNotification, { notificationObject: n, onVote: handleVote(i) }, i); } else if (n.type === SCNotificationTypologyType.FOLLOW) { return _jsx(ContributionFollowNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.USER_FOLLOW) { return _jsx(UserFollowNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.CONNECTION_REQUEST || n.type === SCNotificationTypologyType.CONNECTION_ACCEPT) { return _jsx(UserConnectionNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.VOTE_UP) { return _jsx(VoteUpNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.KINDLY_NOTICE_ADVERTISING || n.type === SCNotificationTypologyType.KINDLY_NOTICE_AGGRESSIVE || n.type === SCNotificationTypologyType.KINDLY_NOTICE_POOR || n.type === SCNotificationTypologyType.KINDLY_NOTICE_VULGAR || n.type === SCNotificationTypologyType.KINDLY_NOTICE_OFFTOPIC) { return _jsx(KindlyNoticeForNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.KINDLY_NOTICE_FLAG) { return _jsx(KindlyNoticeFlagNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.DELETED_FOR_ADVERTISING || n.type === SCNotificationTypologyType.DELETED_FOR_AGGRESSIVE || n.type === SCNotificationTypologyType.DELETED_FOR_POOR || n.type === SCNotificationTypologyType.DELETED_FOR_VULGAR || n.type === SCNotificationTypologyType.DELETED_FOR_OFFTOPIC) { return _jsx(DeletedForNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.UNDELETED_FOR) { return _jsx(UndeletedForNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.COLLAPSED_FOR_ADVERTISING || n.type === SCNotificationTypologyType.COLLAPSED_FOR_AGGRESSIVE || n.type === SCNotificationTypologyType.COLLAPSED_FOR_POOR || n.type === SCNotificationTypologyType.COLLAPSED_FOR_VULGAR || n.type === SCNotificationTypologyType.COLLAPSED_FOR_OFFTOPIC) { return _jsx(CollapsedForNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.PRIVATE_MESSAGE) { return _jsx(PrivateMessageNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.BLOCKED_USER || n.type === SCNotificationTypologyType.UNBLOCKED_USER) { return _jsx(UserBlockedNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.MENTION) { return _jsx(MentionNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.INCUBATOR_APPROVED) { return _jsx(IncubatorApprovedNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.CUSTOM_NOTIFICATION) { handleCustomNotification && handleCustomNotification(n); } else if (n.type === SCNotificationTypologyType.CONTRIBUTION) { return _jsx(ContributionNotification, { notificationObject: n, onVote: handleVote(i) }, i); } else if (n.type === SCNotificationTypologyType.USER_ADDED_TO_GROUP || n.type === SCNotificationTypologyType.USER_INVITED_TO_JOIN_GROUP || n.type === SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_GROUP || n.type === SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_GROUP) { return _jsx(GroupNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.USER_ADDED_TO_EVENT || n.type === SCNotificationTypologyType.USER_INVITED_TO_JOIN_EVENT || n.type === SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_EVENT || n.type === SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_EVENT) { return _jsx(EventNotification, { notificationObject: n }, i); } else if (n.type === SCNotificationTypologyType.LIVE_STREAM_STARTED) { return _jsx(LiveStreamNotification, { notificationObject: n }, i); } return null; } /** * Renders root object */ return (_jsxs(_Fragment, { children: [_jsxs(Root, Object.assign({ id: id, className: classNames(classes.root, className) }, rest, { children: [renderNotificationHeader(), _jsxs(CardContent, Object.assign({ className: classes.content }, { children: [_jsx("div", Object.assign({ className: classes.unCollapsed }, { children: notificationObject.aggregated.slice(0, showMaxAggregated).map((n, i) => renderAggregatedItem(n, i)) })), notificationObject.aggregated.length > showMaxAggregated && (_jsxs(_Fragment, { children: [_jsxs(ListItemButton, Object.assign({ onClick: setStateAggregated, classes: { root: classes.showOtherAggregated } }, { children: [_jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: 'ui.notification.showOthers', defaultMessage: 'ui.notification.showOthers' }) }), openOtherAggregated ? _jsx(Icon, { children: "expand_less" }) : _jsx(Icon, { children: "expand_more" })] })), _jsx(Collapse, Object.assign({ in: openOtherAggregated, timeout: "auto", unmountOnExit: true, classes: { root: classes.collapsed } }, { children: notificationObject.aggregated.slice(showMaxAggregated).map((n, i) => renderAggregatedItem(n, i)) }))] }))] }))] })), openAlert && _jsx(UserDeletedSnackBar, { open: openAlert, handleClose: () => setOpenAlert(false) })] })); }