From 54632f16e0f76cf92da727f1f7fb9027332e4617 Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Thu, 24 Oct 2024 14:58:29 -0500 Subject: [PATCH] Add Browser SDK example --- examples/react-vite-browser-sdk/README.md | 28 ++ examples/react-vite-browser-sdk/index.html | 12 + examples/react-vite-browser-sdk/package.json | 34 +++ .../react-vite-browser-sdk/postcss.config.cjs | 5 + .../public/xmtp-icon.png | Bin 0 -> 21829 bytes examples/react-vite-browser-sdk/src/App.tsx | 253 ++++++++++++++++++ .../src/createClient.ts | 35 +++ .../react-vite-browser-sdk/src/globals.d.ts | 15 ++ examples/react-vite-browser-sdk/src/index.css | 111 ++++++++ examples/react-vite-browser-sdk/src/main.tsx | 33 +++ .../react-vite-browser-sdk/src/wallets.ts | 31 +++ examples/react-vite-browser-sdk/tsconfig.json | 4 + .../react-vite-browser-sdk/vite.config.ts | 16 ++ 13 files changed, 577 insertions(+) create mode 100644 examples/react-vite-browser-sdk/README.md create mode 100644 examples/react-vite-browser-sdk/index.html create mode 100644 examples/react-vite-browser-sdk/package.json create mode 100644 examples/react-vite-browser-sdk/postcss.config.cjs create mode 100644 examples/react-vite-browser-sdk/public/xmtp-icon.png create mode 100644 examples/react-vite-browser-sdk/src/App.tsx create mode 100644 examples/react-vite-browser-sdk/src/createClient.ts create mode 100644 examples/react-vite-browser-sdk/src/globals.d.ts create mode 100644 examples/react-vite-browser-sdk/src/index.css create mode 100644 examples/react-vite-browser-sdk/src/main.tsx create mode 100644 examples/react-vite-browser-sdk/src/wallets.ts create mode 100644 examples/react-vite-browser-sdk/tsconfig.json create mode 100644 examples/react-vite-browser-sdk/vite.config.ts diff --git a/examples/react-vite-browser-sdk/README.md b/examples/react-vite-browser-sdk/README.md new file mode 100644 index 000000000..3795dcc31 --- /dev/null +++ b/examples/react-vite-browser-sdk/README.md @@ -0,0 +1,28 @@ +# React Vite example app + +Use this React Vite example app as a tool to start building an app with XMTP. This basic messaging app has an intentionally unopinionated UI to help make it easier for you to build with. + +The app is built using the [React XMTP client SDK](/packages/react-sdk/README.md), [React](https://react.dev/), [Vite](https://vitejs.dev/), and [RainbowKit](https://www.rainbowkit.com/). + +To keep up with the latest example app developments, see the [Issues tab](https://github.com/xmtp/xmtp-web/issues) in this repo. + +To learn more about XMTP and get answers to frequently asked questions, see the [XMTP documentation](https://xmtp.org/docs). + +## Limitations + +This example app isn't a complete solution. For example, the list of conversations doesn't update when new messages arrive in existing conversations. + +## Developing + +1. In `packages/react-sdk`, run `yarn build` to build the React SDK. +2. In `examples/react-vite`, run `yarn dev` to start the development server. + +## Useful commands + +- `yarn build`: Builds the example app +- `yarn clean`: Removes `node_modules`, `dist`, and `.turbo` folders +- `yarn dev`: Launches the example app and watches for changes, which will trigger a rebuild +- `yarn format`: Runs prettier format and write changes +- `yarn format:check`: Runs prettier format check +- `yarn lint`: Runs ESLint +- `yarn typecheck`: Runs `tsc` diff --git a/examples/react-vite-browser-sdk/index.html b/examples/react-vite-browser-sdk/index.html new file mode 100644 index 000000000..31cf5d729 --- /dev/null +++ b/examples/react-vite-browser-sdk/index.html @@ -0,0 +1,12 @@ + + + + + + XMTP V3 Browser SDK Example + + +
+ + + diff --git a/examples/react-vite-browser-sdk/package.json b/examples/react-vite-browser-sdk/package.json new file mode 100644 index 000000000..102500c6b --- /dev/null +++ b/examples/react-vite-browser-sdk/package.json @@ -0,0 +1,34 @@ +{ + "name": "@xmtp/react-vite-browser-sdk-example", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "clean": "rm -rf .turbo && rm -rf node_modules && yarn clean:dist", + "clean:dist": "rm -rf dist", + "dev": "vite", + "quickstart": "yarn dev", + "typecheck": "tsc" + }, + "dependencies": { + "@rainbow-me/rainbowkit": "^2.1.3", + "@tanstack/react-query": "^5.51.1", + "@wagmi/core": "^2.11.7", + "@xmtp/browser-sdk": "workspace:*", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "viem": "^2.17.4", + "wagmi": "^2.10.10" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.39", + "postcss-preset-env": "^9.6.0", + "tsconfig": "workspace:*", + "typescript": "^5.5.3", + "vite": "^5.4.9" + } +} diff --git a/examples/react-vite-browser-sdk/postcss.config.cjs b/examples/react-vite-browser-sdk/postcss.config.cjs new file mode 100644 index 000000000..eaccdea29 --- /dev/null +++ b/examples/react-vite-browser-sdk/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + "postcss-preset-env": {}, + }, +}; diff --git a/examples/react-vite-browser-sdk/public/xmtp-icon.png b/examples/react-vite-browser-sdk/public/xmtp-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6c610d7d85a9de809ff0fd3dca4d3f0c22f853f3 GIT binary patch literal 21829 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 T*oxXIqNI9SS2Sxi@R9!q&(Ik; literal 0 HcmV?d00001 diff --git a/examples/react-vite-browser-sdk/src/App.tsx b/examples/react-vite-browser-sdk/src/App.tsx new file mode 100644 index 000000000..ea6e39b27 --- /dev/null +++ b/examples/react-vite-browser-sdk/src/App.tsx @@ -0,0 +1,253 @@ +import { + Conversation, + type Client, + type DecodedMessage, +} from "@xmtp/browser-sdk"; +import { useState } from "react"; +import { createClient } from "./createClient"; + +export const App = () => { + const [client, setClient] = useState(undefined); + const [conversations, setConversations] = useState([]); + const [messages, setMessages] = useState>( + new Map(), + ); + + const handleCreateClient = async () => { + setClient(await createClient("key1")); + }; + + const handleResetClient = () => { + if (client) { + client.close(); + } + setClient(undefined); + setConversations([]); + setMessages(new Map()); + }; + + const handleListGroups = async () => { + if (client) { + const groups = await client.conversations.list(); + setConversations(groups); + } + }; + + const handleUpdateGroupName = async (groupId: string, elementId: string) => { + if (client) { + const conversation = new Conversation(client, groupId); + await conversation.sync(); + const element = document.getElementById(elementId) as HTMLInputElement; + const name = element.value; + await conversation.updateName(name); + element.value = ""; + await handleListGroups(); + } + }; + + const handleUpdateGroupDescription = async ( + groupId: string, + elementId: string, + ) => { + if (client) { + const conversation = new Conversation(client, groupId); + await conversation.sync(); + const element = document.getElementById(elementId) as HTMLInputElement; + const description = element.value; + await conversation.updateDescription(description); + element.value = ""; + await handleListGroups(); + } + }; + + const handleListGroupMessages = async (groupId: string) => { + if (client) { + const conversation = new Conversation(client, groupId); + await conversation.sync(); + const groupMessages = await conversation.messages(); + setMessages((prevMessages) => { + const newMessages = new Map(prevMessages); + newMessages.set(groupId, groupMessages); + return newMessages; + }); + } + }; + + const handleSendGroupMessage = async (groupId: string, elementId: string) => { + if (client) { + const conversation = new Conversation(client, groupId); + await conversation.sync(); + const element = document.getElementById(elementId) as HTMLInputElement; + const message = element.value; + await conversation.send(message); + element.value = ""; + } + }; + + const handleCreateGroup = async () => { + if (client) { + const element = document.getElementById( + "create-group-name", + ) as HTMLInputElement; + const name = element.value; + const group = await client.conversations.newGroup([]); + await group.sync(); + await group.updateName(name); + element.value = ""; + await handleListGroups(); + } + }; + + const handleSyncGroup = async (groupId: string) => { + if (client) { + const conversation = new Conversation(client, groupId); + await conversation.sync(); + await handleListGroupMessages(groupId); + } + }; + + return ( +
+

XMTP V3

+
+ {!client && ( + + )} + {client && ( + <> + + + + )} +
+ {client && ( + <> +
+

Client details

+
+
Address:
+
{client.address}
+
+
+
Inbox ID:
+
{client.inboxId}
+
+
+
Installation ID:
+
{client.installationId}
+
+
+
+
+ + +
+
+ + )} + {conversations.length > 0 && ( +
+

Conversations

+
+ {conversations.map((conversation) => ( +
+

{conversation.id}

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
Name:
+
{conversation.name}
+
+
+
Description:
+
{conversation.description}
+
+ {messages.get(conversation.id) && ( +
+

Messages

+ {messages.get(conversation.id)?.map((message) => ( +
+
{JSON.stringify(message.content, null, 2)}
+
+ ))} +
+ )} +
+ ))} +
+
+ )} +
+ ); +}; diff --git a/examples/react-vite-browser-sdk/src/createClient.ts b/examples/react-vite-browser-sdk/src/createClient.ts new file mode 100644 index 000000000..c9b362f5b --- /dev/null +++ b/examples/react-vite-browser-sdk/src/createClient.ts @@ -0,0 +1,35 @@ +import { Client, WasmSignatureRequestType } from "@xmtp/browser-sdk"; +import { toBytes } from "viem/utils"; +import { createWallet } from "./wallets"; + +type Wallet = ReturnType; + +export const getSignature = async (client: Client, wallet: Wallet) => { + const signatureText = await client.getCreateInboxSignatureText(); + if (signatureText) { + const signature = await wallet.signMessage({ + message: signatureText, + }); + return toBytes(signature); + } + return null; +}; + +export const createClient = async (walletKey: string) => { + const wallet = createWallet(walletKey); + const client = await Client.create(wallet.account.address, { + env: "local", + }); + const isRegistered = await client.isRegistered(); + if (!isRegistered) { + const signature = await getSignature(client, wallet); + if (signature) { + await client.addSignature( + WasmSignatureRequestType.CreateInbox, + signature, + ); + } + await client.registerIdentity(); + } + return client; +}; diff --git a/examples/react-vite-browser-sdk/src/globals.d.ts b/examples/react-vite-browser-sdk/src/globals.d.ts new file mode 100644 index 000000000..5b948c9b6 --- /dev/null +++ b/examples/react-vite-browser-sdk/src/globals.d.ts @@ -0,0 +1,15 @@ +interface ImportMeta { + env: { + VITE_PROJECT_ID: string; + }; +} + +declare module "*.module.css" { + const classes: { [key: string]: string }; + export default classes; +} + +declare module "*.png" { + const src: string; + export default src; +} diff --git a/examples/react-vite-browser-sdk/src/index.css b/examples/react-vite-browser-sdk/src/index.css new file mode 100644 index 000000000..cf988d17b --- /dev/null +++ b/examples/react-vite-browser-sdk/src/index.css @@ -0,0 +1,111 @@ +:root { + font-family: "SF Pro Rounded", Inter, system-ui, Avenir, Helvetica, Arial, + sans-serif; + line-height: 1.3; + font-weight: 400; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + min-width: 320px; + height: 100vh; + display: flex; + flex-direction: column; + color: #213547; + background-color: #fff; +} + +#root { + flex-grow: 1; + display: flex; + flex-direction: column; +} + +#root > [data-rk] { + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.App { + width: 800px; + margin: 0 auto; + padding: 20px; +} + +.App h1 { + text-align: center; + margin-top: 0; +} + +.Actions { + display: flex; + gap: 10px; + justify-content: center; + padding: 20px; +} + +.ClientDetail { + display: flex; + gap: 10px; + justify-content: space-between; +} + +.ConversationActions { + display: flex; + gap: 10px; + justify-content: center; + align-items: center; + padding: 10px; +} + +.ConversationAction { + padding: 6px; + border: 1px solid #213547; + border-radius: 6px; + background-color: #f0f0f0; + display: flex; + gap: 2px; + flex-direction: column; +} + +.ConversationWrapper { + display: flex; + flex-direction: column; + gap: 10px; +} + +.Conversation { + border: 1px solid #213547; + border-radius: 10px; + padding: 10px; +} + +.Conversation > h3 { + margin-top: 0; +} + +.ConversationDetail { + display: flex; + gap: 10px; + justify-content: space-between; +} + +.ConversationMessages { + display: flex; + flex-direction: column; + gap: 4px; +} + +.ConversationMessage { + border: 1px solid #213547; + border-radius: 6px; + padding: 4px; + background-color: #f0f0f0; + text-wrap: pretty; +} diff --git a/examples/react-vite-browser-sdk/src/main.tsx b/examples/react-vite-browser-sdk/src/main.tsx new file mode 100644 index 000000000..c4833794e --- /dev/null +++ b/examples/react-vite-browser-sdk/src/main.tsx @@ -0,0 +1,33 @@ +import "@rainbow-me/rainbowkit/styles.css"; +import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { http } from "@wagmi/core"; +import { mainnet } from "@wagmi/core/chains"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { WagmiProvider } from "wagmi"; +import { App } from "./App"; +import "./index.css"; + +export const config = getDefaultConfig({ + appName: "XMTP V3 Browser SDK Example", + projectId: import.meta.env.VITE_PROJECT_ID, + chains: [mainnet], + transports: { + [mainnet.id]: http(), + }, +}); + +const queryClient = new QueryClient(); + +createRoot(document.getElementById("root") as HTMLElement).render( + + + + + + + + + , +); diff --git a/examples/react-vite-browser-sdk/src/wallets.ts b/examples/react-vite-browser-sdk/src/wallets.ts new file mode 100644 index 000000000..a2b438a7c --- /dev/null +++ b/examples/react-vite-browser-sdk/src/wallets.ts @@ -0,0 +1,31 @@ +import { + createWalletClient, + http, + type PrivateKeyAccount, + type Transport, + type WalletClient, +} from "viem"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; +import { mainnet } from "viem/chains"; + +const keys: Record = { + // address: 0xb879f1d8FD73EC057c02D681880169e5721a6d7F + key1: "0xf8ced372cdb9a67bed1843650a89a59859369bf9900c0bc75741f2740e93cb04", + // address: 0x7ad9d3892D5EEC0586920D3E0ac813aaeF881488 + key2: "0xb562d61bc9fe203a639dfc0c3f875b3411fe8ae211c5722ab9124a1009bda32a", + // address: 0x73655B77df59d378d396918C3426cc5219EfB3c8 + key3: "0x724028dcbf931ff1f2730ad76c0b7b8b07dbf7f0a56408be3e305be1b81edfe0", + // address: 0x5aB557A6b8FF7D7a9A42F223fAA376A4732Eb15a + key4: "0x4420cde3d475a038739d1d47cfd690799c0f2e1b84d871c24f221c2dee4e4121", + // address: 0x38F966794cf349f2c91116e94f587Fc3aafDC3F4 + key5: "0xd34cc37587785349013f3f10cadbe7bf8dfeb8a95c86724887e58816b734fcfb", +}; + +export const createWallet = ( + key: keyof typeof keys, +): WalletClient => + createWalletClient({ + account: privateKeyToAccount(keys[key] ?? generatePrivateKey()), + chain: mainnet, + transport: http(), + }); diff --git a/examples/react-vite-browser-sdk/tsconfig.json b/examples/react-vite-browser-sdk/tsconfig.json new file mode 100644 index 000000000..ce1c7e0fd --- /dev/null +++ b/examples/react-vite-browser-sdk/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "tsconfig/react-app.json", + "include": ["src", "vite.config.ts", "postcss.config.cjs"] +} diff --git a/examples/react-vite-browser-sdk/vite.config.ts b/examples/react-vite-browser-sdk/vite.config.ts new file mode 100644 index 000000000..3d7f96fe2 --- /dev/null +++ b/examples/react-vite-browser-sdk/vite.config.ts @@ -0,0 +1,16 @@ +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + optimizeDeps: { + exclude: ["@xmtp/wasm-bindings"], + }, + server: { + headers: { + "Cross-Origin-Embedder-Policy": "require-corp", + "Cross-Origin-Opener-Policy": "same-origin", + }, + }, +});