From cbc60c39246d34f4cf79dfd301b71f3690926f15 Mon Sep 17 00:00:00 2001 From: daria-github Date: Mon, 22 Jan 2024 11:23:04 -0800 Subject: [PATCH] updated consent flow --- .../components/AddressInput/AddressInput.tsx | 23 ++--- .../FullConversation/FullConversation.tsx | 7 +- src/controllers/AddressInputController.tsx | 10 +- .../ConversationListController.tsx | 98 +++++++++---------- src/store/xmtp.tsx | 5 + 5 files changed, 75 insertions(+), 68 deletions(-) diff --git a/src/component-library/components/AddressInput/AddressInput.tsx b/src/component-library/components/AddressInput/AddressInput.tsx index 954c146d..5e3076f9 100644 --- a/src/component-library/components/AddressInput/AddressInput.tsx +++ b/src/component-library/components/AddressInput/AddressInput.tsx @@ -1,7 +1,4 @@ -import { - ChevronLeftIcon, - InformationCircleIcon, -} from "@heroicons/react/outline"; +import { ChevronLeftIcon, XCircleIcon } from "@heroicons/react/outline"; import { useTranslation } from "react-i18next"; import { Avatar } from "../Avatar/Avatar"; import { classNames } from "../../../helpers"; @@ -41,10 +38,6 @@ interface AddressInputProps { * Upon submit, is something loading? */ isLoading?: boolean; - /** - * Is there a tooltip click event that needs to be handled? - */ - onTooltipClick?: () => void; /** * Input Value */ @@ -53,6 +46,10 @@ interface AddressInputProps { * Is there a left icon click event that needs to be handled? */ onLeftIconClick?: () => void; + /** + * Is there a right icon click event that needs to be handled? + */ + onRightIconClick?: () => void; } export const AddressInput = ({ @@ -61,9 +58,9 @@ export const AddressInput = ({ avatarUrlProps, onChange, isError, - onTooltipClick, value, onLeftIconClick, + onRightIconClick, }: AddressInputProps) => { const { t } = useTranslation(); const subtextColor = isError ? "text-red-600" : "text-gray-500"; @@ -127,8 +124,12 @@ export const AddressInput = ({ - {onTooltipClick && ( - + {onRightIconClick && ( + )} ); diff --git a/src/component-library/components/FullConversation/FullConversation.tsx b/src/component-library/components/FullConversation/FullConversation.tsx index 96effeb7..3876988a 100644 --- a/src/component-library/components/FullConversation/FullConversation.tsx +++ b/src/component-library/components/FullConversation/FullConversation.tsx @@ -35,7 +35,8 @@ const AcceptOrDeny = ({ address }: { address: string }) => { const { t } = useTranslation(); const { allow, deny } = useConsent(); const activeTab = useXmtpStore((s) => s.activeTab); - const setActiveTab = useXmtpStore((s) => s.setActiveTab); + const changedConsentCount = useXmtpStore((s) => s.changedConsentCount); + const setChangedConsentCount = useXmtpStore((s) => s.setChangedConsentCount); const [modalOpen, setModalOpen] = useState(true); @@ -51,8 +52,8 @@ const AcceptOrDeny = ({ address }: { address: string }) => { className="text-indigo-600 flex w-full justify-center border border-2 border-indigo-600 rounded-md p-2 hover:bg-indigo-600 hover:text-white" onClick={() => { void allow([address]); - setActiveTab("messages"); setModalOpen(false); + setChangedConsentCount(changedConsentCount + 1); }}> {t("consent.accept")} @@ -61,8 +62,8 @@ const AcceptOrDeny = ({ address }: { address: string }) => { className="text-red-600 flex w-full justify-center border border-2 border-red-600 rounded-md p-2 hover:bg-red-600 hover:text-white" onClick={() => { void deny([address]); - setActiveTab("blocked"); setModalOpen(false); + setChangedConsentCount(changedConsentCount + 1); }}> {t("consent.block")} diff --git a/src/controllers/AddressInputController.tsx b/src/controllers/AddressInputController.tsx index 133e2a1e..97e9c141 100644 --- a/src/controllers/AddressInputController.tsx +++ b/src/controllers/AddressInputController.tsx @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { useConversation } from "@xmtp/react-sdk"; +import { useConversation, useConsent } from "@xmtp/react-sdk"; import { AddressInput } from "../component-library/components/AddressInput/AddressInput"; import { getRecipientInputSubtext, shortAddress } from "../helpers"; import useWindowSize from "../hooks/useWindowSize"; @@ -20,7 +20,11 @@ export const AddressInputController = () => { const setRecipientInput = useXmtpStore((s) => s.setRecipientInput); const setStartedFirstMessage = useXmtpStore((s) => s.setStartedFirstMessage); const setConversationTopic = useXmtpStore((s) => s.setConversationTopic); + const changedConsentCount = useXmtpStore((s) => s.changedConsentCount); + const setChangedConsentCount = useXmtpStore((s) => s.setChangedConsentCount); + const { getCachedByPeerAddress, getCachedByTopic } = useConversation(); + const { deny } = useConsent(); // manage address input state useAddressInput(); @@ -100,6 +104,10 @@ export const AddressInputController = () => { setStartedFirstMessage(false); setConversationTopic(""); }} + onRightIconClick={() => { + void deny([recipientAddress]); + setChangedConsentCount(changedConsentCount + 1); + }} /> ); }; diff --git a/src/controllers/ConversationListController.tsx b/src/controllers/ConversationListController.tsx index d2646b84..52e78459 100644 --- a/src/controllers/ConversationListController.tsx +++ b/src/controllers/ConversationListController.tsx @@ -1,12 +1,6 @@ import { useEffect, useMemo, useState } from "react"; -import { - getLastMessage, - getMessageByXmtpID, - useClient, - useConsent, - useDb, - useMessages, -} from "@xmtp/react-sdk"; +import { useClient, useConsent, useDb } from "@xmtp/react-sdk"; +import type { CachedConversation, CachedMessage } from "@xmtp/react-sdk"; import type { ActiveTab } from "../store/xmtp"; import { useXmtpStore } from "../store/xmtp"; import useListConversations from "../hooks/useListConversations"; @@ -14,7 +8,6 @@ import { ConversationList } from "../component-library/components/ConversationLi import { MessagePreviewCardController } from "./MessagePreviewCardController"; import useStreamAllMessages from "../hooks/useStreamAllMessages"; import { updateConversationIdentities } from "../helpers/conversation"; -import { useWalletClient } from "wagmi"; type ConversationListControllerProps = { setStartedFirstMessage: (startedFirstMessage: boolean) => void; @@ -22,6 +15,7 @@ type ConversationListControllerProps = { type ConsentProps = { tab: ActiveTab; + convo: CachedConversation; }; type NodeWithConsent = React.ReactElement; @@ -33,12 +27,13 @@ export const ConversationListController = ({ const { isAllowed, isDenied } = useConsent(); const { db } = useDb(); - const [messages, setMessages] = useState([]); + const [messages, setMessages] = useState([]); const messagesDb = db.table("messages"); useStreamAllMessages(); const { client: walletAddress } = useClient(); const recipientInput = useXmtpStore((s) => s.recipientInput); + const changedConsentCount = useXmtpStore((s) => s.changedConsentCount); const activeTab = useXmtpStore((s) => s.activeTab); @@ -51,84 +46,81 @@ export const ConversationListController = ({ }; void runUpdate(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLoaded, activeTab]); - - const filteredConversations = useMemo(() => { - const convos = conversations.map((conversation) => ( - - )); - return convos; - }, [conversations, isAllowed, isDenied]); - - let isFilterLoading = false; + }, [isLoaded, activeTab, changedConsentCount]); useEffect(() => { - // Fetch messages asynchronously + // This may make more sense to come from the React SDK, but we're pulling from here for now const fetchMessages = async () => messagesDb .where("senderAddress") - .equals(walletAddress?.address) + .equals(walletAddress?.address as string) .toArray() - .then((messages) => { - // Process your messages here - setMessages(messages); + .then((dbMessages: CachedMessage[]) => { + setMessages(dbMessages); }) - .catch((error) => { + .catch((error: Error) => { console.error("Error querying messages:", error); }); void fetchMessages(); - }, [filteredConversations, messagesDb, walletAddress?.address]); + }, [conversations.length, messagesDb, walletAddress?.address]); const messagesToPass = useMemo(() => { - isFilterLoading = true; - const sortedConvos = filteredConversations.filter( + const conversationsWithTab = conversations.map( + (conversation: CachedConversation) => { + const tab = isAllowed(conversation.peerAddress) + ? "messages" + : isDenied(conversation.peerAddress) + ? "blocked" + : "requests"; + return ( + + ); + }, + ); + const sortedConvos = conversationsWithTab.filter( (item: NodeWithConsent) => { - console.log("MESSAGES", messages); const hasSentMessages = messages.find( (message) => message?.conversationTopic === item.props.convo.topic, ); + const isAddressBlocked = isDenied(item.props.convo.peerAddress); + const isAddressAllowed = isAllowed(item.props.convo.peerAddress); + if (activeTab === "messages") { // Still want to keep blocked in blocked, even if those still have messages - return ( - item.props.tab === "messages" || - (item.props.tab === "requests" && hasSentMessages) - ); + return isAddressAllowed || (!isAddressBlocked && hasSentMessages); } if (activeTab === "blocked") { - return item.props.tab === "blocked"; + return isAddressBlocked; } - // Find the sent messages in this conversation - - return item.props.tab === "requests"; + if (activeTab === "requests") { + return !hasSentMessages && !isAddressBlocked && !isAddressAllowed; + } + return null; }, ); - isFilterLoading = false; return sortedConvos; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ - filteredConversations, + conversations, + messages, isLoading, - activeTab, walletAddress, db, - isFilterLoading, + changedConsentCount, + isAllowed, + isDenied, ]); return ( setStartedFirstMessage(true)} - isLoading={isLoading || isFilterLoading} + isLoading={isLoading} messages={messagesToPass} activeTab={activeTab} /> diff --git a/src/store/xmtp.tsx b/src/store/xmtp.tsx index cf9f8bcb..608d84b2 100644 --- a/src/store/xmtp.tsx +++ b/src/store/xmtp.tsx @@ -39,6 +39,8 @@ interface XmtpState { setActiveMessage: (message?: CachedMessageWithId) => void; activeTab: ActiveTab; setActiveTab: (activeTab: ActiveTab) => void; + changedConsentCount: number; + setChangedConsentCount: (changedConsentCount: number) => void; } export const useXmtpStore = create((set) => ({ @@ -93,4 +95,7 @@ export const useXmtpStore = create((set) => ({ setActiveMessage: (activeMessage) => set(() => ({ activeMessage })), activeTab: "messages", setActiveTab: (activeTab) => set(() => ({ activeTab })), + changedConsentCount: 0, + setChangedConsentCount: (changedConsentCount) => + set(() => ({ changedConsentCount })), }));