UNPKG

@selfcommunity/react-ui

Version:

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

289 lines (280 loc) • 16.3 kB
import { __rest } from "tslib"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useMemo, useRef, useState } from 'react'; import { styled } from '@mui/material/styles'; import CommentNotification from '../Notification/Comment'; import UserFollowNotification from '../Notification/UserFollow'; import UndeletedForNotification from '../Notification/UndeletedFor'; import DeletedForNotification from '../Notification/DeletedFor'; import UserConnectionNotification from '../Notification/UserConnection'; import PrivateMessageNotification from '../Notification/PrivateMessage'; import UserBlockedNotification from '../Notification/UserBlocked'; import MentionNotification from '../Notification/Mention'; import CollapsedForNotification from '../Notification/CollapsedFor'; import KindlyNoticeForNotification from '../Notification/KindlyNoticeFor'; import KindlyNoticeFlagNotification from '../Notification/KindlyNoticeFlag'; import VoteUpNotification from '../Notification/VoteUp'; import { SCOPE_SC_UI } from '../../constants/Errors'; import PubSub from 'pubsub-js'; import ContributionFollowNotification from '../Notification/ContributionFollow'; import { Avatar, Box, MenuItem, MenuList, Typography } from '@mui/material'; import IncubatorApprovedNotification from '../Notification/IncubatorApproved'; import classNames from 'classnames'; import Skeleton from './Skeleton'; import { SCNotificationObjectTemplateType } from '../../types'; import ScrollContainer from '../../shared/ScrollContainer'; import { FormattedMessage, useIntl } from 'react-intl'; import { SCNotificationTopicType, SCNotificationTypologyType } from '@selfcommunity/types'; import { Endpoints, http } from '@selfcommunity/api-services'; import { Logger } from '@selfcommunity/utils'; import { Link, SCNotification, SCPreferences, SCRoutes, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core'; import { useThemeProps } from '@mui/system'; import ContributionNotification from '../Notification/Contribution'; import NotificationItem from '../../shared/NotificationItem'; import { PREFIX } from './constants'; import GroupNotification from '../Notification/Group'; import EventNotification from '../Notification/Event/Event'; import LiveStreamNotification from '../Notification/LiveStream'; const classes = { root: `${PREFIX}-root`, notificationsWrap: `${PREFIX}-notifications-wrap`, emptyBoxNotifications: `${PREFIX}-empty-box-notifications`, list: `${PREFIX}-list`, broadcastMessagesBanner: `${PREFIX}-broadcast-messages-banner`, item: `${PREFIX}-item` }; const Root = styled(Box, { name: PREFIX, slot: 'Root' })(() => ({})); const PREFERENCES = [SCPreferences.LOGO_NAVBAR_LOGO_MOBILE, SCPreferences.TEXT_APPLICATION_NAME]; /** * > API documentation for the Community-JS SnippetNotifications component. Learn about the available props and the CSS API. * * * This component renders the notification list. * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/SnippetNotifications) #### Import ```jsx import {SnippetNotifications} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCSnippetNotifications` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCSnippetNotification-root|Styles applied to the root element.| |notificationsWrap|.SCSnippetNotification-notification-wrap|Styles applied to the notifications wrap.| |emptyBoxNotifications|.SCSnippetNotification-empty-box-notifications|Styles applied to the box indicating that there are no notifications.| |list|.SCSnippetNotification-list|Styles applied to the list of notifications.| |item|.SCSnippetNotification-item|Styles applied to the single notification.| |broadcastMessagesBanner|.SCSnippetNotification-broadcast-messages-banner|Styles applied to the broadcast message banner.| * @param inProps */ export default function SnippetNotifications(inProps) { // PROPS const props = useThemeProps({ props: inProps, name: PREFIX }); const { id = `snippetNotifications`, className, showMax = 20, handleCustomNotification, handleNotification, ScrollContainerProps = {}, onNotificationClick, onFetchNotifications } = props, rest = __rest(props, ["id", "className", "showMax", "handleCustomNotification", "handleNotification", "ScrollContainerProps", "onNotificationClick", "onFetchNotifications"]); // CONTEXT const scUserContext = useSCUser(); const scRoutingContext = useSCRouting(); // STATE const [notifications, setNotifications] = useState([]); const [initialized, setInitialized] = useState(false); const [loading, setLoading] = useState(false); // REFS const notificationSubscription = useRef(null); // Compute preferences const scPreferences = useSCPreferences(); const preferences = useMemo(() => { const _preferences = {}; PREFERENCES.map((p) => (_preferences[p] = p in scPreferences.preferences ? scPreferences.preferences[p].value : null)); return _preferences; }, [scPreferences.preferences]); // HOOKS const intl = useIntl(); /** * Perform vote */ const performFetchNotifications = useMemo(() => () => { return http .request({ url: Endpoints.UserNotificationList.url(), method: Endpoints.UserNotificationList.method }) .then((res) => { if (res.status >= 300) { return Promise.reject(res); } return Promise.resolve(res.data); }); }, []); /** * Handles vote * @param comment */ const fetchNotifications = useMemo(() => () => { setInitialized(true); if (!loading) { setLoading(true); performFetchNotifications() .then((data) => { setNotifications(data.results); setLoading(false); scUserContext.refreshCounters(); onFetchNotifications && onFetchNotifications(data.results); }) .catch((error) => { Logger.error(SCOPE_SC_UI, error); }); } }, [loading, notifications.length, onFetchNotifications, setInitialized]); /** * Fetch notifications */ useEffect(() => { let _t; if (scUserContext.user && !initialized) { _t = setTimeout(fetchNotifications); return () => { _t && clearTimeout(_t); }; } }, [scUserContext.user, initialized]); /** * Notification subscriber * @param msg * @param data */ const notificationSubscriber = (msg, data) => { /** * Ignore notifications of type: notification_banner * (data.data.activity_type === SCNotificationTypologyType.NOTIFICATION_BANNER) */ if (data && data.type === SCNotificationTopicType.INTERACTION && SCNotification.SCNotificationMapping[data.data.activity_type] && !SCNotification.SCSilentSnippetNotifications.includes(data.data.activity_type)) { if (data.data.notification_obj) { setNotifications([...[{ is_new: true, sid: '', aggregated: [data.data.notification_obj] }], ...notifications]); } } }; const handleSingleNotificationClick = (e, n) => { if (onNotificationClick) { onNotificationClick(e, n); } }; /** * On mount, fetches first page of notifications * On mount, subscribe to receive notification updates */ useEffect(() => { if (!loading) { notificationSubscription.current = PubSub.subscribe(SCNotificationTopicType.INTERACTION, notificationSubscriber); } return () => { notificationSubscription.current && PubSub.unsubscribe(notificationSubscription.current); }; }, [loading]); /** * Render every single notification in aggregated group * @param n * @param i */ const renderAggregatedItem = (n, i) => { const type = n.type; let content; if (type === SCNotificationTypologyType.COMMENT || type === SCNotificationTypologyType.NESTED_COMMENT) { content = _jsx(CommentNotification, { notificationObject: n, index: i, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.FOLLOW) { content = _jsx(ContributionFollowNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.USER_FOLLOW) { content = _jsx(UserFollowNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.CONNECTION_REQUEST || type === SCNotificationTypologyType.CONNECTION_ACCEPT) { content = _jsx(UserConnectionNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.VOTE_UP) { content = _jsx(VoteUpNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.KINDLY_NOTICE_ADVERTISING || type === SCNotificationTypologyType.KINDLY_NOTICE_AGGRESSIVE || type === SCNotificationTypologyType.KINDLY_NOTICE_POOR || type === SCNotificationTypologyType.KINDLY_NOTICE_VULGAR || type === SCNotificationTypologyType.KINDLY_NOTICE_OFFTOPIC) { content = _jsx(KindlyNoticeForNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.KINDLY_NOTICE_FLAG) { content = _jsx(KindlyNoticeFlagNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.DELETED_FOR_ADVERTISING || type === SCNotificationTypologyType.DELETED_FOR_AGGRESSIVE || type === SCNotificationTypologyType.DELETED_FOR_POOR || type === SCNotificationTypologyType.DELETED_FOR_VULGAR || type === SCNotificationTypologyType.DELETED_FOR_OFFTOPIC) { content = _jsx(DeletedForNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.UNDELETED_FOR) { content = _jsx(UndeletedForNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.COLLAPSED_FOR_ADVERTISING || type === SCNotificationTypologyType.COLLAPSED_FOR_AGGRESSIVE || type === SCNotificationTypologyType.COLLAPSED_FOR_POOR || type === SCNotificationTypologyType.COLLAPSED_FOR_VULGAR || type === SCNotificationTypologyType.COLLAPSED_FOR_OFFTOPIC) { content = _jsx(CollapsedForNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.PRIVATE_MESSAGE) { content = _jsx(PrivateMessageNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.BLOCKED_USER || type === SCNotificationTypologyType.UNBLOCKED_USER) { content = _jsx(UserBlockedNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.MENTION) { content = _jsx(MentionNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.INCUBATOR_APPROVED) { content = _jsx(IncubatorApprovedNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.CUSTOM_NOTIFICATION && handleCustomNotification) { content = handleCustomNotification(n); } else if (type === SCNotificationTypologyType.CONTRIBUTION) { content = _jsx(ContributionNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, 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, template: SCNotificationObjectTemplateType.SNIPPET }, 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, template: SCNotificationObjectTemplateType.SNIPPET }, i); } else if (type === SCNotificationTypologyType.LIVE_STREAM_STARTED) { content = _jsx(LiveStreamNotification, { notificationObject: n, template: SCNotificationObjectTemplateType.SNIPPET }, i); } if (type && handleNotification) { /** Override content */ content = handleNotification(type, n, content); } return content; }; /** * Renders root object */ return (_jsx(Root, Object.assign({ id: id, className: classNames(classes.root, className) }, rest, { children: _jsx(Box, Object.assign({ className: classes.notificationsWrap }, { children: !initialized || loading ? (_jsx(Skeleton, { elevation: 0 })) : (_jsx(ScrollContainer, Object.assign({}, ScrollContainerProps, { children: _jsxs(MenuList, Object.assign({ className: classes.list, disabledItemsFocusable: true, disableListWrap: true }, { children: [scUserContext.user.unseen_notification_banners_counter ? (_jsx(MenuItem, Object.assign({ className: classNames(classes.item, classes.broadcastMessagesBanner), component: Link, to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}) }, { children: _jsx(NotificationItem, { template: SCNotificationObjectTemplateType.SNIPPET, isNew: true, disableTypography: true, image: _jsx(Avatar, { alt: preferences[SCPreferences.TEXT_APPLICATION_NAME], src: preferences[SCPreferences.LOGO_NAVBAR_LOGO_MOBILE] }), primary: _jsx(Typography, Object.assign({ component: 'div' }, { children: intl.formatMessage({ id: 'ui.snippetNotifications.broadcastMessages', defaultMessage: 'ui.snippetNotifications.broadcastMessages' }, { count: scUserContext.user.unseen_notification_banners_counter, b: (...chunks) => _jsx("strong", { children: chunks }), link: (...chunks) => _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}) }, { children: chunks })) }) })) }) }), "banner")) : null, notifications.length === 0 ? (_jsx(MenuItem, Object.assign({ className: classes.emptyBoxNotifications }, { children: _jsx(FormattedMessage, { id: "ui.snippetNotifications.noNotifications", defaultMessage: "ui.snippetNotifications.noNotifications" }) }))) : (notifications.slice(0, showMax).map((notificationObject, i) => notificationObject.aggregated.map((n, k) => (_jsx(MenuItem, Object.assign({ className: classes.item, onClick: (e) => handleSingleNotificationClick(e, n), disableRipple: true, disableTouchRipple: true }, { children: renderAggregatedItem(n, i) }), k)))))] })) }))) })) }))); }