diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx
index 32dde14ba..4f4a64b38 100644
--- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx
@@ -1,5 +1,5 @@
-import { useState } from 'react';
import styled from '@emotion/styled';
+import { useState } from 'react';
import { EmailThreadMessageBody } from '@/activities/emails/components/EmailThreadMessageBody';
import { EmailThreadMessageBodyPreview } from '@/activities/emails/components/EmailThreadMessageBodyPreview';
@@ -30,6 +30,7 @@ const StyledThreadMessageBody = styled.div`
type EmailThreadMessageProps = {
body: string;
sentAt: string;
+ sender: EmailThreadMessageParticipant;
participants: EmailThreadMessageParticipant[];
isExpanded?: boolean;
};
@@ -37,17 +38,17 @@ type EmailThreadMessageProps = {
export const EmailThreadMessage = ({
body,
sentAt,
+ sender,
participants,
isExpanded = false,
}: EmailThreadMessageProps) => {
const [isOpen, setIsOpen] = useState(isExpanded);
- const from = participants.find((participant) => participant.role === 'from');
const receivers = participants.filter(
(participant) => participant.role !== 'from',
);
- if (!from || receivers.length === 0) {
+ if (!sender || receivers.length === 0) {
return null;
}
@@ -57,7 +58,7 @@ export const EmailThreadMessage = ({
style={{ cursor: isOpen ? 'auto' : 'pointer' }}
>
isOpen && setIsOpen(false)}>
-
+
{isOpen && }
diff --git a/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts b/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts
index d141d867b..f818332fd 100644
--- a/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts
+++ b/packages/twenty-front/src/modules/activities/emails/graphql/operation-signatures/factories/fetchAllThreadMessagesOperationSignatureFactory.ts
@@ -47,11 +47,7 @@ export const fetchAllThreadMessagesOperationSignatureFactory: RecordGqlOperation
id: true,
role: true,
displayName: true,
- participant: {
- id: true,
- email: true,
- name: true,
- },
+ handle: true,
person: true,
workspaceMember: true,
},
diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/IntermediaryMessages.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/IntermediaryMessages.tsx
index a830e8367..3ef96d573 100644
--- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/IntermediaryMessages.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/IntermediaryMessages.tsx
@@ -1,9 +1,9 @@
-import { useState } from 'react';
import styled from '@emotion/styled';
+import { useState } from 'react';
import { IconArrowsVertical } from 'twenty-ui';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
-import { EmailThreadMessage as EmailThreadMessageType } from '@/activities/emails/types/EmailThreadMessage';
+import { EmailThreadMessageWithSender } from '@/activities/emails/types/EmailThreadMessageWithSender';
import { Button } from '@/ui/input/button/components/Button';
const StyledButtonContainer = styled.div`
@@ -14,7 +14,7 @@ const StyledButtonContainer = styled.div`
export const IntermediaryMessages = ({
messages,
}: {
- messages: EmailThreadMessageType[];
+ messages: EmailThreadMessageWithSender[];
}) => {
const [areMessagesOpen, setAreMessagesOpen] = useState(false);
@@ -26,6 +26,7 @@ export const IntermediaryMessages = ({
messages.map((message) => (
{
messageChannelLoading,
} = useRightDrawerEmailThread();
- const visibleMessages = useMemo(() => {
- return messages.filter(({ messageParticipants }) => {
- const from = messageParticipants.find(
- (participant) => participant.role === 'from',
- );
- const receivers = messageParticipants.filter(
- (participant) => participant.role !== 'from',
- );
- return from && receivers.length > 0;
- });
- }, [messages]);
-
useEffect(() => {
- if (!visibleMessages[0]?.messageThread) {
+ if (!messages[0]?.messageThread) {
return;
}
- setMessageThread(visibleMessages[0]?.messageThread);
+ setMessageThread(messages[0]?.messageThread);
});
const { useRegisterClickOutsideListenerCallback } = useClickOutsideListener(
@@ -93,17 +81,17 @@ export const RightDrawerEmailThread = () => {
),
});
- const visibleMessagesCount = visibleMessages.length;
- const is5OrMoreMessages = visibleMessagesCount >= 5;
- const firstMessages = visibleMessages.slice(
+ const messagesCount = messages.length;
+ const is5OrMoreMessages = messagesCount >= 5;
+ const firstMessages = messages.slice(
0,
- is5OrMoreMessages ? 2 : visibleMessagesCount - 1,
+ is5OrMoreMessages ? 2 : messagesCount - 1,
);
const intermediaryMessages = is5OrMoreMessages
- ? visibleMessages.slice(2, visibleMessagesCount - 1)
+ ? messages.slice(2, messagesCount - 1)
: [];
- const lastMessage = visibleMessages[visibleMessagesCount - 1];
- const subject = visibleMessages[0]?.subject;
+ const lastMessage = messages[messagesCount - 1];
+ const subject = messages[0]?.subject;
const canReply = useMemo(() => {
return (
@@ -119,7 +107,7 @@ export const RightDrawerEmailThread = () => {
const url = `https://mail.google.com/mail/?authuser=${connectedAccountHandle}#all/${messageThreadExternalId}`;
window.open(url, '_blank');
};
- if (!thread) {
+ if (!thread || !messages.length) {
return null;
}
return (
@@ -136,6 +124,7 @@ export const RightDrawerEmailThread = () => {
{firstMessages.map((message) => (
{
{
const viewableRecordId = useRecoilValue(viewableRecordIdState);
@@ -74,6 +77,30 @@ export const useRightDrawerEmailThread = () => {
}
}, [messages, isMessagesFetchComplete]);
+ // TODO: introduce nested filters so we can retrieve the message sender directly from the message query
+ const { records: messageSenders } =
+ useFindManyRecords({
+ filter: {
+ messageId: {
+ in: messages.map(({ id }) => id),
+ },
+ role: {
+ eq: 'from',
+ },
+ },
+ objectNameSingular: CoreObjectNameSingular.MessageParticipant,
+ recordGqlFields: {
+ id: true,
+ role: true,
+ displayName: true,
+ messageId: true,
+ handle: true,
+ person: true,
+ workspaceMember: true,
+ },
+ skip: messages.length === 0,
+ });
+
const { records: messageChannelMessageAssociationData } =
useFindManyRecords({
filter: {
@@ -123,9 +150,24 @@ export const useRightDrawerEmailThread = () => {
const connectedAccountHandle =
messageChannelData.length > 0 ? messageChannelData[0].handle : null;
+ const messagesWithSender: EmailThreadMessageWithSender[] = messages
+ .map((message) => {
+ const sender = messageSenders.find(
+ (messageSender) => messageSender.messageId === message.id,
+ );
+ if (!sender) {
+ return null;
+ }
+ return {
+ ...message,
+ sender,
+ };
+ })
+ .filter(isDefined);
+
return {
thread,
- messages,
+ messages: messagesWithSender,
messageThreadExternalId,
connectedAccountHandle,
threadLoading: messagesLoading,
diff --git a/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageParticipant.ts b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageParticipant.ts
index ed81fa848..72dfa74df 100644
--- a/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageParticipant.ts
+++ b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageParticipant.ts
@@ -3,9 +3,12 @@ import { Person } from '@/people/types/Person';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
export type EmailThreadMessageParticipant = {
+ id: string;
displayName: string;
handle: string;
role: EmailParticipantRole;
+ messageId: string;
person: Person;
workspaceMember: WorkspaceMember;
+ __typename: 'EmailThreadMessageParticipant';
};
diff --git a/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageWithSender.ts b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageWithSender.ts
new file mode 100644
index 000000000..fe6916da2
--- /dev/null
+++ b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessageWithSender.ts
@@ -0,0 +1,6 @@
+import { EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage';
+import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
+
+export type EmailThreadMessageWithSender = EmailThreadMessage & {
+ sender: EmailThreadMessageParticipant;
+};
diff --git a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts
index 7b4d8c7a8..28c971308 100644
--- a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts
+++ b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts
@@ -4,9 +4,12 @@ import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'
describe('getDisplayNameFromParticipant', () => {
const participantWithName: EmailThreadMessageParticipant = {
+ id: '2cac0ba7-0e60-46c6-86e7-e5b0bc55b7cf',
+ __typename: 'EmailThreadMessageParticipant',
displayName: '',
handle: '',
role: 'from',
+ messageId: '638f52d1-fd55-4a2b-b0f3-9858ea3b2e91',
person: {
__typename: 'Person',
id: '1',