From 0f96669f8c0d578d888c06496d97929130d34a1f Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Wed, 7 May 2025 10:23:33 -0500
Subject: [APP-1158] Refactor email-related dialogs (#8296)

* WIP

* Update email

* Fire off confirmation email after change

* Verify step, integrate stateful control

* Remove tentative EnterCode step

* Handle token step

* Handle instructions and integrate into 2FA setting

* Fix load state when reusing same email

* Add new state

* Add 2FA screens

* Clean up state in Update step

* Clean up verify state, handle normal callback

* Normalize convetions

* Add verification reminder screen

* Improve session refresh

* Handle verification requirements for composer and convo

* Fix lint

* Do better

* Couple missing translations

* Format

* Use listeners for easier to grok logic

* Clean errors

* Move to global context

* [APP-1158] Gate features by email verification state (#8305)

* Use new hook in all locations

* Format

* Seems to work, not great duplication

* Wrap all open composer calls

* Remove unneeded spans

* Missed one

* Fix handler on Conversation

* Gate new chat in header

* Add comment

* Remove whoopsie

* Format

* add hackfix for dialog not showing

* add prompt to accept chat btn

* navigation not necessary

* send back one screen, rather than home

* Update comment

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* Clear dialog state

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* Update icon

* Check color

* Add 2FA warning

* Update instructions

* Fix X button

* Use an effect silly goose

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/dialaUpdate copyogs/EmailDialog/screens/Update.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

* Update copy

* Update copy

* Update copy

* Update copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update copy

* Add link back to update email from verify email dialog

* Handle token field validation

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
---
 .../EmailDialog/screens/Manage2FA/Enable.tsx       | 137 +++++++++++++++++++++
 1 file changed, 137 insertions(+)
 create mode 100644 src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx

(limited to 'src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx')

diff --git a/src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx b/src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx
new file mode 100644
index 000000000..7a126792a
--- /dev/null
+++ b/src/components/dialogs/EmailDialog/screens/Manage2FA/Enable.tsx
@@ -0,0 +1,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>
+  )
+}
-- 
cgit 1.4.1

