diff --git a/package-lock.json b/package-lock.json index 4d02a0b9..1e8354e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@xmtp/content-type-reaction": "^1.1.3", "@xmtp/content-type-remote-attachment": "^1.1.4", "@xmtp/content-type-reply": "^1.1.5", - "@xmtp/experimental-content-type-screen-effect": "^1.0.1", + "@xmtp/experimental-content-type-screen-effect": "^1.0.2", "@xmtp/react-sdk": "^3.0.0", "@xmtp/xmtp-js": "^11.2.1", "buffer": "^6.0.3", @@ -14325,9 +14325,9 @@ } }, "node_modules/@xmtp/experimental-content-type-screen-effect": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@xmtp/experimental-content-type-screen-effect/-/experimental-content-type-screen-effect-1.0.1.tgz", - "integrity": "sha512-Hn39MlZU/U2kDGnKi6zB2w1kuIlW96VAZFXTc+Tl0Y5/yZbz1le6Uk9dzC+9hFRxVRDYsvBg67gaueE4hwDo1g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@xmtp/experimental-content-type-screen-effect/-/experimental-content-type-screen-effect-1.0.2.tgz", + "integrity": "sha512-n9WbWNqYLfEGXKmHt4GZD6126s5BbkCVhxbfumxw4tT88Zig3aBJ2gSxzwqMtAlObsMibryFi79Rs+QjnxcfsA==", "dependencies": { "@xmtp/xmtp-js": "^11.1.2" }, @@ -42985,9 +42985,9 @@ } }, "@xmtp/experimental-content-type-screen-effect": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@xmtp/experimental-content-type-screen-effect/-/experimental-content-type-screen-effect-1.0.1.tgz", - "integrity": "sha512-Hn39MlZU/U2kDGnKi6zB2w1kuIlW96VAZFXTc+Tl0Y5/yZbz1le6Uk9dzC+9hFRxVRDYsvBg67gaueE4hwDo1g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@xmtp/experimental-content-type-screen-effect/-/experimental-content-type-screen-effect-1.0.2.tgz", + "integrity": "sha512-n9WbWNqYLfEGXKmHt4GZD6126s5BbkCVhxbfumxw4tT88Zig3aBJ2gSxzwqMtAlObsMibryFi79Rs+QjnxcfsA==", "requires": { "@xmtp/xmtp-js": "^11.1.2" } diff --git a/package.json b/package.json index 5828ea17..ad25141b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@xmtp/content-type-reaction": "^1.1.3", "@xmtp/content-type-remote-attachment": "^1.1.4", "@xmtp/content-type-reply": "^1.1.5", - "@xmtp/experimental-content-type-screen-effect": "^1.0.1", + "@xmtp/experimental-content-type-screen-effect": "^1.0.2", "@xmtp/react-sdk": "^3.0.0", "@xmtp/xmtp-js": "^11.2.1", "buffer": "^6.0.3", diff --git a/src/component-library/components/MessageInput/MessageInput.tsx b/src/component-library/components/MessageInput/MessageInput.tsx index 2afbd44c..3898dea3 100644 --- a/src/component-library/components/MessageInput/MessageInput.tsx +++ b/src/component-library/components/MessageInput/MessageInput.tsx @@ -31,7 +31,7 @@ import { ContentTypeScreenEffect } from "@xmtp/experimental-content-type-screen- import { IconButton } from "../IconButton/IconButton"; import { useAttachmentChange } from "../../../hooks/useAttachmentChange"; import { typeLookup, type contentTypes } from "../../../helpers/attachments"; -import { classNames } from "../../../helpers"; +import { TAILWIND_MD_BREAKPOINT, classNames } from "../../../helpers"; import type { RecipientAddress } from "../../../store/xmtp"; import { useXmtpStore } from "../../../store/xmtp"; import { useVoiceRecording } from "../../../hooks/useVoiceRecording"; @@ -39,6 +39,7 @@ import { useRecordingTimer } from "../../../hooks/useRecordingTimer"; import "react-tooltip/dist/react-tooltip.css"; import { useLongPress } from "../../../hooks/useLongPress"; import { EffectDialog } from "../EffectDialog/EffectDialog"; +import useWindowSize from "../../../hooks/useWindowSize"; type InputProps = { /** @@ -81,10 +82,6 @@ type InputProps = { * Function to set whether content is being dragged over the draggable area, including the message input */ setIsDragActive: (status: boolean) => void; - /** - * Message identifier for a message a new message is attached to (e.g. a message sent with effect) - */ - associatedMessageId?: string; }; export const MessageInput = ({ @@ -98,8 +95,9 @@ export const MessageInput = ({ attachmentPreview, setAttachmentPreview, setIsDragActive, - associatedMessageId, }: InputProps) => { + const [width] = useWindowSize(); + const { getCachedByPeerAddress } = useConversation(); // For effects const { sendMessage: _sendMessage } = _useSendMessage(); @@ -248,16 +246,21 @@ export const MessageInput = ({ ]); const handleLongPress = () => { - setOpenEffectDialog(true); + // Don't run effect on mobile + if (width > TAILWIND_MD_BREAKPOINT) { + setOpenEffectDialog(true); + } }; const handleSendEffect = (effectType: string) => { void _sendMessage( conversation as CachedConversationWithId, - { messageId: associatedMessageId, effectType }, + // To-do: remove this when codec is updated + { messageId: "", effectType }, ContentTypeScreenEffect, ); void send(); + setOpenEffectDialog(false); }; diff --git a/src/component-library/components/ScreenEffects/RainEffect.tsx b/src/component-library/components/ScreenEffects/RainEffect.tsx index bd52dd5d..0cc9984f 100644 --- a/src/component-library/components/ScreenEffects/RainEffect.tsx +++ b/src/component-library/components/ScreenEffects/RainEffect.tsx @@ -8,7 +8,7 @@ interface logoStyles { animationDelay: string; } -const RainEffect = ({ attachedMessageId }: { attachedMessageId: string }) => { +const RainEffect = ({ messageId }: { messageId: string }) => { const [logos, setLogos] = useState([]); const [isVisible, setIsVisible] = useState(true); @@ -30,12 +30,12 @@ const RainEffect = ({ attachedMessageId }: { attachedMessageId: string }) => { const timeout = setTimeout(() => { setIsVisible(false); document.body.style.pointerEvents = "auto"; - localStorage.setItem(attachedMessageId, "RAIN"); + localStorage.setItem(messageId, "RAIN"); }, 3000); // Clear the timeout if the component unmounts return () => clearTimeout(timeout); - }, [attachedMessageId]); + }, [messageId]); return isVisible ? (
diff --git a/src/component-library/components/ScreenEffects/SnowEffect.tsx b/src/component-library/components/ScreenEffects/SnowEffect.tsx index e7ae9199..5db713f1 100644 --- a/src/component-library/components/ScreenEffects/SnowEffect.tsx +++ b/src/component-library/components/ScreenEffects/SnowEffect.tsx @@ -8,7 +8,7 @@ interface snowflakeStyles { animationDelay: string; } -const SnowEffect = ({ attachedMessageId }: { attachedMessageId: string }) => { +const SnowEffect = ({ messageId }: { messageId: string }) => { const [snowflakes, setSnowflakes] = useState([]); const [isVisible, setIsVisible] = useState(true); @@ -29,12 +29,12 @@ const SnowEffect = ({ attachedMessageId }: { attachedMessageId: string }) => { const timeout = setTimeout(() => { setIsVisible(false); document.body.style.pointerEvents = "auto"; - localStorage.setItem(attachedMessageId, "SNOW"); + localStorage.setItem(messageId, "SNOW"); }, 3000); // // Clear the timeout if the component unmounts return () => clearTimeout(timeout); - }, [attachedMessageId]); + }, [messageId]); return isVisible ? (
diff --git a/src/controllers/FullConversationController.tsx b/src/controllers/FullConversationController.tsx index 20a5af7a..85bfe5b5 100644 --- a/src/controllers/FullConversationController.tsx +++ b/src/controllers/FullConversationController.tsx @@ -16,6 +16,7 @@ import { isMessageSupported } from "../helpers/isMessagerSupported"; import { updateConversationIdentity } from "../helpers/conversation"; import SnowEffect from "../component-library/components/ScreenEffects/SnowEffect"; import RainEffect from "../component-library/components/ScreenEffects/RainEffect"; +import { useXmtpStore } from "../store/xmtp"; type FullConversationControllerProps = { conversation: CachedConversation; @@ -26,9 +27,10 @@ export const FullConversationController: React.FC< > = ({ conversation }) => { const lastMessageDateRef = useRef(); const renderedDatesRef = useRef([]); - const [effect, setEffect] = useState<"snow" | "rain" | undefined>(undefined); + const [effect, setEffect] = useState<"SNOW" | "RAIN" | undefined>(undefined); const { db } = useDb(); - const [attachedMessageId, setAttachedMessageId] = useState(""); + const [messageId, setMessageId] = useState(""); + const conversationTopic = useXmtpStore((s) => s.conversationTopic); useEffect(() => { void updateConversationIdentity(conversation, db); @@ -45,16 +47,23 @@ export const FullConversationController: React.FC< // if the message content type is not support and has no fallback, // disregard it - if (msg.content?.effectType === "SNOW") { - if (!localStorage.getItem(msg.content?.messageId)) { - setEffect("snow"); - setAttachedMessageId(msg.content.messageId); + // In this component so it takes up the entirety of the conversation view + if ( + msg.content?.effectType === "SNOW" && + msg.conversationTopic === conversationTopic + ) { + if (!localStorage.getItem(String(msg.id))) { + setEffect("SNOW"); + setMessageId(String(msg.id)); } } - if (msg.content?.effectType === "RAIN") { - if (!localStorage.getItem(msg.content?.messageId)) { - setEffect("rain"); - setAttachedMessageId(msg.content.messageId); + if ( + msg.content?.effectType === "RAIN" && + msg.conversationTopic === conversationTopic + ) { + if (!localStorage.getItem(String(msg.id))) { + setEffect("RAIN"); + setMessageId(String(msg.id)); } } @@ -87,7 +96,7 @@ export const FullConversationController: React.FC< lastMessageDateRef.current = msg.sentAt; return msg?.content?.effectType || !msg.content ? null : messageDiv; }), - [messages, conversation], + [messages, conversation, conversationTopic], ); return ( @@ -96,16 +105,10 @@ export const FullConversationController: React.FC< // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex tabIndex={0} className="w-full h-full flex flex-col overflow-auto relative"> - {effect === "snow" ? ( - - ) : effect === "rain" ? ( - + {effect === "SNOW" ? ( + + ) : effect === "RAIN" ? ( + ) : null}
diff --git a/src/controllers/MessageInputController.tsx b/src/controllers/MessageInputController.tsx index 8fa12813..11729372 100644 --- a/src/controllers/MessageInputController.tsx +++ b/src/controllers/MessageInputController.tsx @@ -27,7 +27,7 @@ export const MessageInputController = ({ const activeMessage = useXmtpStore((s) => s.activeMessage); const { startConversation } = useStartConversation(); - const { sendMessage, messageId } = useSendMessage( + const { sendMessage } = useSendMessage( attachment || undefined, activeMessage, ); @@ -38,7 +38,6 @@ export const MessageInputController = ({ isDisabled={!recipientOnNetwork} startConversation={startConversation} sendMessage={sendMessage} - associatedMessageId={messageId} conversation={conversation} attachment={attachment} setAttachment={setAttachment} diff --git a/src/controllers/MessagePreviewCardController.tsx b/src/controllers/MessagePreviewCardController.tsx index 488680d6..60b24c80 100644 --- a/src/controllers/MessagePreviewCardController.tsx +++ b/src/controllers/MessagePreviewCardController.tsx @@ -14,6 +14,7 @@ import { } from "@xmtp/content-type-remote-attachment"; import type { Reaction } from "@xmtp/content-type-reaction"; import { ContentTypeReaction } from "@xmtp/content-type-reaction"; +import { ContentTypeScreenEffect } from "@xmtp/experimental-content-type-screen-effect"; import { MessagePreviewCard } from "../component-library/components/MessagePreviewCard/MessagePreviewCard"; import type { ETHAddress } from "../helpers"; import { shortAddress } from "../helpers"; @@ -90,6 +91,10 @@ export const MessagePreviewCardController = ({ lastMessage.contentType, ); + if (ContentTypeScreenEffect.sameAs(previewContentType)) { + return undefined; + } + if (ContentTypeReply.sameAs(previewContentType)) { const reply = lastMessage.content as Reply; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment diff --git a/src/hooks/useSendMessage.ts b/src/hooks/useSendMessage.ts index b00819da..fef63a22 100644 --- a/src/hooks/useSendMessage.ts +++ b/src/hooks/useSendMessage.ts @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react"; +import { useCallback } from "react"; import type { CachedConversation, CachedMessageWithId } from "@xmtp/react-sdk"; import { ContentTypeText, @@ -25,7 +25,6 @@ const useSendMessage = ( ) => { const { sendMessage: _sendMessage, isLoading, error } = _useSendMessage(); const recipientOnNetwork = useXmtpStore((s) => s.recipientOnNetwork); - const [messageId, setMessageId] = useState(""); const sendMessage = useCallback( async ( @@ -93,8 +92,7 @@ const useSendMessage = ( ContentTypeReply, ); } else { - const messageResponse = await _sendMessage(conversation, message); - setMessageId(messageResponse?.id ?? ""); + await _sendMessage(conversation, message); } } }, @@ -103,7 +101,6 @@ const useSendMessage = ( return { sendMessage, - messageId, loading: isLoading, error, };