diff options
Diffstat (limited to 'src/state/messages')
-rw-r--r-- | src/state/messages/index.tsx | 5 | ||||
-rw-r--r-- | src/state/messages/message-drafts.tsx | 83 |
2 files changed, 87 insertions, 1 deletions
diff --git a/src/state/messages/index.tsx b/src/state/messages/index.tsx index 205d17e8c..04ace8d60 100644 --- a/src/state/messages/index.tsx +++ b/src/state/messages/index.tsx @@ -2,11 +2,14 @@ import React from 'react' import {CurrentConvoIdProvider} from '#/state/messages/current-convo-id' import {MessagesEventBusProvider} from '#/state/messages/events' +import {MessageDraftsProvider} from './message-drafts' export function MessagesProvider({children}: {children: React.ReactNode}) { return ( <CurrentConvoIdProvider> - <MessagesEventBusProvider>{children}</MessagesEventBusProvider> + <MessageDraftsProvider> + <MessagesEventBusProvider>{children}</MessagesEventBusProvider> + </MessageDraftsProvider> </CurrentConvoIdProvider> ) } diff --git a/src/state/messages/message-drafts.tsx b/src/state/messages/message-drafts.tsx new file mode 100644 index 000000000..132e85967 --- /dev/null +++ b/src/state/messages/message-drafts.tsx @@ -0,0 +1,83 @@ +import React, {useEffect, useMemo, useReducer, useRef} from 'react' + +import {useCurrentConvoId} from './current-convo-id' + +const MessageDraftsContext = React.createContext<{ + state: State + dispatch: React.Dispatch<Actions> +} | null>(null) + +function useMessageDraftsContext() { + const ctx = React.useContext(MessageDraftsContext) + if (!ctx) { + throw new Error( + 'useMessageDrafts must be used within a MessageDraftsContext', + ) + } + return ctx +} + +export function useMessageDraft() { + const {currentConvoId} = useCurrentConvoId() + const {state, dispatch} = useMessageDraftsContext() + return useMemo( + () => ({ + getDraft: () => (currentConvoId && state[currentConvoId]) || '', + clearDraft: () => { + if (currentConvoId) { + dispatch({type: 'clear', convoId: currentConvoId}) + } + }, + }), + [state, dispatch, currentConvoId], + ) +} + +export function useSaveMessageDraft(message: string) { + const {currentConvoId} = useCurrentConvoId() + const {dispatch} = useMessageDraftsContext() + const messageRef = useRef(message) + messageRef.current = message + + useEffect(() => { + return () => { + if (currentConvoId) { + dispatch({ + type: 'set', + convoId: currentConvoId, + draft: messageRef.current, + }) + } + } + }, [currentConvoId, dispatch]) +} + +type State = {[convoId: string]: string} +type Actions = + | {type: 'set'; convoId: string; draft: string} + | {type: 'clear'; convoId: string} + +function reducer(state: State, action: Actions): State { + switch (action.type) { + case 'set': + return {...state, [action.convoId]: action.draft} + case 'clear': + return {...state, [action.convoId]: ''} + default: + return state + } +} + +export function MessageDraftsProvider({children}: {children: React.ReactNode}) { + const [state, dispatch] = useReducer(reducer, {}) + + const ctx = useMemo(() => { + return {state, dispatch} + }, [state]) + + return ( + <MessageDraftsContext.Provider value={ctx}> + {children} + </MessageDraftsContext.Provider> + ) +} |