Skip to main content
Glama
deso-protocol

DeSo MCP Server

Official
messaging-conversation-accounts.tsx9.42 kB
import { Tab, TabPanel, Tabs, TabsBody, TabsHeader, Tooltip, } from "@material-tailwind/react"; import { ChatType, identity, ProfileEntryResponse } from "deso-protocol"; import { ethers } from "ethers"; import sortBy from "lodash/sortBy"; import { FC, useState } from "react"; import { MAX_MEMBERS_IN_GROUP_SUMMARY_SHOWN, MAX_MEMBERS_TO_REQUEST_IN_GROUP, } from "../utils/constants"; import { getChatNameFromConversation } from "../utils/helpers"; import { ConversationMap } from "../utils/types"; import { MessagingDisplayAvatar } from "./messaging-display-avatar"; import { MessagingStartNewConversation } from "./messaging-start-new-conversation"; import { shortenLongWord } from "./search-users"; import { SaveToClipboard } from "./shared/save-to-clipboard"; import { StartGroupChat } from "./start-group-chat"; export const MessagingConversationAccount: FC<{ conversations: ConversationMap; getUsernameByPublicKeyBase58Check: { [key: string]: string }; selectedConversationPublicKey: string; onClick: (publicKey: string) => void; rehydrateConversation: (publicKey?: string) => void; membersByGroupKey: { [groupKey: string]: { [publicKey: string]: ProfileEntryResponse | null }; }; }> = ({ conversations, getUsernameByPublicKeyBase58Check, selectedConversationPublicKey, onClick, rehydrateConversation, membersByGroupKey, }) => { // TODO: move to identity package const provider = new ethers.providers.InfuraProvider("homestead"); //, process.env.REACT_APP_INFURA_API_KEY); const activeTab = { className: "bg-blue-800" }; return ( <div className="h-full rounded-md rounded-r-none"> <div className="m-0"> <StartGroupChat onSuccess={rehydrateConversation} /> </div> <MessagingStartNewConversation rehydrateConversation={rehydrateConversation} /> <Tabs id="main-chat-tabs" value="chats" className="h-full max-h-[calc(100%-144px)]" > <TabsHeader className="bg-blue-900/20 py-2 px-4" indicatorProps={activeTab} > <Tab key="chats" value="chats" className="text-blue-100 font-bold"> Chats </Tab> <Tab key="requests" value="requests" className="text-blue-100 font-bold" > Requests </Tab> </TabsHeader> <TabsBody className="h-[calc(100%-50px)] relative py-4" animate={{ mount: { transition: { duration: 0, times: 0 } }, unmount: { transition: { duration: 0, times: 0 } }, }} > <TabPanel key="chats" value="chats" className="conversations-list overflow-y-auto max-h-full [&>:nth-child(1)]:border-t-0 custom-scrollbar" > <div className="h-full"> {Object.entries(conversations) .sort(([aPub, convoA], [bPub, convoB]) => { if (convoA.messages.length === 0) { return aPub === selectedConversationPublicKey ? -1 : 1; } if (convoB.messages.length === 0) { return bPub === selectedConversationPublicKey ? 1 : -1; } return ( convoB.messages[0].MessageInfo.TimestampNanos - convoA.messages[0].MessageInfo.TimestampNanos ); }) .map(([key, value]) => { const isDM = value.ChatType === ChatType.DM; const isGroupChat = value.ChatType === ChatType.GROUPCHAT; const publicKey = isDM ? value.firstMessagePublicKey : value.messages[0].RecipientInfo.OwnerPublicKeyBase58Check; const chatName = getChatNameFromConversation( value, getUsernameByPublicKeyBase58Check ); const selectedConversationStyle = key === selectedConversationPublicKey ? "selected-conversation bg-blue-900/20" : ""; return ( <div onClick={() => onClick(key)} className={`px-2 py-4 ${selectedConversationStyle} hover:bg-blue-900/10 cursor-pointer flex justify-start`} key={`message-thread-${key}`} > <MessagingDisplayAvatar username={isDM ? chatName : undefined} publicKey={ isDM ? value.firstMessagePublicKey : chatName || "" } groupChat={isGroupChat} diameter={50} classNames="mx-2" /> <div className="w-[calc(100%-70px)] text-left"> <header className="flex items-center justify-between"> <div className="text-left ml-2 text-blue-100 font-semibold"> {isDM && chatName ? "@" : ""} {shortenLongWord(chatName, 7, 7) || shortenLongWord(publicKey)} </div> {isDM && ( <ETHSection desoPublicKey={publicKey} provider={provider} /> )} {isGroupChat && ( <MessagingGroupMembers membersMap={membersByGroupKey[key] || {}} /> )} </header> {value.messages[0] && ( <div className="text-left break-all truncate w-full text-blue-300/60 ml-2"> {value.messages[0].DecryptedMessage.slice(0, 50)}... </div> )} </div> </div> ); })} </div> </TabPanel> <TabPanel key="requests" value="requests"> <h2 className="text-white font-semibold text-2xl mt-5 mb-2"> Coming soon! </h2> <div className="text-blue-300/60 text-xl px-10"> An on-chain message request & approval flow will be launching soon. </div> </TabPanel> </TabsBody> </Tabs> </div> ); }; export const MessagingGroupMembers: FC<{ membersMap: { [publicKey: string]: ProfileEntryResponse | null }; maxMembersShown?: number; }> = ({ membersMap, maxMembersShown = MAX_MEMBERS_IN_GROUP_SUMMARY_SHOWN }) => { // Sorting by members who have a profile, and then by 'Username' in ascending order const allPubKeys = sortBy(Object.keys(membersMap), (key) => membersMap[key]?.Username.toLowerCase() ); const pubKeys = allPubKeys.slice(0, maxMembersShown); const hiddenMembersNum = allPubKeys.slice(maxMembersShown).length; return ( <div className="flex justify-start ml-2"> {pubKeys && pubKeys.map((pubKey) => ( <Tooltip key={pubKey} content={membersMap[pubKey]?.Username || shortenLongWord(pubKey)} > <div> <MessagingDisplayAvatar username={membersMap[pubKey]?.Username} publicKey={pubKey} diameter={26} classNames="-ml-2 pb-1" borderColor="border-black" /> </div> </Tooltip> ))} {hiddenMembersNum > 0 && ( <Tooltip content={`${hiddenMembersNum} members more in this group`}> <div className="-ml-2 rounded-full bg-indigo-50 w-[25px] h-[25px] text-center text-[10px] font-black flex items-center justify-center"> {hiddenMembersNum > MAX_MEMBERS_TO_REQUEST_IN_GROUP ? `>${MAX_MEMBERS_TO_REQUEST_IN_GROUP}` : `+${hiddenMembersNum}`} </div> </Tooltip> )} </div> ); }; export const ETHSection: FC<{ desoPublicKey: string; provider: ethers.providers.InfuraProvider; }> = ({ desoPublicKey }) => { const [ensName] = useState<string | null>(null); const ethAddress = identity.desoAddressToEthereumAddress(desoPublicKey); // Disabling ENS name display for now // useEffect(() => { // const getENSName = async () => { // const name = await provider.lookupAddress(ethAddress); // setENSName(name); // } // if (ethAddress) { // getENSName(); // } else { // setENSName(null); // } // }, [ethAddress, provider]); return ( <div className="relative inline-flex align-baseline font-sans text-[10px] font-bold uppercase center leading-none whitespace-nowrap py-1 px-2 rounded-lg select-none bg-blue-900/40 text-blue-200/80"> <SaveToClipboard text={ensName ? ensName : ethAddress}> {ensName ? "ENS" : "ETH"} <i className="ml-1"> {ensName ? shortenLongWord(ensName, 6, 6) : shortenLongWord(ethAddress, 3, 3)} </i> </SaveToClipboard> </div> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/deso-protocol/deso-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server