forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 createContext,
3 useCallback,
4 useContext,
5 useEffect,
6 useState,
7} from 'react'
8
9import * as persisted from '#/state/persisted'
10import {useAgent, useSession} from '../session'
11
12type StateContext = Map<string, boolean>
13type SetStateContext = (uri: string, value: boolean) => void
14
15const stateContext = createContext<StateContext>(new Map())
16stateContext.displayName = 'ThreadMutesStateContext'
17const setStateContext = createContext<SetStateContext>((_: string) => false)
18setStateContext.displayName = 'ThreadMutesSetStateContext'
19
20export function Provider({children}: React.PropsWithChildren<{}>) {
21 const [state, setState] = useState<StateContext>(() => new Map())
22
23 const setThreadMute = useCallback(
24 (uri: string, value: boolean) => {
25 setState(prev => {
26 const next = new Map(prev)
27 next.set(uri, value)
28 return next
29 })
30 },
31 [setState],
32 )
33
34 useMigrateMutes(setThreadMute)
35
36 return (
37 <stateContext.Provider value={state}>
38 <setStateContext.Provider value={setThreadMute}>
39 {children}
40 </setStateContext.Provider>
41 </stateContext.Provider>
42 )
43}
44
45export function useMutedThreads() {
46 return useContext(stateContext)
47}
48
49export function useIsThreadMuted(uri: string, defaultValue = false) {
50 const state = useContext(stateContext)
51 return state.get(uri) ?? defaultValue
52}
53
54export function useSetThreadMute() {
55 return useContext(setStateContext)
56}
57
58function useMigrateMutes(setThreadMute: SetStateContext) {
59 const agent = useAgent()
60 const {currentAccount} = useSession()
61
62 useEffect(() => {
63 if (currentAccount) {
64 if (
65 !persisted
66 .get('mutedThreads')
67 .some(uri => uri.includes(currentAccount.did))
68 ) {
69 return
70 }
71
72 let cancelled = false
73
74 const migrate = async () => {
75 while (!cancelled) {
76 const threads = persisted.get('mutedThreads')
77
78 // @ts-ignore findLast is polyfilled - esb
79 const root = threads.findLast(uri => uri.includes(currentAccount.did))
80
81 if (!root) break
82
83 persisted.write(
84 'mutedThreads',
85 threads.filter(uri => uri !== root),
86 )
87
88 setThreadMute(root, true)
89
90 await agent.api.app.bsky.graph
91 .muteThread({root})
92 // not a big deal if this fails, since the post might have been deleted
93 .catch(console.error)
94 }
95 }
96
97 migrate()
98
99 return () => {
100 cancelled = true
101 }
102 }
103 }, [agent, currentAccount, setThreadMute])
104}