forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useCallback, useState} from 'react'
2import {View} from 'react-native'
3import {useSafeAreaInsets} from 'react-native-safe-area-context'
4import {msg} from '@lingui/core/macro'
5import {useLingui} from '@lingui/react'
6import {Trans} from '@lingui/react/macro'
7import {useQueryClient} from '@tanstack/react-query'
8
9import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
10import {logger} from '#/logger'
11import {
12 type SessionAccount,
13 useAgent,
14 useSession,
15 useSessionApi,
16} from '#/state/session'
17import {pdsAgent} from '#/state/session/agent'
18import {useLoggedOutViewControls} from '#/state/shell/logged-out'
19import {Logo} from '#/view/icons/Logo'
20import {atoms as a, useTheme} from '#/alf'
21import {AccountList} from '#/components/AccountList'
22import {Button, ButtonIcon, ButtonText} from '#/components/Button'
23import {Divider} from '#/components/Divider'
24import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
25import * as Layout from '#/components/Layout'
26import {Loader} from '#/components/Loader'
27import {Text} from '#/components/Typography'
28import {IS_WEB} from '#/env'
29
30const COL_WIDTH = 400
31
32export function Deactivated() {
33 const {_} = useLingui()
34 const t = useTheme()
35 const insets = useSafeAreaInsets()
36 const {currentAccount, accounts} = useSession()
37 const {onPressSwitchAccount, pendingDid} = useAccountSwitcher()
38 const {setShowLoggedOut} = useLoggedOutViewControls()
39 const hasOtherAccounts = accounts.length > 1
40 const {logoutCurrentAccount} = useSessionApi()
41 const agent = useAgent()
42 const [pending, setPending] = useState(false)
43 const [error, setError] = useState<string | undefined>()
44 const queryClient = useQueryClient()
45
46 const onSelectAccount = useCallback(
47 (account: SessionAccount) => {
48 if (account.did !== currentAccount?.did) {
49 onPressSwitchAccount(account, 'SwitchAccount')
50 }
51 },
52 [currentAccount, onPressSwitchAccount],
53 )
54
55 const onPressAddAccount = useCallback(() => {
56 setShowLoggedOut(true)
57 }, [setShowLoggedOut])
58
59 const onPressLogout = useCallback(() => {
60 if (IS_WEB) {
61 // We're switching accounts, which remounts the entire app.
62 // On mobile, this gets us Home, but on the web we also need reset the URL.
63 // We can't change the URL via a navigate() call because the navigator
64 // itself is about to unmount, and it calls pushState() too late.
65 // So we change the URL ourselves. The navigator will pick it up on remount.
66 history.pushState(null, '', '/')
67 }
68 logoutCurrentAccount('Deactivated')
69 }, [logoutCurrentAccount])
70
71 const handleActivate = useCallback(async () => {
72 try {
73 setPending(true)
74 await pdsAgent(agent).com.atproto.server.activateAccount()
75 await queryClient.resetQueries()
76 await agent.resumeSession(agent.session!)
77 } catch (e: any) {
78 switch (e.message) {
79 case 'Bad token scope':
80 setError(
81 _(
82 msg`You're signed in with an App Password. Please sign in with your main password to continue deactivating your account.`,
83 ),
84 )
85 break
86 default:
87 setError(_(msg`Something went wrong, please try again`))
88 break
89 }
90
91 logger.error(e, {
92 message: 'Failed to activate account',
93 })
94 } finally {
95 setPending(false)
96 }
97 }, [_, agent, setPending, setError, queryClient])
98
99 return (
100 <View style={[a.util_screen_outer, a.flex_1]}>
101 <Layout.Content
102 ignoreTabletLayoutOffset
103 contentContainerStyle={[
104 a.px_2xl,
105 {
106 paddingTop: IS_WEB ? 64 : insets.top + 16,
107 paddingBottom: IS_WEB ? 64 : insets.bottom,
108 },
109 ]}>
110 <View
111 style={[a.w_full, {marginHorizontal: 'auto', maxWidth: COL_WIDTH}]}>
112 <View style={[a.w_full, a.justify_center, a.align_center, a.pb_5xl]}>
113 <Logo width={40} />
114 </View>
115
116 <View style={[a.gap_xs, a.pb_3xl]}>
117 <Text style={[a.text_xl, a.font_semi_bold, a.leading_snug]}>
118 <Trans>Welcome back!</Trans>
119 </Text>
120 <Text style={[a.text_sm, a.leading_snug]}>
121 <Trans>
122 You previously deactivated @{currentAccount?.handle}.
123 </Trans>
124 </Text>
125 <Text style={[a.text_sm, a.leading_snug, a.pb_md]}>
126 <Trans>
127 You can reactivate your account to continue logging in. Your
128 profile and posts will be visible to other users.
129 </Trans>
130 </Text>
131
132 <View style={[a.gap_sm]}>
133 <Button
134 label={_(msg`Reactivate your account`)}
135 size="large"
136 variant="solid"
137 color="primary"
138 onPress={handleActivate}>
139 <ButtonText>
140 <Trans>Yes, reactivate my account</Trans>
141 </ButtonText>
142 {pending && <ButtonIcon icon={Loader} position="right" />}
143 </Button>
144 <Button
145 label={_(msg`Cancel reactivation and sign out`)}
146 size="large"
147 variant="solid"
148 color="secondary"
149 onPress={onPressLogout}>
150 <ButtonText>
151 <Trans>Cancel</Trans>
152 </ButtonText>
153 </Button>
154 </View>
155
156 {error && (
157 <View
158 style={[
159 a.flex_row,
160 a.gap_sm,
161 a.mt_md,
162 a.p_md,
163 a.rounded_sm,
164 t.atoms.bg_contrast_25,
165 ]}>
166 <CircleInfo size="md" fill={t.palette.negative_400} />
167 <Text style={[a.flex_1, a.leading_snug]}>{error}</Text>
168 </View>
169 )}
170 </View>
171
172 <View style={[a.pb_3xl]}>
173 <Divider />
174 </View>
175
176 {hasOtherAccounts ? (
177 <>
178 <Text
179 style={[t.atoms.text_contrast_medium, a.pb_md, a.leading_snug]}>
180 <Trans>Or, sign in to one of your other accounts.</Trans>
181 </Text>
182 <AccountList
183 onSelectAccount={onSelectAccount}
184 onSelectOther={onPressAddAccount}
185 otherLabel={_(msg`Add account`)}
186 pendingDid={pendingDid}
187 />
188 </>
189 ) : (
190 <>
191 <Text
192 style={[t.atoms.text_contrast_medium, a.pb_md, a.leading_snug]}>
193 <Trans>Or, continue with another account.</Trans>
194 </Text>
195 <Button
196 label={_(msg`Sign in or create an account`)}
197 size="large"
198 variant="solid"
199 color="secondary"
200 onPress={() => setShowLoggedOut(true)}>
201 <ButtonText>
202 <Trans>Sign in or create an account</Trans>
203 </ButtonText>
204 </Button>
205 </>
206 )}
207 </View>
208 </Layout.Content>
209 </View>
210 )
211}