forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import React, {useEffect, useMemo, useReducer, useRef} from 'react'
2
3import {useCurrentConvoId} from './current-convo-id'
4
5const MessageDraftsContext = React.createContext<{
6 state: State
7 dispatch: React.Dispatch<Actions>
8} | null>(null)
9MessageDraftsContext.displayName = 'MessageDraftsContext'
10
11function useMessageDraftsContext() {
12 const ctx = React.useContext(MessageDraftsContext)
13 if (!ctx) {
14 throw new Error(
15 'useMessageDrafts must be used within a MessageDraftsContext',
16 )
17 }
18 return ctx
19}
20
21export function useMessageDraft() {
22 const {currentConvoId} = useCurrentConvoId()
23 const {state, dispatch} = useMessageDraftsContext()
24 return useMemo(
25 () => ({
26 getDraft: () => (currentConvoId && state[currentConvoId]) || '',
27 clearDraft: () => {
28 if (currentConvoId) {
29 dispatch({type: 'clear', convoId: currentConvoId})
30 }
31 },
32 }),
33 [state, dispatch, currentConvoId],
34 )
35}
36
37export function useSaveMessageDraft(message: string) {
38 const {currentConvoId} = useCurrentConvoId()
39 const {dispatch} = useMessageDraftsContext()
40 const messageRef = useRef(message)
41 messageRef.current = message
42
43 useEffect(() => {
44 return () => {
45 if (currentConvoId) {
46 dispatch({
47 type: 'set',
48 convoId: currentConvoId,
49 draft: messageRef.current,
50 })
51 }
52 }
53 }, [currentConvoId, dispatch])
54}
55
56type State = {[convoId: string]: string}
57type Actions =
58 | {type: 'set'; convoId: string; draft: string}
59 | {type: 'clear'; convoId: string}
60
61function reducer(state: State, action: Actions): State {
62 switch (action.type) {
63 case 'set':
64 return {...state, [action.convoId]: action.draft}
65 case 'clear':
66 return {...state, [action.convoId]: ''}
67 default:
68 return state
69 }
70}
71
72export function MessageDraftsProvider({children}: {children: React.ReactNode}) {
73 const [state, dispatch] = useReducer(reducer, {})
74
75 const ctx = useMemo(() => {
76 return {state, dispatch}
77 }, [state])
78
79 return (
80 <MessageDraftsContext.Provider value={ctx}>
81 {children}
82 </MessageDraftsContext.Provider>
83 )
84}