Skip to content

Commit

Permalink
fix(web/notify): prevent resetting the notifications circle without a…
Browse files Browse the repository at this point in the history
…n id (#566)
  • Loading branch information
RrybaN authored May 2, 2024
1 parent d102f2a commit 88edfbe
Showing 1 changed file with 42 additions and 84 deletions.
126 changes: 42 additions & 84 deletions web/src/features/notifications/NotificationWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useNuiEvent } from '../../hooks/useNuiEvent';
import { toast, Toaster } from 'react-hot-toast';
import ReactMarkdown from 'react-markdown';
import { Box, Center, createStyles, Group, keyframes, RingProgress, Stack, Text, ThemeIcon } from '@mantine/core';
import React, { useRef } from 'react';
import React, { useState } from 'react';
import tinycolor from 'tinycolor2';
import type { NotificationProps } from '../../typings';
import MarkdownComponents from '../../config/MarkdownComponents';
Expand Down Expand Up @@ -37,72 +37,39 @@ const useStyles = createStyles((theme) => ({
},
}));

// I hate this
const enterAnimationTop = keyframes({
const createAnimation = (from: string, to: string, visible: boolean) => keyframes({
from: {
opacity: 0,
transform: 'translateY(-30px)',
opacity: visible ? 0 : 1,
transform: `translate${from}`,
},
to: {
opacity: 1,
transform: 'translateY(0px)',
opacity: visible ? 1 : 0,
transform: `translate${to}`,
},
});

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 getAnimation = (visible: boolean, position: string) => {
const animationOptions = visible ? '0.2s ease-out forwards' : '0.4s ease-in forwards'
let animation: { from: string; to: string };

if (visible) {
animation = position.includes('bottom') ? { from: 'Y(30px)', to: 'Y(0px)' } : { from: 'Y(-30px)', to:'Y(0px)' };
} else {
if (position.includes('right')) {
animation = { from: 'X(0px)', to: 'X(100%)' }
} else if (position.includes('left')) {
animation = { from: 'X(0px)', to: 'X(-100%)' };
} else if (position === 'top-center') {
animation = { from: 'Y(0px)', to: 'Y(-100%)' };
} else if (position === 'bottom') {
animation = { from: 'Y(0px)', to: 'Y(100%)' };
} else {
animation = { from: 'X(0px)', to: 'X(100%)' };
}
}

const exitAnimationBottom = keyframes({
from: {
opacity: 1,
transform: 'translateY(0px)',
},
to: {
opacity: 0,
transform: 'translateY(100%)',
},
});
return `${createAnimation(animation.from, animation.to, visible)} ${animationOptions}`
};

const durationCircle = keyframes({
'0%': { strokeDasharray: `0, ${15.1 * 2 * Math.PI}` },
Expand All @@ -111,22 +78,22 @@ const durationCircle = keyframes({

const Notifications: React.FC = () => {
const { classes } = useStyles();
const toastKeyRef = useRef(0);
const [toastKey, setToastKey] = useState(0);

useNuiEvent<NotificationProps>('notify', (data) => {
const toastId = data.id?.toString();

if (toastId) toastKeyRef.current++;

if (!data.title && !data.description) return;

const toastId = data.id?.toString();
const duration = data.duration || 3000;

let iconColor: string;
let duration = data.duration || 3000;
let position = data.position || 'top-right';

data.showDuration = data.showDuration !== undefined ? data.showDuration : true;

if (toastId) setToastKey(prevKey => prevKey + 1);

// Backwards compat with old notifications
let position = data.position;
switch (position) {
case 'top':
position = 'top-center';
Expand All @@ -135,6 +102,7 @@ const Notifications: React.FC = () => {
position = 'bottom-center';
break;
}

if (!data.icon) {
switch (data.type) {
case 'error':
Expand All @@ -151,6 +119,7 @@ const Notifications: React.FC = () => {
break;
}
}

if (!data.iconColor) {
switch (data.type) {
case 'error':
Expand All @@ -169,23 +138,12 @@ const Notifications: React.FC = () => {
} else {
iconColor = tinycolor(data.iconColor).toRgbString();
}

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`,
animation: getAnimation(t.visible, position),
...data.style,
}}
className={`${classes.container}`}
Expand All @@ -195,7 +153,7 @@ const Notifications: React.FC = () => {
<>
{data.showDuration ? (
<RingProgress
key={toastKeyRef.current}
key={toastKey}
size={38}
thickness={2}
sections={[{ value: 100, color: iconColor }]}
Expand All @@ -215,7 +173,7 @@ const Notifications: React.FC = () => {
color={iconColor}
radius="xl"
size={32}
variant={tinycolor(iconColor).getAlpha() === 0 ? undefined : 'light'}
variant={tinycolor(iconColor).getAlpha() < 0 ? undefined : 'light'}
>
<LibIcon icon={data.icon} fixedWidth color={iconColor} animation={data.iconAnimation} />
</ThemeIcon>
Expand All @@ -227,7 +185,7 @@ const Notifications: React.FC = () => {
color={iconColor}
radius="xl"
size={32}
variant={tinycolor(iconColor).getAlpha() === 0 ? undefined : 'light'}
variant={tinycolor(iconColor).getAlpha() < 0 ? undefined : 'light'}
style={{ alignSelf: !data.alignIcon || data.alignIcon === 'center' ? 'center' : 'start' }}
>
<LibIcon icon={data.icon} fixedWidth color={iconColor} animation={data.iconAnimation} />
Expand All @@ -252,7 +210,7 @@ const Notifications: React.FC = () => {
{
id: toastId,
duration: duration,
position: position || 'top-right',
position: position,
}
);
});
Expand Down

0 comments on commit 88edfbe

Please sign in to comment.