forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 💫
1import React from 'react'
2import {View} from 'react-native'
3import {AppBskyGraphDefs} from '@atproto/api'
4import {msg, Trans} from '@lingui/macro'
5import {useLingui} from '@lingui/react'
6import {useQueryClient} from '@tanstack/react-query'
7
8import {useGoBack} from '#/lib/hooks/useGoBack'
9import {sanitizeHandle} from '#/lib/strings/handles'
10import {logger} from '#/logger'
11import {RQKEY_ROOT as listQueryRoot} from '#/state/queries/list'
12import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list'
13import {
14 type UsePreferencesQueryResponse,
15 useRemoveFeedMutation,
16} from '#/state/queries/preferences'
17import {useSession} from '#/state/session'
18import * as Toast from '#/view/com/util/Toast'
19import {CenteredView} from '#/view/com/util/Views'
20import {atoms as a, useBreakpoints, useTheme} from '#/alf'
21import {Button, ButtonIcon, ButtonText} from '#/components/Button'
22import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
23import {Loader} from '#/components/Loader'
24import {useHider} from '#/components/moderation/Hider'
25import {Text} from '#/components/Typography'
26
27export function ListHiddenScreen({
28 list,
29 preferences,
30}: {
31 list: AppBskyGraphDefs.ListView
32 preferences: UsePreferencesQueryResponse
33}) {
34 const {_} = useLingui()
35 const t = useTheme()
36 const {currentAccount} = useSession()
37 const {gtMobile} = useBreakpoints()
38 const isOwner = currentAccount?.did === list.creator.did
39 const goBack = useGoBack()
40 const queryClient = useQueryClient()
41
42 const isModList = list.purpose === AppBskyGraphDefs.MODLIST
43
44 const [isProcessing, setIsProcessing] = React.useState(false)
45 const listBlockMutation = useListBlockMutation()
46 const listMuteMutation = useListMuteMutation()
47 const {mutateAsync: removeSavedFeed} = useRemoveFeedMutation()
48
49 const {setIsContentVisible} = useHider()
50
51 const savedFeedConfig = preferences.savedFeeds.find(f => f.value === list.uri)
52
53 const onUnsubscribe = async () => {
54 setIsProcessing(true)
55 if (list.viewer?.muted) {
56 try {
57 await listMuteMutation.mutateAsync({uri: list.uri, mute: false})
58 } catch (e) {
59 setIsProcessing(false)
60 logger.error('Failed to unmute list', {message: e})
61 Toast.show(
62 _(
63 msg`There was an issue. Please check your internet connection and try again.`,
64 ),
65 )
66 return
67 }
68 }
69 if (list.viewer?.blocked) {
70 try {
71 await listBlockMutation.mutateAsync({uri: list.uri, block: false})
72 } catch (e) {
73 setIsProcessing(false)
74 logger.error('Failed to unblock list', {message: e})
75 Toast.show(
76 _(
77 msg`There was an issue. Please check your internet connection and try again.`,
78 ),
79 )
80 return
81 }
82 }
83 queryClient.invalidateQueries({
84 queryKey: [listQueryRoot],
85 })
86 Toast.show(_(msg`Unsubscribed from list`))
87 setIsProcessing(false)
88 }
89
90 const onRemoveList = async () => {
91 if (!savedFeedConfig) return
92 try {
93 await removeSavedFeed(savedFeedConfig)
94 Toast.show(_(msg`Removed from saved feeds`))
95 } catch (e) {
96 logger.error('Failed to remove list from saved feeds', {message: e})
97 Toast.show(
98 _(
99 msg`There was an issue. Please check your internet connection and try again.`,
100 ),
101 )
102 } finally {
103 setIsProcessing(false)
104 }
105 }
106
107 return (
108 <CenteredView
109 style={[
110 a.flex_1,
111 a.align_center,
112 a.gap_5xl,
113 !gtMobile && a.justify_between,
114 t.atoms.border_contrast_low,
115 {paddingTop: 175, paddingBottom: 110},
116 ]}
117 sideBorders={true}>
118 <View style={[a.w_full, a.align_center, a.gap_lg]}>
119 <EyeSlash
120 style={{color: t.atoms.text_contrast_medium.color}}
121 height={42}
122 width={42}
123 />
124 <View style={[a.gap_sm, a.align_center]}>
125 <Text style={[a.font_semi_bold, a.text_3xl]}>
126 {list.creator.viewer?.blocking || list.creator.viewer?.blockedBy ? (
127 <Trans>Creator has been blocked</Trans>
128 ) : (
129 <Trans>List has been hidden</Trans>
130 )}
131 </Text>
132 <Text
133 style={[
134 a.text_md,
135 a.text_center,
136 a.px_md,
137 t.atoms.text_contrast_high,
138 {lineHeight: 1.4},
139 ]}>
140 {list.creator.viewer?.blocking || list.creator.viewer?.blockedBy ? (
141 <Trans>
142 Either the creator of this list has blocked you or you have
143 blocked the creator.
144 </Trans>
145 ) : isOwner ? (
146 <Trans>
147 This list – created by you – contains possible violations of
148 Bluesky's community guidelines in its name or description.
149 </Trans>
150 ) : (
151 <Trans>
152 This list – created by{' '}
153 <Text style={[a.font_semi_bold]}>
154 {sanitizeHandle(list.creator.handle, '@')}
155 </Text>{' '}
156 – contains possible violations of Bluesky's community guidelines
157 in its name or description.
158 </Trans>
159 )}
160 </Text>
161 </View>
162 </View>
163 <View style={[a.gap_md, gtMobile ? {width: 350} : [a.w_full, a.px_lg]]}>
164 <View style={[a.gap_md]}>
165 {savedFeedConfig ? (
166 <Button
167 variant="solid"
168 color="secondary"
169 size="large"
170 label={_(msg`Remove from saved feeds`)}
171 onPress={onRemoveList}
172 disabled={isProcessing}>
173 <ButtonText>
174 <Trans>Remove from saved feeds</Trans>
175 </ButtonText>
176 {isProcessing ? (
177 <ButtonIcon icon={Loader} position="right" />
178 ) : null}
179 </Button>
180 ) : null}
181 {isOwner ? (
182 <Button
183 variant="solid"
184 color="secondary"
185 size="large"
186 label={_(msg`Show list anyway`)}
187 onPress={() => setIsContentVisible(true)}
188 disabled={isProcessing}>
189 <ButtonText>
190 <Trans>Show anyway</Trans>
191 </ButtonText>
192 </Button>
193 ) : list.viewer?.muted || list.viewer?.blocked ? (
194 <Button
195 variant="solid"
196 color="secondary"
197 size="large"
198 label={_(msg`Unsubscribe from list`)}
199 onPress={() => {
200 if (isModList) {
201 onUnsubscribe()
202 } else {
203 onRemoveList()
204 }
205 }}
206 disabled={isProcessing}>
207 <ButtonText>
208 <Trans>Unsubscribe from list</Trans>
209 </ButtonText>
210 {isProcessing ? (
211 <ButtonIcon icon={Loader} position="right" />
212 ) : null}
213 </Button>
214 ) : null}
215 </View>
216 <Button
217 variant="solid"
218 color="primary"
219 label={_(msg`Return to previous page`)}
220 onPress={goBack}
221 size="large"
222 disabled={isProcessing}>
223 <ButtonText>
224 <Trans>Go Back</Trans>
225 </ButtonText>
226 </Button>
227 </View>
228 </CenteredView>
229 )
230}