@@ -6,6 +6,8 @@ import { MessageComposerContext } from './context/MessageComposerContext'
66import { useAuthStore , useChatStore , useStore } from '@stores'
77import { TChannelSettings } from '@types'
88import { toolbarStorage } from './helpers/toolbarStorage'
9+ import { getComposerState , clearComposerState , ComposerState } from '@db/messageComposerDB'
10+ import { SignInDialog } from '@components/ui/dialogs'
911
1012import { EditorContent } from '@tiptap/react'
1113import {
@@ -58,10 +60,11 @@ const MessageComposer = ({
5860 const usersPresence = useStore ( ( state : any ) => state . usersPresence )
5961 const startThreadMessage = useChatStore ( ( state ) => state . startThreadMessage )
6062 const channels = useChatStore ( ( state ) => state . channels )
61- const { workspaceId } = useChatStore ( ( state ) => state . workspaceSettings )
63+ const { workspaceId } = useStore ( ( state ) => state . settings )
6264 const editorRef = useRef < HTMLDivElement | null > ( null )
6365 const [ isToolbarOpen , setIsToolbarOpen ] = useState ( ( ) => toolbarStorage . get ( ) )
6466 const setOrUpdateChatRoom = useChatStore ( ( state ) => state . setOrUpdateChatRoom )
67+ const openDialog = useStore ( ( state ) => state . openDialog )
6568
6669 const setEditMsgMemory = useChatStore ( ( state ) => state . setEditMessageMemory )
6770 const setReplyMsgMemory = useChatStore ( ( state ) => state . setReplyMessageMemory )
@@ -89,7 +92,9 @@ const MessageComposer = ({
8992
9093 const { editor, text, html, isEmojiOnly } = useTiptapEditor ( {
9194 loading,
92- onSubmit : ( ) => submitRef . current ?.( )
95+ onSubmit : ( ) => submitRef . current ?.( ) ,
96+ workspaceId,
97+ channelId
9398 } )
9499
95100 const chatChannels = useChatStore ( ( state ) => state . workspaceSettings . channels )
@@ -117,6 +122,20 @@ const MessageComposer = ({
117122 users . forEach ( ( user ) => user && setOrUpdateUserPresence ( user . id , user ) )
118123 } , [ replyMessageMemory , editMessageMemory , usersPresence , setOrUpdateUserPresence ] )
119124
125+ // Load persisted draft from IndexedDB on mount or channel change
126+ useEffect ( ( ) => {
127+ if ( ! editor || ! workspaceId || ! channelId ) return
128+
129+ // Don't load draft if we're editing/replying/commenting
130+ if ( editMessageMemory || replyMessageMemory || commentMessageMemory ) return
131+
132+ getComposerState ( workspaceId , channelId ) . then ( ( draft : ComposerState | null ) => {
133+ if ( draft ?. html ) {
134+ editor . chain ( ) . setContent ( draft . html ) . focus ( 'end' ) . run ( )
135+ }
136+ } )
137+ } , [ editor , workspaceId , channelId , editMessageMemory , replyMessageMemory , commentMessageMemory ] )
138+
120139 // set the editor content if it is a reply message
121140 useEffect ( ( ) => {
122141 if ( ! editor || ! editMessageMemory || editMessageMemory . channel_id !== channelId ) return
@@ -130,6 +149,8 @@ const MessageComposer = ({
130149 // Validation helpers
131150 const validateSubmission = useCallback ( ( ) => {
132151 if ( ! editor || ! user ) return { isValid : false , error : 'Editor or user not available' }
152+ const html = editor ?. getHTML ( )
153+ const text = editor ?. getText ( )
133154
134155 const isContentEmpty =
135156 ! html || ! text || html . replace ( / < [ ^ > ] * > / g, '' ) . trim ( ) === '' || text . trim ( ) === ''
@@ -138,10 +159,14 @@ const MessageComposer = ({
138159 if ( loading ) return { isValid : false , error : 'Already loading' }
139160
140161 return { isValid : true }
141- } , [ editor , user , html , text , loading ] )
162+ } , [ editor , user , loading ] )
142163
143164 // Content preparation
144165 const prepareContent = useCallback ( ( ) => {
166+ const html = editor ?. getHTML ( )
167+ const text = editor ?. getText ( )
168+ if ( ! html || ! text ) return { sanitizedHtml : '' , sanitizedText : '' , chunks : [ ] }
169+
145170 const { sanitizedHtml, sanitizedText } = sanitizeMessageContent ( html , text )
146171
147172 if ( ! sanitizedHtml || ! sanitizedText ) {
@@ -153,7 +178,7 @@ const MessageComposer = ({
153178 sanitizedText,
154179 chunks : chunkHtmlContent ( sanitizedHtml , 3000 )
155180 }
156- } , [ html , text ] )
181+ } , [ editor ] )
157182
158183 // Message type handlers
159184 const handleThreadMessage = useCallback (
@@ -292,13 +317,21 @@ const MessageComposer = ({
292317 text : null ,
293318 html : null
294319 } )
295- // document.dispatchEvent(new CustomEvent('messages:container:scroll:down'))
320+
321+ // Clear IndexedDB draft
322+ if ( workspaceId && channelId ) {
323+ clearComposerState ( workspaceId , channelId )
324+ }
325+
326+ // Clear editor content
327+ editor ?. chain ( ) . clearContent ( true ) . focus ( 'start' ) . run ( )
296328 } , [
297329 editor ,
298330 replyMessageMemory ,
299331 editMessageMemory ,
300332 commentMessageMemory ,
301333 channelId ,
334+ workspaceId ,
302335 setReplyMsgMemory ,
303336 setEditMsgMemory ,
304337 setCommentMsgMemory ,
@@ -325,23 +358,38 @@ const MessageComposer = ({
325358 [ ]
326359 )
327360
361+ const openSignInModalHandler = useCallback ( ( ) => {
362+ // append search query to the URL, for when they back to the page they will be redirected to the channel
363+ const url = new URL ( window . location . href )
364+ url . searchParams . set ( 'open_heading_chat' , channelId )
365+ window . history . pushState ( { } , '' , url . href )
366+
367+ openDialog ( < SignInDialog /> , { size : 'sm' , dismissible : true } )
368+ } , [ openDialog ] )
369+
328370 // Main submit function - now clean and focused
329371 const submitMessage = useCallback (
330372 async ( e ?: any ) => {
331373 e ?. preventDefault ( )
332374 editor ?. view . focus ( )
333375
376+ // 0. check if user is signed in
377+ if ( ! user ) {
378+ openSignInModalHandler ( )
379+ return
380+ }
381+
334382 // 1. Validate
335383 const validation = validateSubmission ( )
336384 if ( ! validation . isValid ) return
337385
338386 try {
339387 // 2. Prepare content
340388 const { sanitizedHtml, sanitizedText, chunks } = prepareContent ( )
341- const { htmlChunks, textChunks } = chunks
389+ const { htmlChunks, textChunks } = chunks as { htmlChunks : string [ ] ; textChunks : string [ ] }
342390
343- // 3. Update user presence
344- updateUserPresence ( )
391+ // 3. Update user presence // TODO: review this part, we do not need it anymore
392+ // updateUserPresence()
345393
346394 // 4. Send message(s)
347395 if ( htmlChunks . length === 0 ) {
@@ -357,6 +405,7 @@ const MessageComposer = ({
357405 }
358406 } ,
359407 [
408+ user ,
360409 editor ,
361410 validateSubmission ,
362411 prepareContent ,
@@ -372,21 +421,6 @@ const MessageComposer = ({
372421 submitRef . current = ( ) => submitMessage ( )
373422 } , [ submitMessage ] )
374423
375- // Handle Draft Memory
376- useEffect ( ( ) => {
377- return ( ) => {
378- // Save draft before unmounting
379- const html = editor ?. getHTML ( )
380- const text = editor ?. getText ( )
381- if ( html && text ) {
382- setMsgDraftMemory ( channelId , {
383- text : text ,
384- html : html
385- } )
386- }
387- }
388- } , [ editor , channelId , setMsgDraftMemory ] )
389-
390424 useEffect ( ( ) => {
391425 const setAttributes = ( ) => {
392426 const firstChild = editorRef . current ?. firstChild as HTMLElement | null
@@ -429,7 +463,7 @@ const MessageComposer = ({
429463 replyMessageMemory,
430464 editMessageMemory,
431465 commentMessageMemory,
432- messageDraftMemory,
466+ messageDraftMemory : messageDraftMemory ?? null ,
433467 setEditMsgMemory,
434468 setReplyMsgMemory,
435469 setCommentMsgMemory,
0 commit comments