Skip to content

Commit

Permalink
Dev tool fixes and optimizations (#797)
Browse files Browse the repository at this point in the history
* Fix useConversations loading state

* Add react-virtuoso

* Optimize manage conversation for DM groups

* Optimize conversation list
  • Loading branch information
rygine authored Jan 23, 2025
1 parent 336471d commit db36e20
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 245 deletions.
1 change: 1 addition & 0 deletions apps/xmtp.chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"react-18-blockies": "^1.0.6",
"react-dom": "^18.3.1",
"react-router": "^7.1.1",
"react-virtuoso": "^4.12.3",
"uint8array-extras": "^1.4.0",
"viem": "^2.21.52",
"wagmi": "^2.13.2"
Expand Down
91 changes: 31 additions & 60 deletions apps/xmtp.chat/src/components/ConversationCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import { Card, Flex, Stack, Text } from "@mantine/core";
import {
SortDirection,
type Conversation,
type DecodedMessage,
} from "@xmtp/browser-sdk";
import { formatDistanceToNow } from "date-fns";
import { Box, Card, Flex, Stack, Text } from "@mantine/core";
import { type Conversation } from "@xmtp/browser-sdk";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router";
import { nsToDate } from "../helpers/date";
import { useConversation } from "../hooks/useConversation";
import styles from "./ConversationCard.module.css";

export type ConversationCardProps = {
Expand All @@ -20,21 +13,6 @@ export const ConversationCard: React.FC<ConversationCardProps> = ({
}) => {
const [memberCount, setMemberCount] = useState(0);
const navigate = useNavigate();
const [messageCount, setMessageCount] = useState(0);
const [lastMessage, setLastMessage] = useState<DecodedMessage | null>(null);
const { getMessages } = useConversation(conversation);

useEffect(() => {
const loadMessages = async () => {
const messages = await getMessages({
direction: SortDirection.Descending,
limit: 1n,
});
setLastMessage(messages[0] ?? null);
setMessageCount(messages.length);
};
void loadMessages();
}, [conversation]);

useEffect(() => {
void conversation.members().then((members) => {
Expand All @@ -43,42 +21,35 @@ export const ConversationCard: React.FC<ConversationCardProps> = ({
}, [conversation.id]);

return (
<Card
shadow="sm"
padding="sm"
radius="md"
withBorder
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "Enter") {
void navigate(`/conversations/${conversation.id}`);
}
}}
onClick={() => void navigate(`/conversations/${conversation.id}`)}
style={{ cursor: "pointer" }}
classNames={{ root: styles.root }}>
<Stack gap="0">
<Flex align="center">
<Text
fw={700}
c={conversation.name ? "text.primary" : "dimmed"}
truncate="end">
{conversation.name || "Untitled"}
</Text>
</Flex>
<Text size="sm">
{memberCount} member{memberCount !== 1 ? "s" : ""}, {messageCount}{" "}
message{messageCount !== 1 ? "s" : ""}
</Text>
{lastMessage && (
<Text size="sm" c="dimmed" mt="xs">
Last message sent{" "}
{formatDistanceToNow(nsToDate(lastMessage.sentAtNs), {
addSuffix: true,
})}
<Box pb="sm" px="sm">
<Card
shadow="sm"
padding="sm"
radius="md"
withBorder
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "Enter") {
void navigate(`/conversations/${conversation.id}`);
}
}}
onClick={() => void navigate(`/conversations/${conversation.id}`)}
style={{ cursor: "pointer" }}
classNames={{ root: styles.root }}>
<Stack gap="0">
<Flex align="center">
<Text
fw={700}
c={conversation.name ? "text.primary" : "dimmed"}
truncate="end">
{conversation.name || "Untitled"}
</Text>
</Flex>
<Text size="sm">
{memberCount} member{memberCount !== 1 ? "s" : ""}
</Text>
)}
</Stack>
</Card>
</Stack>
</Card>
</Box>
);
};
33 changes: 14 additions & 19 deletions apps/xmtp.chat/src/components/ConversationsNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,19 @@ import {
Button,
Group,
LoadingOverlay,
ScrollArea,
Stack,
Text,
} from "@mantine/core";
import type { Conversation } from "@xmtp/browser-sdk";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Virtuoso } from "react-virtuoso";
import { useConversations } from "../hooks/useConversations";
import { ConversationCard } from "./ConversationCard";

export const ConversationsNavbar: React.FC = () => {
const { list, loading, syncing } = useConversations();
const [conversations, setConversations] = useState<Conversation[]>([]);

useEffect(() => {
const loadConversations = async () => {
const conversations = await list();
setConversations(conversations);
};
void loadConversations();
}, []);

const handleSync = async () => {
const conversations = await list(undefined, true);
setConversations(conversations);
Expand All @@ -50,18 +42,21 @@ export const ConversationsNavbar: React.FC = () => {
</Group>
</Stack>
</AppShell.Section>
<AppShell.Section grow my="md" component={ScrollArea} px="md">
<AppShell.Section
grow
my="md"
display="flex"
style={{ flexDirection: "column" }}>
{conversations.length === 0 ? (
<Text>No conversations found</Text>
) : (
<Stack gap="sm">
{conversations.map((conversation) => (
<ConversationCard
key={conversation.id}
conversation={conversation}
/>
))}
</Stack>
<Virtuoso
style={{ flexGrow: 1 }}
data={conversations}
itemContent={(_, conversation) => (
<ConversationCard conversation={conversation} />
)}
/>
)}
</AppShell.Section>
</>
Expand Down
Loading

0 comments on commit db36e20

Please sign in to comment.