@oxyhq/services 16.0.0 → 18.0.0

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 (278) hide show
  1. package/README.md +77 -98
  2. package/lib/commonjs/index.js +40 -51
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/ui/client.js +0 -14
  5. package/lib/commonjs/ui/client.js.map +1 -1
  6. package/lib/commonjs/ui/components/OxyAccountDialog.js +742 -0
  7. package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -0
  8. package/lib/commonjs/ui/components/OxyConsentScreen.js +461 -0
  9. package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -0
  10. package/lib/commonjs/ui/components/OxyProvider.js +13 -6
  11. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  12. package/lib/commonjs/ui/components/OxySignInButton.js +180 -22
  13. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  14. package/lib/commonjs/ui/components/ProfileButton.js +25 -112
  15. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/RequireOxyAuth.js +299 -0
  17. package/lib/commonjs/ui/components/RequireOxyAuth.js.map +1 -0
  18. package/lib/commonjs/ui/components/oauthNavigation.js +73 -0
  19. package/lib/commonjs/ui/components/oauthNavigation.js.map +1 -0
  20. package/lib/commonjs/ui/context/OxyContext.js +122 -4
  21. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  22. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +1 -1
  23. package/lib/commonjs/ui/hooks/useAuth.js +19 -30
  24. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +37 -267
  26. package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
  27. package/lib/commonjs/ui/index.js +5 -40
  28. package/lib/commonjs/ui/index.js.map +1 -1
  29. package/lib/commonjs/ui/navigation/accountDialogManager.js +91 -0
  30. package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -0
  31. package/lib/commonjs/ui/navigation/routes.js +0 -2
  32. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  33. package/lib/commonjs/ui/screens/ManageAccountScreen.js +4 -3
  34. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  35. package/lib/commonjs/ui/session/createSessionClient.js +10 -2
  36. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
  37. package/lib/module/index.js +19 -16
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/ui/client.js +1 -2
  40. package/lib/module/ui/client.js.map +1 -1
  41. package/lib/module/ui/components/OxyAccountDialog.js +739 -0
  42. package/lib/module/ui/components/OxyAccountDialog.js.map +1 -0
  43. package/lib/module/ui/components/OxyConsentScreen.js +454 -0
  44. package/lib/module/ui/components/OxyConsentScreen.js.map +1 -0
  45. package/lib/module/ui/components/OxyProvider.js +13 -6
  46. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  47. package/lib/module/ui/components/OxySignInButton.js +181 -22
  48. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  49. package/lib/module/ui/components/ProfileButton.js +26 -112
  50. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  51. package/lib/module/ui/components/RequireOxyAuth.js +294 -0
  52. package/lib/module/ui/components/RequireOxyAuth.js.map +1 -0
  53. package/lib/module/ui/components/oauthNavigation.js +70 -0
  54. package/lib/module/ui/components/oauthNavigation.js.map +1 -0
  55. package/lib/module/ui/context/OxyContext.js +123 -5
  56. package/lib/module/ui/context/OxyContext.js.map +1 -1
  57. package/lib/module/ui/hooks/mutations/useAccountMutations.js +1 -1
  58. package/lib/module/ui/hooks/useAuth.js +19 -30
  59. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  60. package/lib/module/ui/hooks/useSwitchableAccounts.js +38 -267
  61. package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
  62. package/lib/module/ui/index.js +1 -5
  63. package/lib/module/ui/index.js.map +1 -1
  64. package/lib/module/ui/navigation/accountDialogManager.js +81 -0
  65. package/lib/module/ui/navigation/accountDialogManager.js.map +1 -0
  66. package/lib/module/ui/navigation/routes.js +0 -2
  67. package/lib/module/ui/navigation/routes.js.map +1 -1
  68. package/lib/module/ui/screens/ManageAccountScreen.js +4 -3
  69. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  70. package/lib/module/ui/session/createSessionClient.js +10 -2
  71. package/lib/module/ui/session/createSessionClient.js.map +1 -1
  72. package/lib/typescript/commonjs/index.d.ts +8 -12
  73. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/ui/client.d.ts +0 -4
  75. package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +51 -0
  77. package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts +45 -0
  79. package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +2 -2
  81. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +56 -0
  83. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +11 -23
  85. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +55 -0
  87. package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +36 -0
  89. package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +27 -1
  91. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  93. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  94. package/lib/typescript/commonjs/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  95. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  96. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +13 -152
  97. package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/ui/index.d.ts +2 -5
  99. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +49 -0
  101. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  103. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
  105. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +9 -2
  107. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/ui/types/navigation.d.ts +27 -0
  109. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  110. package/lib/typescript/module/index.d.ts +8 -12
  111. package/lib/typescript/module/index.d.ts.map +1 -1
  112. package/lib/typescript/module/ui/client.d.ts +0 -4
  113. package/lib/typescript/module/ui/client.d.ts.map +1 -1
  114. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +51 -0
  115. package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -0
  116. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts +45 -0
  117. package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -0
  118. package/lib/typescript/module/ui/components/OxyProvider.d.ts +2 -2
  119. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  120. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +56 -0
  121. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  122. package/lib/typescript/module/ui/components/ProfileButton.d.ts +11 -23
  123. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  124. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +55 -0
  125. package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts.map +1 -0
  126. package/lib/typescript/module/ui/components/oauthNavigation.d.ts +36 -0
  127. package/lib/typescript/module/ui/components/oauthNavigation.d.ts.map +1 -0
  128. package/lib/typescript/module/ui/context/OxyContext.d.ts +27 -1
  129. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  130. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  131. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts +1 -1
  132. package/lib/typescript/module/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  133. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  134. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +13 -152
  135. package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
  136. package/lib/typescript/module/ui/index.d.ts +2 -5
  137. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  138. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +49 -0
  139. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -0
  140. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  141. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  142. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
  143. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  144. package/lib/typescript/module/ui/session/createSessionClient.d.ts +9 -2
  145. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
  146. package/lib/typescript/module/ui/types/navigation.d.ts +27 -0
  147. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  148. package/package.json +4 -4
  149. package/src/index.ts +33 -27
  150. package/src/ui/client.ts +0 -4
  151. package/src/ui/components/OxyAccountDialog.tsx +735 -0
  152. package/src/ui/components/OxyConsentScreen.tsx +456 -0
  153. package/src/ui/components/OxyProvider.tsx +14 -6
  154. package/src/ui/components/OxySignInButton.tsx +227 -22
  155. package/src/ui/components/ProfileButton.tsx +23 -126
  156. package/src/ui/components/RequireOxyAuth.tsx +266 -0
  157. package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +130 -0
  158. package/src/ui/components/oauthNavigation.ts +89 -0
  159. package/src/ui/context/OxyContext.tsx +176 -9
  160. package/src/ui/context/__tests__/OxyContext.coldBoot.test.tsx +165 -0
  161. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  162. package/src/ui/hooks/useAuth.ts +19 -31
  163. package/src/ui/hooks/useSwitchableAccounts.ts +42 -376
  164. package/src/ui/index.ts +2 -5
  165. package/src/ui/navigation/accountDialogManager.ts +84 -0
  166. package/src/ui/navigation/routes.ts +0 -4
  167. package/src/ui/screens/ManageAccountScreen.tsx +3 -2
  168. package/src/ui/session/createSessionClient.ts +9 -1
  169. package/src/ui/types/navigation.ts +27 -0
  170. package/lib/commonjs/ui/components/AccountMenu.js +0 -598
  171. package/lib/commonjs/ui/components/AccountMenu.js.map +0 -1
  172. package/lib/commonjs/ui/components/AccountMenuButton.js +0 -135
  173. package/lib/commonjs/ui/components/AccountMenuButton.js.map +0 -1
  174. package/lib/commonjs/ui/components/AccountSwitcher.js +0 -780
  175. package/lib/commonjs/ui/components/AccountSwitcher.js.map +0 -1
  176. package/lib/commonjs/ui/components/AnotherDeviceQR.js +0 -116
  177. package/lib/commonjs/ui/components/AnotherDeviceQR.js.map +0 -1
  178. package/lib/commonjs/ui/components/ProfileMenu.js +0 -518
  179. package/lib/commonjs/ui/components/ProfileMenu.js.map +0 -1
  180. package/lib/commonjs/ui/components/SignInAccountChooser.js +0 -189
  181. package/lib/commonjs/ui/components/SignInAccountChooser.js.map +0 -1
  182. package/lib/commonjs/ui/components/SignInModal.js +0 -600
  183. package/lib/commonjs/ui/components/SignInModal.js.map +0 -1
  184. package/lib/commonjs/ui/hooks/useOxyAuthSession.js +0 -501
  185. package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +0 -1
  186. package/lib/commonjs/ui/hooks/usePasswordSignIn.js +0 -170
  187. package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +0 -1
  188. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -51
  189. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
  190. package/lib/commonjs/ui/screens/OxyAuthScreen.js +0 -312
  191. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +0 -1
  192. package/lib/commonjs/utils/deviceFlowSignIn.js +0 -109
  193. package/lib/commonjs/utils/deviceFlowSignIn.js.map +0 -1
  194. package/lib/module/ui/components/AccountMenu.js +0 -593
  195. package/lib/module/ui/components/AccountMenu.js.map +0 -1
  196. package/lib/module/ui/components/AccountMenuButton.js +0 -130
  197. package/lib/module/ui/components/AccountMenuButton.js.map +0 -1
  198. package/lib/module/ui/components/AccountSwitcher.js +0 -774
  199. package/lib/module/ui/components/AccountSwitcher.js.map +0 -1
  200. package/lib/module/ui/components/AnotherDeviceQR.js +0 -110
  201. package/lib/module/ui/components/AnotherDeviceQR.js.map +0 -1
  202. package/lib/module/ui/components/ProfileMenu.js +0 -514
  203. package/lib/module/ui/components/ProfileMenu.js.map +0 -1
  204. package/lib/module/ui/components/SignInAccountChooser.js +0 -183
  205. package/lib/module/ui/components/SignInAccountChooser.js.map +0 -1
  206. package/lib/module/ui/components/SignInModal.js +0 -591
  207. package/lib/module/ui/components/SignInModal.js.map +0 -1
  208. package/lib/module/ui/hooks/useOxyAuthSession.js +0 -495
  209. package/lib/module/ui/hooks/useOxyAuthSession.js.map +0 -1
  210. package/lib/module/ui/hooks/usePasswordSignIn.js +0 -165
  211. package/lib/module/ui/hooks/usePasswordSignIn.js.map +0 -1
  212. package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -48
  213. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
  214. package/lib/module/ui/screens/OxyAuthScreen.js +0 -306
  215. package/lib/module/ui/screens/OxyAuthScreen.js.map +0 -1
  216. package/lib/module/utils/deviceFlowSignIn.js +0 -106
  217. package/lib/module/utils/deviceFlowSignIn.js.map +0 -1
  218. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +0 -47
  219. package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +0 -1
  220. package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +0 -26
  221. package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +0 -1
  222. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +0 -46
  223. package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +0 -1
  224. package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts +0 -34
  225. package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts.map +0 -1
  226. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +0 -49
  227. package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +0 -1
  228. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +0 -29
  229. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +0 -1
  230. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +0 -28
  231. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +0 -1
  232. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +0 -105
  233. package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
  234. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +0 -31
  235. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
  236. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -11
  237. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
  238. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +0 -22
  239. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +0 -1
  240. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +0 -97
  241. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +0 -1
  242. package/lib/typescript/module/ui/components/AccountMenu.d.ts +0 -47
  243. package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +0 -1
  244. package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +0 -26
  245. package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +0 -1
  246. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +0 -46
  247. package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +0 -1
  248. package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts +0 -34
  249. package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts.map +0 -1
  250. package/lib/typescript/module/ui/components/ProfileMenu.d.ts +0 -49
  251. package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +0 -1
  252. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +0 -29
  253. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +0 -1
  254. package/lib/typescript/module/ui/components/SignInModal.d.ts +0 -28
  255. package/lib/typescript/module/ui/components/SignInModal.d.ts.map +0 -1
  256. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +0 -105
  257. package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
  258. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +0 -31
  259. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
  260. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -11
  261. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
  262. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +0 -22
  263. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +0 -1
  264. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +0 -97
  265. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +0 -1
  266. package/src/ui/components/AccountMenu.tsx +0 -645
  267. package/src/ui/components/AccountMenuButton.tsx +0 -126
  268. package/src/ui/components/AccountSwitcher.tsx +0 -751
  269. package/src/ui/components/AnotherDeviceQR.tsx +0 -119
  270. package/src/ui/components/ProfileMenu.tsx +0 -564
  271. package/src/ui/components/SignInAccountChooser.tsx +0 -162
  272. package/src/ui/components/SignInModal.tsx +0 -530
  273. package/src/ui/hooks/useOxyAuthSession.ts +0 -635
  274. package/src/ui/hooks/usePasswordSignIn.ts +0 -207
  275. package/src/ui/screens/AccountSwitcherScreen.tsx +0 -43
  276. package/src/ui/screens/OxyAuthScreen.tsx +0 -324
  277. package/src/utils/__tests__/deviceFlowSignIn.test.ts +0 -231
  278. package/src/utils/deviceFlowSignIn.ts +0 -152
@@ -1,162 +0,0 @@
1
- import type React from 'react';
2
- import { View, Text, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native';
3
- import { Ionicons } from '@expo/vector-icons';
4
- import { useTheme } from '@oxyhq/bloom/theme';
5
- import Avatar from './Avatar';
6
- import { useI18n } from '../hooks/useI18n';
7
- import type { SwitchableAccount } from '../hooks/useSwitchableAccounts';
8
-
9
- export interface SignInAccountChooserProps {
10
- /** Accounts available on this device / in the caller's graph, current first. */
11
- accounts: SwitchableAccount[];
12
- /** Selecting a row — the active account continues, others switch into. */
13
- onSelectAccount: (account: SwitchableAccount) => void;
14
- /** "Use another account" → reveal the sign-in options (password / QR / add). */
15
- onUseAnother: () => void;
16
- /** The account id currently being switched into (shows a per-row spinner). */
17
- pendingAccountId?: string | null;
18
- /** Disables every row while a selection is in flight. */
19
- disabled?: boolean;
20
- }
21
-
22
- /**
23
- * Google-style account chooser (React Native). Lists every account the user can
24
- * continue as — device sign-ins + linked graph accounts, from
25
- * {@link SwitchableAccount} — plus a "Use another account" affordance. Rendered
26
- * as the FRONT screen of the sign-in surfaces (`SignInModal` web,
27
- * `OxyAuthScreen` native) whenever accounts exist; selecting a row funnels into
28
- * the SAME `switchToAccount` path the account switcher uses. When no accounts
29
- * exist the surfaces skip this and show the sign-in options directly.
30
- *
31
- * Presentational + chrome-agnostic (no modal/sheet wrapper, no data fetching) so
32
- * both containers reuse it and it is unit-testable in isolation.
33
- */
34
- export const SignInAccountChooser: React.FC<SignInAccountChooserProps> = ({
35
- accounts,
36
- onSelectAccount,
37
- onUseAnother,
38
- pendingAccountId,
39
- disabled,
40
- }) => {
41
- const { colors } = useTheme();
42
- const { t } = useI18n();
43
-
44
- return (
45
- <View style={styles.container}>
46
- {accounts.map((account) => {
47
- const isPending = pendingAccountId === account.accountId;
48
- const secondary = account.email;
49
- return (
50
- <TouchableOpacity
51
- key={account.accountId}
52
- accessibilityRole="button"
53
- accessibilityLabel={t('signin.chooser.continueAs', { name: account.displayName })}
54
- accessibilityState={{ selected: account.isCurrent, disabled: Boolean(disabled) }}
55
- onPress={() => onSelectAccount(account)}
56
- disabled={disabled}
57
- activeOpacity={0.7}
58
- style={[
59
- styles.row,
60
- { borderColor: colors.border },
61
- account.isCurrent && { backgroundColor: colors.primarySubtle, borderColor: colors.primarySubtle },
62
- disabled && !isPending && styles.rowDisabled,
63
- ]}
64
- >
65
- <Avatar uri={account.avatarUrl} name={account.displayName} size={44} />
66
- <View style={styles.info}>
67
- <Text style={[styles.name, { color: colors.text }]} numberOfLines={1}>
68
- {account.displayName}
69
- </Text>
70
- {secondary ? (
71
- <Text style={[styles.secondary, { color: colors.textSecondary }]} numberOfLines={1}>
72
- {secondary}
73
- </Text>
74
- ) : null}
75
- </View>
76
- {isPending ? (
77
- <ActivityIndicator size="small" color={colors.primary} />
78
- ) : account.isCurrent ? (
79
- <View style={[styles.currentPill, { backgroundColor: colors.card }]}>
80
- <Ionicons name="checkmark" size={14} color={colors.primary} />
81
- <Text style={[styles.currentPillText, { color: colors.primary }]}>
82
- {t('signin.chooser.signedIn')}
83
- </Text>
84
- </View>
85
- ) : (
86
- <Ionicons name="chevron-forward" size={20} color={colors.textSecondary} />
87
- )}
88
- </TouchableOpacity>
89
- );
90
- })}
91
-
92
- <TouchableOpacity
93
- accessibilityRole="button"
94
- accessibilityLabel={t('signin.chooser.useAnother')}
95
- onPress={onUseAnother}
96
- disabled={disabled}
97
- activeOpacity={0.7}
98
- style={[styles.row, { borderColor: colors.border }, disabled && styles.rowDisabled]}
99
- >
100
- <View style={[styles.addIcon, { backgroundColor: colors.backgroundSecondary }]}>
101
- <Ionicons name="person-add-outline" size={20} color={colors.textSecondary} />
102
- </View>
103
- <View style={styles.info}>
104
- <Text style={[styles.name, { color: colors.text }]}>{t('signin.chooser.useAnother')}</Text>
105
- </View>
106
- <Ionicons name="chevron-forward" size={20} color={colors.textSecondary} />
107
- </TouchableOpacity>
108
- </View>
109
- );
110
- };
111
-
112
- const styles = StyleSheet.create({
113
- container: {
114
- width: '100%',
115
- gap: 8,
116
- },
117
- row: {
118
- flexDirection: 'row',
119
- alignItems: 'center',
120
- gap: 12,
121
- borderWidth: 1,
122
- borderRadius: 14,
123
- paddingHorizontal: 14,
124
- paddingVertical: 12,
125
- },
126
- rowDisabled: {
127
- opacity: 0.5,
128
- },
129
- info: {
130
- flex: 1,
131
- minWidth: 0,
132
- },
133
- name: {
134
- fontSize: 15,
135
- fontWeight: '600',
136
- },
137
- secondary: {
138
- fontSize: 13,
139
- marginTop: 2,
140
- },
141
- currentPill: {
142
- flexDirection: 'row',
143
- alignItems: 'center',
144
- gap: 3,
145
- paddingHorizontal: 8,
146
- paddingVertical: 3,
147
- borderRadius: 999,
148
- },
149
- currentPillText: {
150
- fontSize: 12,
151
- fontWeight: '600',
152
- },
153
- addIcon: {
154
- width: 44,
155
- height: 44,
156
- borderRadius: 22,
157
- alignItems: 'center',
158
- justifyContent: 'center',
159
- },
160
- });
161
-
162
- export default SignInAccountChooser;
@@ -1,530 +0,0 @@
1
- /**
2
- * SignInModal — web-first centered sign-in modal.
3
- *
4
- * Two phases, Google-style:
5
- * 1. Account chooser (FRONT screen, shown when the device/user already has
6
- * accounts): pick an account to continue as — one tap switches through the
7
- * SAME `switchToAccount` path the account switcher uses — or "Use another
8
- * account" to reveal the sign-in options.
9
- * 2. Sign-in options: the first-party password flow (identifier → password →
10
- * optional 2FA, `usePasswordSignIn`) as the PRIMARY action, with the
11
- * cross-app device flow (same-device deep-link + "sign in on another device"
12
- * QR) as a SECONDARY option below an "or" divider.
13
- *
14
- * When there are no accounts the modal opens straight on the sign-in options.
15
- * The device-flow machinery lives in the shared `useOxyAuthSession` hook (the
16
- * native `OxyAuthScreen` consumes it too — neither container re-implements the
17
- * transport). Animates with a fade + scale; per-phase content cross-fades and
18
- * respects reduced motion.
19
- */
20
-
21
- import type React from 'react';
22
- import { useState, useEffect, useCallback } from 'react';
23
- import { View, Text, TextInput, TouchableOpacity, StyleSheet, Modal, Linking, AccessibilityInfo } from 'react-native';
24
- import Animated, {
25
- useSharedValue,
26
- useAnimatedStyle,
27
- withTiming,
28
- FadeIn,
29
- } from 'react-native-reanimated';
30
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
31
- import { useTheme } from '@oxyhq/bloom/theme';
32
- import { Button } from '@oxyhq/bloom/button';
33
- import { Loading } from '@oxyhq/bloom/loading';
34
- import { toast } from '@oxyhq/bloom';
35
- import { Ionicons } from '@expo/vector-icons';
36
- import { isDev, logger as loggerUtil } from '@oxyhq/core';
37
- import { useOxy } from '../context/OxyContext';
38
- import OxyLogo from './OxyLogo';
39
- import AnotherDeviceQR from './AnotherDeviceQR';
40
- import SignInAccountChooser from './SignInAccountChooser';
41
- import { useSwitchableAccounts, type SwitchableAccount } from '../hooks/useSwitchableAccounts';
42
- import { useI18n } from '../hooks/useI18n';
43
- import { useOxyAuthSession, OXY_ACCOUNTS_WEB_URL } from '../hooks/useOxyAuthSession';
44
- import { usePasswordSignIn } from '../hooks/usePasswordSignIn';
45
-
46
- // Store for modal visibility with subscription support
47
- let modalVisible = false;
48
- let setModalVisibleCallback: ((visible: boolean) => void) | null = null;
49
- const visibilityListeners = new Set<(visible: boolean) => void>();
50
-
51
- export const showSignInModal = () => {
52
- modalVisible = true;
53
- setModalVisibleCallback?.(true);
54
- for (const listener of visibilityListeners) listener(true);
55
- };
56
-
57
- export const hideSignInModal = () => {
58
- modalVisible = false;
59
- setModalVisibleCallback?.(false);
60
- for (const listener of visibilityListeners) listener(false);
61
- };
62
-
63
- export const isSignInModalVisible = () => modalVisible;
64
-
65
- /** Subscribe to modal visibility changes */
66
- export const subscribeToSignInModal = (listener: (visible: boolean) => void): (() => void) => {
67
- visibilityListeners.add(listener);
68
- return () => visibilityListeners.delete(listener);
69
- };
70
-
71
- const SignInModal: React.FC = () => {
72
- const [visible, setVisible] = useState(false);
73
- const insets = useSafeAreaInsets();
74
- const theme = useTheme();
75
-
76
- // Register the imperative visibility callback.
77
- useEffect(() => {
78
- setModalVisibleCallback = setVisible;
79
- return () => {
80
- setModalVisibleCallback = null;
81
- };
82
- }, []);
83
-
84
- if (!visible) return null;
85
-
86
- // Mounting the content only while visible preserves the session-created-on-open
87
- // / cleaned-up-on-close behaviour and resets the phase state on every reopen.
88
- return <SignInModalContent theme={theme} insets={insets} />;
89
- };
90
-
91
- interface SignInModalContentProps {
92
- theme: ReturnType<typeof useTheme>;
93
- insets: ReturnType<typeof useSafeAreaInsets>;
94
- }
95
-
96
- const SignInModalContent: React.FC<SignInModalContentProps> = ({ theme, insets }) => {
97
- const { oxyServices, handleWebSession, clientId, switchToAccount } = useOxy();
98
- const { t } = useI18n();
99
- const { accounts } = useSwitchableAccounts();
100
-
101
- // Phase: the chooser is the front screen whenever accounts exist AND the user
102
- // has not tapped "Use another account" this session.
103
- const [useAnother, setUseAnother] = useState(false);
104
- const [switchingId, setSwitchingId] = useState<string | null>(null);
105
- const showChooser = !useAnother && accounts.length > 0;
106
-
107
- const { qrData, qrPayload, isLoading, error, isWaiting, openSameDeviceApproval, retry } = useOxyAuthSession(
108
- oxyServices,
109
- clientId,
110
- handleWebSession,
111
- { onSignedIn: hideSignInModal },
112
- );
113
-
114
- // First-party password sign-in — the PRIMARY option once past the chooser.
115
- const pw = usePasswordSignIn({ onSignedIn: hideSignInModal });
116
-
117
- // Entrance animation (respects reduced motion).
118
- const opacity = useSharedValue(0);
119
- const scale = useSharedValue(0.96);
120
- // biome-ignore lint/correctness/useExhaustiveDependencies: opacity/scale are Reanimated SharedValues (stable refs), not deps; runs once on mount.
121
- useEffect(() => {
122
- let cancelled = false;
123
- AccessibilityInfo.isReduceMotionEnabled().then((reduced) => {
124
- if (cancelled) return;
125
- const duration = reduced ? 0 : 250;
126
- opacity.value = withTiming(1, { duration });
127
- scale.value = withTiming(1, { duration });
128
- });
129
- return () => {
130
- cancelled = true;
131
- };
132
- }, []);
133
-
134
- const backdropStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
135
- const contentStyle = useAnimatedStyle(() => ({
136
- opacity: opacity.value,
137
- transform: [{ scale: scale.value }],
138
- }));
139
-
140
- const handleClose = useCallback(() => hideSignInModal(), []);
141
- const handleCreateAccount = useCallback(() => Linking.openURL(OXY_ACCOUNTS_WEB_URL), []);
142
-
143
- const handleSelectAccount = useCallback(async (account: SwitchableAccount) => {
144
- // The active account is already signed in — selecting it just continues.
145
- if (account.isCurrent) {
146
- hideSignInModal();
147
- return;
148
- }
149
- if (switchingId) return;
150
- setSwitchingId(account.accountId);
151
- try {
152
- await switchToAccount(account.accountId);
153
- hideSignInModal();
154
- } catch (switchError) {
155
- if (isDev()) {
156
- loggerUtil.warn('SignInModal: switch account failed', { component: 'SignInModal' }, switchError as unknown);
157
- }
158
- toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
159
- } finally {
160
- setSwitchingId(null);
161
- }
162
- }, [switchingId, switchToAccount, t]);
163
-
164
- const title = showChooser ? t('signin.chooser.title') : 'Sign in to Oxy';
165
- const subtitle = showChooser
166
- ? t('signin.chooser.subtitle')
167
- : 'Continue with your Oxy identity to sign in securely.';
168
-
169
- return (
170
- <Modal visible transparent animationType="none" statusBarTranslucent onRequestClose={handleClose}>
171
- <Animated.View style={[styles.backdrop, { backgroundColor: theme.colors.overlay }, backdropStyle]}>
172
- <TouchableOpacity style={StyleSheet.absoluteFill} onPress={handleClose} activeOpacity={1} />
173
-
174
- <Animated.View
175
- style={[
176
- styles.card,
177
- { backgroundColor: theme.colors.card, paddingTop: insets.top + 28, paddingBottom: insets.bottom + 24 },
178
- contentStyle,
179
- ]}
180
- >
181
- <TouchableOpacity
182
- style={[styles.closeButton, { backgroundColor: theme.colors.backgroundSecondary }]}
183
- onPress={handleClose}
184
- accessibilityRole="button"
185
- accessibilityLabel="Close sign in"
186
- >
187
- <Ionicons name="close" size={22} color={theme.colors.textSecondary} />
188
- </TouchableOpacity>
189
-
190
- {/* Branded header */}
191
- <View style={styles.header}>
192
- <OxyLogo variant="icon" size={52} />
193
- <Text className="text-foreground" style={styles.title}>{title}</Text>
194
- <Text className="text-muted-foreground" style={styles.subtitle}>{subtitle}</Text>
195
- </View>
196
-
197
- {showChooser ? (
198
- <Animated.View key="chooser" entering={FadeIn.duration(180)} style={styles.phase}>
199
- <SignInAccountChooser
200
- accounts={accounts}
201
- onSelectAccount={handleSelectAccount}
202
- onUseAnother={() => setUseAnother(true)}
203
- pendingAccountId={switchingId}
204
- disabled={switchingId !== null}
205
- />
206
- </Animated.View>
207
- ) : (
208
- <Animated.View key="signIn" entering={FadeIn.duration(180)} style={styles.phase}>
209
- {/* Back to the chooser when accounts exist. */}
210
- {accounts.length > 0 && (
211
- <TouchableOpacity
212
- onPress={() => setUseAnother(false)}
213
- accessibilityRole="button"
214
- style={styles.backRow}
215
- >
216
- <Ionicons name="chevron-back" size={18} color={theme.colors.textSecondary} />
217
- <Text style={[styles.backText, { color: theme.colors.textSecondary }]}>{t('signin.chooser.title')}</Text>
218
- </TouchableOpacity>
219
- )}
220
-
221
- {/* PRIMARY — first-party password sign-in. Always usable; the
222
- device-flow loading/error state below never gates it. */}
223
- <View style={styles.form}>
224
- {pw.step === 'identifier' && (
225
- <TextInput
226
- style={[styles.input, { borderColor: theme.colors.border, color: theme.colors.text, backgroundColor: theme.colors.backgroundSecondary }]}
227
- value={pw.identifier}
228
- onChangeText={pw.setIdentifier}
229
- onSubmitEditing={pw.submitIdentifier}
230
- placeholder="Username or email"
231
- placeholderTextColor={theme.colors.textSecondary}
232
- autoCapitalize="none"
233
- autoCorrect={false}
234
- keyboardType="email-address"
235
- returnKeyType="next"
236
- accessibilityLabel="Username or email"
237
- />
238
- )}
239
-
240
- {pw.step === 'password' && (
241
- <>
242
- <Text style={[styles.contextText, { color: theme.colors.textSecondary }]}>{pw.identifier}</Text>
243
- <TextInput
244
- style={[styles.input, { borderColor: theme.colors.border, color: theme.colors.text, backgroundColor: theme.colors.backgroundSecondary }]}
245
- value={pw.password}
246
- onChangeText={pw.setPassword}
247
- onSubmitEditing={pw.submitPassword}
248
- placeholder="Password"
249
- placeholderTextColor={theme.colors.textSecondary}
250
- secureTextEntry
251
- autoCapitalize="none"
252
- autoCorrect={false}
253
- returnKeyType="go"
254
- accessibilityLabel="Password"
255
- />
256
- </>
257
- )}
258
-
259
- {pw.step === 'twoFactor' && (
260
- <TextInput
261
- style={[styles.input, { borderColor: theme.colors.border, color: theme.colors.text, backgroundColor: theme.colors.backgroundSecondary }]}
262
- value={pw.code}
263
- onChangeText={pw.setCode}
264
- onSubmitEditing={pw.submitTwoFactor}
265
- placeholder={pw.useBackupCode ? 'Backup code' : '6-digit code'}
266
- placeholderTextColor={theme.colors.textSecondary}
267
- autoCapitalize="none"
268
- autoCorrect={false}
269
- keyboardType={pw.useBackupCode ? 'default' : 'number-pad'}
270
- returnKeyType="go"
271
- accessibilityLabel={pw.useBackupCode ? 'Backup code' : 'Two-factor code'}
272
- />
273
- )}
274
-
275
- <Button
276
- variant="primary"
277
- onPress={
278
- pw.step === 'identifier' ? pw.submitIdentifier
279
- : pw.step === 'password' ? pw.submitPassword
280
- : pw.submitTwoFactor
281
- }
282
- loading={pw.isSubmitting}
283
- disabled={pw.isSubmitting}
284
- style={styles.primaryButton}
285
- >
286
- {pw.step === 'identifier' ? 'Continue' : pw.step === 'password' ? 'Sign in' : 'Verify'}
287
- </Button>
288
-
289
- {pw.error && (
290
- <Text className="text-destructive" style={styles.formError}>{pw.error}</Text>
291
- )}
292
-
293
- {pw.step === 'twoFactor' && (
294
- <TouchableOpacity onPress={() => pw.setUseBackupCode(!pw.useBackupCode)} accessibilityRole="button" style={styles.linkButton}>
295
- <Text style={[styles.linkText, { color: theme.colors.primary }]}>
296
- {pw.useBackupCode ? 'Use authenticator code' : 'Use a backup code'}
297
- </Text>
298
- </TouchableOpacity>
299
- )}
300
-
301
- {pw.step !== 'identifier' && (
302
- <TouchableOpacity onPress={pw.back} accessibilityRole="button" style={styles.linkButton}>
303
- <Text style={[styles.linkText, { color: theme.colors.textSecondary }]}>Back</Text>
304
- </TouchableOpacity>
305
- )}
306
- </View>
307
-
308
- {/* "or" divider */}
309
- <View style={styles.dividerRow}>
310
- <View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
311
- <Text style={[styles.dividerText, { color: theme.colors.textSecondary }]}>or</Text>
312
- <View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
313
- </View>
314
-
315
- {/* SECONDARY — cross-app device flow. Its loading/error state gates
316
- ONLY this section; the password form above is always usable. */}
317
- {isLoading ? (
318
- <View style={styles.deviceLoading}>
319
- <Loading size="small" style={styles.statusSpinner} />
320
- <Text style={[styles.statusText, { color: theme.colors.textSecondary }]}>Preparing sign in…</Text>
321
- </View>
322
- ) : error ? (
323
- <View style={styles.errorContainer}>
324
- <Text className="text-destructive" style={styles.errorText}>{error}</Text>
325
- <Button variant="secondary" onPress={retry} style={styles.secondaryButton}>Try Again</Button>
326
- </View>
327
- ) : (
328
- <>
329
- {qrPayload && (
330
- <Button
331
- variant="secondary"
332
- onPress={openSameDeviceApproval}
333
- icon={<OxyLogo variant="icon" size={20} fillColor={theme.colors.text} style={styles.buttonIcon} />}
334
- style={styles.secondaryButton}
335
- >
336
- Sign in with the Oxy app
337
- </Button>
338
- )}
339
-
340
- {isWaiting && (
341
- <View style={styles.statusContainer}>
342
- <Loading size="small" style={styles.statusSpinner} />
343
- <Text style={[styles.statusText, { color: theme.colors.textSecondary }]}>Waiting for authorization…</Text>
344
- </View>
345
- )}
346
-
347
- <View style={styles.qrSection}>
348
- <AnotherDeviceQR qrData={qrData} qrPayload={qrPayload} />
349
- </View>
350
- </>
351
- )}
352
- </Animated.View>
353
- )}
354
-
355
- {/* Footer — create an account */}
356
- <View style={styles.footer}>
357
- <Text style={styles.footerText} className="text-muted-foreground">
358
- Don't have an Oxy account?{' '}
359
- </Text>
360
- <TouchableOpacity onPress={handleCreateAccount} accessibilityRole="link">
361
- <Text style={styles.footerLink} className="text-primary">Create one</Text>
362
- </TouchableOpacity>
363
- </View>
364
- </Animated.View>
365
- </Animated.View>
366
- </Modal>
367
- );
368
- };
369
-
370
- const styles = StyleSheet.create({
371
- backdrop: {
372
- flex: 1,
373
- justifyContent: 'center',
374
- alignItems: 'center',
375
- },
376
- card: {
377
- width: '100%',
378
- maxWidth: 420,
379
- alignItems: 'center',
380
- paddingHorizontal: 24,
381
- borderRadius: 28,
382
- },
383
- closeButton: {
384
- position: 'absolute',
385
- top: 16,
386
- right: 16,
387
- width: 36,
388
- height: 36,
389
- borderRadius: 18,
390
- justifyContent: 'center',
391
- alignItems: 'center',
392
- zIndex: 10,
393
- },
394
- header: {
395
- alignItems: 'center',
396
- marginBottom: 24,
397
- },
398
- title: {
399
- fontSize: 26,
400
- fontWeight: '800',
401
- letterSpacing: -0.5,
402
- marginTop: 16,
403
- textAlign: 'center',
404
- },
405
- subtitle: {
406
- fontSize: 15,
407
- lineHeight: 21,
408
- marginTop: 8,
409
- textAlign: 'center',
410
- },
411
- phase: {
412
- width: '100%',
413
- },
414
- backRow: {
415
- flexDirection: 'row',
416
- alignItems: 'center',
417
- gap: 4,
418
- alignSelf: 'flex-start',
419
- paddingVertical: 6,
420
- marginBottom: 8,
421
- },
422
- backText: {
423
- fontSize: 14,
424
- fontWeight: '600',
425
- },
426
- primaryButton: {
427
- width: '100%',
428
- borderRadius: 12,
429
- },
430
- secondaryButton: {
431
- width: '100%',
432
- borderRadius: 12,
433
- marginTop: 12,
434
- },
435
- buttonIcon: {
436
- marginRight: 10,
437
- },
438
- form: {
439
- width: '100%',
440
- },
441
- input: {
442
- width: '100%',
443
- borderWidth: 1,
444
- borderRadius: 12,
445
- paddingHorizontal: 16,
446
- paddingVertical: 13,
447
- fontSize: 15,
448
- marginBottom: 12,
449
- },
450
- contextText: {
451
- fontSize: 14,
452
- textAlign: 'center',
453
- marginBottom: 12,
454
- },
455
- formError: {
456
- fontSize: 14,
457
- textAlign: 'center',
458
- marginTop: 12,
459
- },
460
- linkButton: {
461
- alignSelf: 'center',
462
- paddingVertical: 8,
463
- marginTop: 8,
464
- },
465
- linkText: {
466
- fontSize: 14,
467
- fontWeight: '600',
468
- },
469
- dividerRow: {
470
- flexDirection: 'row',
471
- alignItems: 'center',
472
- width: '100%',
473
- marginVertical: 20,
474
- },
475
- dividerLine: {
476
- flex: 1,
477
- height: 1,
478
- },
479
- dividerText: {
480
- marginHorizontal: 12,
481
- fontSize: 13,
482
- },
483
- deviceLoading: {
484
- flexDirection: 'row',
485
- alignItems: 'center',
486
- justifyContent: 'center',
487
- paddingVertical: 12,
488
- },
489
- statusContainer: {
490
- flexDirection: 'row',
491
- alignItems: 'center',
492
- marginTop: 20,
493
- },
494
- statusSpinner: {
495
- flex: undefined,
496
- },
497
- statusText: {
498
- marginLeft: 8,
499
- fontSize: 14,
500
- },
501
- qrSection: {
502
- width: '100%',
503
- marginTop: 24,
504
- },
505
- errorContainer: {
506
- alignItems: 'center',
507
- paddingVertical: 20,
508
- width: '100%',
509
- },
510
- errorText: {
511
- fontSize: 14,
512
- textAlign: 'center',
513
- marginBottom: 16,
514
- },
515
- footer: {
516
- flexDirection: 'row',
517
- flexWrap: 'wrap',
518
- justifyContent: 'center',
519
- marginTop: 28,
520
- },
521
- footerText: {
522
- fontSize: 14,
523
- },
524
- footerLink: {
525
- fontSize: 14,
526
- fontWeight: '600',
527
- },
528
- });
529
-
530
- export default SignInModal;