diff --git a/src/components/Dashboard/common/Notification.jsx b/src/components/Dashboard/common/Notification.jsx index d7bd2cc..162f0a2 100644 --- a/src/components/Dashboard/common/Notification.jsx +++ b/src/components/Dashboard/common/Notification.jsx @@ -1,12 +1,15 @@ -import { useState } from 'react' +import { useState, memo, useMemo } from 'react' import PropTypes from 'prop-types' -import { Typography, Button, Tag, Badge, Flex, Card, Divider } from 'antd' import { - BellOutlined, - InfoCircleOutlined, - ExclamationCircleOutlined, - CheckCircleOutlined -} from '@ant-design/icons' + Typography, + Button, + Tag, + Badge, + Flex, + Card, + Divider, + Popover +} from 'antd' import TimeDisplay from './TimeDisplay' import EditIcon from '../../Icons/EditIcon' import PropertyChanges from './PropertyChanges' @@ -15,9 +18,194 @@ import ObjectDisplay from './ObjectDisplay' import BinIcon from '../../Icons/BinIcon' import NoteItem from './NoteItem' import PlusIcon from '../../Icons/PlusIcon' +import InfoCircleIcon from '../../Icons/InfoCircleIcon' +import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon' +import CheckCircleIcon from '../../Icons/CheckCircleIcon' +import BellIcon from '../../Icons/BellIcon' +import { getModelByName } from '../../../database/ObjectModels' const { Text, Paragraph } = Typography +const getNotificationMessage = (type, metadata) => { + const objectType = metadata?.objectType ?? metadata?.note?.parentType + const model = objectType ? getModelByName(objectType) : null + const objectLabel = model?.label?.toLowerCase() ?? 'object' + + switch (type) { + case 'editObject': + return `A ${objectLabel} was updated.` + case 'deleteObject': + return `A ${objectLabel} was deleted.` + case 'newNote': + return 'A new note was added.' + case 'info': + return 'You have a new notification.' + case 'error': + return 'An error occurred.' + case 'success': + return 'Action completed successfully.' + default: + return 'You have a new notification.' + } +} + +const getParagraphProps = (largeSpacing) => ({ + ellipsis: { + rows: 2, + expandable: true, + symbol: 'Show more' + }, + style: { + margin: largeSpacing ? '10px 0 0 0' : 0, + lineHeight: 1.7, + marginBottom: 2 + } +}) + +const NotificationBody = memo(function NotificationBody({ + type, + message, + metadata, + largeSpacing +}) { + const paragraph = getParagraphProps(largeSpacing) + + switch (type) { + case 'editObject': + if (metadata?.old || metadata?.new) { + return ( + + ) + } + return {message} + case 'newNote': + return ( + + ) + case 'deleteObject': + return {message} + case 'info': + case 'error': + case 'success': + return {message} + default: + return {message} + } +}) + +NotificationBody.propTypes = { + type: PropTypes.string, + message: PropTypes.string, + metadata: PropTypes.object, + largeSpacing: PropTypes.bool +} + +const NotificationDetails = memo(function NotificationDetails({ + type, + message, + metadata, + largeSpacing +}) { + const paragraph = getParagraphProps(largeSpacing) + const object = metadata?.object + const user = metadata?.user + const objectType = metadata?.objectType + const note = metadata?.note + + switch (type) { + case 'editObject': + return ( + + + Object: + + + + User: + + + + ) + case 'newNote': + return ( + + + + ) + case 'deleteObject': + return ( + + + Object: + + + + User: + + + + ) + case 'info': + case 'error': + case 'success': + return {message} + default: + return {message} + } +}) + +NotificationDetails.propTypes = { + type: PropTypes.string, + message: PropTypes.string, + metadata: PropTypes.object, + largeSpacing: PropTypes.bool +} + const Notification = ({ notification, onMarkAsRead, @@ -27,14 +215,16 @@ const Notification = ({ showExtraInfo = true, inlineIcon = false, largeSpacing = false, - showSince = true + showSince = true, + showDetails = true, + largeTitleSpacing = false }) => { const [deleting, setDeleting] = useState(false) - const getNotificationIcon = (type) => { + const getNotificationTagIcon = (type) => { switch (type) { case 'info': - return + return case 'editObject': return case 'newNote': @@ -42,16 +232,29 @@ const Notification = ({ case 'deleteObject': return case 'error': - return + return case 'success': - return + return default: - return + return } } + const getNotificationIcon = (type, metadata) => { + if (['editObject', 'newNote', 'deleteObject'].includes(type)) { + const objectType = metadata?.objectType ?? metadata?.note?.parentType + const model = objectType ? getModelByName(objectType) : null + if (model?.icon) { + const Icon = model.icon + return + } + } + + return getNotificationTagIcon(type) + } + const getNotificationTag = (type) => { - const icon = getNotificationIcon(type) + const icon = getNotificationTagIcon(type) switch (type) { case 'info': return ( @@ -98,71 +301,6 @@ const Notification = ({ } } - const getMetadataDisplay = (metadata, type) => { - if (metadata.old && metadata.new && type === 'editObject') { - return ( - - ) - } - return null - } - - const getNotificationMessage = (metadata, type) => { - const paragraph = { - ellipsis: { - rows: 2, - expandable: true, - symbol: 'Show more' - }, - style: { margin: largeSpacing ? '10px 0 0 0' : 0 } - } - switch (type) { - case 'editObject': { - return ( - - Object: - - User: - - - ) - } - case 'newNote': { - return ( - - - - ) - } - default: - return {notification.message} - } - } - const handleMarkAsRead = () => { if (onMarkAsRead && !notification.read) { onMarkAsRead(notification._id) @@ -181,46 +319,114 @@ const Notification = ({ } } + const message = useMemo( + () => getNotificationMessage(notification.type, notification.metadata), + [notification.type, notification.metadata] + ) + + const notificationDetails = useMemo( + () => ( + + ), + [notification.type, message, notification.metadata, largeSpacing] + ) + + const notificationBody = useMemo( + () => ( + + ), + [notification.type, message, notification.metadata, largeSpacing] + ) + const content = ( - - - - - {inlineIcon && getNotificationIcon(notification.type)} - - {notification.title} - + + + + + + {inlineIcon && + getNotificationIcon(notification.type, notification.metadata)} + + + {notification.title} + + + + {showDetails && ( + + {notificationDetails} + + } + > + + + )} + {showDelete && ( + +