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