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