import React, { FC, useContext, useMemo, useReducer } from 'react';
import NotificationContext from './context';
import Notification from './Notification';
import {
IPosition,
IToasts,
NotificationActionType,
PayloadType,
} from './types';
import NotificationStyles from './Notification.styles';
const { NotificationContainerStyled } = NotificationStyles;
const initialState: PayloadType[] = [];
function reducer(state: PayloadType[], action: NotificationActionType) {
switch (action.type) {
case 'add_notification':
return [...state, { ...action.payload }];
case 'remove_notification':
return state.filter((toast) => toast.id !== action.id);
case 'clear_notifications':
return [];
default:
return state;
}
}
const NotificationProvider: FC<{ children: React.ReactNode }> = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
const toasts = useMemo(() => {
const toaster: IToasts = {
topR: [],
topL: [],
bottomR: [],
bottomL: [],
};
state.forEach((toast: PayloadType) =>
toaster[toast.position].push(toast),
);
return (Object.keys(toaster) as IPosition[]).map((pos) => {
return (
{toaster?.[pos]?.map((toast: PayloadType) => (
))}
);
});
}, [state]);
return (
{toasts}
{props.children}
);
};
export const useNotification = () => {
const dispatch = useContext(NotificationContext);
if (dispatch === undefined) {
throw new Error(
'useNotification hook must be used within a NotificationProvider',
);
}
return (props: PayloadType) => {
// @ts-ignore
dispatch({
type: 'add_notification',
payload: {
id: String(Date.now()),
...props,
},
});
};
};
export default NotificationProvider;