@oxyhq/services 15.0.0 → 17.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.
- package/lib/commonjs/index.js +25 -55
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +0 -14
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js +764 -0
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +11 -6
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +10 -21
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +25 -112
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/RequireOxyAuth.js +299 -0
- package/lib/commonjs/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +106 -2
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/mutationKeys.js +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +10 -10
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +7 -8
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +19 -30
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +37 -267
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/commonjs/ui/index.js +5 -40
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +91 -0
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/commonjs/ui/navigation/routes.js +0 -2
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +17 -18
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/session/createSessionClient.js +10 -2
- package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
- package/lib/module/index.js +20 -17
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +1 -2
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialog.js +761 -0
- package/lib/module/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +11 -6
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +10 -21
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +26 -112
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/RequireOxyAuth.js +294 -0
- package/lib/module/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +107 -3
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/mutations/mutationKeys.js +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +8 -8
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +5 -6
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +19 -30
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useSwitchableAccounts.js +38 -267
- package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/module/ui/index.js +1 -5
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +81 -0
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/module/ui/navigation/routes.js +0 -2
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js +19 -20
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/session/createSessionClient.js +10 -2
- package/lib/module/ui/session/createSessionClient.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +6 -13
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +0 -4
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +4 -4
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +6 -7
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +2 -5
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/storageHelpers.d.ts +7 -7
- package/lib/typescript/module/index.d.ts +6 -13
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +0 -4
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +4 -4
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +6 -7
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +2 -5
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -0
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/storageHelpers.d.ts +7 -7
- package/package.json +4 -4
- package/src/index.ts +23 -28
- package/src/ui/client.ts +0 -4
- package/src/ui/components/OxyAccountDialog.tsx +760 -0
- package/src/ui/components/OxyProvider.tsx +12 -6
- package/src/ui/components/OxySignInButton.tsx +10 -21
- package/src/ui/components/ProfileButton.tsx +23 -126
- package/src/ui/components/RequireOxyAuth.tsx +266 -0
- package/src/ui/context/OxyContext.tsx +146 -7
- package/src/ui/hooks/mutations/mutationKeys.ts +1 -1
- package/src/ui/hooks/mutations/useAccountMutations.ts +8 -8
- package/src/ui/hooks/queries/queryKeys.ts +1 -1
- package/src/ui/hooks/queries/useAccountQueries.ts +8 -9
- package/src/ui/hooks/useAuth.ts +19 -31
- package/src/ui/hooks/useSwitchableAccounts.ts +42 -376
- package/src/ui/index.ts +2 -5
- package/src/ui/navigation/accountDialogManager.ts +84 -0
- package/src/ui/navigation/routes.ts +1 -5
- package/src/ui/screens/ConnectedAppsScreen.tsx +23 -24
- package/src/ui/screens/ManageAccountScreen.tsx +3 -2
- package/src/ui/session/createSessionClient.ts +9 -1
- package/src/ui/types/navigation.ts +9 -0
- package/src/ui/utils/storageHelpers.ts +7 -7
- package/lib/commonjs/ui/components/AccountMenu.js +0 -598
- package/lib/commonjs/ui/components/AccountMenu.js.map +0 -1
- package/lib/commonjs/ui/components/AccountMenuButton.js +0 -135
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/commonjs/ui/components/AccountSwitcher.js +0 -780
- package/lib/commonjs/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/commonjs/ui/components/AnotherDeviceQR.js +0 -116
- package/lib/commonjs/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/commonjs/ui/components/ProfileMenu.js +0 -518
- package/lib/commonjs/ui/components/ProfileMenu.js.map +0 -1
- package/lib/commonjs/ui/components/SignInAccountChooser.js +0 -189
- package/lib/commonjs/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/commonjs/ui/components/SignInModal.js +0 -600
- package/lib/commonjs/ui/components/SignInModal.js.map +0 -1
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js +0 -501
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js +0 -170
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -51
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +0 -312
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/commonjs/utils/deviceFlowSignIn.js +0 -109
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/module/ui/components/AccountMenu.js +0 -593
- package/lib/module/ui/components/AccountMenu.js.map +0 -1
- package/lib/module/ui/components/AccountMenuButton.js +0 -130
- package/lib/module/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/module/ui/components/AccountSwitcher.js +0 -774
- package/lib/module/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/module/ui/components/AnotherDeviceQR.js +0 -110
- package/lib/module/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/module/ui/components/ProfileMenu.js +0 -514
- package/lib/module/ui/components/ProfileMenu.js.map +0 -1
- package/lib/module/ui/components/SignInAccountChooser.js +0 -183
- package/lib/module/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/module/ui/components/SignInModal.js +0 -591
- package/lib/module/ui/components/SignInModal.js.map +0 -1
- package/lib/module/ui/hooks/useOxyAuthSession.js +0 -495
- package/lib/module/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/module/ui/hooks/usePasswordSignIn.js +0 -165
- package/lib/module/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -48
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +0 -306
- package/lib/module/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/module/utils/deviceFlowSignIn.js +0 -106
- package/lib/module/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/module/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/src/ui/components/AccountMenu.tsx +0 -645
- package/src/ui/components/AccountMenuButton.tsx +0 -126
- package/src/ui/components/AccountSwitcher.tsx +0 -751
- package/src/ui/components/AnotherDeviceQR.tsx +0 -119
- package/src/ui/components/ProfileMenu.tsx +0 -564
- package/src/ui/components/SignInAccountChooser.tsx +0 -162
- package/src/ui/components/SignInModal.tsx +0 -530
- package/src/ui/hooks/useOxyAuthSession.ts +0 -635
- package/src/ui/hooks/usePasswordSignIn.ts +0 -207
- package/src/ui/screens/AccountSwitcherScreen.tsx +0 -43
- package/src/ui/screens/OxyAuthScreen.tsx +0 -324
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +0 -231
- package/src/utils/deviceFlowSignIn.ts +0 -152
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `usePasswordSignIn` — the first-party password sign-in state machine.
|
|
3
|
-
*
|
|
4
|
-
* Drives the in-app "Sign in with Oxy" password flow shared by the web
|
|
5
|
-
* `SignInModal` and the native `OxyAuthScreen`: identifier → password → optional
|
|
6
|
-
* two-factor. It is a thin UI state machine over the context methods
|
|
7
|
-
* `signInWithPassword` + `completeTwoFactorSignIn` (which own the network call,
|
|
8
|
-
* the persisted-refresh commit, and the device-set registration) — so both
|
|
9
|
-
* surfaces present an identical flow without re-implementing any transport.
|
|
10
|
-
*
|
|
11
|
-
* On a committed session `onSignedIn` fires (the modal/screen closes); the
|
|
12
|
-
* device-first cold boot / SessionClient projection then drive the app into the
|
|
13
|
-
* authenticated state.
|
|
14
|
-
*/
|
|
15
|
-
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
16
|
-
import { useOxy } from '../context/OxyContext';
|
|
17
|
-
import { handleAuthError } from '../utils/errorHandlers';
|
|
18
|
-
|
|
19
|
-
export type PasswordSignInStep = 'identifier' | 'password' | 'twoFactor';
|
|
20
|
-
|
|
21
|
-
export interface UsePasswordSignInOptions {
|
|
22
|
-
/** Fired once a session has been committed (the surface should close). */
|
|
23
|
-
onSignedIn?: () => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface UsePasswordSignInResult {
|
|
27
|
-
step: PasswordSignInStep;
|
|
28
|
-
identifier: string;
|
|
29
|
-
setIdentifier: (value: string) => void;
|
|
30
|
-
password: string;
|
|
31
|
-
setPassword: (value: string) => void;
|
|
32
|
-
/** The current 2FA input — a TOTP code or a backup code, per `useBackupCode`. */
|
|
33
|
-
code: string;
|
|
34
|
-
setCode: (value: string) => void;
|
|
35
|
-
useBackupCode: boolean;
|
|
36
|
-
setUseBackupCode: (value: boolean) => void;
|
|
37
|
-
error: string | null;
|
|
38
|
-
isSubmitting: boolean;
|
|
39
|
-
/** Advance identifier → password (validates a non-empty identifier). */
|
|
40
|
-
submitIdentifier: () => void;
|
|
41
|
-
/** Submit the password: commits a one-step session, or advances to 2FA. */
|
|
42
|
-
submitPassword: () => Promise<void>;
|
|
43
|
-
/** Submit the 2FA code / backup code and commit the session. */
|
|
44
|
-
submitTwoFactor: () => Promise<void>;
|
|
45
|
-
/** Step back one screen (2FA → password → identifier), clearing the error. */
|
|
46
|
-
back: () => void;
|
|
47
|
-
/** Reset every field back to the identifier step. */
|
|
48
|
-
reset: () => void;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function usePasswordSignIn(options: UsePasswordSignInOptions = {}): UsePasswordSignInResult {
|
|
52
|
-
const { signInWithPassword, completeTwoFactorSignIn } = useOxy();
|
|
53
|
-
const { onSignedIn } = options;
|
|
54
|
-
|
|
55
|
-
const [step, setStep] = useState<PasswordSignInStep>('identifier');
|
|
56
|
-
const [identifier, setIdentifier] = useState('');
|
|
57
|
-
const [password, setPassword] = useState('');
|
|
58
|
-
const [code, setCode] = useState('');
|
|
59
|
-
const [useBackupCode, setUseBackupCode] = useState(false);
|
|
60
|
-
const [error, setError] = useState<string | null>(null);
|
|
61
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
62
|
-
const [loginToken, setLoginToken] = useState<string | null>(null);
|
|
63
|
-
|
|
64
|
-
// Synchronous in-flight guard. `isSubmitting` state drives the UI, but a rapid
|
|
65
|
-
// double-tap fires both handlers in the SAME tick — before React re-renders —
|
|
66
|
-
// so a state read would still see `false` on the second call and double-fire
|
|
67
|
-
// the network request (rate-limit + race). This ref is set/checked
|
|
68
|
-
// synchronously, so the second call is a true no-op.
|
|
69
|
-
const submittingRef = useRef(false);
|
|
70
|
-
|
|
71
|
-
const surfaceError = useCallback((err: unknown, defaultMessage: string): void => {
|
|
72
|
-
setError(handleAuthError(err, { defaultMessage, code: 'PASSWORD_SIGN_IN_ERROR' }));
|
|
73
|
-
}, []);
|
|
74
|
-
|
|
75
|
-
const submitIdentifier = useCallback(() => {
|
|
76
|
-
if (!identifier.trim()) {
|
|
77
|
-
setError('Enter your username or email');
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
setError(null);
|
|
81
|
-
setStep('password');
|
|
82
|
-
}, [identifier]);
|
|
83
|
-
|
|
84
|
-
const submitPassword = useCallback(async () => {
|
|
85
|
-
// A second call while one is already in flight is a no-op (double-tap guard).
|
|
86
|
-
if (submittingRef.current) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (!password) {
|
|
90
|
-
setError('Enter your password');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
setError(null);
|
|
94
|
-
submittingRef.current = true;
|
|
95
|
-
setIsSubmitting(true);
|
|
96
|
-
try {
|
|
97
|
-
const result = await signInWithPassword(identifier.trim(), password);
|
|
98
|
-
if (result.status === '2fa_required') {
|
|
99
|
-
setLoginToken(result.loginToken);
|
|
100
|
-
setCode('');
|
|
101
|
-
setUseBackupCode(false);
|
|
102
|
-
setStep('twoFactor');
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
onSignedIn?.();
|
|
106
|
-
} catch (err) {
|
|
107
|
-
surfaceError(err, 'Sign in failed');
|
|
108
|
-
} finally {
|
|
109
|
-
submittingRef.current = false;
|
|
110
|
-
setIsSubmitting(false);
|
|
111
|
-
}
|
|
112
|
-
}, [identifier, password, signInWithPassword, onSignedIn, surfaceError]);
|
|
113
|
-
|
|
114
|
-
const submitTwoFactor = useCallback(async () => {
|
|
115
|
-
// A second call while one is already in flight is a no-op (double-tap guard).
|
|
116
|
-
if (submittingRef.current) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (!loginToken) {
|
|
120
|
-
setError('Your sign-in session expired. Start again.');
|
|
121
|
-
setStep('password');
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (!code.trim()) {
|
|
125
|
-
setError(useBackupCode ? 'Enter a backup code' : 'Enter your 6-digit code');
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
setError(null);
|
|
129
|
-
submittingRef.current = true;
|
|
130
|
-
setIsSubmitting(true);
|
|
131
|
-
try {
|
|
132
|
-
await completeTwoFactorSignIn({
|
|
133
|
-
loginToken,
|
|
134
|
-
...(useBackupCode ? { backupCode: code.trim() } : { token: code.trim() }),
|
|
135
|
-
});
|
|
136
|
-
onSignedIn?.();
|
|
137
|
-
} catch (err) {
|
|
138
|
-
surfaceError(err, 'Verification failed');
|
|
139
|
-
} finally {
|
|
140
|
-
submittingRef.current = false;
|
|
141
|
-
setIsSubmitting(false);
|
|
142
|
-
}
|
|
143
|
-
}, [loginToken, code, useBackupCode, completeTwoFactorSignIn, onSignedIn, surfaceError]);
|
|
144
|
-
|
|
145
|
-
const back = useCallback(() => {
|
|
146
|
-
setError(null);
|
|
147
|
-
setStep((current) => {
|
|
148
|
-
if (current === 'twoFactor') {
|
|
149
|
-
setLoginToken(null);
|
|
150
|
-
setCode('');
|
|
151
|
-
return 'password';
|
|
152
|
-
}
|
|
153
|
-
if (current === 'password') {
|
|
154
|
-
setPassword('');
|
|
155
|
-
return 'identifier';
|
|
156
|
-
}
|
|
157
|
-
return current;
|
|
158
|
-
});
|
|
159
|
-
}, []);
|
|
160
|
-
|
|
161
|
-
const reset = useCallback(() => {
|
|
162
|
-
setStep('identifier');
|
|
163
|
-
setIdentifier('');
|
|
164
|
-
setPassword('');
|
|
165
|
-
setCode('');
|
|
166
|
-
setUseBackupCode(false);
|
|
167
|
-
setLoginToken(null);
|
|
168
|
-
setError(null);
|
|
169
|
-
submittingRef.current = false;
|
|
170
|
-
setIsSubmitting(false);
|
|
171
|
-
}, []);
|
|
172
|
-
|
|
173
|
-
return useMemo(
|
|
174
|
-
() => ({
|
|
175
|
-
step,
|
|
176
|
-
identifier,
|
|
177
|
-
setIdentifier,
|
|
178
|
-
password,
|
|
179
|
-
setPassword,
|
|
180
|
-
code,
|
|
181
|
-
setCode,
|
|
182
|
-
useBackupCode,
|
|
183
|
-
setUseBackupCode,
|
|
184
|
-
error,
|
|
185
|
-
isSubmitting,
|
|
186
|
-
submitIdentifier,
|
|
187
|
-
submitPassword,
|
|
188
|
-
submitTwoFactor,
|
|
189
|
-
back,
|
|
190
|
-
reset,
|
|
191
|
-
}),
|
|
192
|
-
[
|
|
193
|
-
step,
|
|
194
|
-
identifier,
|
|
195
|
-
password,
|
|
196
|
-
code,
|
|
197
|
-
useBackupCode,
|
|
198
|
-
error,
|
|
199
|
-
isSubmitting,
|
|
200
|
-
submitIdentifier,
|
|
201
|
-
submitPassword,
|
|
202
|
-
submitTwoFactor,
|
|
203
|
-
back,
|
|
204
|
-
reset,
|
|
205
|
-
],
|
|
206
|
-
);
|
|
207
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
|
-
import { View } from 'react-native';
|
|
4
|
-
import type { BaseScreenProps } from '../types/navigation';
|
|
5
|
-
import Header from '../components/Header';
|
|
6
|
-
import { AccountSwitcherView } from '../components/AccountSwitcher';
|
|
7
|
-
import { useI18n } from '../hooks/useI18n';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Bottom-sheet route wrapper around {@link AccountSwitcherView}. Used when the
|
|
11
|
-
* switcher is opened as a sheet (e.g. from the "Your accounts" entry in
|
|
12
|
-
* ManageAccount) rather than as the header-chip popover (which uses the
|
|
13
|
-
* `AccountSwitcher` modal directly).
|
|
14
|
-
*/
|
|
15
|
-
const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, navigate }) => {
|
|
16
|
-
const { t } = useI18n();
|
|
17
|
-
|
|
18
|
-
const close = useCallback(() => {
|
|
19
|
-
(onClose ?? goBack)?.();
|
|
20
|
-
}, [onClose, goBack]);
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<View className="flex-1 bg-bg">
|
|
24
|
-
<Header
|
|
25
|
-
title={t('accountSwitcher.title') || 'Switch account'}
|
|
26
|
-
onBack={goBack}
|
|
27
|
-
onClose={onClose}
|
|
28
|
-
showBackButton={!!goBack}
|
|
29
|
-
showCloseButton={!!onClose}
|
|
30
|
-
elevation="subtle"
|
|
31
|
-
/>
|
|
32
|
-
<AccountSwitcherView
|
|
33
|
-
onClose={close}
|
|
34
|
-
onAddAccount={() => navigate?.('OxyAuth')}
|
|
35
|
-
onNavigateManage={() => navigate?.('ManageAccount')}
|
|
36
|
-
onCreateAccount={() => navigate?.('CreateAccount')}
|
|
37
|
-
onOpenAccountSettings={(accountId) => navigate?.('AccountSettings', { accountId })}
|
|
38
|
-
/>
|
|
39
|
-
</View>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default AccountSwitcherScreen;
|
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OxyAuthScreen — Sign in with Oxy (native bottom-sheet container).
|
|
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
|
-
* The device-flow machinery lives in the shared `useOxyAuthSession` hook (the
|
|
15
|
-
* web `SignInModal` consumes it too). This screen should NOT be used within the
|
|
16
|
-
* Oxy Accounts app itself.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import type React from 'react';
|
|
20
|
-
import { useCallback, useState } from 'react';
|
|
21
|
-
import { View, TextInput, Linking, type TextStyle } from 'react-native';
|
|
22
|
-
import type { BaseScreenProps } from '../types/navigation';
|
|
23
|
-
import { useTheme } from '@oxyhq/bloom/theme';
|
|
24
|
-
import { Button } from '@oxyhq/bloom/button';
|
|
25
|
-
import { Loading } from '@oxyhq/bloom/loading';
|
|
26
|
-
import { H4, Text } from '@oxyhq/bloom/typography';
|
|
27
|
-
import { IconCircle } from '@oxyhq/bloom/icon-circle';
|
|
28
|
-
import * as Icons from '@oxyhq/bloom/icons';
|
|
29
|
-
import { toast } from '@oxyhq/bloom';
|
|
30
|
-
import { isDev, logger as loggerUtil } from '@oxyhq/core';
|
|
31
|
-
import { useOxy } from '../context/OxyContext';
|
|
32
|
-
import OxyLogo from '../components/OxyLogo';
|
|
33
|
-
import AnotherDeviceQR from '../components/AnotherDeviceQR';
|
|
34
|
-
import LoadingState from '../components/LoadingState';
|
|
35
|
-
import SignInAccountChooser from '../components/SignInAccountChooser';
|
|
36
|
-
import { useSwitchableAccounts, type SwitchableAccount } from '../hooks/useSwitchableAccounts';
|
|
37
|
-
import { useI18n } from '../hooks/useI18n';
|
|
38
|
-
import { useOxyAuthSession, OXY_ACCOUNTS_WEB_URL } from '../hooks/useOxyAuthSession';
|
|
39
|
-
import { usePasswordSignIn } from '../hooks/usePasswordSignIn';
|
|
40
|
-
|
|
41
|
-
const OxyAuthScreen: React.FC<BaseScreenProps> = ({ goBack, onAuthenticated }) => {
|
|
42
|
-
const bloomTheme = useTheme();
|
|
43
|
-
const { oxyServices, handleWebSession, clientId, switchToAccount } = useOxy();
|
|
44
|
-
const { t } = useI18n();
|
|
45
|
-
const { accounts } = useSwitchableAccounts();
|
|
46
|
-
|
|
47
|
-
const [useAnother, setUseAnother] = useState(false);
|
|
48
|
-
const [switchingId, setSwitchingId] = useState<string | null>(null);
|
|
49
|
-
const showChooser = !useAnother && accounts.length > 0;
|
|
50
|
-
|
|
51
|
-
const { qrData, qrPayload, isLoading, error, isWaiting, openSameDeviceApproval, retry } = useOxyAuthSession(
|
|
52
|
-
oxyServices,
|
|
53
|
-
clientId,
|
|
54
|
-
handleWebSession,
|
|
55
|
-
{ onSignedIn: onAuthenticated },
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const pw = usePasswordSignIn({ onSignedIn: onAuthenticated });
|
|
59
|
-
|
|
60
|
-
const handleSelectAccount = useCallback(async (account: SwitchableAccount) => {
|
|
61
|
-
if (account.isCurrent) {
|
|
62
|
-
onAuthenticated?.();
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (switchingId) return;
|
|
66
|
-
setSwitchingId(account.accountId);
|
|
67
|
-
try {
|
|
68
|
-
await switchToAccount(account.accountId);
|
|
69
|
-
onAuthenticated?.();
|
|
70
|
-
} catch (switchError) {
|
|
71
|
-
if (isDev()) {
|
|
72
|
-
loggerUtil.warn('OxyAuthScreen: switch account failed', { component: 'OxyAuthScreen' }, switchError as unknown);
|
|
73
|
-
}
|
|
74
|
-
toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
|
|
75
|
-
} finally {
|
|
76
|
-
setSwitchingId(null);
|
|
77
|
-
}
|
|
78
|
-
}, [switchingId, switchToAccount, onAuthenticated, t]);
|
|
79
|
-
|
|
80
|
-
const inputStyle: TextStyle = {
|
|
81
|
-
width: '100%',
|
|
82
|
-
borderWidth: 1,
|
|
83
|
-
borderRadius: 12,
|
|
84
|
-
paddingHorizontal: 16,
|
|
85
|
-
paddingVertical: 13,
|
|
86
|
-
fontSize: 15,
|
|
87
|
-
marginBottom: 12,
|
|
88
|
-
borderColor: bloomTheme.colors.border,
|
|
89
|
-
color: bloomTheme.colors.text,
|
|
90
|
-
backgroundColor: bloomTheme.colors.backgroundSecondary,
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const title = showChooser ? t('signin.chooser.title') : 'Sign in to Oxy';
|
|
94
|
-
const subtitle = showChooser
|
|
95
|
-
? t('signin.chooser.subtitle')
|
|
96
|
-
: 'Continue with your Oxy identity to sign in securely';
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<View className="flex-1 items-center justify-center bg-bg px-screen-margin">
|
|
100
|
-
{/* Branded header */}
|
|
101
|
-
<View className="items-center mb-space-24 gap-space-12">
|
|
102
|
-
<OxyLogo variant="icon" size={52} />
|
|
103
|
-
<H4 className="text-headerBold font-headerBold text-text text-center">{title}</H4>
|
|
104
|
-
<Text className="font-sans text-body text-text-secondary text-center">{subtitle}</Text>
|
|
105
|
-
</View>
|
|
106
|
-
|
|
107
|
-
{showChooser ? (
|
|
108
|
-
<SignInAccountChooser
|
|
109
|
-
accounts={accounts}
|
|
110
|
-
onSelectAccount={handleSelectAccount}
|
|
111
|
-
onUseAnother={() => setUseAnother(true)}
|
|
112
|
-
pendingAccountId={switchingId}
|
|
113
|
-
disabled={switchingId !== null}
|
|
114
|
-
/>
|
|
115
|
-
) : (
|
|
116
|
-
<>
|
|
117
|
-
{/* Back to the chooser when accounts exist. */}
|
|
118
|
-
{accounts.length > 0 && (
|
|
119
|
-
<Button
|
|
120
|
-
variant="text"
|
|
121
|
-
size="small"
|
|
122
|
-
className="self-start mb-space-8"
|
|
123
|
-
onPress={() => setUseAnother(false)}
|
|
124
|
-
accessibilityLabel="Choose an account"
|
|
125
|
-
icon={<Icons.ArrowLeft_Stroke2_Corner0_Rounded size="sm" style={{ color: bloomTheme.colors.textSecondary }} />}
|
|
126
|
-
>
|
|
127
|
-
Choose an account
|
|
128
|
-
</Button>
|
|
129
|
-
)}
|
|
130
|
-
|
|
131
|
-
{/* PRIMARY — first-party password sign-in. Always usable; the device-flow
|
|
132
|
-
loading/error state below never gates it. */}
|
|
133
|
-
<View className="w-full">
|
|
134
|
-
{pw.step === 'identifier' && (
|
|
135
|
-
<TextInput
|
|
136
|
-
style={inputStyle}
|
|
137
|
-
value={pw.identifier}
|
|
138
|
-
onChangeText={pw.setIdentifier}
|
|
139
|
-
onSubmitEditing={pw.submitIdentifier}
|
|
140
|
-
placeholder="Username or email"
|
|
141
|
-
placeholderTextColor={bloomTheme.colors.textSecondary}
|
|
142
|
-
autoCapitalize="none"
|
|
143
|
-
autoCorrect={false}
|
|
144
|
-
keyboardType="email-address"
|
|
145
|
-
returnKeyType="next"
|
|
146
|
-
accessibilityLabel="Username or email"
|
|
147
|
-
/>
|
|
148
|
-
)}
|
|
149
|
-
|
|
150
|
-
{pw.step === 'password' && (
|
|
151
|
-
<>
|
|
152
|
-
<Text className="font-sans text-body text-text-secondary text-center mb-space-12">
|
|
153
|
-
{pw.identifier}
|
|
154
|
-
</Text>
|
|
155
|
-
<TextInput
|
|
156
|
-
style={inputStyle}
|
|
157
|
-
value={pw.password}
|
|
158
|
-
onChangeText={pw.setPassword}
|
|
159
|
-
onSubmitEditing={pw.submitPassword}
|
|
160
|
-
placeholder="Password"
|
|
161
|
-
placeholderTextColor={bloomTheme.colors.textSecondary}
|
|
162
|
-
secureTextEntry
|
|
163
|
-
autoCapitalize="none"
|
|
164
|
-
autoCorrect={false}
|
|
165
|
-
returnKeyType="go"
|
|
166
|
-
accessibilityLabel="Password"
|
|
167
|
-
/>
|
|
168
|
-
</>
|
|
169
|
-
)}
|
|
170
|
-
|
|
171
|
-
{pw.step === 'twoFactor' && (
|
|
172
|
-
<TextInput
|
|
173
|
-
style={inputStyle}
|
|
174
|
-
value={pw.code}
|
|
175
|
-
onChangeText={pw.setCode}
|
|
176
|
-
onSubmitEditing={pw.submitTwoFactor}
|
|
177
|
-
placeholder={pw.useBackupCode ? 'Backup code' : '6-digit code'}
|
|
178
|
-
placeholderTextColor={bloomTheme.colors.textSecondary}
|
|
179
|
-
autoCapitalize="none"
|
|
180
|
-
autoCorrect={false}
|
|
181
|
-
keyboardType={pw.useBackupCode ? 'default' : 'number-pad'}
|
|
182
|
-
returnKeyType="go"
|
|
183
|
-
accessibilityLabel={pw.useBackupCode ? 'Backup code' : 'Two-factor code'}
|
|
184
|
-
/>
|
|
185
|
-
)}
|
|
186
|
-
|
|
187
|
-
<Button
|
|
188
|
-
variant="primary"
|
|
189
|
-
size="large"
|
|
190
|
-
fullWidth
|
|
191
|
-
className="w-full"
|
|
192
|
-
onPress={
|
|
193
|
-
pw.step === 'identifier' ? pw.submitIdentifier
|
|
194
|
-
: pw.step === 'password' ? pw.submitPassword
|
|
195
|
-
: pw.submitTwoFactor
|
|
196
|
-
}
|
|
197
|
-
loading={pw.isSubmitting}
|
|
198
|
-
disabled={pw.isSubmitting}
|
|
199
|
-
>
|
|
200
|
-
{pw.step === 'identifier' ? 'Continue' : pw.step === 'password' ? 'Sign in' : 'Verify'}
|
|
201
|
-
</Button>
|
|
202
|
-
|
|
203
|
-
{pw.error && (
|
|
204
|
-
<Text className="font-sans text-body text-destructive text-center mt-space-12">
|
|
205
|
-
{pw.error}
|
|
206
|
-
</Text>
|
|
207
|
-
)}
|
|
208
|
-
|
|
209
|
-
{pw.step === 'twoFactor' && (
|
|
210
|
-
<Button
|
|
211
|
-
variant="text"
|
|
212
|
-
size="small"
|
|
213
|
-
className="mt-space-8"
|
|
214
|
-
onPress={() => pw.setUseBackupCode(!pw.useBackupCode)}
|
|
215
|
-
>
|
|
216
|
-
{pw.useBackupCode ? 'Use authenticator code' : 'Use a backup code'}
|
|
217
|
-
</Button>
|
|
218
|
-
)}
|
|
219
|
-
|
|
220
|
-
{pw.step !== 'identifier' && (
|
|
221
|
-
<Button
|
|
222
|
-
variant="text"
|
|
223
|
-
size="small"
|
|
224
|
-
className="mt-space-8"
|
|
225
|
-
onPress={pw.back}
|
|
226
|
-
accessibilityLabel="Back"
|
|
227
|
-
>
|
|
228
|
-
Back
|
|
229
|
-
</Button>
|
|
230
|
-
)}
|
|
231
|
-
</View>
|
|
232
|
-
|
|
233
|
-
{/* "or" divider — separates the password form from the SECONDARY device flow. */}
|
|
234
|
-
<View className="flex-row items-center w-full my-space-16 gap-space-8">
|
|
235
|
-
<View className="flex-1" style={{ height: 1, backgroundColor: bloomTheme.colors.border }} />
|
|
236
|
-
<Text className="font-sans text-caption text-text-tertiary">or</Text>
|
|
237
|
-
<View className="flex-1" style={{ height: 1, backgroundColor: bloomTheme.colors.border }} />
|
|
238
|
-
</View>
|
|
239
|
-
|
|
240
|
-
{/* SECONDARY — cross-app device flow. Its loading/error state gates ONLY
|
|
241
|
-
this section; the password form above is always usable. */}
|
|
242
|
-
{isLoading ? (
|
|
243
|
-
<LoadingState
|
|
244
|
-
size="small"
|
|
245
|
-
color={bloomTheme.colors.primary}
|
|
246
|
-
message="Preparing sign in…"
|
|
247
|
-
/>
|
|
248
|
-
) : error ? (
|
|
249
|
-
<View className="items-center gap-space-16 w-full">
|
|
250
|
-
<IconCircle icon={Icons.Warning_Stroke2_Corner0_Rounded} />
|
|
251
|
-
<Text className="font-sans text-body text-text-secondary text-center">{error}</Text>
|
|
252
|
-
<Button
|
|
253
|
-
variant="secondary"
|
|
254
|
-
fullWidth
|
|
255
|
-
className="w-full"
|
|
256
|
-
onPress={retry}
|
|
257
|
-
icon={
|
|
258
|
-
<Icons.ArrowRotateClockwise_Stroke2_Corner0_Rounded
|
|
259
|
-
size="sm"
|
|
260
|
-
style={{ color: bloomTheme.colors.text }}
|
|
261
|
-
/>
|
|
262
|
-
}
|
|
263
|
-
>
|
|
264
|
-
Try Again
|
|
265
|
-
</Button>
|
|
266
|
-
</View>
|
|
267
|
-
) : (
|
|
268
|
-
<>
|
|
269
|
-
{qrPayload && (
|
|
270
|
-
<Button
|
|
271
|
-
variant="secondary"
|
|
272
|
-
size="large"
|
|
273
|
-
fullWidth
|
|
274
|
-
className="w-full"
|
|
275
|
-
onPress={openSameDeviceApproval}
|
|
276
|
-
icon={<OxyLogo variant="icon" size={20} fillColor={bloomTheme.colors.text} />}
|
|
277
|
-
>
|
|
278
|
-
Sign in with the Oxy app
|
|
279
|
-
</Button>
|
|
280
|
-
)}
|
|
281
|
-
|
|
282
|
-
{isWaiting && (
|
|
283
|
-
<View className="flex-row items-center mt-space-16 gap-space-8">
|
|
284
|
-
<Loading size="small" />
|
|
285
|
-
<Text className="font-sans text-body text-text-secondary">
|
|
286
|
-
Waiting for authorization…
|
|
287
|
-
</Text>
|
|
288
|
-
</View>
|
|
289
|
-
)}
|
|
290
|
-
|
|
291
|
-
<View className="w-full mt-space-24">
|
|
292
|
-
<AnotherDeviceQR qrData={qrData} qrPayload={qrPayload} />
|
|
293
|
-
</View>
|
|
294
|
-
</>
|
|
295
|
-
)}
|
|
296
|
-
</>
|
|
297
|
-
)}
|
|
298
|
-
|
|
299
|
-
{/* Footer — create an account */}
|
|
300
|
-
<View className="flex-row flex-wrap justify-center items-center mt-space-24">
|
|
301
|
-
<Text className="font-sans text-body text-text-secondary">
|
|
302
|
-
Don't have an Oxy account?
|
|
303
|
-
</Text>
|
|
304
|
-
<Button
|
|
305
|
-
variant="text"
|
|
306
|
-
size="small"
|
|
307
|
-
onPress={() => Linking.openURL(OXY_ACCOUNTS_WEB_URL)}
|
|
308
|
-
accessibilityLabel="Create an Oxy account"
|
|
309
|
-
>
|
|
310
|
-
Create one
|
|
311
|
-
</Button>
|
|
312
|
-
</View>
|
|
313
|
-
|
|
314
|
-
{/* Cancel */}
|
|
315
|
-
{goBack && (
|
|
316
|
-
<Button variant="text" onPress={goBack} className="mt-space-8" accessibilityLabel="Cancel">
|
|
317
|
-
Cancel
|
|
318
|
-
</Button>
|
|
319
|
-
)}
|
|
320
|
-
</View>
|
|
321
|
-
);
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
export default OxyAuthScreen;
|