buster/web/src/context/BusterNotifications/BusterNotifications.tsx

180 lines
5.0 KiB
TypeScript

'use client';
import React, { PropsWithChildren } from 'react';
import { toast, type ExternalToast } from 'sonner';
import { useMemoizedFn } from 'ahooks';
import {
useContextSelector,
createContext,
ContextSelector
} from '@fluentui/react-context-selector';
export type NotificationType = 'success' | 'info' | 'warning' | 'error';
export interface NotificationProps {
type?: NotificationType;
title?: string;
message?: string;
duration?: number;
action?: {
label: string;
onClick: () => void | (() => Promise<void>);
};
}
export const useBusterNotificationsInternal = () => {
const openNotification = useMemoizedFn((props: NotificationProps) => {
const { title, message, type } = props;
const hasTitle = !!title;
const toastOptions: ExternalToast = {
...props,
description: !hasTitle && message ? message : message,
position: 'top-center'
};
switch (type) {
case 'success':
return toast.success(title, toastOptions);
case 'info':
return toast.info(title, toastOptions);
case 'warning':
return toast.warning(title, toastOptions);
case 'error':
return toast.error(title, toastOptions);
default:
return toast(title, toastOptions);
}
});
const openErrorNotification = useMemoizedFn((data: NotificationProps | unknown) => {
const values = data || ({} as any);
const type = values.type || 'error';
const title = values.title || 'Error';
const message = values.message || 'Something went wrong. Please try again.';
return openNotification({ ...values, message, title, type });
});
const openInfoNotification = useMemoizedFn(
({ type = 'info', message = 'Info', title = 'Info', ...props }: NotificationProps) => {
return openNotification({ ...props, title, message, type });
}
);
const openSuccessNotification = useMemoizedFn(
({ type = 'success', title = 'Success', message = 'success', ...props }: NotificationProps) => {
return openNotification({ ...props, message, title, type });
}
);
const openWarningNotification = useMemoizedFn(
({ type = 'warning', title = 'Warning', message = 'Warning', ...props }: NotificationProps) => {
return openNotification({ ...props, message, title, type });
}
);
//MESSAGES
const openMessage = useMemoizedFn(
(props: {
type: NotificationType;
message: string;
onClose?: () => void;
duration?: number;
}) => {
return openNotification({
...props,
title: props.message,
message: ''
});
}
);
const openErrorMessage = useMemoizedFn((message: string) => {
return openMessage({ type: 'error', message });
});
const openInfoMessage = useMemoizedFn((message: string, duration?: number) => {
return openMessage({ type: 'info', message, duration });
});
const openSuccessMessage = useMemoizedFn((message: string) => {
return openMessage({ type: 'success', message });
});
const openConfirmModal = useMemoizedFn(
(props: {
title: string | React.ReactNode;
content: string | React.ReactNode;
onOk: () => void;
onCancel?: () => void;
icon?: React.ReactNode;
width?: string | number;
useReject?: boolean;
cancelButtonProps?: {
className?: string;
};
}): Promise<void> => {
const useReject = props.useReject ?? true;
return new Promise((resolve, reject) => {
// modal.confirm({
// icon: props.icon || <></>,
// ...props,
// className: cx(styles.modal, ''),
// cancelButtonProps: {
// ...props.cancelButtonProps,
// type: 'text'
// },
// okButtonProps: {
// ...props.okButtonProps,
// type: 'default'
// },
// onOk: async () => {
// await props.onOk();
// resolve();
// },
// onCancel: async () => {
// await props.onCancel?.();
// if (useReject) reject();
// else resolve();
// }
// });
});
}
);
return {
openErrorNotification,
openInfoNotification,
openSuccessNotification,
openWarningNotification,
openErrorMessage,
openInfoMessage,
openSuccessMessage,
openConfirmModal,
openNotification
};
};
const BusterNotifications = createContext<ReturnType<typeof useBusterNotificationsInternal>>(
{} as ReturnType<typeof useBusterNotificationsInternal>
);
export const BusterNotificationsProvider: React.FC<PropsWithChildren> = ({ children }) => {
const value = useBusterNotificationsInternal();
return <BusterNotifications.Provider value={value}>{children}</BusterNotifications.Provider>;
};
const useBusterNotificationsSelector = <T,>(
selector: ContextSelector<ReturnType<typeof useBusterNotificationsInternal>, T>
) => {
return useContextSelector(BusterNotifications, selector);
};
export const useBusterNotifications = () => {
return useBusterNotificationsSelector((state) => state);
};