mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {
3 ActivityIndicator,
4 SafeAreaView,
5 StyleSheet,
6 TouchableOpacity,
7 View,
8} from 'react-native'
9import {LinearGradient} from 'expo-linear-gradient'
10import {msg, Trans} from '@lingui/macro'
11import {useLingui} from '@lingui/react'
12
13import {useModalControls} from '#/state/modals'
14import {useAgent, useSession, useSessionApi} from '#/state/session'
15import {usePalette} from 'lib/hooks/usePalette'
16import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
17import {cleanError} from 'lib/strings/errors'
18import {colors, gradients, s} from 'lib/styles'
19import {useTheme} from 'lib/ThemeContext'
20import {isAndroid} from 'platform/detection'
21import {resetToTab} from '../../../Navigation'
22import {ErrorMessage} from '../util/error/ErrorMessage'
23import {Text} from '../util/text/Text'
24import * as Toast from '../util/Toast'
25import {ScrollView, TextInput} from './util'
26
27export const snapPoints = isAndroid ? ['90%'] : ['55%']
28
29export function Component({}: {}) {
30 const pal = usePalette('default')
31 const theme = useTheme()
32 const {currentAccount} = useSession()
33 const {getAgent} = useAgent()
34 const {clearCurrentAccount, removeAccount} = useSessionApi()
35 const {_} = useLingui()
36 const {closeModal} = useModalControls()
37 const {isMobile} = useWebMediaQueries()
38 const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false)
39 const [confirmCode, setConfirmCode] = React.useState<string>('')
40 const [password, setPassword] = React.useState<string>('')
41 const [isProcessing, setIsProcessing] = React.useState<boolean>(false)
42 const [error, setError] = React.useState<string>('')
43 const onPressSendEmail = async () => {
44 setError('')
45 setIsProcessing(true)
46 try {
47 await getAgent().com.atproto.server.requestAccountDelete()
48 setIsEmailSent(true)
49 } catch (e: any) {
50 setError(cleanError(e))
51 }
52 setIsProcessing(false)
53 }
54 const onPressConfirmDelete = async () => {
55 if (!currentAccount?.did) {
56 throw new Error(`DeleteAccount modal: currentAccount.did is undefined`)
57 }
58
59 setError('')
60 setIsProcessing(true)
61 const token = confirmCode.replace(/\s/g, '')
62
63 try {
64 await getAgent().com.atproto.server.deleteAccount({
65 did: currentAccount.did,
66 password,
67 token,
68 })
69 Toast.show(_(msg`Your account has been deleted`))
70 resetToTab('HomeTab')
71 removeAccount(currentAccount)
72 clearCurrentAccount()
73 closeModal()
74 } catch (e: any) {
75 setError(cleanError(e))
76 }
77 setIsProcessing(false)
78 }
79 const onCancel = () => {
80 closeModal()
81 }
82 return (
83 <SafeAreaView style={[s.flex1]}>
84 <ScrollView style={[pal.view]} keyboardShouldPersistTaps="handled">
85 <View style={[styles.titleContainer, pal.view]}>
86 <Text type="title-xl" style={[s.textCenter, pal.text]}>
87 <Trans>
88 Delete Account{' '}
89 <Text type="title-xl" style={[pal.text, s.bold]}>
90 "
91 </Text>
92 <Text
93 type="title-xl"
94 numberOfLines={1}
95 style={[
96 isMobile ? styles.titleMobile : styles.titleDesktop,
97 pal.text,
98 s.bold,
99 ]}>
100 {currentAccount?.handle}
101 </Text>
102 <Text type="title-xl" style={[pal.text, s.bold]}>
103 "
104 </Text>
105 </Trans>
106 </Text>
107 </View>
108 {!isEmailSent ? (
109 <>
110 <Text type="lg" style={[styles.description, pal.text]}>
111 <Trans>
112 For security reasons, we'll need to send a confirmation code to
113 your email address.
114 </Trans>
115 </Text>
116 {error ? (
117 <View style={s.mt10}>
118 <ErrorMessage message={error} />
119 </View>
120 ) : undefined}
121 {isProcessing ? (
122 <View style={[styles.btn, s.mt10]}>
123 <ActivityIndicator />
124 </View>
125 ) : (
126 <>
127 <TouchableOpacity
128 style={styles.mt20}
129 onPress={onPressSendEmail}
130 accessibilityRole="button"
131 accessibilityLabel={_(msg`Send email`)}
132 accessibilityHint={_(
133 msg`Sends email with confirmation code for account deletion`,
134 )}>
135 <LinearGradient
136 colors={[
137 gradients.blueLight.start,
138 gradients.blueLight.end,
139 ]}
140 start={{x: 0, y: 0}}
141 end={{x: 1, y: 1}}
142 style={[styles.btn]}>
143 <Text type="button-lg" style={[s.white, s.bold]}>
144 <Trans context="action">Send Email</Trans>
145 </Text>
146 </LinearGradient>
147 </TouchableOpacity>
148 <TouchableOpacity
149 style={[styles.btn, s.mt10]}
150 onPress={onCancel}
151 accessibilityRole="button"
152 accessibilityLabel={_(msg`Cancel account deletion`)}
153 accessibilityHint=""
154 onAccessibilityEscape={onCancel}>
155 <Text type="button-lg" style={pal.textLight}>
156 <Trans context="action">Cancel</Trans>
157 </Text>
158 </TouchableOpacity>
159 </>
160 )}
161 </>
162 ) : (
163 <>
164 {/* TODO: Update this label to be more concise */}
165 <Text
166 type="lg"
167 style={[pal.text, styles.description]}
168 nativeID="confirmationCode">
169 <Trans>
170 Check your inbox for an email with the confirmation code to
171 enter below:
172 </Trans>
173 </Text>
174 <TextInput
175 style={[styles.textInput, pal.borderDark, pal.text, styles.mb20]}
176 placeholder={_(msg`Confirmation code`)}
177 placeholderTextColor={pal.textLight.color}
178 keyboardAppearance={theme.colorScheme}
179 value={confirmCode}
180 onChangeText={setConfirmCode}
181 accessibilityLabelledBy="confirmationCode"
182 accessibilityLabel={_(msg`Confirmation code`)}
183 accessibilityHint={_(
184 msg`Input confirmation code for account deletion`,
185 )}
186 />
187 <Text
188 type="lg"
189 style={[pal.text, styles.description]}
190 nativeID="password">
191 <Trans>Please enter your password as well:</Trans>
192 </Text>
193 <TextInput
194 style={[styles.textInput, pal.borderDark, pal.text]}
195 placeholder={_(msg`Password`)}
196 placeholderTextColor={pal.textLight.color}
197 keyboardAppearance={theme.colorScheme}
198 secureTextEntry
199 value={password}
200 onChangeText={setPassword}
201 accessibilityLabelledBy="password"
202 accessibilityLabel={_(msg`Password`)}
203 accessibilityHint={_(msg`Input password for account deletion`)}
204 />
205 {error ? (
206 <View style={styles.mt20}>
207 <ErrorMessage message={error} />
208 </View>
209 ) : undefined}
210 {isProcessing ? (
211 <View style={[styles.btn, s.mt10]}>
212 <ActivityIndicator />
213 </View>
214 ) : (
215 <>
216 <TouchableOpacity
217 style={[styles.btn, styles.evilBtn, styles.mt20]}
218 onPress={onPressConfirmDelete}
219 accessibilityRole="button"
220 accessibilityLabel={_(msg`Confirm delete account`)}
221 accessibilityHint="">
222 <Text type="button-lg" style={[s.white, s.bold]}>
223 <Trans>Delete my account</Trans>
224 </Text>
225 </TouchableOpacity>
226 <TouchableOpacity
227 style={[styles.btn, s.mt10]}
228 onPress={onCancel}
229 accessibilityRole="button"
230 accessibilityLabel={_(msg`Cancel account deletion`)}
231 accessibilityHint={_(msg`Exits account deletion process`)}
232 onAccessibilityEscape={onCancel}>
233 <Text type="button-lg" style={pal.textLight}>
234 <Trans context="action">Cancel</Trans>
235 </Text>
236 </TouchableOpacity>
237 </>
238 )}
239 </>
240 )}
241 </ScrollView>
242 </SafeAreaView>
243 )
244}
245
246const styles = StyleSheet.create({
247 titleContainer: {
248 display: 'flex',
249 flexDirection: 'row',
250 justifyContent: 'center',
251 flexWrap: 'wrap',
252 marginTop: 12,
253 marginBottom: 12,
254 marginLeft: 20,
255 marginRight: 20,
256 },
257 titleMobile: {
258 textAlign: 'center',
259 },
260 titleDesktop: {
261 textAlign: 'center',
262 overflow: 'hidden',
263 whiteSpace: 'nowrap',
264 textOverflow: 'ellipsis',
265 // @ts-ignore only rendered on web
266 maxWidth: '400px',
267 },
268 description: {
269 textAlign: 'center',
270 paddingHorizontal: 22,
271 marginBottom: 10,
272 },
273 mt20: {
274 marginTop: 20,
275 },
276 mb20: {
277 marginBottom: 20,
278 },
279 textInput: {
280 borderWidth: 1,
281 borderRadius: 6,
282 paddingHorizontal: 16,
283 paddingVertical: 12,
284 fontSize: 20,
285 marginHorizontal: 20,
286 },
287 btn: {
288 flexDirection: 'row',
289 alignItems: 'center',
290 justifyContent: 'center',
291 borderRadius: 32,
292 padding: 14,
293 marginHorizontal: 20,
294 },
295 evilBtn: {
296 backgroundColor: colors.red4,
297 },
298})