import { useNuiEvent } from '../../hooks/useNuiEvent'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { toast, Toaster, ToastPosition } from 'react-hot-toast'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import ReactMarkdown from 'react-markdown'; import { Avatar, createStyles, Group, Stack, Box, Text, keyframes } from '@mantine/core'; import React from 'react'; export interface NotificationProps { title?: string; description?: string; duration?: number; position?: ToastPosition | 'top' | 'bottom'; variant?: string; status?: 'info' | 'warning' | 'success' | 'error'; id?: number; } export interface CustomNotificationProps { style?: React.CSSProperties; description?: string; title?: string; duration?: number; icon?: IconProp; iconColor?: string; position?: ToastPosition | 'top' | 'bottom'; id?: number; type?: string; } const useStyles = createStyles((theme) => ({ container: { width: 300, height: 'fit-content', backgroundColor: theme.colors.dark[6], color: theme.colors.dark[0], padding: 12, borderRadius: theme.radius.sm, fontFamily: 'Roboto', boxShadow: theme.shadows.sm, }, title: { fontWeight: 500, }, description: { fontSize: 12, color: theme.colors.dark[2], fontFamily: 'Roboto', }, descriptionOnly: { fontSize: 14, color: theme.colors.dark[2], fontFamily: 'Roboto', }, })); // I hate this const enterAnimationTop = keyframes({ from: { opacity: 0, transform: 'translateY(-30px)', }, to: { opacity: 1, transform: 'translateY(0px)', }, }); const enterAnimationBottom = keyframes({ from: { opacity: 0, transform: 'translateY(30px)', }, to: { opacity: 1, transform: 'translateY(0px)', }, }); const exitAnimationTop = keyframes({ from: { opacity: 1, transform: 'translateY(0px)', }, to: { opacity: 0, transform: 'translateY(-100%)', }, }); const exitAnimationRight = keyframes({ from: { opacity: 1, transform: 'translateX(0px)', }, to: { opacity: 0, transform: 'translateX(100%)', }, }); const exitAnimationLeft = keyframes({ from: { opacity: 1, transform: 'translateX(0px)', }, to: { opacity: 0, transform: 'translateX(-100%)', }, }); const exitAnimationBottom = keyframes({ from: { opacity: 1, transform: 'translateY(0px)', }, to: { opacity: 0, transform: 'translateY(100%)', }, }); const Notifications: React.FC = () => { const { classes } = useStyles(); useNuiEvent('notify', (data) => { if (!data.title && !data.description) return; // Backwards compat with old notifications let position = data.position; switch (position) { case 'top': position = 'top-center'; break; case 'bottom': position = 'bottom-center'; break; } if (!data.icon) { data.icon = data.type === 'error' ? 'xmark' : data.type === 'success' ? 'check' : 'info'; } toast.custom( (t) => ( {data.icon && ( <> {!data.iconColor ? ( ) : ( )} )} {data.title && {data.title}} {data.description && ( {data.description} )} ), { id: data.id?.toString(), duration: data.duration || 3000, position: position || 'top-right', } ); }); return ; }; export default Notifications;