From be4c1836ab6d6cd5e38836292f71029d939b8701 Mon Sep 17 00:00:00 2001 From: Stef Coenen Date: Wed, 8 Jan 2025 15:27:12 +0100 Subject: [PATCH] Community perf (#513) * Marking as read perf improvements; * Lighten up the MessageComposer; * Less intense markAsRead operations; Improved draft saver/fetcher to be faster and cause less re-renders; * Lint fix --- .../composer/CommunityDirectComposer.tsx | 111 ++++++------- .../Community/Message/composer/DraftSaver.tsx | 74 +++++++++ .../Message/composer/MessageComposer.tsx | 152 ++++++++---------- .../Message/composer/useMessageDraft.ts | 34 ++++ .../Message/item/CommunityMessageItem.tsx | 4 +- .../Community/status/MyProfileStatus.tsx | 2 +- .../community/live/useCommunityWebsocket.ts | 1 + .../hooks/community/useMarkCommunityAsRead.ts | 82 +++++++--- .../Community/CommunityChannelNav.tsx | 1 + .../useWebsocketSubscriber.ts | 2 +- .../src/editor/RichTextEditor.tsx | 6 - 11 files changed, 294 insertions(+), 175 deletions(-) create mode 100644 packages/apps/community-app/src/components/Community/Message/composer/DraftSaver.tsx create mode 100644 packages/apps/community-app/src/components/Community/Message/composer/useMessageDraft.ts diff --git a/packages/apps/community-app/src/components/Community/Message/composer/CommunityDirectComposer.tsx b/packages/apps/community-app/src/components/Community/Message/composer/CommunityDirectComposer.tsx index a1c4f4904..2a7541602 100644 --- a/packages/apps/community-app/src/components/Community/Message/composer/CommunityDirectComposer.tsx +++ b/packages/apps/community-app/src/components/Community/Message/composer/CommunityDirectComposer.tsx @@ -8,16 +8,15 @@ import { LinkOverview, t, trimRichText, - useDebounce, useErrors, useLinkPreviewBuilder, VolatileInputRef, } from '@homebase-id/common-app'; -import { useState, useEffect, FC, useRef, lazy } from 'react'; +import { useState, FC, useRef, lazy, useMemo, useCallback } from 'react'; import { getNewId, isTouchDevice } from '@homebase-id/js-lib/helpers'; import { ChatComposerProps } from '@homebase-id/chat-app/src/components/Chat/Composer/ChatComposer'; -import { HomebaseFile, NewHomebaseFile, NewMediaFile, RichText } from '@homebase-id/js-lib/core'; +import { HomebaseFile, NewMediaFile, RichText } from '@homebase-id/js-lib/core'; import { useChatMessage } from '@homebase-id/chat-app/src/hooks/chat/useChatMessage'; import { Plus, PaperPlane, Times } from '@homebase-id/common-app/icons'; import { LinkPreview } from '@homebase-id/js-lib/media'; @@ -29,8 +28,9 @@ const RichTextEditor = lazy(() => import { EmbeddedMessage } from '@homebase-id/chat-app/src/components/Chat/Detail/EmbeddedMessage'; import { ChatMessage } from '@homebase-id/chat-app/src/providers/ChatProvider'; import { useParams } from 'react-router-dom'; -import { useCommunityMetadata } from '../../../../hooks/community/useCommunityMetadata'; -import { CommunityMetadata, Draft } from '../../../../providers/CommunityMetadataProvider'; +import { DraftSaver } from './DraftSaver'; +import { useCommunity } from '../../../../hooks/community/useCommunity'; +import { useMessageDraft } from './useMessageDraft'; const HUNDRED_MEGA_BYTES = 100 * 1024 * 1024; @@ -43,64 +43,29 @@ export const CommunityDirectComposer: FC = ({ const { odinKey, communityKey } = useParams(); const volatileRef = useRef(null); - const { - single: { data: metadata }, - update: { mutate: updateMetadata }, - } = useCommunityMetadata({ + const { data: community } = useCommunity({ odinId: odinKey, communityId: communityKey, - }); - - const [toSaveMeta, setToSaveMeta] = useState< - HomebaseFile | NewHomebaseFile | undefined - >(); - const drafts = (toSaveMeta || metadata)?.fileMetadata.appData.content.drafts || {}; - const [message, setMessage] = useState( - conversation?.fileMetadata.appData.uniqueId - ? drafts[conversation.fileMetadata.appData.uniqueId]?.message - : undefined - ); - const [files, setFiles] = useState(); - - const instantSave = ( - toSaveMeta: NewHomebaseFile | HomebaseFile - ) => updateMetadata({ metadata: toSaveMeta }); - const debouncedSave = useDebounce(() => toSaveMeta && updateMetadata({ metadata: toSaveMeta }), { - timeoutMillis: 2000, - }); - useEffect(() => { - if (metadata && conversation && conversation?.fileMetadata.appData.uniqueId) { - if (drafts[conversation.fileMetadata.appData.uniqueId]?.message === message) return; - - const newDrafts: Record = { - ...drafts, - [conversation.fileMetadata.appData.uniqueId]: { - message, - updatedAt: new Date().getTime(), - }, - }; + }).fetch; - const newMeta = { - ...metadata, - fileMetadata: { - ...metadata?.fileMetadata, - appData: { - ...metadata?.fileMetadata.appData, - content: { ...metadata?.fileMetadata.appData.content, drafts: newDrafts }, - }, - }, - }; + const [message, setMessage] = useState(undefined); + const [files, setFiles] = useState(); - if (message === undefined) { - instantSave(newMeta); - return; - } - setToSaveMeta(newMeta); - debouncedSave(); - } - }, [conversation, message, debouncedSave]); + const draft = useMessageDraft( + !message + ? { + community, + draftKey: conversation?.fileMetadata.appData.uniqueId, + } + : undefined + ); - const plainMessage = message && getTextRootsRecursive(message).join(' '); + const plainMessage = useMemo( + () => + ((message || draft?.message) && getTextRootsRecursive(message || draft?.message).join(' ')) || + '', + [message, draft] + ); const { linkPreviews, setLinkPreviews } = useLinkPreviewBuilder(plainMessage || ''); const addError = useErrors().add; @@ -108,6 +73,8 @@ export const CommunityDirectComposer: FC = ({ const conversationContent = conversation?.fileMetadata.appData.content; const doSend = async () => { + const toSendMessage = message || draft?.message; + const trimmedVal = plainMessage?.trim(); const replyId = replyMsg?.fileMetadata.appData.uniqueId; const newFiles = [...(files || [])]; @@ -120,7 +87,7 @@ export const CommunityDirectComposer: FC = ({ return; // Clear internal state and allow excessive senders - setMessage(undefined); + setMessage([]); setFiles([]); volatileRef.current?.clear(); volatileRef.current?.focus(); @@ -129,7 +96,7 @@ export const CommunityDirectComposer: FC = ({ try { await sendMessage({ conversation, - message: trimRichText(message) || '', + message: trimRichText(toSendMessage) || '', replyId: replyId, files: newFiles, chatId: getNewId(), @@ -147,8 +114,26 @@ export const CommunityDirectComposer: FC = ({ } }; + const changeHandler = useCallback( + (newVal: { + target: { + name: string; + value: RichText; + }; + }) => setMessage(newVal.target.value), + [] + ); + + const onSubmit = useMemo(() => (isTouchDevice() ? undefined : doSend), [doSend]); + return ( <> + +
= ({ setMessage(newVal.target.value)} - defaultValue={message} + onChange={changeHandler} + defaultValue={message || draft?.message} autoFocus={!isTouchDevice()} - onSubmit={isTouchDevice() ? undefined : doSend} + onSubmit={onSubmit} placeholder={t('Your message')} ref={volatileRef} > diff --git a/packages/apps/community-app/src/components/Community/Message/composer/DraftSaver.tsx b/packages/apps/community-app/src/components/Community/Message/composer/DraftSaver.tsx new file mode 100644 index 000000000..1c1d70f2b --- /dev/null +++ b/packages/apps/community-app/src/components/Community/Message/composer/DraftSaver.tsx @@ -0,0 +1,74 @@ +import { useDebounce } from '@homebase-id/common-app'; +import { HomebaseFile, RichText, NewHomebaseFile } from '@homebase-id/js-lib/core'; +import { useState, useEffect } from 'react'; +import { useCommunityMetadata } from '../../../../hooks/community/useCommunityMetadata'; +import { CommunityDefinition } from '../../../../providers/CommunityDefinitionProvider'; +import { CommunityMetadata, Draft } from '../../../../providers/CommunityMetadataProvider'; + +export const DraftSaver = ({ + community, + draftKey, + message, +}: { + community: HomebaseFile | undefined; + draftKey: string | undefined; + message: RichText | undefined; +}) => { + const { + single: { data: metadata }, + update: { mutate: updateMetadata }, + } = useCommunityMetadata({ + odinId: community?.fileMetadata.senderOdinId, + communityId: community?.fileMetadata.appData.uniqueId, + }); + + const drafts = metadata?.fileMetadata.appData.content.drafts || {}; + + const [toSaveMeta, setToSaveMeta] = useState< + HomebaseFile | NewHomebaseFile | undefined + >(); + + const debouncedSave = useDebounce( + () => { + toSaveMeta && updateMetadata({ metadata: toSaveMeta }); + }, + { + timeoutMillis: 2000, + } + ); + + useEffect(() => { + if (metadata && draftKey) { + if (drafts[draftKey]?.message === message) return; + + const newDrafts: Record = { + ...drafts, + [draftKey]: { + message, + updatedAt: new Date().getTime(), + }, + }; + + const newMeta: NewHomebaseFile | HomebaseFile = { + ...metadata, + fileMetadata: { + ...metadata?.fileMetadata, + appData: { + ...metadata?.fileMetadata.appData, + content: { ...metadata?.fileMetadata.appData.content, drafts: newDrafts }, + }, + }, + }; + + if (message === undefined || message.length === 0) { + updateMetadata({ metadata: newMeta }); + return; + } else { + setToSaveMeta(newMeta); + debouncedSave(); + } + } + }, [draftKey, message, debouncedSave]); + + return null; +}; diff --git a/packages/apps/community-app/src/components/Community/Message/composer/MessageComposer.tsx b/packages/apps/community-app/src/components/Community/Message/composer/MessageComposer.tsx index 679691a7f..81d0ec9ea 100644 --- a/packages/apps/community-app/src/components/Community/Message/composer/MessageComposer.tsx +++ b/packages/apps/community-app/src/components/Community/Message/composer/MessageComposer.tsx @@ -13,23 +13,22 @@ import { useAllContacts, findMentionedInRichText, trimRichText, - useDebounce, } from '@homebase-id/common-app'; import { PaperPlane, Plus } from '@homebase-id/common-app/icons'; -import { HomebaseFile, NewHomebaseFile, NewMediaFile, RichText } from '@homebase-id/js-lib/core'; +import { HomebaseFile, NewMediaFile, RichText } from '@homebase-id/js-lib/core'; -import { useState, useEffect, useRef, useMemo, lazy, Suspense } from 'react'; +import { useState, useRef, useMemo, lazy, Suspense, useCallback } from 'react'; import { getNewId, isTouchDevice } from '@homebase-id/js-lib/helpers'; import { LinkPreview } from '@homebase-id/js-lib/media'; import { useCommunityMessage } from '../../../../hooks/community/messages/useCommunityMessage'; -import { useCommunityMetadata } from '../../../../hooks/community/useCommunityMetadata'; import { CommunityDefinition } from '../../../../providers/CommunityDefinitionProvider'; import { CommunityMessage } from '../../../../providers/CommunityMessageProvider'; -import { CommunityMetadata, Draft } from '../../../../providers/CommunityMetadataProvider'; import { CommunityChannel } from '../../../../providers/CommunityProvider'; import { ChannelPlugin } from '../RTEChannelDropdown/RTEChannelDropdownPlugin'; import { Mentionable } from '@homebase-id/rich-text-editor/src/components/plate-ui/mention-input-element'; +import { useMessageDraft } from './useMessageDraft'; +import { DraftSaver } from './DraftSaver'; const RichTextEditor = lazy(() => import('@homebase-id/rich-text-editor').then((rootExport) => ({ @@ -55,91 +54,41 @@ export const MessageComposer = ({ onKeyDown?: (e: React.KeyboardEvent) => void; className?: string; }) => { - const threadId = thread?.fileMetadata.globalTransitId; const volatileRef = useRef(null); - const { - single: { data: metadata }, - update: { mutate: updateMetadata }, - } = useCommunityMetadata({ - odinId: community?.fileMetadata.senderOdinId, - communityId: community?.fileMetadata.appData.uniqueId, - }); - - const [toSaveMeta, setToSaveMeta] = useState< - HomebaseFile | NewHomebaseFile | undefined - >(); - const drafts = (toSaveMeta || metadata)?.fileMetadata.appData.content.drafts || {}; - const [message, setMessage] = useState( - threadId || (channel && channel.fileMetadata.appData.uniqueId) - ? drafts[(threadId || channel?.fileMetadata.appData.uniqueId) as string]?.message - : undefined - ); - + const [message, setMessage] = useState(undefined); const [files, setFiles] = useState(); - - const instantSave = ( - toSaveMeta: NewHomebaseFile | HomebaseFile - ) => updateMetadata({ metadata: toSaveMeta }); - const debouncedSave = useDebounce(() => toSaveMeta && updateMetadata({ metadata: toSaveMeta }), { - timeoutMillis: 2000, - }); - useEffect(() => { - if (metadata && (threadId || (channel && channel.fileMetadata.appData.uniqueId))) { - if ( - drafts[threadId || ((channel && channel.fileMetadata.appData.uniqueId) as string)] - ?.message === message - ) - return; - - const newDrafts: Record = { - ...drafts, - [threadId || ((channel && channel.fileMetadata.appData.uniqueId) as string)]: { - message, - updatedAt: new Date().getTime(), - }, - }; - - const newMeta: NewHomebaseFile | HomebaseFile = { - ...metadata, - fileMetadata: { - ...metadata?.fileMetadata, - appData: { - ...metadata?.fileMetadata.appData, - content: { ...metadata?.fileMetadata.appData.content, drafts: newDrafts }, - }, - }, - }; - - if (message === undefined) { - instantSave(newMeta); - return; - } - setToSaveMeta(newMeta); - debouncedSave(); - } - }, [threadId, channel, message, debouncedSave]); - const { linkPreviews, setLinkPreviews } = useLinkPreviewBuilder( (message && getTextRootsRecursive(message)?.join(' ')) || '' ); + const draft = useMessageDraft( + !message + ? { + community, + draftKey: thread?.fileMetadata.globalTransitId || channel?.fileMetadata.appData.uniqueId, + } + : undefined + ); + const addError = useErrors().add; const { mutateAsync: sendMessage } = useCommunityMessage().send; - const doSend = async () => { - const plainVal = (message && getTextRootsRecursive(message).join(' ')) || ''; + const doSend = useCallback(async () => { + const toSendMessage = message || draft?.message; + + const plainVal = (toSendMessage && getTextRootsRecursive(toSendMessage).join(' ')) || ''; const newFiles = [...(files || [])]; - if (((!message || !plainVal) && !files?.length) || !community || !channel) return; + if (((!toSendMessage || !plainVal) && !files?.length) || !community || !channel) return; // Clear internal state and allow excessive senders - setMessage(undefined); + setMessage([]); setFiles([]); volatileRef.current?.clear(); volatileRef.current?.focus(); - const mentionedOdinIds = findMentionedInRichText(message); + const mentionedOdinIds = findMentionedInRichText(toSendMessage); const extendedParticipants = mentionedOdinIds.includes('@channel') ? community.fileMetadata.appData.content.members : Array.from(new Set(threadParticipants?.concat(mentionedOdinIds) || mentionedOdinIds)); @@ -150,7 +99,7 @@ export const MessageComposer = ({ channel, thread, threadParticipants: extendedParticipants, - message: trimRichText(message), + message: trimRichText(toSendMessage), files: newFiles, chatId: getNewId(), userDate: new Date().getTime(), @@ -164,7 +113,18 @@ export const MessageComposer = ({ t('Your message "{0}" was not sent', ellipsisAtMaxChar(plainVal || '', 20) || '') ); } - }; + }, [ + addError, + channel, + community, + files, + linkPreviews, + message, + onSend, + sendMessage, + thread, + threadParticipants, + ]); const { data: contacts } = useAllContacts(true); const mentionables: Mentionable[] = useMemo(() => { @@ -201,16 +161,41 @@ export const MessageComposer = ({ }, [contacts]); const plainMessage = useMemo( - () => (message && getTextRootsRecursive(message).join(' ')) || '', - [message] + () => + ((message || draft?.message) && getTextRootsRecursive(message || draft?.message).join(' ')) || + '', + [message, draft] ); + const changeHandler = useCallback( + (newVal: { + target: { + name: string; + value: RichText; + }; + }) => setMessage(newVal.target.value), + [] + ); + + const plugins = useMemo(() => { + return [ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ChannelPlugin.configure({ options: { insertSpaceAfterChannel: true } } as any), + ]; + }, []); + + const onSubmit = useMemo(() => (isTouchDevice() ? undefined : doSend), [doSend]); + return ( <> +
{ const mediaFiles = [...getImagesFromPasteEvent(e)].map((file) => ({ file })); @@ -228,10 +213,10 @@ export const MessageComposer = ({ setMessage(newVal.target.value)} - defaultValue={message} + onChange={changeHandler} + defaultValue={message || draft?.message} placeholder={ - threadId + thread ? t(`Reply...`) : channel?.fileMetadata.appData.content.title ? `${t('Message')} # ${channel.fileMetadata.appData.content.title}` @@ -239,14 +224,11 @@ export const MessageComposer = ({ } autoFocus={!isTouchDevice()} ref={volatileRef} - onSubmit={isTouchDevice() ? undefined : doSend} + onSubmit={onSubmit} onKeyDown={onKeyDown} disableHeadings={true} mentionables={mentionables} - plugins={[ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ChannelPlugin.configure({ options: { insertSpaceAfterChannel: true } } as any), - ]} + plugins={plugins} >
diff --git a/packages/apps/community-app/src/components/Community/Message/composer/useMessageDraft.ts b/packages/apps/community-app/src/components/Community/Message/composer/useMessageDraft.ts new file mode 100644 index 000000000..f6af2436e --- /dev/null +++ b/packages/apps/community-app/src/components/Community/Message/composer/useMessageDraft.ts @@ -0,0 +1,34 @@ +import { HomebaseFile } from '@homebase-id/js-lib/core'; +import { useState, useEffect } from 'react'; +import { useCommunityMetadata } from '../../../../hooks/community/useCommunityMetadata'; +import { CommunityDefinition } from '../../../../providers/CommunityDefinitionProvider'; +import { Draft } from '../../../../providers/CommunityMetadataProvider'; + +export const useMessageDraft = (props?: { + community: HomebaseFile | undefined; + draftKey: string | undefined; +}) => { + const { community, draftKey } = props || {}; + + const { + single: { data: metadata }, + } = useCommunityMetadata( + props + ? { + odinId: community?.fileMetadata.senderOdinId, + communityId: community?.fileMetadata.appData.uniqueId, + } + : undefined + ); + + const [draft, setDraft] = useState(undefined); + + const drafts = metadata?.fileMetadata.appData.content.drafts || {}; + useEffect(() => { + if (!draftKey || !metadata || draft) return; + + setDraft(draftKey ? drafts[draftKey] : undefined); + }, [draftKey, metadata]); + + return draft || (draftKey && drafts[draftKey]) || undefined; +}; diff --git a/packages/apps/community-app/src/components/Community/Message/item/CommunityMessageItem.tsx b/packages/apps/community-app/src/components/Community/Message/item/CommunityMessageItem.tsx index 833f96566..dee048785 100644 --- a/packages/apps/community-app/src/components/Community/Message/item/CommunityMessageItem.tsx +++ b/packages/apps/community-app/src/components/Community/Message/item/CommunityMessageItem.tsx @@ -321,8 +321,10 @@ const MessageTextRenderer = ({ const { type, attributes } = element; if (type === 'p' || type === 'paragraph') { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { text, ...renderableAttributes } = attributes || {}; return ( -

+

{children}

); diff --git a/packages/apps/community-app/src/components/Community/status/MyProfileStatus.tsx b/packages/apps/community-app/src/components/Community/status/MyProfileStatus.tsx index e908b48ed..c94ffc4e0 100644 --- a/packages/apps/community-app/src/components/Community/status/MyProfileStatus.tsx +++ b/packages/apps/community-app/src/components/Community/status/MyProfileStatus.tsx @@ -18,7 +18,7 @@ import { useCommunity } from '../../../hooks/community/useCommunity'; import { useParams } from 'react-router-dom'; import { HomebaseFile } from '@homebase-id/js-lib/core'; import { CommunityDefinition } from '../../../providers/CommunityDefinitionProvider'; -import { CommunityStatus, setStatus } from '../../../providers/CommunityStatusProvider'; +import { CommunityStatus } from '../../../providers/CommunityStatusProvider'; export const MyProfileStatus = ({ className }: { className?: string }) => { const { odinKey, communityKey } = useParams(); diff --git a/packages/apps/community-app/src/hooks/community/live/useCommunityWebsocket.ts b/packages/apps/community-app/src/hooks/community/live/useCommunityWebsocket.ts index e5731584e..5ca66ae29 100644 --- a/packages/apps/community-app/src/hooks/community/live/useCommunityWebsocket.ts +++ b/packages/apps/community-app/src/hooks/community/live/useCommunityWebsocket.ts @@ -57,6 +57,7 @@ export const useCommunityWebsocket = ( console.warn('[CommunityWebsocket] Invalid community metadata received', notification); return; } + // console.log('new community metadata', communityMetadata); insertNewcommunityMetadata(queryClient, communityMetadata); } } diff --git a/packages/apps/community-app/src/hooks/community/useMarkCommunityAsRead.ts b/packages/apps/community-app/src/hooks/community/useMarkCommunityAsRead.ts index 73713641e..1c6a3ed32 100644 --- a/packages/apps/community-app/src/hooks/community/useMarkCommunityAsRead.ts +++ b/packages/apps/community-app/src/hooks/community/useMarkCommunityAsRead.ts @@ -1,7 +1,10 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useCommunityMetadata } from './useCommunityMetadata'; import { useLastUpdatedChatMessages } from './messages/useCommunityMessages'; import { useLastUpdatedThreadExcludingMine } from './threads/useCommunityThreads'; +import { useCommunityChannelsWithRecentMessages } from './channels/useCommunityChannelsWithRecentMessages'; +import { stringGuidsEqual } from '@homebase-id/js-lib/helpers'; +import { useDotYouClientContext } from '@homebase-id/common-app'; interface MarkCommunityChannelAsReadProps { odinId: string | undefined; @@ -22,6 +25,19 @@ export const useMarkCommunityAsRead = ({ }: MarkCommunityChannelAsReadProps | MarkCommunityThreadsAsReadProps) => { const channelId = (props as MarkCommunityChannelAsReadProps).channelId; const threads = (props as MarkCommunityThreadsAsReadProps).threads; + const loggedInIdentity = useDotYouClientContext().getLoggedInIdentity(); + + const { data: channelsWithRecent } = useCommunityChannelsWithRecentMessages({ + odinId, + communityId, + }).fetch; + const matchedChannel = useMemo( + () => + channelsWithRecent?.find((channel) => + stringGuidsEqual(channel.fileMetadata.appData.uniqueId, channelId) + ), + [channelsWithRecent, channelId] + ); const { single: { data: metadata }, @@ -38,25 +54,45 @@ export const useMarkCommunityAsRead = ({ !lastUpdate || lastUpdate === 0 || updateStatus === 'pending' || - updateStatus === 'error' + updateStatus === 'error' || + (!!channelId && !matchedChannel) ) { return; } - const savedLastReadTime = metadata?.fileMetadata.appData.content.lastReadTime; const savedLastReadTimeChannel = - metadata?.fileMetadata.appData.content.channelLastReadTime[channelId || '']; + channelId && metadata?.fileMetadata.appData.content.channelLastReadTime[channelId]; + const channelReadIsUpToDate = + !matchedChannel?.lastMessage || + matchedChannel?.lastMessage.fileMetadata.originalAuthor === loggedInIdentity || + (savedLastReadTimeChannel && + savedLastReadTimeChannel >= matchedChannel.lastMessage.fileMetadata.created); - if ( - savedLastReadTime && - savedLastReadTime >= lastUpdate && - (!channelId || (savedLastReadTimeChannel && savedLastReadTimeChannel >= lastUpdate)) && - (!lastUpdatedThreads || - lastUpdatedThreads <= metadata?.fileMetadata.appData.content.threadsLastReadTime) - ) { + const threadsReadIsUpToDate = + !lastUpdatedThreads || + lastUpdatedThreads <= metadata?.fileMetadata.appData.content.threadsLastReadTime; + + if (channelReadIsUpToDate && threadsReadIsUpToDate) { return; } + // console.log('marking as read', { + // current: metadata.fileMetadata.appData.content, + // new: { + // ...metadata.fileMetadata.appData.content, + // lastReadTime: lastUpdate, + // threadsLastReadTime: + // lastUpdatedThreads || metadata.fileMetadata.appData.content.threadsLastReadTime || 0, + // channelLastReadTime: + // matchedChannel && matchedChannel.lastMessage + // ? { + // ...metadata.fileMetadata.appData.content.channelLastReadTime, + // [matchedChannel.fileMetadata.appData.uniqueId as string]: + // matchedChannel.lastMessage.fileMetadata.created, + // } + // : metadata.fileMetadata.appData.content.channelLastReadTime, + // }, + // }); updateMetadata({ metadata: { ...metadata, @@ -72,16 +108,26 @@ export const useMarkCommunityAsRead = ({ lastUpdatedThreads || metadata.fileMetadata.appData.content.threadsLastReadTime || 0, - channelLastReadTime: channelId - ? { - ...metadata.fileMetadata.appData.content.channelLastReadTime, - [channelId || '']: lastUpdate, - } - : metadata.fileMetadata.appData.content.channelLastReadTime, + channelLastReadTime: + matchedChannel && matchedChannel.lastMessage + ? { + ...metadata.fileMetadata.appData.content.channelLastReadTime, + [matchedChannel.fileMetadata.appData.uniqueId as string]: + matchedChannel.lastMessage.fileMetadata.created, + } + : metadata.fileMetadata.appData.content.channelLastReadTime, }, }, }, }, }); - }, [updateStatus, metadata, communityId, channelId, lastUpdate, lastUpdatedThreads]); + }, [ + updateStatus, + metadata, + communityId, + channelId, + lastUpdate, + lastUpdatedThreads, + matchedChannel, + ]); }; diff --git a/packages/apps/community-app/src/templates/Community/CommunityChannelNav.tsx b/packages/apps/community-app/src/templates/Community/CommunityChannelNav.tsx index e2ffa2eaa..3b808d334 100644 --- a/packages/apps/community-app/src/templates/Community/CommunityChannelNav.tsx +++ b/packages/apps/community-app/src/templates/Community/CommunityChannelNav.tsx @@ -357,6 +357,7 @@ const ChannelItem = ({ ...metadata, }; newMeta.fileMetadata.appData.content.pinnedChannels = newPins; + // console.log('pinning'); updateMetadata({ metadata: newMeta }); }} > diff --git a/packages/common/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts b/packages/common/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts index df6a51848..a2d052485 100644 --- a/packages/common/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts +++ b/packages/common/common-app/src/hooks/transitProcessor/useWebsocketSubscriber.ts @@ -122,7 +122,7 @@ export const useWebsocketSubscriber = ( } } }; - }, [localHandler]); + }, [localHandler, setIsConected]); return isConnected; }; diff --git a/packages/common/rich-text-editor/src/editor/RichTextEditor.tsx b/packages/common/rich-text-editor/src/editor/RichTextEditor.tsx index 35cff1c09..3c6d0f0d9 100644 --- a/packages/common/rich-text-editor/src/editor/RichTextEditor.tsx +++ b/packages/common/rich-text-editor/src/editor/RichTextEditor.tsx @@ -393,12 +393,6 @@ const InnerRichTextEditor = memo( className={`relative flex w-[100%] flex-col ${className ?? ''} [&_.slate-selected]:!bg-primary/20 [&_.slate-selection-area]:border [&_.slate-selection-area]:bg-primary/10`} onSubmit={(e) => e.stopPropagation()} onClick={disabled ? undefined : (e) => e.stopPropagation()} - // onPaste={(e) => { - // e.preventDefault(); - // const text = e.clipboardData.getData('text'); - // console.log('pure text', text); - // editor?.insertText(text); - // }} >