feat(notification): add custom notification component support (#5605)
* feat: add custom notification component support * update the documentation of UINotificationService to support custom component integration --------- Co-authored-by: trenser-belbin <belbin.kunjumon@prenuvo.com>
This commit is contained in:
parent
fd86a9e3e8
commit
c4e5a4616d
@ -4,6 +4,7 @@ const serviceImplementation = {
|
||||
console.debug('show() NOT IMPLEMENTED');
|
||||
return null;
|
||||
},
|
||||
_customComponent: null,
|
||||
};
|
||||
|
||||
type ToastType = 'success' | 'error' | 'info' | 'warning' | 'loading';
|
||||
@ -17,21 +18,38 @@ class UINotificationService {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This provides flexibility in customizing the Notification default component
|
||||
*
|
||||
* @returns {React.Component}
|
||||
*/
|
||||
getCustomComponent() {
|
||||
return serviceImplementation._customComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {*} {
|
||||
* hide: hideImplementation,
|
||||
* show: showImplementation,
|
||||
* component: componentImplementation
|
||||
* }
|
||||
*/
|
||||
public setServiceImplementation({ hide: hideImplementation, show: showImplementation }): void {
|
||||
public setServiceImplementation({
|
||||
hide: hideImplementation,
|
||||
show: showImplementation,
|
||||
customComponent: customComponentImplementation,
|
||||
}): void {
|
||||
if (hideImplementation) {
|
||||
serviceImplementation._hide = hideImplementation;
|
||||
}
|
||||
if (showImplementation) {
|
||||
serviceImplementation._show = showImplementation;
|
||||
}
|
||||
if (customComponentImplementation) {
|
||||
serviceImplementation._customComponent = customComponentImplementation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -34,12 +34,14 @@ is expected to support, [check out it's interface in `@ohif/core`][interface]
|
||||
| ---------- | --------------------------------------- |
|
||||
| `hide()` | Hides the specified notification |
|
||||
| `show()` | Creates and displays a new notification |
|
||||
| `customComponent()` | Overrides the default Notification component |
|
||||
|
||||
## Implementations
|
||||
|
||||
| Implementation | Consumer |
|
||||
| ---------------------------------------- | ----------------------------------------- |
|
||||
| [Snackbar Provider][snackbar-provider]\* | [SnackbarContainer][snackbar-container]\* |
|
||||
| customComponent | user extensions via `setServiceImplementation({customComponent: Snackbar})` |
|
||||
|
||||
`*` - Denotes maintained by OHIF
|
||||
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
import React, { createContext, useContext, useCallback, useEffect, ReactNode, useRef } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useCallback,
|
||||
useEffect,
|
||||
ReactNode,
|
||||
useState,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Toaster, toast } from '../components';
|
||||
|
||||
@ -27,17 +35,26 @@ const NotificationProvider = ({
|
||||
title: '',
|
||||
message: '',
|
||||
duration: 5000,
|
||||
position: 'bottom-right', // Aligning to Sonner's positioning system
|
||||
type: 'info', // info, success, error
|
||||
position: 'bottom-right',
|
||||
type: 'info',
|
||||
visible: true,
|
||||
};
|
||||
const [options, setOptions] = useState([]);
|
||||
|
||||
// Cache for recent notifications to prevent duplicates
|
||||
// Structure: { [title_message_type]: { timestamp, id } }
|
||||
const recentNotificationsRef = useRef<Record<string, NotificationCacheEntry>>({});
|
||||
|
||||
const CustomNotification = service?.getCustomComponent();
|
||||
|
||||
// Use the configurable deduplication interval from props
|
||||
|
||||
const show = useCallback(options => {
|
||||
const newNotification = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
};
|
||||
|
||||
const {
|
||||
title,
|
||||
message,
|
||||
@ -48,10 +65,7 @@ const NotificationProvider = ({
|
||||
allowDuplicates = false,
|
||||
deduplicationInterval: optionsDeduplicationInterval,
|
||||
action,
|
||||
} = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
};
|
||||
} = newNotification;
|
||||
|
||||
// Use the provider's deduplicationInterval by default, but allow it to be overridden per notification
|
||||
const notificationDeduplicationInterval = optionsDeduplicationInterval || deduplicationInterval;
|
||||
@ -143,10 +157,13 @@ const NotificationProvider = ({
|
||||
// The entry will be checked against the deduplication interval
|
||||
}
|
||||
|
||||
setOptions(prev => [...prev, { ...newNotification, id: id }]);
|
||||
|
||||
return id;
|
||||
}, []);
|
||||
|
||||
const hide = useCallback(id => {
|
||||
setOptions(state => [...state.filter(item => item.id !== id)]);
|
||||
toast.dismiss(id);
|
||||
|
||||
// Remove from cache if present
|
||||
@ -160,6 +177,7 @@ const NotificationProvider = ({
|
||||
}, []);
|
||||
|
||||
const hideAll = useCallback(() => {
|
||||
setOptions([]);
|
||||
toast.dismiss();
|
||||
// Clear notification cache
|
||||
recentNotificationsRef.current = {};
|
||||
@ -198,7 +216,11 @@ const NotificationProvider = ({
|
||||
|
||||
return (
|
||||
<NotificationContext.Provider value={{ show, hide, hideAll, getNotificationCache }}>
|
||||
<Toaster position="bottom-right" />
|
||||
{CustomNotification ? (
|
||||
<CustomNotification options={options} />
|
||||
) : (
|
||||
<Toaster position="bottom-right" />
|
||||
)}
|
||||
{children}
|
||||
</NotificationContext.Provider>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user