@bifold/core 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/lib/commonjs/components/inputs/PINInput.js +6 -2
  2. package/lib/commonjs/components/inputs/PINInput.js.map +1 -1
  3. package/lib/commonjs/components/modals/CommonRemoveModal.js +10 -4
  4. package/lib/commonjs/components/modals/CommonRemoveModal.js.map +1 -1
  5. package/lib/commonjs/components/modals/DeveloperModal.js.map +1 -1
  6. package/lib/commonjs/container-impl.js +1 -0
  7. package/lib/commonjs/container-impl.js.map +1 -1
  8. package/lib/commonjs/contexts/activity.js +2 -2
  9. package/lib/commonjs/contexts/activity.js.map +1 -1
  10. package/lib/commonjs/contexts/auth.js +13 -5
  11. package/lib/commonjs/contexts/auth.js.map +1 -1
  12. package/lib/commonjs/index.js +7 -0
  13. package/lib/commonjs/index.js.map +1 -1
  14. package/lib/commonjs/localization/en/index.js +5 -2
  15. package/lib/commonjs/localization/en/index.js.map +1 -1
  16. package/lib/commonjs/localization/fr/index.js +4 -1
  17. package/lib/commonjs/localization/fr/index.js.map +1 -1
  18. package/lib/commonjs/localization/pt-br/index.js +5 -2
  19. package/lib/commonjs/localization/pt-br/index.js.map +1 -1
  20. package/lib/commonjs/modules/openid/screens/OpenIDCredentialOffer.js +2 -1
  21. package/lib/commonjs/modules/openid/screens/OpenIDCredentialOffer.js.map +1 -1
  22. package/lib/commonjs/screens/NameWallet.js.map +1 -1
  23. package/lib/commonjs/screens/PINEnter.js +4 -1
  24. package/lib/commonjs/screens/PINEnter.js.map +1 -1
  25. package/lib/commonjs/screens/RenameWallet.js.map +1 -1
  26. package/lib/commonjs/screens/Settings.js +9 -0
  27. package/lib/commonjs/screens/Settings.js.map +1 -1
  28. package/lib/commonjs/screens/Splash.js +8 -8
  29. package/lib/commonjs/screens/Splash.js.map +1 -1
  30. package/lib/commonjs/screens/ToggleBiometry.js.map +1 -1
  31. package/lib/module/components/inputs/PINInput.js +7 -3
  32. package/lib/module/components/inputs/PINInput.js.map +1 -1
  33. package/lib/module/components/modals/CommonRemoveModal.js +10 -4
  34. package/lib/module/components/modals/CommonRemoveModal.js.map +1 -1
  35. package/lib/module/components/modals/DeveloperModal.js.map +1 -1
  36. package/lib/module/container-impl.js +1 -0
  37. package/lib/module/container-impl.js.map +1 -1
  38. package/lib/module/contexts/activity.js +3 -3
  39. package/lib/module/contexts/activity.js.map +1 -1
  40. package/lib/module/contexts/auth.js +12 -4
  41. package/lib/module/contexts/auth.js.map +1 -1
  42. package/lib/module/index.js +1 -0
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/localization/en/index.js +5 -2
  45. package/lib/module/localization/en/index.js.map +1 -1
  46. package/lib/module/localization/fr/index.js +4 -1
  47. package/lib/module/localization/fr/index.js.map +1 -1
  48. package/lib/module/localization/pt-br/index.js +5 -2
  49. package/lib/module/localization/pt-br/index.js.map +1 -1
  50. package/lib/module/modules/openid/screens/OpenIDCredentialOffer.js +2 -1
  51. package/lib/module/modules/openid/screens/OpenIDCredentialOffer.js.map +1 -1
  52. package/lib/module/screens/NameWallet.js.map +1 -1
  53. package/lib/module/screens/PINEnter.js +5 -2
  54. package/lib/module/screens/PINEnter.js.map +1 -1
  55. package/lib/module/screens/RenameWallet.js.map +1 -1
  56. package/lib/module/screens/Settings.js +9 -0
  57. package/lib/module/screens/Settings.js.map +1 -1
  58. package/lib/module/screens/Splash.js +9 -9
  59. package/lib/module/screens/Splash.js.map +1 -1
  60. package/lib/module/screens/ToggleBiometry.js.map +1 -1
  61. package/lib/typescript/src/components/inputs/PINInput.d.ts.map +1 -1
  62. package/lib/typescript/src/components/modals/CommonRemoveModal.d.ts +1 -0
  63. package/lib/typescript/src/components/modals/CommonRemoveModal.d.ts.map +1 -1
  64. package/lib/typescript/src/components/modals/DeveloperModal.d.ts.map +1 -1
  65. package/lib/typescript/src/container-impl.d.ts.map +1 -1
  66. package/lib/typescript/src/contexts/auth.d.ts +5 -1
  67. package/lib/typescript/src/contexts/auth.d.ts.map +1 -1
  68. package/lib/typescript/src/index.d.ts +1 -0
  69. package/lib/typescript/src/index.d.ts.map +1 -1
  70. package/lib/typescript/src/localization/en/index.d.ts +3 -0
  71. package/lib/typescript/src/localization/en/index.d.ts.map +1 -1
  72. package/lib/typescript/src/localization/fr/index.d.ts +3 -0
  73. package/lib/typescript/src/localization/fr/index.d.ts.map +1 -1
  74. package/lib/typescript/src/localization/pt-br/index.d.ts +3 -0
  75. package/lib/typescript/src/localization/pt-br/index.d.ts.map +1 -1
  76. package/lib/typescript/src/modules/openid/screens/OpenIDCredentialOffer.d.ts.map +1 -1
  77. package/lib/typescript/src/screens/NameWallet.d.ts.map +1 -1
  78. package/lib/typescript/src/screens/PINEnter.d.ts.map +1 -1
  79. package/lib/typescript/src/screens/RenameWallet.d.ts.map +1 -1
  80. package/lib/typescript/src/screens/Settings.d.ts.map +1 -1
  81. package/lib/typescript/src/screens/Splash.d.ts.map +1 -1
  82. package/lib/typescript/src/screens/ToggleBiometry.d.ts.map +1 -1
  83. package/lib/typescript/src/theme.d.ts.map +1 -1
  84. package/package.json +3 -3
  85. package/src/components/inputs/PINInput.tsx +7 -3
  86. package/src/components/modals/CommonRemoveModal.tsx +9 -4
  87. package/src/components/modals/DeveloperModal.tsx +5 -2
  88. package/src/container-impl.ts +1 -0
  89. package/src/contexts/activity.tsx +3 -3
  90. package/src/contexts/auth.tsx +20 -14
  91. package/src/index.ts +1 -0
  92. package/src/localization/en/index.ts +3 -0
  93. package/src/localization/fr/index.ts +3 -0
  94. package/src/localization/pt-br/index.ts +3 -0
  95. package/src/modules/openid/screens/OpenIDCredentialOffer.tsx +1 -0
  96. package/src/screens/NameWallet.tsx +1 -3
  97. package/src/screens/PINEnter.tsx +13 -4
  98. package/src/screens/RenameWallet.tsx +8 -7
  99. package/src/screens/Settings.tsx +8 -0
  100. package/src/screens/Splash.tsx +11 -10
  101. package/src/screens/ToggleBiometry.tsx +2 -3
  102. package/src/theme.ts +9 -9
@@ -23,6 +23,7 @@ interface CommonRemoveModalProps {
23
23
  onSubmit?: GenericFn
24
24
  onCancel?: GenericFn
25
25
  visible?: boolean
26
+ extraDetails?: string
26
27
  }
27
28
 
28
29
  interface RemoveProps {
@@ -66,7 +67,7 @@ const Dropdown: React.FC<RemoveProps> = ({ title, content }) => {
66
67
  )
67
68
  }
68
69
 
69
- const CommonRemoveModal: React.FC<CommonRemoveModalProps> = ({ usage, visible, onSubmit, onCancel }) => {
70
+ const CommonRemoveModal: React.FC<CommonRemoveModalProps> = ({ usage, visible, onSubmit, onCancel, extraDetails }) => {
70
71
  if (!usage) {
71
72
  throw new Error('usage cannot be undefined')
72
73
  }
@@ -246,9 +247,13 @@ const CommonRemoveModal: React.FC<CommonRemoveModalProps> = ({ usage, visible, o
246
247
  case ModalUsage.CredentialOfferDecline:
247
248
  return (
248
249
  <View style={{ marginBottom: 25 }}>
249
- <ThemedText variant="modalTitle">{t('CredentialOffer.DeclineTitle')}</ThemedText>
250
- <ThemedText variant="modalNormal" style={{ marginTop: 30 }}>
251
- {t('CredentialOffer.DeclineParagraph1')}
250
+ <ThemedText variant="modalTitle" style={{ marginTop: 15 }}>
251
+ {t('CredentialOffer.DeclineTitle')}
252
+ </ThemedText>
253
+ <ThemedText variant="modalNormal" style={{ marginVertical: 30 }}>
254
+ {extraDetails
255
+ ? t('CredentialOffer.DeclineParagraph1WithIssuerName', { issuer: extraDetails })
256
+ : t('CredentialOffer.DeclineParagraph1')}
252
257
  </ThemedText>
253
258
  <ThemedText variant="modalNormal">{t('CredentialOffer.DeclineParagraph2')}</ThemedText>
254
259
  </View>
@@ -18,7 +18,10 @@ const DeveloperModal: React.FC<DeveloperModalProps> = ({ onBackPressed }) => {
18
18
 
19
19
  return (
20
20
  <SafeAreaModal>
21
- <SafeAreaView edges={['left', 'right', 'top']} style={{ flex: 1, backgroundColor: NavigationTheme.colors.primary }}>
21
+ <SafeAreaView
22
+ edges={['left', 'right', 'top']}
23
+ style={{ flex: 1, backgroundColor: NavigationTheme.colors.primary }}
24
+ >
22
25
  <FauxHeader title={t('Screens.Developer')} onBackPressed={onBackPressed} />
23
26
  <Developer />
24
27
  </SafeAreaView>
@@ -27,4 +30,4 @@ const DeveloperModal: React.FC<DeveloperModalProps> = ({ onBackPressed }) => {
27
30
  )
28
31
  }
29
32
 
30
- export default DeveloperModal
33
+ export default DeveloperModal
@@ -63,6 +63,7 @@ export const defaultConfig: Config = {
63
63
  settings: [],
64
64
  enableChat: true,
65
65
  enableTours: false,
66
+ preventScreenCapture: false,
66
67
  supportedLanguages: [Locales.en, Locales.fr, Locales.ptBr],
67
68
  showPreface: false,
68
69
  disableOnboardingSkip: false,
@@ -12,7 +12,7 @@ import React, {
12
12
  import { AppState, AppStateStatus, PanResponder, View } from 'react-native'
13
13
  import { defaultAutoLockTime } from '../constants'
14
14
  import { TOKENS, useServices } from '../container-api'
15
- import { useAuth } from './auth'
15
+ import { LockoutReason, useAuth } from './auth'
16
16
  import { useStore } from './store'
17
17
 
18
18
  // number of minutes before the timeout action is triggered
@@ -60,7 +60,7 @@ export const ActivityProvider: React.FC<PropsWithChildren> = ({ children }) => {
60
60
  // do not set timeout if timeout duration is set to 0
61
61
  if (milliseconds > 0) {
62
62
  // create new timeout
63
- inactivityTimeoutRef.current = setTimeout(lockOutUser, milliseconds)
63
+ inactivityTimeoutRef.current = setTimeout(() => lockOutUser(LockoutReason.Timeout), milliseconds)
64
64
  }
65
65
  },
66
66
  [clearInactivityTimeoutIfExists, lockOutUser]
@@ -89,7 +89,7 @@ export const ActivityProvider: React.FC<PropsWithChildren> = ({ children }) => {
89
89
  Date.now() - lastActiveTimeRef.current >= timeoutInMilliseconds.current &&
90
90
  timeoutInMilliseconds.current > 0
91
91
  ) {
92
- lockOutUser()
92
+ lockOutUser(LockoutReason.Timeout)
93
93
  } else {
94
94
  // otherwise restart message pickup
95
95
  try {
@@ -26,7 +26,7 @@ import { BifoldError } from '../types/error'
26
26
  import { EventTypes } from '../constants'
27
27
 
28
28
  export interface AuthContext {
29
- lockOutUser: () => void
29
+ lockOutUser: (reason: LockoutReason) => void
30
30
  checkWalletPIN: (PIN: string) => Promise<boolean>
31
31
  getWalletSecret: () => Promise<WalletSecret | undefined>
32
32
  walletSecret?: WalletSecret
@@ -40,6 +40,10 @@ export interface AuthContext {
40
40
  }
41
41
 
42
42
  export const AuthContext = createContext<AuthContext>(null as unknown as AuthContext)
43
+ export enum LockoutReason {
44
+ Timeout = 'Timeout',
45
+ Logout = 'Logout',
46
+ }
43
47
 
44
48
  export const AuthProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
45
49
  const [walletSecret, setWalletSecret] = useState<WalletSecret>()
@@ -118,8 +122,7 @@ export const AuthProvider: React.FC<React.PropsWithChildren> = ({ children }) =>
118
122
 
119
123
  await askarWallet.close()
120
124
 
121
- const fullSecret = await secretForPIN(PIN, secret.salt)
122
- setWalletSecret(fullSecret)
125
+ setWalletSecret({ id: secret.id, key: hash, salt: secret.salt })
123
126
  return true
124
127
  } catch (e) {
125
128
  return false
@@ -132,17 +135,20 @@ export const AuthProvider: React.FC<React.PropsWithChildren> = ({ children }) =>
132
135
  setWalletSecret(undefined)
133
136
  }, [])
134
137
 
135
- const lockOutUser = useCallback(() => {
136
- removeSavedWalletSecret()
137
- dispatch({
138
- type: DispatchAction.DID_AUTHENTICATE,
139
- payload: [false],
140
- })
141
- dispatch({
142
- type: DispatchAction.LOCKOUT_UPDATED,
143
- payload: [{ displayNotification: true }],
144
- })
145
- }, [removeSavedWalletSecret, dispatch])
138
+ const lockOutUser = useCallback(
139
+ (reason: LockoutReason) => {
140
+ removeSavedWalletSecret()
141
+ dispatch({
142
+ type: DispatchAction.DID_AUTHENTICATE,
143
+ payload: [false],
144
+ })
145
+ dispatch({
146
+ type: DispatchAction.LOCKOUT_UPDATED,
147
+ payload: [{ displayNotification: reason === LockoutReason.Timeout }],
148
+ })
149
+ },
150
+ [removeSavedWalletSecret, dispatch]
151
+ )
146
152
 
147
153
  const disableBiometrics = useCallback(async () => {
148
154
  await wipeWalletKey(true)
package/src/index.ts CHANGED
@@ -153,6 +153,7 @@ export type { Config, HistoryEventsLoggerConfig } from './types/config'
153
153
  export { BaseTourID } from './types/tour'
154
154
  export type { SplashProps } from './screens/Splash'
155
155
  export type { OnboardingStackProps } from './navigators/OnboardingStack'
156
+ export { LockoutReason } from './contexts/auth'
156
157
 
157
158
  export {
158
159
  createApp,
@@ -247,6 +247,7 @@ const translation = {
247
247
  "PINDisclaimer": "If you forget it, you may need to set up your wallet again and re-add your cards.",
248
248
  "Show": "Show PIN",
249
249
  "Hide": "Hide PIN",
250
+ "Masked": "PIN Masked for privacy",
250
251
  },
251
252
  "PINChange": {
252
253
  "PinChangeSuccessTitle": "Successfully changed your PIN",
@@ -641,6 +642,7 @@ const translation = {
641
642
  "DeclineTitle": "Decline credential offer?",
642
643
  "Declined": "Declined",
643
644
  "DeclineParagraph1": "In order to receive the credential offer again, you will need to restart the issuing process again with the issuing service.",
645
+ "DeclineParagraph1WithIssuerName": "If you change your mind you will need to request the card from {{ issuer }} again.",
644
646
  "DeclineParagraph2": "Are you sure you want to decline this credential offer?",
645
647
  "CustomOfferTitle": "Delete this offer?",
646
648
  "CustomOfferParagraph1": "Deleting this offer will remove the notification from your list.",
@@ -741,6 +743,7 @@ const translation = {
741
743
  "Developer": "Developer options",
742
744
  "Notifications": "Notifications",
743
745
  "AutoLockTime": "Auto lock time",
746
+ "Logout": "Log out",
744
747
  },
745
748
  "AutoLockTimes": {
746
749
  "FiveMinutes": "Five Minutes",
@@ -258,6 +258,7 @@ const translation = {
258
258
  "PINDisclaimer": "Si vous l'oubliez, vous devrez configurer à nouveau votre portefeuille et vos cartes.",
259
259
  "Show": "Afficher NIP",
260
260
  "Hide": "Masquer NIP",
261
+ "Masked": "PIN Masked for privacy (FR)",
261
262
  "ChangePIN": "Changer votre NIP",
262
263
  "Continue": "Continuer",
263
264
  "EnterYourCurrentPIN": "Entrez votre NIP actuel"
@@ -644,6 +645,7 @@ const translation = {
644
645
  "DeclineTitle": "Refuser l'offre d'attestation d'identité?",
645
646
  "Declined": "Refusé",
646
647
  "DeclineParagraph1": "Afin de recevoir à nouveau l'offre d'attestation d'identité, vous devrez recommencer le processus d'émission avec le service d'émission.",
648
+ "DeclineParagraph1WithIssuerName": "If you change your mind you will need to request the card from {{ issuer }} again. (FR)",
647
649
  "DeclineParagraph2": "Êtes-vous sûr de vouloir refuser cette offre d'attestation d'identité?",
648
650
  "CustomOfferTitle": "Supprimer cette offre?",
649
651
  "CustomOfferParagraph1": "La suppression de cette offre supprimera la notification de votre liste.",
@@ -729,6 +731,7 @@ const translation = {
729
731
  "ScanMyQR": "Scanner mon code QR",
730
732
  "Developer": "Options de développeur",
731
733
  "AutoLockTime": "Auto lock time (FR)",
734
+ "Logout": "Déconnexion",
732
735
  },
733
736
  "AutoLockTimes": {
734
737
  "FiveMinutes": "Five Minutes (FR)",
@@ -239,6 +239,7 @@ const translation = {
239
239
  "PINDisclaimer": "Se você o esquecer, você precisará redefinir sua carteira e readicionar seus cards.",
240
240
  "Show": "Mostrar PIN",
241
241
  "Hide": "Esconder PIN",
242
+ "Masked": "PIN Masked for privacy (PT-BR)",
242
243
  },
243
244
  "PINChange": {
244
245
  "PinChangeSuccessTitle": "Seu PIN foi alterado com sucesso",
@@ -626,6 +627,7 @@ const translation = {
626
627
  "ShareFollowingInformation_one": "está compartilhando as seguintes informações de credenciais {{count}}.",
627
628
  "ShareFollowingInformation_other": "está compartilhando as seguintes informações de credenciais {{count}}.",
628
629
  "DeclineParagraph1": "Para receber novamente a oferta de credencial, você precisara iniciar novamente o processo de emissão com o serviço emissor.",
630
+ "DeclineParagraph1WithIssuerName": "If you change your mind you will need to request the card from {{ issuer }} again. (PT-BR)",
629
631
  "DeclineParagraph2": "Você tem certeza que quer recusar esta oferta de credencial?",
630
632
  "CustomOfferTitle": "Remover esta oferta?",
631
633
  "CustomOfferParagraph1": "Remover esta oferta irá remover a notificação de sua lista.",
@@ -713,6 +715,7 @@ const translation = {
713
715
  "ScanMyQR": "Scanear meu QR code",
714
716
  "Developer": "Opções de Desenvolvedor",
715
717
  "AutoLockTime": "Auto lock time (PT-BR)",
718
+ "Logout": "Sair",
716
719
  },
717
720
  "AutoLockTimes": {
718
721
  "FiveMinutes": "Five Minutes (PT-BR)",
@@ -183,6 +183,7 @@ const OpenIDCredentialOffer: React.FC<OpenIDCredentialDetailsProps> = ({ navigat
183
183
  visible={isRemoveModalDisplayed}
184
184
  onSubmit={handleDeclineTouched}
185
185
  onCancel={toggleDeclineModalVisible}
186
+ extraDetails={display.issuer.name}
186
187
  />
187
188
  </ScreenLayout>
188
189
  )
@@ -3,9 +3,7 @@ import React from 'react'
3
3
  import WalletNameForm from '../components/forms/WalletNameForm'
4
4
 
5
5
  const NameWallet: React.FC = () => {
6
- return (
7
- <WalletNameForm />
8
- )
6
+ return <WalletNameForm />
9
7
  }
10
8
 
11
9
  export default NameWallet
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react'
2
2
  import { useTranslation } from 'react-i18next'
3
- import { DeviceEventEmitter, InteractionManager, Keyboard, Pressable, StyleSheet, View } from 'react-native'
3
+ import { DeviceEventEmitter, InteractionManager, Keyboard, Pressable, StyleSheet, Vibration, View } from 'react-native'
4
4
 
5
5
  import Button, { ButtonType } from '../components/buttons/Button'
6
6
  import { InlineErrorType, InlineMessageProps } from '../components/inputs/InlineErrorText'
@@ -41,14 +41,23 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated }) => {
41
41
  const [biometricsEnrollmentChange, setBiometricsEnrollmentChange] = useState(false)
42
42
  const { ColorPallet } = useTheme()
43
43
  const { ButtonLoading } = useAnimatedComponents()
44
- const [logger, { preventScreenCapture, enableHiddenDevModeTrigger, attemptLockoutConfig: { thresholdRules } = attemptLockoutConfig }] =
45
- useServices([TOKENS.UTIL_LOGGER, TOKENS.CONFIG])
44
+ const [
45
+ logger,
46
+ {
47
+ preventScreenCapture,
48
+ enableHiddenDevModeTrigger,
49
+ attemptLockoutConfig: { thresholdRules } = attemptLockoutConfig,
50
+ },
51
+ ] = useServices([TOKENS.UTIL_LOGGER, TOKENS.CONFIG])
46
52
  const [inlineMessageField, setInlineMessageField] = useState<InlineMessageProps>()
47
53
  const [inlineMessages] = useServices([TOKENS.INLINE_ERRORS])
48
54
  const [alertModalMessage, setAlertModalMessage] = useState('')
49
55
  const { getLockoutPenalty, attemptLockout, unMarkServedPenalty } = useLockout()
50
56
  const onBackPressed = () => setDevModalVisible(false)
51
- const onDevModeTriggered = () => setDevModalVisible(true)
57
+ const onDevModeTriggered = () => {
58
+ Vibration.vibrate()
59
+ setDevModalVisible(true)
60
+ }
52
61
  const { incrementDeveloperMenuCounter } = useDeveloperMode(onDevModeTriggered)
53
62
  const gotoPostAuthScreens = useGotoPostAuthScreens()
54
63
  const isContinueDisabled = inlineMessages.enabled ? !continueEnabled : !continueEnabled || PIN.length < minPINLength
@@ -12,14 +12,15 @@ const RenameWallet: React.FC = () => {
12
12
  navigation.goBack()
13
13
  }, [navigation])
14
14
 
15
- const onSubmitSuccess = useCallback((name: string) => {
16
- agent.config.label = name
17
- navigation.goBack()
18
- }, [navigation, agent])
19
-
20
- return (
21
- <WalletNameForm isRenaming onCancel={onCancel} onSubmitSuccess={onSubmitSuccess} />
15
+ const onSubmitSuccess = useCallback(
16
+ (name: string) => {
17
+ agent.config.label = name
18
+ navigation.goBack()
19
+ },
20
+ [navigation, agent]
22
21
  )
22
+
23
+ return <WalletNameForm isRenaming onCancel={onCancel} onSubmitSuccess={onSubmitSuccess} />
23
24
  }
24
25
 
25
26
  export default RenameWallet
@@ -1,6 +1,7 @@
1
1
  import { StackScreenProps } from '@react-navigation/stack'
2
2
  import React from 'react'
3
3
  import { useTranslation } from 'react-i18next'
4
+ import { LockoutReason, useAuth } from '../contexts/auth'
4
5
  import {
5
6
  ScrollView,
6
7
  SectionList,
@@ -33,6 +34,7 @@ type SettingsProps = StackScreenProps<SettingStackParams>
33
34
  const Settings: React.FC<SettingsProps> = ({ navigation }) => {
34
35
  const { t, i18n } = useTranslation()
35
36
  const [store] = useStore()
37
+ const { lockOutUser } = useAuth()
36
38
  const onDevModeTriggered = () => {
37
39
  Vibration.vibrate()
38
40
  navigation.navigate(Screens.Developer)
@@ -216,6 +218,12 @@ const Settings: React.FC<SettingsProps> = ({ navigation }) => {
216
218
  testID: testIdWithKey('DeveloperOptions'),
217
219
  onPress: () => navigation.navigate(Screens.Developer),
218
220
  },
221
+ {
222
+ title: t('Settings.Logout'),
223
+ accessibilityLabel: t('Settings.Logout'),
224
+ testID: testIdWithKey('Logout'),
225
+ onPress: () => lockOutUser(LockoutReason.Logout),
226
+ },
219
227
  ]
220
228
  }
221
229
  }
@@ -1,5 +1,5 @@
1
1
  import { RemoteOCABundleResolver } from '@bifold/oca/build/legacy'
2
- import React, { useEffect } from 'react'
2
+ import React, { useEffect, useRef } from 'react'
3
3
  import { useTranslation } from 'react-i18next'
4
4
  import { DeviceEventEmitter, StyleSheet } from 'react-native'
5
5
  import { SafeAreaView } from 'react-native-safe-area-context'
@@ -27,6 +27,7 @@ const Splash: React.FC<SplashProps> = ({ initializeAgent }) => {
27
27
  const [store] = useStore()
28
28
  const { ColorPallet } = useTheme()
29
29
  const { LoadingIndicator } = useAnimatedComponents()
30
+ const initializing = useRef(false)
30
31
  const [logger, ocaBundleResolver] = useServices([TOKENS.UTIL_LOGGER, TOKENS.UTIL_OCA_RESOLVER])
31
32
 
32
33
  const styles = StyleSheet.create({
@@ -39,19 +40,19 @@ const Splash: React.FC<SplashProps> = ({ initializeAgent }) => {
39
40
  })
40
41
 
41
42
  useEffect(() => {
43
+ if (initializing.current || !store.authentication.didAuthenticate) {
44
+ return
45
+ }
46
+
47
+ if (!walletSecret) {
48
+ throw new Error('Wallet secret is missing')
49
+ }
50
+ initializing.current = true
51
+
42
52
  const initAgentAsyncEffect = async (): Promise<void> => {
43
53
  try {
44
54
  await (ocaBundleResolver as RemoteOCABundleResolver).checkForUpdates?.()
45
55
 
46
- // User hasn't authenticated yet, no point in trying to initialize wallet agent
47
- if (!store.authentication.didAuthenticate) {
48
- return
49
- }
50
-
51
- if (!walletSecret) {
52
- throw new Error('Wallet secret is missing')
53
- }
54
-
55
56
  await initializeAgent(walletSecret)
56
57
  } catch (err: unknown) {
57
58
  const error = new BifoldError(
@@ -14,7 +14,6 @@ import { useAppAgent } from '../utils/agent'
14
14
  import PINVerify, { PINEntryUsage } from './PINVerify'
15
15
  import { SafeAreaView } from 'react-native-safe-area-context'
16
16
 
17
-
18
17
  const ToggleBiometry: React.FC = () => {
19
18
  const [store, dispatch] = useStore()
20
19
  const { agent } = useAppAgent()
@@ -138,8 +137,8 @@ const ToggleBiometry: React.FC = () => {
138
137
  animationType={'slide'}
139
138
  presentationStyle={'fullScreen'}
140
139
  >
141
- <SafeAreaView edges={['top']} style={{ backgroundColor: NavigationTheme.colors.primary }}/>
142
- <FauxHeader title={t('Screens.EnterPIN')} onBackPressed={onBackPressed}/>
140
+ <SafeAreaView edges={['top']} style={{ backgroundColor: NavigationTheme.colors.primary }} />
141
+ <FauxHeader title={t('Screens.EnterPIN')} onBackPressed={onBackPressed} />
143
142
  <PINVerify
144
143
  usage={PINEntryUsage.ChangeBiometrics}
145
144
  setAuthenticated={onAuthenticationComplete}
package/src/theme.ts CHANGED
@@ -730,21 +730,21 @@ export interface ITabTheme {
730
730
  shadowOpacity: number
731
731
  borderTopWidth: number
732
732
  paddingBottom: number
733
- },
734
- tabBarContainerStyle: ViewStyle,
735
- tabBarActiveTintColor: string,
736
- tabBarInactiveTintColor: string,
733
+ }
734
+ tabBarContainerStyle: ViewStyle
735
+ tabBarActiveTintColor: string
736
+ tabBarInactiveTintColor: string
737
737
  tabBarTextStyle: TextStyle & {
738
738
  fontSize: number
739
- },
739
+ }
740
740
  tabBarButtonIconStyle: {
741
741
  color: string
742
- },
743
- focusTabIconStyle: ViewStyle,
742
+ }
743
+ focusTabIconStyle: ViewStyle
744
744
  focusTabActiveTintColor: {
745
745
  backgroundColor: string
746
- },
747
- tabBarSecondaryBackgroundColor: string,
746
+ }
747
+ tabBarSecondaryBackgroundColor: string
748
748
  }
749
749
 
750
750
  export const TabTheme: ITabTheme = {