Add record chip for sender and add receivers (#3629)
* Add record chip for sender and add receivers * Build enum for roles * Rename var and use string literal --------- Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
@ -3,6 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
|
|
||||||
import { EmailThreadMessageBody } from '@/activities/emails/components/EmailThreadMessageBody';
|
import { EmailThreadMessageBody } from '@/activities/emails/components/EmailThreadMessageBody';
|
||||||
import { EmailThreadMessageBodyPreview } from '@/activities/emails/components/EmailThreadMessageBodyPreview';
|
import { EmailThreadMessageBodyPreview } from '@/activities/emails/components/EmailThreadMessageBodyPreview';
|
||||||
|
import { EmailThreadMessageReceivers } from '@/activities/emails/components/EmailThreadMessageReceivers';
|
||||||
import { EmailThreadMessageSender } from '@/activities/emails/components/EmailThreadMessageSender';
|
import { EmailThreadMessageSender } from '@/activities/emails/components/EmailThreadMessageSender';
|
||||||
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
||||||
|
|
||||||
@ -27,28 +28,6 @@ type EmailThreadMessageProps = {
|
|||||||
participants: EmailThreadMessageParticipant[];
|
participants: EmailThreadMessageParticipant[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDisplayNameFromParticipant = (
|
|
||||||
participant: EmailThreadMessageParticipant,
|
|
||||||
) => {
|
|
||||||
if (participant.person) {
|
|
||||||
return `${participant.person?.name?.firstName} ${participant.person?.name?.lastName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participant.workspaceMember) {
|
|
||||||
return `${participant.workspaceMember?.name?.firstName} ${participant.workspaceMember?.name?.lastName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participant.displayName) {
|
|
||||||
return participant.displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participant.handle) {
|
|
||||||
return participant.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Unknown';
|
|
||||||
};
|
|
||||||
|
|
||||||
export const EmailThreadMessage = ({
|
export const EmailThreadMessage = ({
|
||||||
body,
|
body,
|
||||||
sentAt,
|
sentAt,
|
||||||
@ -57,25 +36,19 @@ export const EmailThreadMessage = ({
|
|||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const from = participants.find((participant) => participant.role === 'from');
|
const from = participants.find((participant) => participant.role === 'from');
|
||||||
const to = participants.filter((participant) => participant.role === 'to');
|
const receivers = participants.filter(
|
||||||
|
(participant) => participant.role !== 'from',
|
||||||
|
);
|
||||||
|
|
||||||
if (!from || to.length === 0) {
|
if (!from || receivers.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayName = getDisplayNameFromParticipant(from);
|
|
||||||
|
|
||||||
const avatarUrl =
|
|
||||||
from.person?.avatarUrl ?? from.workspaceMember?.avatarUrl ?? '';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledThreadMessage onClick={() => setIsOpen(!isOpen)}>
|
<StyledThreadMessage onClick={() => setIsOpen(!isOpen)}>
|
||||||
<StyledThreadMessageHeader>
|
<StyledThreadMessageHeader>
|
||||||
<EmailThreadMessageSender
|
<EmailThreadMessageSender sender={from} sentAt={sentAt} />
|
||||||
displayName={displayName}
|
{isOpen && <EmailThreadMessageReceivers receivers={receivers} />}
|
||||||
avatarUrl={avatarUrl}
|
|
||||||
sentAt={sentAt}
|
|
||||||
/>
|
|
||||||
</StyledThreadMessageHeader>
|
</StyledThreadMessageHeader>
|
||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<EmailThreadMessageBody body={body} />
|
<EmailThreadMessageBody body={body} />
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
||||||
|
import { getDisplayNameFromParticipant } from '@/activities/emails/utils/getDisplayNameFromParticipant';
|
||||||
|
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
|
||||||
|
|
||||||
|
type EmailThreadMessageReceiversProps = {
|
||||||
|
receivers: EmailThreadMessageParticipant[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledThreadMessageReceivers = styled.span`
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
display: flex;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
|
padding: ${({ theme }) => theme.spacing(2, 0, 0, 1)};
|
||||||
|
width: 50%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const EmailThreadMessageReceivers = ({
|
||||||
|
receivers,
|
||||||
|
}: EmailThreadMessageReceiversProps) => {
|
||||||
|
const displayedReceivers = receivers
|
||||||
|
.map((receiver) => getDisplayNameFromParticipant({ participant: receiver }))
|
||||||
|
.join(', ');
|
||||||
|
|
||||||
|
const body = `to: ${displayedReceivers}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledThreadMessageReceivers>
|
||||||
|
<OverflowingTextWithTooltip text={body} />
|
||||||
|
</StyledThreadMessageReceivers>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,6 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
||||||
|
import { getDisplayNameFromParticipant } from '@/activities/emails/utils/getDisplayNameFromParticipant';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||||
import { Avatar } from '@/users/components/Avatar';
|
import { Avatar } from '@/users/components/Avatar';
|
||||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||||
|
|
||||||
@ -32,26 +36,42 @@ const StyledThreadMessageSentAt = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type EmailThreadMessageSenderProps = {
|
type EmailThreadMessageSenderProps = {
|
||||||
displayName: string;
|
sender: EmailThreadMessageParticipant;
|
||||||
avatarUrl: string;
|
|
||||||
sentAt: string;
|
sentAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EmailThreadMessageSender = ({
|
export const EmailThreadMessageSender = ({
|
||||||
displayName,
|
sender,
|
||||||
avatarUrl,
|
|
||||||
sentAt,
|
sentAt,
|
||||||
}: EmailThreadMessageSenderProps) => {
|
}: EmailThreadMessageSenderProps) => {
|
||||||
|
const { person, workspaceMember } = sender;
|
||||||
|
|
||||||
|
const displayName = getDisplayNameFromParticipant({
|
||||||
|
participant: sender,
|
||||||
|
shouldUseFullName: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const avatarUrl = person?.avatarUrl ?? workspaceMember?.avatarUrl ?? '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledEmailThreadMessageSender>
|
<StyledEmailThreadMessageSender>
|
||||||
<StyledEmailThreadMessageSenderUser>
|
<StyledEmailThreadMessageSenderUser>
|
||||||
<StyledAvatar
|
{person ? (
|
||||||
avatarUrl={avatarUrl}
|
<RecordChip
|
||||||
type="rounded"
|
objectNameSingular={CoreObjectNameSingular.Person}
|
||||||
placeholder={displayName}
|
record={person}
|
||||||
size="sm"
|
/>
|
||||||
/>
|
) : (
|
||||||
<StyledSenderName>{displayName}</StyledSenderName>
|
<>
|
||||||
|
<StyledAvatar
|
||||||
|
avatarUrl={avatarUrl}
|
||||||
|
type="rounded"
|
||||||
|
placeholder={displayName}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<StyledSenderName>{displayName}</StyledSenderName>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</StyledEmailThreadMessageSenderUser>
|
</StyledEmailThreadMessageSenderUser>
|
||||||
<StyledThreadMessageSentAt>
|
<StyledThreadMessageSentAt>
|
||||||
{beautifyPastDateRelativeToNow(sentAt)}
|
{beautifyPastDateRelativeToNow(sentAt)}
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export type EmailParticipantRole = 'from' | 'to' | 'cc' | 'bcc';
|
||||||
@ -1,10 +1,11 @@
|
|||||||
|
import { EmailParticipantRole } from '@/activities/emails/types/EmailParticipantRole';
|
||||||
import { Person } from '@/people/types/Person';
|
import { Person } from '@/people/types/Person';
|
||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
|
||||||
export type EmailThreadMessageParticipant = {
|
export type EmailThreadMessageParticipant = {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
handle: string;
|
handle: string;
|
||||||
role: string;
|
role: EmailParticipantRole;
|
||||||
person: Person;
|
person: Person;
|
||||||
workspaceMember: WorkspaceMember;
|
workspaceMember: WorkspaceMember;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
||||||
|
|
||||||
|
export const getDisplayNameFromParticipant = ({
|
||||||
|
participant,
|
||||||
|
shouldUseFullName = false,
|
||||||
|
}: {
|
||||||
|
participant: EmailThreadMessageParticipant;
|
||||||
|
shouldUseFullName?: boolean;
|
||||||
|
}) => {
|
||||||
|
if (participant.person) {
|
||||||
|
return (
|
||||||
|
`${participant.person?.name?.firstName}` +
|
||||||
|
(shouldUseFullName ? ` ${participant.person?.name?.lastName}` : '')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participant.workspaceMember) {
|
||||||
|
return (
|
||||||
|
participant.workspaceMember?.name?.firstName +
|
||||||
|
(shouldUseFullName
|
||||||
|
? ` ${participant.workspaceMember?.name?.lastName}`
|
||||||
|
: '')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participant.displayName) {
|
||||||
|
return participant.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participant.handle) {
|
||||||
|
return participant.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Unknown';
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user