forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {View} from 'react-native'
2import {type ModerationCause} from '@atproto/api'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
7import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription'
8import {makeProfileLink} from '#/lib/routes/links'
9import {listUriToHref} from '#/lib/strings/url-helpers'
10import {isNative} from '#/platform/detection'
11import {useSession} from '#/state/session'
12import {atoms as a, useGutters, useTheme} from '#/alf'
13import * as Dialog from '#/components/Dialog'
14import {InlineLinkText} from '#/components/Link'
15import {type AppModerationCause} from '#/components/Pills'
16import {Text} from '#/components/Typography'
17
18export {useDialogControl as useModerationDetailsDialogControl} from '#/components/Dialog'
19
20export interface ModerationDetailsDialogProps {
21 control: Dialog.DialogOuterProps['control']
22 modcause?: ModerationCause | AppModerationCause
23}
24
25export function ModerationDetailsDialog(props: ModerationDetailsDialogProps) {
26 return (
27 <Dialog.Outer
28 control={props.control}
29 nativeOptions={{preventExpansion: true}}>
30 <Dialog.Handle />
31 <ModerationDetailsDialogInner {...props} />
32 </Dialog.Outer>
33 )
34}
35
36function ModerationDetailsDialogInner({
37 modcause,
38 control,
39}: ModerationDetailsDialogProps & {
40 control: Dialog.DialogOuterProps['control']
41}) {
42 const t = useTheme()
43 const xGutters = useGutters([0, 'base'])
44 const {_} = useLingui()
45 const desc = useModerationCauseDescription(modcause)
46 const {currentAccount} = useSession()
47 const timeDiff = useGetTimeAgo({future: true})
48
49 let name
50 let description
51 if (!modcause) {
52 name = _(msg`Content Warning`)
53 description = _(
54 msg`Moderator has chosen to set a general warning on the content.`,
55 )
56 } else if (modcause.type === 'blocking') {
57 if (modcause.source.type === 'list') {
58 const list = modcause.source.list
59 name = _(msg`User Blocked by List`)
60 description = (
61 <Trans>
62 This user is included in the{' '}
63 <InlineLinkText
64 label={list.name}
65 to={listUriToHref(list.uri)}
66 style={[a.text_sm]}>
67 {list.name}
68 </InlineLinkText>{' '}
69 list which you have blocked.
70 </Trans>
71 )
72 } else {
73 name = _(msg`User Blocked`)
74 description = _(
75 msg`You have blocked this user. You cannot view their content.`,
76 )
77 }
78 } else if (modcause.type === 'blocked-by') {
79 name = _(msg`User Blocks You`)
80 description = _(
81 msg`This user has blocked you. You cannot view their content.`,
82 )
83 } else if (modcause.type === 'block-other') {
84 name = _(msg`Content Not Available`)
85 description = _(
86 msg`This content is not available because one of the users involved has blocked the other.`,
87 )
88 } else if (modcause.type === 'muted') {
89 if (modcause.source.type === 'list') {
90 const list = modcause.source.list
91 name = _(msg`Account Muted by List`)
92 description = (
93 <Trans>
94 This user is included in the{' '}
95 <InlineLinkText
96 label={list.name}
97 to={listUriToHref(list.uri)}
98 style={[a.text_sm]}>
99 {list.name}
100 </InlineLinkText>{' '}
101 list which you have muted.
102 </Trans>
103 )
104 } else {
105 name = _(msg`Account Muted`)
106 description = _(msg`You have muted this account.`)
107 }
108 } else if (modcause.type === 'mute-word') {
109 name = _(msg`Skeet Hidden by Muted Word`)
110 description = _(msg`You've chosen to hide a word or tag within this skeet.`)
111 } else if (modcause.type === 'hidden') {
112 name = _(msg`Skeet Hidden by You`)
113 description = _(msg`You have hidden this skeet.`)
114 } else if (modcause.type === 'reply-hidden') {
115 const isYou = currentAccount?.did === modcause.source.did
116 name = isYou
117 ? _(msg`Reply Hidden by You`)
118 : _(msg`Reply Hidden by Thread Author`)
119 description = isYou
120 ? _(msg`You hid this reply.`)
121 : _(msg`The author of this thread has hidden this reply.`)
122 } else if (modcause.type === 'label') {
123 name = desc.name
124 description = (
125 <Text emoji style={[t.atoms.text, a.text_md, a.leading_snug]}>
126 {desc.description}
127 </Text>
128 )
129 } else {
130 // should never happen
131 name = ''
132 description = ''
133 }
134
135 const sourceName =
136 desc.source || desc.sourceDisplayName || _(msg`an unknown labeler`)
137
138 return (
139 <Dialog.ScrollableInner
140 label={_(msg`Moderation details`)}
141 contentContainerStyle={{
142 paddingLeft: 0,
143 paddingRight: 0,
144 paddingBottom: 0,
145 }}>
146 <View style={[xGutters, a.pb_lg]}>
147 <Text emoji style={[t.atoms.text, a.text_2xl, a.font_bold, a.mb_sm]}>
148 {name}
149 </Text>
150 <Text style={[t.atoms.text, a.text_sm, a.leading_snug]}>
151 {description}
152 </Text>
153 </View>
154
155 {modcause?.type === 'label' && (
156 <View
157 style={[
158 xGutters,
159 a.py_md,
160 a.border_t,
161 !isNative && t.atoms.bg_contrast_25,
162 t.atoms.border_contrast_low,
163 {
164 borderBottomLeftRadius: a.rounded_md.borderRadius,
165 borderBottomRightRadius: a.rounded_md.borderRadius,
166 },
167 ]}>
168 {modcause.source.type === 'user' ? (
169 <Text style={[t.atoms.text, a.text_md, a.leading_snug]}>
170 <Trans>This label was applied by the author.</Trans>
171 </Text>
172 ) : (
173 <>
174 <View
175 style={[
176 a.flex_row,
177 a.justify_between,
178 a.gap_xl,
179 {paddingBottom: 1},
180 ]}>
181 <Text
182 style={[
183 a.flex_1,
184 a.leading_snug,
185 t.atoms.text_contrast_medium,
186 ]}
187 numberOfLines={1}>
188 <Trans>
189 Source:{' '}
190 <InlineLinkText
191 label={sourceName}
192 to={makeProfileLink({
193 did: modcause.label.src,
194 handle: '',
195 })}
196 onPress={() => control.close()}>
197 {sourceName}
198 </InlineLinkText>
199 </Trans>
200 </Text>
201 {modcause.label.exp && (
202 <View>
203 <Text
204 style={[
205 a.leading_snug,
206 a.text_sm,
207 a.italic,
208 t.atoms.text_contrast_medium,
209 ]}>
210 <Trans>
211 Expires in {timeDiff(Date.now(), modcause.label.exp)}
212 </Trans>
213 </Text>
214 </View>
215 )}
216 </View>
217 </>
218 )}
219 </View>
220 )}
221
222 {isNative && <View style={{height: 40}} />}
223
224 <Dialog.Close />
225 </Dialog.ScrollableInner>
226 )
227}