about summary refs log tree commit diff
path: root/src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx
blob: 7a126792a292fb977f421ee570e2ca72df6b3dc9 (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
131
132
133
134
135
136
137
import {useReducer} from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'

import {wait} from '#/lib/async/wait'
import {useCleanError} from '#/lib/hooks/useCleanError'
import {logger} from '#/logger'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {useDialogContext} from '#/components/Dialog'
import {useManageEmail2FA} from '#/components/dialogs/EmailDialog/data/useManageEmail2FA'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {ShieldCheck_Stroke2_Corner0_Rounded as ShieldIcon} from '#/components/icons/Shield'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'

type State = {
  error: string
  status: 'pending' | 'success' | 'error' | 'default'
}

type Action =
  | {
      type: 'setError'
      error: string
    }
  | {
      type: 'setStatus'
      status: State['status']
    }

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'setError': {
      return {
        ...state,
        error: action.error,
        status: 'error',
      }
    }
    case 'setStatus': {
      return {
        ...state,
        error: '',
        status: action.status,
      }
    }
    default: {
      return state
    }
  }
}

export function Enable() {
  const t = useTheme()
  const {_} = useLingui()
  const cleanError = useCleanError()
  const {gtPhone} = useBreakpoints()
  const {mutateAsync: manageEmail2FA} = useManageEmail2FA()
  const control = useDialogContext()

  const [state, dispatch] = useReducer(reducer, {
    error: '',
    status: 'default',
  })

  const handleManageEmail2FA = async () => {
    dispatch({type: 'setStatus', status: 'pending'})

    try {
      await wait(1000, manageEmail2FA({enabled: true}))
      dispatch({type: 'setStatus', status: 'success'})
      setTimeout(() => {
        control.close()
      }, 1000)
    } catch (e) {
      logger.error('Manage2FA: enable email 2FA failed', {safeMessage: e})
      const {clean} = cleanError(e)
      dispatch({
        type: 'setError',
        error: clean || _(msg`Failed to update email 2FA settings`),
      })
    }
  }

  return (
    <View style={[a.gap_lg]}>
      <View style={[a.gap_sm]}>
        <Text style={[a.text_xl, a.font_heavy, a.leading_snug]}>
          <Trans>Enable email 2FA</Trans>
        </Text>

        <Text style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
          <Trans>Require an email code to sign in to your account.</Trans>
        </Text>
      </View>

      {state.error && <Admonition type="error">{state.error}</Admonition>}

      <View style={[a.gap_sm, gtPhone && [a.flex_row_reverse]]}>
        <Button
          label={_(msg`Enable`)}
          size="large"
          variant="solid"
          color="primary"
          onPress={handleManageEmail2FA}
          disabled={state.status === 'pending'}>
          <ButtonText>
            <Trans>Enable</Trans>
          </ButtonText>
          <ButtonIcon
            position="right"
            icon={
              state.status === 'pending'
                ? Loader
                : state.status === 'success'
                ? Check
                : ShieldIcon
            }
          />
        </Button>
        <Button
          label={_(msg`Cancel`)}
          size="large"
          variant="solid"
          color="secondary"
          onPress={() => control.close()}>
          <ButtonText>
            <Trans>Cancel</Trans>
          </ButtonText>
        </Button>
      </View>
    </View>
  )
}