2022-08-27 15:58:36 +02:00
|
|
|
import { useNuiEvent } from '../../hooks/useNuiEvent';
|
2023-02-15 13:00:09 +01:00
|
|
|
import { toast, Toaster } from 'react-hot-toast';
|
2022-08-27 15:58:36 +02:00
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
2022-12-15 17:43:14 -05:00
|
|
|
import ReactMarkdown from 'react-markdown';
|
2023-01-02 21:50:49 +01:00
|
|
|
import { Avatar, createStyles, Group, Stack, Box, Text, keyframes } from '@mantine/core';
|
2023-01-01 14:31:11 +01:00
|
|
|
import React from 'react';
|
2023-02-15 13:00:09 +01:00
|
|
|
import type { NotificationProps } from '../../typings';
|
2022-03-14 15:53:59 +01:00
|
|
|
|
2023-01-01 14:31:11 +01:00
|
|
|
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,
|
2023-01-13 17:21:01 +01:00
|
|
|
lineHeight: 'normal',
|
2023-01-01 14:31:11 +01:00
|
|
|
},
|
|
|
|
|
description: {
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
color: theme.colors.dark[2],
|
2023-01-01 19:25:12 +01:00
|
|
|
fontFamily: 'Roboto',
|
2023-01-13 17:21:01 +01:00
|
|
|
lineHeight: 'normal',
|
2023-01-01 14:31:11 +01:00
|
|
|
},
|
2023-01-11 21:06:05 +01:00
|
|
|
descriptionOnly: {
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
color: theme.colors.dark[2],
|
|
|
|
|
fontFamily: 'Roboto',
|
2023-01-13 17:21:01 +01:00
|
|
|
lineHeight: 'normal',
|
2023-01-11 21:06:05 +01:00
|
|
|
},
|
2023-01-01 14:31:11 +01:00
|
|
|
}));
|
|
|
|
|
|
2023-01-02 21:50:49 +01:00
|
|
|
// 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%)',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2022-03-14 15:53:59 +01:00
|
|
|
const Notifications: React.FC = () => {
|
2023-01-01 14:31:11 +01:00
|
|
|
const { classes } = useStyles();
|
2022-03-14 15:53:59 +01:00
|
|
|
|
2023-02-15 13:00:09 +01:00
|
|
|
useNuiEvent<NotificationProps>('notify', (data) => {
|
2022-04-11 14:51:28 +02:00
|
|
|
if (!data.title && !data.description) return;
|
2023-01-01 14:31:11 +01:00
|
|
|
// Backwards compat with old notifications
|
|
|
|
|
let position = data.position;
|
|
|
|
|
switch (position) {
|
|
|
|
|
case 'top':
|
|
|
|
|
position = 'top-center';
|
|
|
|
|
break;
|
|
|
|
|
case 'bottom':
|
|
|
|
|
position = 'bottom-center';
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-04-11 03:52:18 +00:00
|
|
|
if (!data.icon) {
|
2023-05-01 12:08:02 +02:00
|
|
|
switch (data.type) {
|
|
|
|
|
case 'error':
|
|
|
|
|
data.icon = 'circle-xmark';
|
|
|
|
|
break;
|
|
|
|
|
case 'success':
|
|
|
|
|
data.icon = 'circle-check';
|
|
|
|
|
break;
|
|
|
|
|
case 'warning':
|
|
|
|
|
data.icon = 'circle-exclamation';
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
data.icon = 'circle-info';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-02 21:50:49 +01:00
|
|
|
toast.custom(
|
|
|
|
|
(t) => (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
animation: t.visible
|
|
|
|
|
? `${position?.includes('bottom') ? enterAnimationBottom : enterAnimationTop} 0.2s ease-out forwards`
|
|
|
|
|
: `${
|
|
|
|
|
position?.includes('right')
|
|
|
|
|
? exitAnimationRight
|
|
|
|
|
: position?.includes('left')
|
|
|
|
|
? exitAnimationLeft
|
|
|
|
|
: position === 'top-center'
|
|
|
|
|
? exitAnimationTop
|
|
|
|
|
: position
|
|
|
|
|
? exitAnimationBottom
|
|
|
|
|
: exitAnimationRight
|
|
|
|
|
} 0.4s ease-in forwards`,
|
|
|
|
|
}}
|
2023-01-03 18:55:02 +01:00
|
|
|
style={data.style}
|
2023-01-02 21:50:49 +01:00
|
|
|
className={`${classes.container}`}
|
|
|
|
|
>
|
|
|
|
|
<Group noWrap spacing={12}>
|
|
|
|
|
{data.icon && (
|
|
|
|
|
<>
|
|
|
|
|
{!data.iconColor ? (
|
|
|
|
|
<Avatar
|
2023-05-01 12:08:02 +02:00
|
|
|
color={data.type === 'error' ? 'red' : data.type === 'success' ? 'teal' : data.type === 'warning' ? 'yellow' : 'blue'}
|
2023-01-02 21:50:49 +01:00
|
|
|
radius="xl"
|
2023-01-13 17:21:01 +01:00
|
|
|
size={32}
|
2023-01-02 21:50:49 +01:00
|
|
|
>
|
|
|
|
|
<FontAwesomeIcon icon={data.icon} fixedWidth size="lg" />
|
|
|
|
|
</Avatar>
|
|
|
|
|
) : (
|
|
|
|
|
<FontAwesomeIcon icon={data.icon} style={{ color: data.iconColor }} fixedWidth size="lg" />
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
<Stack spacing={0}>
|
|
|
|
|
{data.title && <Text className={classes.title}>{data.title}</Text>}
|
2023-01-11 21:06:05 +01:00
|
|
|
{data.description && (
|
|
|
|
|
<ReactMarkdown className={!data.title ? classes.descriptionOnly : classes.description}>
|
|
|
|
|
{data.description}
|
|
|
|
|
</ReactMarkdown>
|
|
|
|
|
)}
|
2023-01-02 21:50:49 +01:00
|
|
|
</Stack>
|
|
|
|
|
</Group>
|
|
|
|
|
</Box>
|
|
|
|
|
),
|
2023-01-01 14:31:11 +01:00
|
|
|
{
|
|
|
|
|
id: data.id?.toString(),
|
|
|
|
|
duration: data.duration || 3000,
|
|
|
|
|
position: position || 'top-right',
|
|
|
|
|
}
|
|
|
|
|
);
|
2022-03-14 15:53:59 +01:00
|
|
|
});
|
|
|
|
|
|
2023-01-01 19:25:12 +01:00
|
|
|
return <Toaster />;
|
2022-03-14 15:53:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Notifications;
|