about summary refs log tree commit diff
path: root/src/screens/Settings/components/DeactivateAccountDialog.tsx
blob: 78c685770a90f8ee1368c050c1351175d1b99416 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import React from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'

import {logger} from '#/logger'
import {useAgent, useSessionApi} from '#/state/session'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {DialogOuterProps} from '#/components/Dialog'
import {Divider} from '#/components/Divider'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {Loader} from '#/components/Loader'
import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography'

export function DeactivateAccountDialog({
  control,
}: {
  control: DialogOuterProps['control']
}) {
  return (
    <Prompt.Outer control={control}>
      <DeactivateAccountDialogInner control={control} />
    </Prompt.Outer>
  )
}

function DeactivateAccountDialogInner({
  control,
}: {
  control: DialogOuterProps['control']
}) {
  const t = useTheme()
  const {gtMobile} = useBreakpoints()
  const {_} = useLingui()
  const agent = useAgent()
  const {logoutCurrentAccount} = useSessionApi()
  const [pending, setPending] = React.useState(false)
  const [error, setError] = React.useState<string | undefined>()

  const handleDeactivate = React.useCallback(async () => {
    try {
      setPending(true)
      await agent.com.atproto.server.deactivateAccount({})
      control.close(() => {
        logoutCurrentAccount('Deactivated')
      })
    } catch (e: any) {
      switch (e.message) {
        case 'Bad token scope':
          setError(
            _(
              msg`You're signed in with an App Password. Please sign in with your main password to continue deactivating your account.`,
            ),
          )
          break
        default:
          setError(_(msg`Something went wrong, please try again`))
          break
      }

      logger.error(e, {
        message: 'Failed to deactivate account',
      })
    } finally {
      setPending(false)
    }
  }, [agent, control, logoutCurrentAccount, _, setPending])

  return (
    <>
      <Prompt.TitleText>{_(msg`Deactivate account`)}</Prompt.TitleText>
      <Prompt.DescriptionText>
        <Trans>
          Your profile, posts, feeds, and lists will no longer be visible to
          other Bluesky users. You can reactivate your account at any time by
          logging in.
        </Trans>
      </Prompt.DescriptionText>

      <View style={[a.pb_xl]}>
        <Divider />
        <View style={[a.gap_sm, a.pt_lg, a.pb_xl]}>
          <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
            <Trans>
              There is no time limit for account deactivation, come back any
              time.
            </Trans>
          </Text>
          <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
            <Trans>
              If you're trying to change your handle or email, do so before you
              deactivate.
            </Trans>
          </Text>
        </View>

        <Divider />
      </View>
      <Prompt.Actions>
        <Button
          variant="solid"
          color="negative"
          size={gtMobile ? 'small' : 'large'}
          label={_(msg`Yes, deactivate`)}
          onPress={handleDeactivate}>
          <ButtonText>{_(msg`Yes, deactivate`)}</ButtonText>
          {pending && <ButtonIcon icon={Loader} position="right" />}
        </Button>
        <Prompt.Cancel />
      </Prompt.Actions>

      {error && (
        <View
          style={[
            a.flex_row,
            a.gap_sm,
            a.mt_md,
            a.p_md,
            a.rounded_sm,
            t.atoms.bg_contrast_25,
          ]}>
          <CircleInfo size="md" fill={t.palette.negative_400} />
          <Text style={[a.flex_1, a.leading_snug]}>{error}</Text>
        </View>
      )}
    </>
  )
}