forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useCallback, useState} from 'react'
2import {View} from 'react-native'
3import {ToolsOzoneReportDefs} from '@atproto/api'
4import {msg, Trans} from '@lingui/macro'
5import {useLingui} from '@lingui/react'
6import {useMutation} from '@tanstack/react-query'
7
8import {BLUESKY_MOD_SERVICE_HEADERS} from '#/lib/constants'
9import {logger} from '#/logger'
10import {useAgent, useSession} from '#/state/session'
11import * as Toast from '#/view/com/util/Toast'
12import {atoms as a, useBreakpoints, useTheme} from '#/alf'
13import {Button, ButtonIcon, ButtonText} from '#/components/Button'
14import * as Dialog from '#/components/Dialog'
15import {Loader} from '#/components/Loader'
16import {Text} from '#/components/Typography'
17
18export function ChatDisabled() {
19 const t = useTheme()
20 return (
21 <View style={[a.p_md]}>
22 <View
23 style={[a.align_start, a.p_xl, a.rounded_md, t.atoms.bg_contrast_25]}>
24 <Text
25 style={[
26 a.text_md,
27 a.font_semi_bold,
28 a.pb_sm,
29 t.atoms.text_contrast_high,
30 ]}>
31 <Trans>Your chats have been disabled</Trans>
32 </Text>
33 <Text style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
34 <Trans>
35 Our moderators have reviewed reports and decided to disable your
36 access to chats on Bluesky.
37 </Trans>
38 </Text>
39 <AppealDialog />
40 </View>
41 </View>
42 )
43}
44
45function AppealDialog() {
46 const control = Dialog.useDialogControl()
47 const {_} = useLingui()
48
49 return (
50 <>
51 <Button
52 testID="appealDisabledChatBtn"
53 variant="ghost"
54 color="secondary"
55 size="small"
56 onPress={control.open}
57 label={_(msg`Appeal this decision`)}
58 style={a.mt_sm}>
59 <ButtonText>{_(msg`Appeal this decision`)}</ButtonText>
60 </Button>
61
62 <Dialog.Outer control={control}>
63 <Dialog.Handle />
64 <DialogInner />
65 </Dialog.Outer>
66 </>
67 )
68}
69
70function DialogInner() {
71 const {_} = useLingui()
72 const control = Dialog.useDialogContext()
73 const [details, setDetails] = useState('')
74 const {gtMobile} = useBreakpoints()
75 const agent = useAgent()
76 const {currentAccount} = useSession()
77
78 const {mutate, isPending} = useMutation({
79 mutationFn: async () => {
80 if (!currentAccount)
81 throw new Error('No current account, should be unreachable')
82 await agent.createModerationReport(
83 {
84 reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
85 subject: {
86 $type: 'com.atproto.admin.defs#repoRef',
87 did: currentAccount.did,
88 },
89 reason: details,
90 },
91 {
92 encoding: 'application/json',
93 headers: BLUESKY_MOD_SERVICE_HEADERS,
94 },
95 )
96 },
97 onError: err => {
98 logger.error('Failed to submit chat appeal', {message: err})
99 Toast.show(_(msg`Failed to submit appeal, please try again.`), 'xmark')
100 },
101 onSuccess: () => {
102 control.close()
103 Toast.show(_(msg({message: 'Appeal submitted', context: 'toast'})))
104 },
105 })
106
107 const onSubmit = useCallback(() => mutate(), [mutate])
108 const onBack = useCallback(() => control.close(), [control])
109
110 return (
111 <Dialog.ScrollableInner label={_(msg`Appeal this decision`)}>
112 <Text style={[a.text_2xl, a.font_semi_bold, a.pb_xs, a.leading_tight]}>
113 <Trans>Appeal this decision</Trans>
114 </Text>
115 <Text style={[a.text_md, a.leading_snug]}>
116 <Trans>This appeal will be sent to Bluesky's moderation service.</Trans>
117 </Text>
118 <View style={[a.my_md]}>
119 <Dialog.Input
120 label={_(msg`Text input field`)}
121 placeholder={_(
122 msg`Please explain why you think your chats were incorrectly disabled`,
123 )}
124 value={details}
125 onChangeText={setDetails}
126 autoFocus={true}
127 numberOfLines={3}
128 multiline
129 maxLength={300}
130 />
131 </View>
132
133 <View
134 style={
135 gtMobile
136 ? [a.flex_row, a.justify_between]
137 : [{flexDirection: 'column-reverse'}, a.gap_sm]
138 }>
139 <Button
140 testID="backBtn"
141 variant="solid"
142 color="secondary"
143 size="large"
144 onPress={onBack}
145 label={_(msg`Back`)}>
146 <ButtonText>{_(msg`Back`)}</ButtonText>
147 </Button>
148 <Button
149 testID="submitBtn"
150 variant="solid"
151 color="primary"
152 size="large"
153 onPress={onSubmit}
154 label={_(msg`Submit`)}>
155 <ButtonText>{_(msg`Submit`)}</ButtonText>
156 {isPending && <ButtonIcon icon={Loader} />}
157 </Button>
158 </View>
159 <Dialog.Close />
160 </Dialog.ScrollableInner>
161 )
162}