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