diff --git a/packages/twenty-front/public/images/placeholders/background/empty_inbox_bg.png b/packages/twenty-front/public/images/placeholders/background/empty_inbox_bg.png
new file mode 100644
index 000000000..7668b8e8f
Binary files /dev/null and b/packages/twenty-front/public/images/placeholders/background/empty_inbox_bg.png differ
diff --git a/packages/twenty-front/public/images/placeholders/moving-image/empty_inbox.png b/packages/twenty-front/public/images/placeholders/moving-image/empty_inbox.png
new file mode 100644
index 000000000..7c9fb2576
Binary files /dev/null and b/packages/twenty-front/public/images/placeholders/moving-image/empty_inbox.png differ
diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx
index 879bda969..0d2567234 100644
--- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx
@@ -17,6 +17,13 @@ import {
H1TitleFontColor,
} from '@/ui/display/typography/components/H1Title';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
+import {
+ StyledEmptyContainer,
+ StyledEmptySubTitle,
+ StyledEmptyTextContainer,
+ StyledEmptyTitle,
+} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
import { Card } from '@/ui/layout/card/components/Card';
import { Section } from '@/ui/layout/section/components/Section';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
@@ -141,14 +148,27 @@ export const EmailThreads = ({
const { totalNumberOfThreads, timelineThreads }: TimelineThreadsWithTotal =
data?.[queryName] ?? [];
+ if (!firstQueryLoading && !timelineThreads?.length) {
+ return (
+
+
+
+ Empty Inbox
+
+ No email exchange has occurred with this record yet.
+
+
+
+ );
+ }
+
return (
- Inbox{' '}
- {totalNumberOfThreads ?? 0}
+ Inbox {totalNumberOfThreads}
>
}
fontColor={H1TitleFontColor.Primary}
diff --git a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/AnimatedPlaceholder.tsx b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/AnimatedPlaceholder.tsx
index 0c8a6691a..6bb58a61c 100644
--- a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/AnimatedPlaceholder.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/AnimatedPlaceholder.tsx
@@ -1,6 +1,7 @@
import { useEffect } from 'react';
import styled from '@emotion/styled';
import { motion, useMotionValue, useTransform } from 'framer-motion';
+import { animate } from 'framer-motion';
import {
Background,
@@ -56,12 +57,27 @@ const AnimatedPlaceholder = ({ type }: AnimatedPlaceholderProps) => {
y.set(clientY);
};
+ const handleLeave = () => {
+ animate(x, window.innerWidth / 2, {
+ type: 'spring',
+ stiffness: 100,
+ damping: 10,
+ });
+ animate(y, window.innerHeight / 2, {
+ type: 'spring',
+ stiffness: 100,
+ damping: 10,
+ });
+ };
+
window.addEventListener('mousemove', handleMove);
window.addEventListener('touchmove', handleMove);
+ window.document.addEventListener('mouseleave', handleLeave);
return () => {
window.removeEventListener('mousemove', handleMove);
window.removeEventListener('touchmove', handleMove);
+ window.document.removeEventListener('mouseleave', handleLeave);
};
}, [x, y]);
diff --git a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx
index 84c4f76da..bbc1dac1e 100644
--- a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled.tsx
@@ -9,7 +9,6 @@ export const StyledEmptyContainer = styled.div`
gap: ${({ theme }) => theme.spacing(6)};
justify-content: center;
text-align: center;
- margin: ${({ theme }) => theme.spacing(16)} 0px;
`;
export const StyledEmptyTextContainer = styled.div`
diff --git a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/constants/AnimatedImages.ts b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/constants/AnimatedImages.ts
index 5185a6683..ac941cff2 100644
--- a/packages/twenty-front/src/modules/ui/layout/animated-placeholder/constants/AnimatedImages.ts
+++ b/packages/twenty-front/src/modules/ui/layout/animated-placeholder/constants/AnimatedImages.ts
@@ -5,6 +5,7 @@ export const Background: Record = {
noTask: '/images/placeholders/background/no_task_bg.png',
errorIndex: '/images/placeholders/background/error_index_bg.png',
emptyTimeline: '/images/placeholders/background/empty_timeline_bg.png',
+ emptyInbox: '/images/placeholders/background/empty_inbox_bg.png',
error404: '/images/placeholders/background/404_bg.png',
error500: '/images/placeholders/background/500_bg.png',
};
@@ -16,6 +17,7 @@ export const MovingImage: Record = {
noTask: '/images/placeholders/moving-image/no_task.png',
errorIndex: '/images/placeholders/moving-image/error_index.png',
emptyTimeline: '/images/placeholders/moving-image/empty_timeline.png',
+ emptyInbox: '/images/placeholders/moving-image/empty_inbox.png',
error404: '/images/placeholders/moving-image/404.png',
error500: '/images/placeholders/moving-image/500.png',
};
diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
index e33dfe1e9..c7d04d18f 100644
--- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
+++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/__stories__/NavigationDrawer.stories.tsx
@@ -114,7 +114,7 @@ export const Submenu: Story = {
/>