From 64d25ed00823f9352eb23b7081c57b48a7b84942 Mon Sep 17 00:00:00 2001 From: Antoine Moreaux Date: Wed, 15 Jan 2025 14:41:04 +0100 Subject: [PATCH] feat(snack-bar): add deduplication support for notifications Introduced the `dedupeKey` property to prevent duplicate snack bar notifications. Modified related components and hooks to handle deduplication logic efficiently. This ensures a cleaner and more user-friendly notification experience. --- .../src/modules/auth/components/VerifyEffect.tsx | 1 + .../src/modules/auth/components/VerifyEmailEffect.tsx | 3 +++ .../feedback/snack-bar-manager/components/SnackBar.tsx | 1 + .../ui/feedback/snack-bar-manager/hooks/useSnackBar.ts | 10 ++++++++++ 4 files changed, 15 insertions(+) diff --git a/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx b/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx index 8dc84c2e5e5f..d68187d8636b 100644 --- a/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx +++ b/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx @@ -29,6 +29,7 @@ export const VerifyEffect = () => { useEffect(() => { if (isDefined(errorMessage)) { enqueueSnackBar(errorMessage, { + dedupeKey: 'verify-failed-dedupe-key', variant: SnackBarVariant.Error, }); } diff --git a/packages/twenty-front/src/modules/auth/components/VerifyEmailEffect.tsx b/packages/twenty-front/src/modules/auth/components/VerifyEmailEffect.tsx index d2701d40ae0c..6e9cc634d1aa 100644 --- a/packages/twenty-front/src/modules/auth/components/VerifyEmailEffect.tsx +++ b/packages/twenty-front/src/modules/auth/components/VerifyEmailEffect.tsx @@ -25,6 +25,7 @@ export const VerifyEmailEffect = () => { const verifyEmailToken = async () => { if (!email || !emailVerificationToken) { enqueueSnackBar(`Invalid email verification link.`, { + dedupeKey: 'email-verification-link-dedupe-key', variant: SnackBarVariant.Error, }); return navigate(AppPath.SignInUp); @@ -39,12 +40,14 @@ export const VerifyEmailEffect = () => { ); enqueueSnackBar('Email verified.', { + dedupeKey: 'email-verified-dedupe-key', variant: SnackBarVariant.Success, }); navigate(`${AppPath.Verify}?loginToken=${loginToken.token}`); } catch (error) { enqueueSnackBar('Email verification failed.', { + dedupeKey: 'email-verification-failed-dedupe-key', variant: SnackBarVariant.Error, }); setIsError(true); diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx index 1ebc61329855..089f9e9226e9 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx @@ -35,6 +35,7 @@ export type SnackBarProps = Pick, 'id'> & { onClose?: () => void; role?: 'alert' | 'status'; variant?: SnackBarVariant; + dedupeKey?: string; }; const StyledContainer = styled.div` diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts index d60a9d6b3957..26af7af014c8 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { useRecoilCallback } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; +import { isDefined } from '~/utils/isDefined'; import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext'; import { @@ -29,6 +30,15 @@ export const useSnackBar = () => { ({ set }) => (newValue) => set(snackBarInternalScopedState({ scopeId }), (prev) => { + if ( + isDefined(newValue.dedupeKey) && + prev.queue.some( + (snackBar) => snackBar.dedupeKey === newValue.dedupeKey, + ) + ) { + return prev; + } + if (prev.queue.length >= prev.maxQueue) { return { ...prev,