TWNTY-4203 - Improve Email Thread Visibility with Collapse/Expansion Rules (#5202)

### Description

Improve Email Thread Visibility with Collapse/Expansion Rules

### Refs
#4203

### Demo


https://github.com/twentyhq/twenty/assets/140154534/ece1d783-57ef-45c9-9895-3b4b0e02b9e2


Fixes #4203

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
This commit is contained in:
gitstart-app[bot]
2024-04-29 18:10:42 +02:00
committed by GitHub
parent 6065201acd
commit c946572fde
4 changed files with 82 additions and 2 deletions

View File

@ -31,14 +31,16 @@ type EmailThreadMessageProps = {
body: string; body: string;
sentAt: string; sentAt: string;
participants: EmailThreadMessageParticipant[]; participants: EmailThreadMessageParticipant[];
isExpanded?: boolean;
}; };
export const EmailThreadMessage = ({ export const EmailThreadMessage = ({
body, body,
sentAt, sentAt,
participants, participants,
isExpanded = false,
}: EmailThreadMessageProps) => { }: EmailThreadMessageProps) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(isExpanded);
const from = participants.find((participant) => participant.role === 'from'); const from = participants.find((participant) => participant.role === 'from');
const receivers = participants.filter( const receivers = participants.filter(

View File

@ -0,0 +1,44 @@
import { useState } from 'react';
import styled from '@emotion/styled';
import { IconArrowsVertical } from 'twenty-ui';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
import { EmailThreadMessage as EmailThreadMessageType } from '@/activities/emails/types/EmailThreadMessage';
import { Button } from '@/ui/input/button/components/Button';
const StyledButtonContainer = styled.div`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
padding: 16px 24px;
`;
export const IntermediaryMessages = ({
messages,
}: {
messages: EmailThreadMessageType[];
}) => {
const [areMessagesOpen, setAreMessagesOpen] = useState(false);
if (messages.length === 0) {
return null;
}
return areMessagesOpen ? (
messages.map((message) => (
<EmailThreadMessage
key={message.id}
participants={message.messageParticipants}
body={message.text}
sentAt={message.receivedAt}
/>
))
) : (
<StyledButtonContainer>
<Button
Icon={IconArrowsVertical}
title={`${messages.length} email${messages.length > 1 ? 's' : ''}`}
size="small"
onClick={() => setAreMessagesOpen(true)}
/>
</StyledButtonContainer>
);
};

View File

@ -5,8 +5,10 @@ import { FetchMoreLoader } from '@/activities/components/CustomResolverFetchMore
import { EmailLoader } from '@/activities/emails/components/EmailLoader'; import { EmailLoader } from '@/activities/emails/components/EmailLoader';
import { EmailThreadHeader } from '@/activities/emails/components/EmailThreadHeader'; import { EmailThreadHeader } from '@/activities/emails/components/EmailThreadHeader';
import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage'; import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage';
import { IntermediaryMessages } from '@/activities/emails/right-drawer/components/IntermediaryMessages';
import { useRightDrawerEmailThread } from '@/activities/emails/right-drawer/hooks/useRightDrawerEmailThread'; import { useRightDrawerEmailThread } from '@/activities/emails/right-drawer/hooks/useRightDrawerEmailThread';
import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState'; import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState';
import { EmailThreadMessage as EmailThreadMessageType } from '@/activities/emails/types/EmailThreadMessage';
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener'; import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
@ -20,6 +22,17 @@ const StyledContainer = styled.div`
position: relative; position: relative;
`; `;
const getVisibleMessages = (messages: EmailThreadMessageType[]) =>
messages.filter(({ messageParticipants }) => {
const from = messageParticipants.find(
(participant) => participant.role === 'from',
);
const receivers = messageParticipants.filter(
(participant) => participant.role !== 'from',
);
return from && receivers.length > 0;
});
export const RightDrawerEmailThread = () => { export const RightDrawerEmailThread = () => {
const { thread, messages, fetchMoreMessages, loading } = const { thread, messages, fetchMoreMessages, loading } =
useRightDrawerEmailThread(); useRightDrawerEmailThread();
@ -44,6 +57,18 @@ export const RightDrawerEmailThread = () => {
return null; return null;
} }
const visibleMessages = getVisibleMessages(messages);
const visibleMessagesCount = visibleMessages.length;
const is5OrMoreMessages = visibleMessagesCount >= 5;
const firstMessages = visibleMessages.slice(
0,
is5OrMoreMessages ? 2 : visibleMessagesCount - 1,
);
const intermediaryMessages = is5OrMoreMessages
? visibleMessages.slice(2, visibleMessagesCount - 1)
: [];
const lastMessage = visibleMessages[visibleMessagesCount - 1];
return ( return (
<StyledContainer> <StyledContainer>
<EmailThreadHeader <EmailThreadHeader
@ -54,7 +79,7 @@ export const RightDrawerEmailThread = () => {
<EmailLoader loadingText="Loading thread" /> <EmailLoader loadingText="Loading thread" />
) : ( ) : (
<> <>
{messages.map((message) => ( {firstMessages.map((message) => (
<EmailThreadMessage <EmailThreadMessage
key={message.id} key={message.id}
participants={message.messageParticipants} participants={message.messageParticipants}
@ -62,6 +87,14 @@ export const RightDrawerEmailThread = () => {
sentAt={message.receivedAt} sentAt={message.receivedAt}
/> />
))} ))}
<IntermediaryMessages messages={intermediaryMessages} />
<EmailThreadMessage
key={lastMessage.id}
participants={lastMessage.messageParticipants}
body={lastMessage.text}
sentAt={lastMessage.receivedAt}
isExpanded
/>
<FetchMoreLoader <FetchMoreLoader
loading={loading} loading={loading}
onLastRowVisible={fetchMoreMessages} onLastRowVisible={fetchMoreMessages}

View File

@ -11,6 +11,7 @@ export {
IconArrowDown, IconArrowDown,
IconArrowLeft, IconArrowLeft,
IconArrowRight, IconArrowRight,
IconArrowsVertical,
IconArrowUp, IconArrowUp,
IconArrowUpRight, IconArrowUpRight,
IconAt, IconAt,