shellphone.app/app/features/messages/components/conversation.tsx

82 lines
3.0 KiB
TypeScript
Raw Normal View History

2021-08-29 23:13:06 +00:00
import { Suspense, useEffect, useMemo, useRef } from "react";
2022-05-14 10:22:06 +00:00
import { useLoaderData, useParams } from "@remix-run/react";
import clsx from "clsx";
2022-05-14 10:22:06 +00:00
import { Direction } from "@prisma/client";
2021-07-31 14:33:18 +00:00
import NewMessageArea from "./new-message-area";
2022-05-14 10:22:06 +00:00
import { formatDate, formatTime } from "~/features/core/helpers/date-formatter";
import { type ConversationLoaderData } from "~/routes/__app/messages.$recipient";
2021-07-31 14:33:18 +00:00
export default function Conversation() {
2022-05-14 10:22:06 +00:00
const params = useParams<{ recipient: string }>();
const recipient = decodeURIComponent(params.recipient ?? "");
const { conversation } = useLoaderData<ConversationLoaderData>();
2021-08-29 23:13:06 +00:00
const messages = useMemo(() => conversation?.messages ?? [], [conversation?.messages]);
const messagesListRef = useRef<HTMLUListElement>(null);
2021-07-31 14:33:18 +00:00
useEffect(() => {
messagesListRef.current?.querySelector("li:last-child")?.scrollIntoView();
}, [messages, messagesListRef]);
2021-07-31 14:33:18 +00:00
return (
<>
<div className="flex flex-col space-y-6 p-6 pt-12 pb-16">
<ul ref={messagesListRef}>
{messages.length === 0 ? "empty state" : null}
{messages.map((message, index) => {
const isOutbound = message.direction === Direction.Outbound;
const nextMessage = messages![index + 1];
const previousMessage = messages![index - 1];
2021-08-15 03:09:09 +00:00
const isNextMessageFromSameSender = message.from === nextMessage?.from;
const isPreviousMessageFromSameSender = message.from === previousMessage?.from;
const messageSentAt = new Date(message.sentAt);
const previousMessageSentAt = previousMessage ? new Date(previousMessage.sentAt) : null;
const quarter = Math.floor(messageSentAt.getMinutes() / 15);
const sameQuarter =
previousMessage &&
messageSentAt.getTime() - previousMessageSentAt!.getTime() < 15 * 60 * 1000 &&
quarter === Math.floor(previousMessageSentAt!.getMinutes() / 15);
const shouldGroupMessages = previousMessageSentAt && sameQuarter;
2021-07-31 14:33:18 +00:00
return (
<li key={message.id}>
2021-08-15 03:09:09 +00:00
{(!isPreviousMessageFromSameSender || !shouldGroupMessages) && (
2021-07-31 14:33:18 +00:00
<div className="flex py-2 space-x-1 text-xs justify-center">
<strong>
2021-08-30 15:19:33 +00:00
{formatDate(new Date(message.sentAt), {
2021-07-31 14:33:18 +00:00
weekday: "long",
day: "2-digit",
month: "short",
})}
</strong>
2021-08-30 15:19:33 +00:00
<span>{formatTime(new Date(message.sentAt))}</span>
2021-07-31 14:33:18 +00:00
</div>
)}
<div
className={clsx(
2021-08-15 03:09:09 +00:00
isNextMessageFromSameSender ? "pb-1" : "pb-2",
2021-08-01 12:04:04 +00:00
isOutbound ? "text-right" : "text-left",
2021-07-31 14:33:18 +00:00
)}
>
<span
className={clsx(
"inline-block whitespace-pre-line text-left w-[fit-content] p-2 rounded-lg text-white",
2021-08-01 14:03:49 +00:00
isOutbound ? "bg-[#3194ff] rounded-br-none" : "bg-black rounded-bl-none",
2021-07-31 14:33:18 +00:00
)}
>
{message.content}
</span>
</div>
</li>
);
2021-07-31 14:33:18 +00:00
})}
</ul>
</div>
<Suspense fallback={null}>
2021-08-01 07:40:18 +00:00
<NewMessageArea recipient={recipient} />
2021-07-31 14:33:18 +00:00
</Suspense>
</>
);
2021-07-31 14:33:18 +00:00
}