Skip to content

Commit

Permalink
Merge pull request #10 from xmtp/dj/read-receipts
Browse files Browse the repository at this point in the history
Read Receipt Playground Implementation
  • Loading branch information
daria-github committed Jul 24, 2023
2 parents a47f7c4 + b39a09a commit 6e9dc30
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 150 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ Built with React and the [XMTP JavaScript SDK](https://github.com/xmtp/xmtp-js),
- Group chat
- Message reactions
- Message replies
- Read receipts
- [Attachments](https://xmtp.org/docs/build/attachments)
- Images
- More formats to come

The playground's visual design is intentionally limited to help make the code easier for your to use, customize, and deploy.
The playground's visual design is intentionally limited to help make the code easier for you to use, customize, and deploy.

The playground has not undergone a formal security audit.

> **Note**
> You might also be interested in our Vue playground: Coming soon
> You might also be interested in our Vue playground: Coming soon
## Install the package

Expand Down
85 changes: 29 additions & 56 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@heroicons/react": "^2.0.18",
"@rainbow-me/rainbowkit": "^0.10.0",
"@xmtp/content-type-reaction": "^1.0.1",
"@xmtp/content-type-read-receipt": "^1.0.0",
"@xmtp/content-type-remote-attachment": "^1.0.7",
"@xmtp/content-type-reply": "^1.0.0",
"@xmtp/xmtp-js": "^9.4.0-beta.1",
Expand Down
2 changes: 2 additions & 0 deletions src/contexts/ClientContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "@xmtp/content-type-remote-attachment";
import { ReplyCodec } from "@xmtp/content-type-reply";
import { ReactionCodec } from "@xmtp/content-type-reaction";
import { ReadReceiptCodec } from "@xmtp/content-type-read-receipt";

type ClientContextValue = {
client: Client | null;
Expand Down Expand Up @@ -47,6 +48,7 @@ export default function ClientProvider({
client.registerCodec(new RemoteAttachmentCodec());
client.registerCodec(new ReplyCodec());
client.registerCodec(new ReactionCodec());
client.registerCodec(new ReadReceiptCodec());

setClient(client);
setIsLoading(false);
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/useClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "@xmtp/content-type-remote-attachment";
import { ReplyCodec } from "@xmtp/content-type-reply";
import { ReactionCodec } from "@xmtp/content-type-reaction";
import { ReadReceiptCodec } from "@xmtp/content-type-read-receipt";

export function useClient() {
return useContext(ClientContext).client;
Expand All @@ -21,6 +22,8 @@ export function useSetClient() {
client.registerCodec(new RemoteAttachmentCodec());
client.registerCodec(new ReplyCodec());
client.registerCodec(new ReactionCodec());
client.registerCodec(new ReadReceiptCodec());

client.enableGroupChat();

Check failure on line 27 in src/hooks/useClient.tsx

View workflow job for this annotation

GitHub Actions / deploy

Property 'enableGroupChat' does not exist on type 'Client'.
}

Expand Down
51 changes: 51 additions & 0 deletions src/hooks/useReadReceipts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import db, { Conversation } from "../model/db";
import { useClient } from "./useClient";
import { sendMessage } from "../model/messages";
import { Client } from "@xmtp/xmtp-js";
import { ContentTypeReadReceipt } from "@xmtp/content-type-read-receipt";
import { useLiveQuery } from "dexie-react-hooks";
import { useMessages } from "./useMessages";

export function useReadReceipts(conversation: Conversation) {
const client = useClient();
const messages = useMessages(conversation) || [];

const isMostRecentMessageFromSelf = messages[messages.length - 1]?.sentByMe;
const lastMessageTimestamp = messages[messages.length - 1]?.sentAt;

const readReceiptsEnabled =
window.localStorage.getItem("readReceiptsEnabled") === "true";

return useLiveQuery(async () => {
try {
const lastReadReceiptMessage = await db.readReceipts.get({
peerAddress: conversation.peerAddress,
});
const isMostRecentMessageReadReceipt =
lastMessageTimestamp <
new Date(lastReadReceiptMessage?.timestamp as string);

if (isMostRecentMessageFromSelf && isMostRecentMessageReadReceipt) {
return true;
} else if (
isMostRecentMessageFromSelf === false &&
isMostRecentMessageReadReceipt === false &&
readReceiptsEnabled
) {
void sendMessage(
client as Client,
conversation,
{
timestamp: new Date().toISOString(),
},
ContentTypeReadReceipt
);
return false;
} else {
return false;
}
} catch {
console.error("Error sending read receipt");
}
}, [messages]);
}
10 changes: 10 additions & 0 deletions src/model/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,17 @@ export interface MessageReaction {
name: string;
}

export interface ReadReceipt {
peerAddress: string;
timestamp: string;
}

class DB extends Dexie {
conversations!: Dexie.Table<Conversation, number>;
messages!: Dexie.Table<Message, number>;
attachments!: Dexie.Table<MessageAttachment, number>;
reactions!: Dexie.Table<MessageReaction, number>;
readReceipts!: Dexie.Table<ReadReceipt, string>;

constructor() {
super("DB");
Expand Down Expand Up @@ -97,6 +103,10 @@ class DB extends Dexie {
reactor,
name
`,
readReceipts: `
++peerAddress,
timestamp
`,
});
}
}
Expand Down
Loading

0 comments on commit 6e9dc30

Please sign in to comment.