@stokr/components-library 3.0.66 → 3.0.68

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 (51) hide show
  1. package/README.md +179 -179
  2. package/dist/components/2FA/login-with-otp-flow.js +47 -12
  3. package/dist/components/2FA/main-flow.js +28 -4
  4. package/dist/components/StepsProgress/StepsProgress.js +1 -1
  5. package/dist/context/AuthContext.js +3 -2
  6. package/dist/index.js +2 -2
  7. package/dist/manifest.json +25 -25
  8. package/dist/robots.txt +3 -3
  9. package/dist/runtime-config.js +1 -1
  10. package/dist/static/fonts/icomoon/icomoon.eot +0 -0
  11. package/dist/static/fonts/icomoon/icomoon.svg +52 -52
  12. package/dist/static/fonts/icomoon/icomoon.ttf +0 -0
  13. package/dist/static/fonts/icomoon/icomoon.woff +0 -0
  14. package/dist/static/fonts/icomoon/selection.json +0 -0
  15. package/dist/static/fonts/icomoon/style.css +0 -0
  16. package/dist/static/images/Glassess.svg +5 -5
  17. package/dist/static/images/add-folder-icon.svg +4 -4
  18. package/dist/static/images/arrow-down-black.svg +21 -21
  19. package/dist/static/images/check-icon.svg +3 -3
  20. package/dist/static/images/checkmark-circle-icon.svg +3 -3
  21. package/dist/static/images/close-circle-icon.svg +2 -2
  22. package/dist/static/images/copy_icon.svg +4 -4
  23. package/dist/static/images/cross-icon.svg +3 -3
  24. package/dist/static/images/currency/eth.svg +10 -10
  25. package/dist/static/images/currency/eth_logo.svg +8 -8
  26. package/dist/static/images/currency/eur.svg +3 -3
  27. package/dist/static/images/currency/usdc-logo.svg +5 -5
  28. package/dist/static/images/doc-icon.svg +3 -3
  29. package/dist/static/images/download_icon.svg +3 -3
  30. package/dist/static/images/external-link-icon.svg +3 -3
  31. package/dist/static/images/filter-icon.svg +6 -6
  32. package/dist/static/images/globe.svg +15 -15
  33. package/dist/static/images/mangopay.svg +20 -20
  34. package/dist/static/images/numbers/number_eight.svg +3 -3
  35. package/dist/static/images/numbers/number_five.svg +4 -4
  36. package/dist/static/images/numbers/number_four.svg +3 -3
  37. package/dist/static/images/numbers/number_nine.svg +4 -4
  38. package/dist/static/images/numbers/number_one.svg +4 -4
  39. package/dist/static/images/numbers/number_seven.svg +4 -4
  40. package/dist/static/images/numbers/number_six.svg +4 -4
  41. package/dist/static/images/numbers/number_three.svg +3 -3
  42. package/dist/static/images/numbers/number_two.svg +4 -4
  43. package/dist/static/images/numbers/number_zero.svg +3 -3
  44. package/dist/static/images/plus-icon.svg +4 -4
  45. package/dist/static/images/prof-inv.svg +3 -3
  46. package/dist/static/images/search-icon.svg +3 -3
  47. package/dist/static/images/transfer-icon.svg +10 -10
  48. package/dist/static/images/trash.svg +16 -16
  49. package/dist/static/images/upload.svg +5 -5
  50. package/dist/static/images/warning-filled.svg +3 -3
  51. package/package.json +143 -143
package/README.md CHANGED
@@ -1,179 +1,179 @@
1
- # @stokr/components-library
2
-
3
- React UI library for STOKR apps: modals, forms, navigation, tables, auth context, styles.
4
-
5
- ## Contents
6
-
7
- - [Quick start](#quick-start) — install, router, `AuthProvider`, styles
8
- - [Configuration reference](#runtime-config) — `config` keys & helpers
9
- - [AuthProvider & AuthContext](#authprovider-optional-props)
10
- - [Troubleshooting](#troubleshooting)
11
- - [Development](#development--publishing)
12
-
13
- ---
14
-
15
- ## Quick start
16
-
17
- **Install**
18
-
19
- ```bash
20
- npm install @stokr/components-library
21
- npm install react react-dom styled-components react-router-dom
22
- ```
23
-
24
- Peers: React 18+/19+, styled-components 6.x, react-router-dom 6.x when you use routing-driven components (`HeaderHo`, `MainMenu`, …).
25
-
26
- **1. Router** — Navigation helpers need a React Router:
27
-
28
- ```jsx
29
- import { BrowserRouter } from 'react-router-dom'
30
- import { RouterWrapper } from '@stokr/components-library'
31
-
32
- // Normal app
33
- root.render(
34
- <BrowserRouter>
35
- <App />
36
- </BrowserRouter>,
37
- )
38
-
39
- // Outside a Router: RouterWrapper wraps children in BrowserRouter once.
40
- // Inside an existing Router: it renders children only (no nested BrowserRouter).
41
- root.render(
42
- <RouterWrapper>
43
- <App />
44
- </RouterWrapper>,
45
- )
46
- ```
47
-
48
- **2. Auth & runtime config (required when consuming via npm)** — Vite freezes `import.meta.env` inside pre-built deps, so push your `.env` at runtime via `config`:
49
-
50
- ```jsx
51
- import { AuthProvider } from '@stokr/components-library'
52
-
53
- export default function App() {
54
- return (
55
- <AuthProvider
56
- config={{
57
- apiUrl: import.meta.env.VITE_API_URL,
58
- baseUrlPublic: import.meta.env.VITE_BASE_URL_PUBLIC,
59
- cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
60
- websiteDomain: import.meta.env.VITE_WEBSITE_DOMAIN,
61
- photoApiUrl: import.meta.env.VITE_PHOTO_API_URL,
62
- onboardingUrl: import.meta.env.VITE_ONBOARDING_URL,
63
- dashboardUrl: import.meta.env.VITE_DASHBOARD_URL,
64
- adminUrl: import.meta.env.VITE_ADMIN_URL,
65
- registerUrl: import.meta.env.VITE_REGISTER_URL,
66
- firebase: {
67
- apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
68
- authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
69
- projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
70
- storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
71
- messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
72
- appId: import.meta.env.VITE_FIREBASE_APP_ID,
73
- measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
74
- },
75
- }}>
76
- {/* app */}
77
- </AuthProvider>
78
- )
79
- }
80
- ```
81
-
82
- **3. Earlier config** (e.g. analytics before mount): `import { configure } from '@stokr/components-library'` with the same shape as `config`.
83
-
84
- **4. Icons / fonts** — Optional: `<IoniconsStyles />` at root, or rely on lazy injection when a component uses icons; for Layout / Open Sans: `import '@stokr/components-library/styles.css'`.
85
-
86
- **5. Imports** — `import { ConfirmModal, Button, … } from '@stokr/components-library'`.
87
-
88
- Full URL env example:
89
-
90
- ```bash
91
- VITE_WEBSITE_DOMAIN=example.com
92
- VITE_ONBOARDING_URL=https://signup.example.com
93
- VITE_DASHBOARD_URL=https://dashboard.example.com
94
- VITE_ADMIN_URL=https://admin.example.com
95
- VITE_REGISTER_URL=https://example.com/signup
96
- ```
97
-
98
- ---
99
-
100
- ## Configuration reference {#runtime-config}
101
-
102
- | `config` key | Typical `VITE_*` | Role |
103
- | ----------------- | -------------------------- | ----------------------------------------- |
104
- | `apiUrl` | `VITE_API_URL` | Authenticated REST base |
105
- | `baseUrlPublic` | `VITE_BASE_URL_PUBLIC` | Public API base |
106
- | `cookieDomain` | `VITE_COOKIE_DOMAIN` | Auth cookie `domain` attribute |
107
- | `websiteDomain` | `VITE_WEBSITE_DOMAIN` | Bare host → links / `getPlatformURL()` |
108
- | `photoApiUrl` | `VITE_PHOTO_API_URL` | Avatars / media |
109
- | `onboardingUrl` | `VITE_ONBOARDING_URL` | Full signup/sign-in app URL |
110
- | `dashboardUrl` | `VITE_DASHBOARD_URL` | Investor dashboard URL |
111
- | `adminUrl` | `VITE_ADMIN_URL` | Venture / admin dashboard URL |
112
- | `registerUrl` | `VITE_REGISTER_URL` | Public registration entry |
113
- | `firebase` | `VITE_FIREBASE_*` | Firebase client config |
114
-
115
- **Helpers:** `getConfig('…')` for any key above; `getPlatformURL()` → `https://{websiteDomain}`; `getAnalyticsIngestUrl()`, `getBackofficeAppUrl(path)`; **`getFooterGroups()`** replaces static footer URL lists.
116
-
117
- **Auth-only HTTP:** `authenticationApi.post(segment, body)` for `auth/*`; default axios stays the main API client after login.
118
-
119
- Missing overrides may trigger a **one-time** warning listing unresolved `VITE_*` expectations.
120
-
121
- ---
122
-
123
- ## AuthProvider & AuthContext {#authprovider-optional-props}
124
-
125
- `AuthProvider` is wrapped with **`withRouter`** — mount it inside a **`Router`** so redirects work.
126
-
127
- ### Optional provider props
128
-
129
- - **`inactivityTimeMs`** — Idle timeout before auto-logout + session modal (default 5 min).
130
- - **`inactivityWarningBeforeMs`** — How long before that timeout to show the **“session about to expire”** warning modal (default 30 s). See [Inactivity auto-logout](#inactivity-auto-logout).
131
- - **`accessTokenExpiryMs`** — Cookie TTL when **`Auth.setAccessToken`** runs (default **`DEFAULT_TOKEN_EXPIRY_MS`** = 1 h); not extended by **`getUser`** alone.
132
- - **`hideInactivityModal`** — Suppress both built-in inactivity modals (warning + session expired).
133
- - **`onSessionExpiredLoginClick`** — Called when the user clicks **Log in** on the session-expired modal.
134
- - **`customValidateGetUser(user)`** — Hook after **`user/get`** succeeds (see `src/context/AuthContext.js`).
135
-
136
- ### Inactivity auto-logout {#inactivity-auto-logout}
137
-
138
- When a user is logged in, `AuthProvider` resets an idle timer on mouse, keyboard, click, scroll, and touch events.
139
-
140
- 1. **Warning modal** — Shown **`inactivityWarningBeforeMs`** before the idle deadline (default: 30 s before the 5 min timeout). The user can click **To continue, press here** to reset the idle timer, or close the modal (logout still happens at the deadline). Any activity also resets the timer and closes the warning.
141
- 2. **Session expired modal** — Shown when the idle deadline is reached (existing behaviour). The warning modal closes automatically at the same moment.
142
-
143
- Neither modal is shown when the user is not logged in. Both are skipped when **`hideInactivityModal`** is set.
144
-
145
- **Storybook:** `Authentication / Auto-logout (inactivity)` → **With warning modal** (20 s idle, warning at 10 s).
146
-
147
- ### AuthContext consumer {#authcontext-usecontext}
148
-
149
- `import { AuthContext } from '…'` then `useContext(AuthContext)`.
150
-
151
- - **Invalid Firebase guard:** value is **`{ user: null, isFetchingUser: false }`** only (no methods).
152
- - **State (grouped):** `user` / `firebaseUser`, `isFetchingUser`, `avatar`; MFA (`waitingFor2fa`, `userMfaEnrollment`, `firebaseError`); verify-email (`verifyEmailError`, `isVerifyingEmail`); session UX (`loggedOutDueToInactivity`, `loggedOutDueToCookieExpiry`, `sessionExpiryPendingReason`, `showInactivityWarningModal`).
153
- - **Actions (grouped):** `userRef`, `loginUser`, `logoutUser`, `getUser`, `setUser`, `updateUser`, `refreshIdToken`; `checkUserIsValid`, `checkTokenIsValid`; `uploadPhoto`, `deletePhoto`, `checkUserPhoto`; MFA enroll / verify / unenroll + `reset2faFlow`; subscription/onboarding helpers; password & email (`handleResetPassword`, `handleVerifyEmail`, `requestUpdateEmail`, …); wallets / PoA (`uploaProofOfAddress` keeps the source spelling); **`dismissSessionExpiryModal`**, **`extendSessionFromInactivityWarning`**, **`dismissInactivityWarningModal`**.
154
-
155
- Use **`AuthConsumer`** for the render-prop pattern.
156
-
157
- ---
158
-
159
- ## Troubleshooting {#troubleshooting}
160
-
161
- **`useNavigate` / Router**
162
-
163
- Add `BrowserRouter` (or **`RouterWrapper`** from this package where the shell has no router). Install `react-router-dom`.
164
-
165
- **Invalid hook call / duplicated React**
166
-
167
- Dedupe peers in Vite: `resolve: { dedupe: ['react', 'react-dom', 'styled-components'] }`.
168
-
169
- ---
170
-
171
- ## Development {#development--publishing}
172
-
173
- | Command | Meaning |
174
- | -------------------- | -------------------------------- |
175
- | `npm run storybook` | Local docs / stories |
176
- | `npm run build:dist` | Library build + static copy |
177
- | `npm run pub` | Build then publish (`npm login`) |
178
-
179
- Release: changelog entry → `npm version` → `npm run pub`. Details: [CHANGELOG.md](CHANGELOG.md).
1
+ # @stokr/components-library
2
+
3
+ React UI library for STOKR apps: modals, forms, navigation, tables, auth context, styles.
4
+
5
+ ## Contents
6
+
7
+ - [Quick start](#quick-start) — install, router, `AuthProvider`, styles
8
+ - [Configuration reference](#runtime-config) — `config` keys & helpers
9
+ - [AuthProvider & AuthContext](#authprovider-optional-props)
10
+ - [Troubleshooting](#troubleshooting)
11
+ - [Development](#development--publishing)
12
+
13
+ ---
14
+
15
+ ## Quick start
16
+
17
+ **Install**
18
+
19
+ ```bash
20
+ npm install @stokr/components-library
21
+ npm install react react-dom styled-components react-router-dom
22
+ ```
23
+
24
+ Peers: React 18+/19+, styled-components 6.x, react-router-dom 6.x when you use routing-driven components (`HeaderHo`, `MainMenu`, …).
25
+
26
+ **1. Router** — Navigation helpers need a React Router:
27
+
28
+ ```jsx
29
+ import { BrowserRouter } from 'react-router-dom'
30
+ import { RouterWrapper } from '@stokr/components-library'
31
+
32
+ // Normal app
33
+ root.render(
34
+ <BrowserRouter>
35
+ <App />
36
+ </BrowserRouter>,
37
+ )
38
+
39
+ // Outside a Router: RouterWrapper wraps children in BrowserRouter once.
40
+ // Inside an existing Router: it renders children only (no nested BrowserRouter).
41
+ root.render(
42
+ <RouterWrapper>
43
+ <App />
44
+ </RouterWrapper>,
45
+ )
46
+ ```
47
+
48
+ **2. Auth & runtime config (required when consuming via npm)** — Vite freezes `import.meta.env` inside pre-built deps, so push your `.env` at runtime via `config`:
49
+
50
+ ```jsx
51
+ import { AuthProvider } from '@stokr/components-library'
52
+
53
+ export default function App() {
54
+ return (
55
+ <AuthProvider
56
+ config={{
57
+ apiUrl: import.meta.env.VITE_API_URL,
58
+ baseUrlPublic: import.meta.env.VITE_BASE_URL_PUBLIC,
59
+ cookieDomain: import.meta.env.VITE_COOKIE_DOMAIN,
60
+ websiteDomain: import.meta.env.VITE_WEBSITE_DOMAIN,
61
+ photoApiUrl: import.meta.env.VITE_PHOTO_API_URL,
62
+ onboardingUrl: import.meta.env.VITE_ONBOARDING_URL,
63
+ dashboardUrl: import.meta.env.VITE_DASHBOARD_URL,
64
+ adminUrl: import.meta.env.VITE_ADMIN_URL,
65
+ registerUrl: import.meta.env.VITE_REGISTER_URL,
66
+ firebase: {
67
+ apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
68
+ authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
69
+ projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
70
+ storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
71
+ messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
72
+ appId: import.meta.env.VITE_FIREBASE_APP_ID,
73
+ measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
74
+ },
75
+ }}>
76
+ {/* app */}
77
+ </AuthProvider>
78
+ )
79
+ }
80
+ ```
81
+
82
+ **3. Earlier config** (e.g. analytics before mount): `import { configure } from '@stokr/components-library'` with the same shape as `config`.
83
+
84
+ **4. Icons / fonts** — Optional: `<IoniconsStyles />` at root, or rely on lazy injection when a component uses icons; for Layout / Open Sans: `import '@stokr/components-library/styles.css'`.
85
+
86
+ **5. Imports** — `import { ConfirmModal, Button, … } from '@stokr/components-library'`.
87
+
88
+ Full URL env example:
89
+
90
+ ```bash
91
+ VITE_WEBSITE_DOMAIN=example.com
92
+ VITE_ONBOARDING_URL=https://signup.example.com
93
+ VITE_DASHBOARD_URL=https://dashboard.example.com
94
+ VITE_ADMIN_URL=https://admin.example.com
95
+ VITE_REGISTER_URL=https://example.com/signup
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Configuration reference {#runtime-config}
101
+
102
+ | `config` key | Typical `VITE_*` | Role |
103
+ | ----------------- | -------------------------- | ----------------------------------------- |
104
+ | `apiUrl` | `VITE_API_URL` | Authenticated REST base |
105
+ | `baseUrlPublic` | `VITE_BASE_URL_PUBLIC` | Public API base |
106
+ | `cookieDomain` | `VITE_COOKIE_DOMAIN` | Auth cookie `domain` attribute |
107
+ | `websiteDomain` | `VITE_WEBSITE_DOMAIN` | Bare host → links / `getPlatformURL()` |
108
+ | `photoApiUrl` | `VITE_PHOTO_API_URL` | Avatars / media |
109
+ | `onboardingUrl` | `VITE_ONBOARDING_URL` | Full signup/sign-in app URL |
110
+ | `dashboardUrl` | `VITE_DASHBOARD_URL` | Investor dashboard URL |
111
+ | `adminUrl` | `VITE_ADMIN_URL` | Venture / admin dashboard URL |
112
+ | `registerUrl` | `VITE_REGISTER_URL` | Public registration entry |
113
+ | `firebase` | `VITE_FIREBASE_*` | Firebase client config |
114
+
115
+ **Helpers:** `getConfig('…')` for any key above; `getPlatformURL()` → `https://{websiteDomain}`; `getAnalyticsIngestUrl()`, `getBackofficeAppUrl(path)`; **`getFooterGroups()`** replaces static footer URL lists.
116
+
117
+ **Auth-only HTTP:** `authenticationApi.post(segment, body)` for `auth/*`; default axios stays the main API client after login.
118
+
119
+ Missing overrides may trigger a **one-time** warning listing unresolved `VITE_*` expectations.
120
+
121
+ ---
122
+
123
+ ## AuthProvider & AuthContext {#authprovider-optional-props}
124
+
125
+ `AuthProvider` is wrapped with **`withRouter`** — mount it inside a **`Router`** so redirects work.
126
+
127
+ ### Optional provider props
128
+
129
+ - **`inactivityTimeMs`** — Idle timeout before auto-logout + session modal (default 5 min).
130
+ - **`inactivityWarningBeforeMs`** — How long before that timeout to show the **“session about to expire”** warning modal (default 30 s). See [Inactivity auto-logout](#inactivity-auto-logout).
131
+ - **`accessTokenExpiryMs`** — Cookie TTL when **`Auth.setAccessToken`** runs (default **`DEFAULT_TOKEN_EXPIRY_MS`** = 1 h); not extended by **`getUser`** alone.
132
+ - **`hideInactivityModal`** — Suppress both built-in inactivity modals (warning + session expired).
133
+ - **`onSessionExpiredLoginClick`** — Called when the user clicks **Log in** on the session-expired modal.
134
+ - **`customValidateGetUser(user)`** — Hook after **`user/get`** succeeds (see `src/context/AuthContext.js`).
135
+
136
+ ### Inactivity auto-logout {#inactivity-auto-logout}
137
+
138
+ When a user is logged in, `AuthProvider` resets an idle timer on mouse, keyboard, click, scroll, and touch events.
139
+
140
+ 1. **Warning modal** — Shown **`inactivityWarningBeforeMs`** before the idle deadline (default: 30 s before the 5 min timeout). The user can click **To continue, press here** to reset the idle timer, or close the modal (logout still happens at the deadline). Any activity also resets the timer and closes the warning.
141
+ 2. **Session expired modal** — Shown when the idle deadline is reached (existing behaviour). The warning modal closes automatically at the same moment.
142
+
143
+ Neither modal is shown when the user is not logged in. Both are skipped when **`hideInactivityModal`** is set.
144
+
145
+ **Storybook:** `Authentication / Auto-logout (inactivity)` → **With warning modal** (20 s idle, warning at 10 s).
146
+
147
+ ### AuthContext consumer {#authcontext-usecontext}
148
+
149
+ `import { AuthContext } from '…'` then `useContext(AuthContext)`.
150
+
151
+ - **Invalid Firebase guard:** value is **`{ user: null, isFetchingUser: false }`** only (no methods).
152
+ - **State (grouped):** `user` / `firebaseUser`, `isFetchingUser`, `avatar`; MFA (`waitingFor2fa`, `userMfaEnrollment`, `firebaseError`); verify-email (`verifyEmailError`, `isVerifyingEmail`); session UX (`loggedOutDueToInactivity`, `loggedOutDueToCookieExpiry`, `sessionExpiryPendingReason`, `showInactivityWarningModal`).
153
+ - **Actions (grouped):** `userRef`, `loginUser`, `logoutUser`, `getUser`, `setUser`, `updateUser`, `refreshIdToken`; `checkUserIsValid`, `checkTokenIsValid`; `uploadPhoto`, `deletePhoto`, `checkUserPhoto`; MFA enroll / verify / unenroll + `reset2faFlow`; subscription/onboarding helpers; password & email (`handleResetPassword`, `handleVerifyEmail`, `requestUpdateEmail`, …); wallets / PoA (`uploaProofOfAddress` keeps the source spelling); **`dismissSessionExpiryModal`**, **`extendSessionFromInactivityWarning`**, **`dismissInactivityWarningModal`**.
154
+
155
+ Use **`AuthConsumer`** for the render-prop pattern.
156
+
157
+ ---
158
+
159
+ ## Troubleshooting {#troubleshooting}
160
+
161
+ **`useNavigate` / Router**
162
+
163
+ Add `BrowserRouter` (or **`RouterWrapper`** from this package where the shell has no router). Install `react-router-dom`.
164
+
165
+ **Invalid hook call / duplicated React**
166
+
167
+ Dedupe peers in Vite: `resolve: { dedupe: ['react', 'react-dom', 'styled-components'] }`.
168
+
169
+ ---
170
+
171
+ ## Development {#development--publishing}
172
+
173
+ | Command | Meaning |
174
+ | -------------------- | -------------------------------- |
175
+ | `npm run storybook` | Local docs / stories |
176
+ | `npm run build:dist` | Library build + static copy |
177
+ | `npm run pub` | Build then publish (`npm login`) |
178
+
179
+ Release: changelog entry → `npm version` → `npm run pub`. Details: [CHANGELOG.md](CHANGELOG.md).
@@ -1,20 +1,29 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
- import { useContext, useState, useEffect } from "react";
3
- import { AuthContext } from "../../context/AuthContext.js";
2
+ import PropTypes from "prop-types";
3
+ import stdin_default$2 from "./EnterCode.js";
4
+ import stdin_default$3 from "./ResetCode.js";
4
5
  import { Layout } from "../Layout/Layout.js";
6
+ import { useNavigate } from "react-router-dom";
5
7
  import stdin_default$1 from "../LoginModal/LoginModal.js";
6
- import stdin_default$4 from "../ForgotPasswordModal/ForgotPasswordModal.js";
7
- import stdin_default$2 from "./EnterCode.js";
8
+ import { AuthContext } from "../../context/AuthContext.js";
8
9
  import background from "../../static/images/background3.png.js";
9
- import stdin_default$3 from "./ResetCode.js";
10
+ import { hasLoggedInSession } from "../../utils/user-identity.js";
10
11
  import { authenticationApi } from "../../api/authenticationApi.js";
11
- import { useNavigate } from "react-router-dom";
12
12
  import { getConfig, getPlatformURL } from "../../runtime-config.js";
13
+ import { useContext, useRef, useState, useEffect } from "react";
14
+ import stdin_default$4 from "../ForgotPasswordModal/ForgotPasswordModal.js";
13
15
  import { isAccountLockedError, showAccountLockedModal } from "../../utils/show-account-locked-modal.js";
14
16
  import { navigateToHref } from "../../routing/navigate-app.js";
15
- const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
17
+ const closedModalsState = {
18
+ login: false,
19
+ enter2fa: false,
20
+ forgot: false,
21
+ resetCode: false
22
+ };
23
+ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false, onLoginSuccess }) => {
16
24
  const navigate = useNavigate();
17
- const { loginUser, waitingFor2fa, firebaseError, loginUserWithTotp, reset2faFlow, logoutUser } = useContext(AuthContext);
25
+ const { user, loginUser, getUser, waitingFor2fa, firebaseError, loginUserWithTotp, reset2faFlow, logoutUser } = useContext(AuthContext);
26
+ const loginSuccessHandledRef = useRef(false);
18
27
  const [isModalOpen, setIsModalOpen] = useState({
19
28
  login: true,
20
29
  enter2fa: false,
@@ -31,17 +40,32 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
31
40
  message: void 0
32
41
  });
33
42
  const switchOpenModal = (prevModalId, nextModalId) => {
34
- setIsModalOpen({
35
- ...isModalOpen,
43
+ setIsModalOpen((prev) => ({
44
+ ...prev,
36
45
  [prevModalId]: false,
37
46
  [nextModalId]: true
38
- });
47
+ }));
39
48
  };
40
49
  useEffect(() => {
41
50
  if (waitingFor2fa) {
42
- switchOpenModal("login", "enter2fa");
51
+ setIsModalOpen((prev) => ({
52
+ ...prev,
53
+ login: false,
54
+ enter2fa: true
55
+ }));
43
56
  }
44
57
  }, [waitingFor2fa]);
58
+ useEffect(() => {
59
+ if (!hasLoggedInSession(user) || waitingFor2fa) {
60
+ loginSuccessHandledRef.current = false;
61
+ return;
62
+ }
63
+ setIsModalOpen(closedModalsState);
64
+ if (onLoginSuccess && !loginSuccessHandledRef.current) {
65
+ loginSuccessHandledRef.current = true;
66
+ onLoginSuccess(user);
67
+ }
68
+ }, [user, waitingFor2fa, onLoginSuccess]);
45
69
  const handleSetPopupSuccess = (popup, message) => {
46
70
  setPopupSuccess({ popup, message });
47
71
  };
@@ -90,6 +114,8 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
90
114
  return;
91
115
  }
92
116
  await loginUser(email, password);
117
+ await getUser();
118
+ clearPopupError();
93
119
  } catch (error) {
94
120
  const errorMessage = error?.message;
95
121
  if (error?.code === "auth/multi-factor-auth-required") {
@@ -145,6 +171,9 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
145
171
  setIsActionLoading("enter2fa");
146
172
  try {
147
173
  await loginUserWithTotp(otpInput, firebaseError);
174
+ await getUser();
175
+ clearPopupError();
176
+ setIsModalOpen(closedModalsState);
148
177
  } catch (error) {
149
178
  if (error?.code === "auth/invalid-verification-code") {
150
179
  handleSetPopupError("enter2fa", "The verification code is not correct. Try again?");
@@ -220,6 +249,12 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
220
249
  )
221
250
  ] });
222
251
  };
252
+ LoginWithOTP.propTypes = {
253
+ withBackground: PropTypes.bool,
254
+ useRelativePathForMenu: PropTypes.bool,
255
+ /** Called once when login (and optional 2FA) completes and the user session is ready. */
256
+ onLoginSuccess: PropTypes.func
257
+ };
223
258
  var stdin_default = LoginWithOTP;
224
259
  export {
225
260
  LoginWithOTP,
@@ -30,7 +30,7 @@ const Main2FAFlow = ({
30
30
  recentLoginSubtitle = "To continue please log in again and set up your two factor authentication",
31
31
  recentLoginCTA = "Log in again"
32
32
  }) => {
33
- const { user, checkMfaEnrollment, userMfaEnrollment, generateTotpSecret } = useContext(AuthContext);
33
+ const { user, checkMfaEnrollment, userMfaEnrollment, generateTotpSecret, logoutUser } = useContext(AuthContext);
34
34
  const [isFlowopen, setIsFlowOpen] = useState({
35
35
  enable2fa: open2faflow || false,
36
36
  disable2fa: allowDisable2FA && (openDisable2faflow || false),
@@ -40,6 +40,7 @@ const Main2FAFlow = ({
40
40
  const [successMessage, setsuccessMessage] = useState();
41
41
  const [isLoginRequired, setisLoginRequired] = useState(false);
42
42
  const [totpData, settotpData] = useState();
43
+ const [awaitingReauthFor2fa, setAwaitingReauthFor2fa] = useState(false);
43
44
  const enable2faCompletedRef = useRef(false);
44
45
  const disable2faCompletedRef = useRef(false);
45
46
  const onRequiresRecentLoginErrorHandler = () => {
@@ -66,11 +67,23 @@ const Main2FAFlow = ({
66
67
  useEffect(() => {
67
68
  if (userMfaEnrollment?.length > 0) {
68
69
  setis2FAEnabled(true);
69
- } else if (user) {
70
+ } else if (user && !awaitingReauthFor2fa) {
70
71
  checkMfaEnrollment();
71
72
  generateTotp();
72
73
  }
73
- }, [user, userMfaEnrollment]);
74
+ }, [user, userMfaEnrollment, awaitingReauthFor2fa]);
75
+ useEffect(() => {
76
+ if (!user || !awaitingReauthFor2fa) return;
77
+ setAwaitingReauthFor2fa(false);
78
+ setisLoginRequired(false);
79
+ setIsFlowOpen((prev) => ({
80
+ ...prev,
81
+ requiresRecentLogin: false,
82
+ enable2fa: true
83
+ }));
84
+ checkMfaEnrollment();
85
+ generateTotp();
86
+ }, [user, awaitingReauthFor2fa]);
74
87
  useEffect(() => {
75
88
  let timeoutId;
76
89
  if (successMessage) {
@@ -113,6 +126,17 @@ const Main2FAFlow = ({
113
126
  checkMfaEnrollment();
114
127
  setsuccessMessage("Your log in 2FA authentication is removed");
115
128
  };
129
+ const handleLoginAgain = async () => {
130
+ setIsFlowOpen((prev) => ({
131
+ ...prev,
132
+ requiresRecentLogin: false,
133
+ enable2fa: false,
134
+ disable2fa: false
135
+ }));
136
+ await logoutUser();
137
+ setAwaitingReauthFor2fa(true);
138
+ onLoginAgainClick?.();
139
+ };
116
140
  const flowActions = {
117
141
  openEnable2FA: () => switchOpenFlow("disable2fa", "enable2fa"),
118
142
  openDisable2FA: () => {
@@ -225,7 +249,7 @@ const Main2FAFlow = ({
225
249
  continueButtonId: "2fa-requires-recent-login-btn",
226
250
  continueButtonDataCy: "2fa-requires-recent-login-submit",
227
251
  onClick: () => {
228
- onLoginAgainClick?.();
252
+ void handleLoginAgain();
229
253
  },
230
254
  titleText: recentLoginTitle,
231
255
  subTitleLeft: recentLoginSubtitle,
@@ -6,7 +6,7 @@ import { walletTypes } from "../../constants/globalVariables.js";
6
6
  const StepsProgressSignup = (props) => {
7
7
  let navigate = useNavigate();
8
8
  const { user = {} } = props;
9
- const { country, kyc_status, self_declaration, taxId, wallets = [] } = user;
9
+ const { country, kyc_status, self_declaration, wallets = [] } = user;
10
10
  const KYCNotDone = !kyc_status || kyc_status === "Reaply" || kyc_status === "Cancelled" || kyc_status === "Draft";
11
11
  const hasLiquidWallet = wallets?.filter((wallet) => wallet.type === walletTypes.LIQUID).length > 0;
12
12
  const isActiveStep = (path) => typeof window !== "undefined" ? window.location.pathname.includes(path) : false;
@@ -275,8 +275,9 @@ class AuthProviderClass extends Component {
275
275
  this.setState({ waitingFor2fa: true, firebaseError: error });
276
276
  throw error;
277
277
  case "auth/requires-recent-login":
278
- this.logoutUser();
279
- break;
278
+ await this.logoutUser();
279
+ error.message = "Your session has expired. Please log in again to continue.";
280
+ throw error;
280
281
  case "auth/invalid-login-credentials":
281
282
  case "auth/invalid-credential":
282
283
  if (email) {
package/dist/index.js CHANGED
@@ -138,6 +138,8 @@ import { navigateToHref, pathnameIfSameOrigin } from "./routing/navigate-app.js"
138
138
  import { RouterWrapper } from "./routing/RouterWrapper.js";
139
139
  import { isAlreadyOnOnboardingFlow } from "./utils/app-urls.js";
140
140
  import { authenticationApi } from "./api/authenticationApi.js";
141
+ import { Auth, DEFAULT_TOKEN_EXPIRY_MS } from "./context/Auth.js";
142
+ import { AuthConsumer, AuthContext, AuthProvider } from "./context/AuthContext.js";
141
143
  import { colors } from "./styles/colors.js";
142
144
  import { default as default2 } from "./styles/fonts.js";
143
145
  import { GlobalStyle } from "./styles/global.js";
@@ -153,8 +155,6 @@ import { LoanActivityTypes, ProfessionalInvestorStatuses, ProjectStates, Project
153
155
  import { default as default9 } from "./components/SvgIcons/AdminBadgeSvg.js";
154
156
  import { Arrow } from "./components/icons/Arrow.js";
155
157
  import { ArrowSimple } from "./components/icons/ArrowSimple.js";
156
- import { Auth, DEFAULT_TOKEN_EXPIRY_MS } from "./context/Auth.js";
157
- import { AuthConsumer, AuthContext, AuthProvider } from "./context/AuthContext.js";
158
158
  import { BackButtonIcon, StyledBackButton, StyledBackButtonExternal, StyledWindowBackButton } from "./components/BackButton/BackButton.styles.js";
159
159
  import { Breakdown } from "./components/breakdown/Breakdown.js";
160
160
  import { default as default10 } from "./components/SvgIcons/CameraSvg.js";
@@ -1,25 +1,25 @@
1
- {
2
- "short_name": "Vite React App",
3
- "name": "Vite React App",
4
- "icons": [
5
- {
6
- "src": "favicon.ico",
7
- "sizes": "64x64 32x32 24x24 16x16",
8
- "type": "image/x-icon"
9
- },
10
- {
11
- "src": "logo192.png",
12
- "type": "image/png",
13
- "sizes": "192x192"
14
- },
15
- {
16
- "src": "logo512.png",
17
- "type": "image/png",
18
- "sizes": "512x512"
19
- }
20
- ],
21
- "start_url": ".",
22
- "display": "standalone",
23
- "theme_color": "#000000",
24
- "background_color": "#ffffff"
25
- }
1
+ {
2
+ "short_name": "Vite React App",
3
+ "name": "Vite React App",
4
+ "icons": [
5
+ {
6
+ "src": "favicon.ico",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/x-icon"
9
+ },
10
+ {
11
+ "src": "logo192.png",
12
+ "type": "image/png",
13
+ "sizes": "192x192"
14
+ },
15
+ {
16
+ "src": "logo512.png",
17
+ "type": "image/png",
18
+ "sizes": "512x512"
19
+ }
20
+ ],
21
+ "start_url": ".",
22
+ "display": "standalone",
23
+ "theme_color": "#000000",
24
+ "background_color": "#ffffff"
25
+ }
package/dist/robots.txt CHANGED
@@ -1,3 +1,3 @@
1
- # https://www.robotstxt.org/robotstxt.html
2
- User-agent: *
3
- Disallow:
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow:
@@ -1,4 +1,4 @@
1
- const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false, "VITE_ADMIN_URL": "https://admin.stokr.info", "VITE_API_URL": "https://platform-api.stokr.info/api/v1", "VITE_BASE_URL_PUBLIC": "https://platform-api-no-auth.stokr.info/api/v1", "VITE_COOKIE_DOMAIN": "localhost", "VITE_DASHBOARD_URL": "https://dashboard.stokr.info", "VITE_FIREBASE_API_KEY": "AIzaSyBBp_3Romnfv--YpUuV0mJgDymvSp3oq0c", "VITE_FIREBASE_APP_ID": "1:568229412804:web:2391857e3e2a0b02346e91", "VITE_FIREBASE_AUTH_DOMAIN": "stokr-development-env.firebaseapp.com", "VITE_FIREBASE_MEASUREMENT_ID": "G-CP53SZVSMN", "VITE_FIREBASE_MESSAGING_SENDER_ID": "568229412804", "VITE_FIREBASE_PROJECT_ID": "stokr-development-env", "VITE_FIREBASE_STORAGE_BUCKET": "stokr-development-env.appspot.com", "VITE_MIXPANEL_TOKEN": "a7bb1e881f9b2600762fded84d8ce0ea", "VITE_ONBOARDING_URL": "https://signup.stokr.info", "VITE_PHOTO_API_URL": "https://platform-api.stokr.info/api/v1", "VITE_REGISTER_URL": "https://stokr.info/signup", "VITE_WEBSITE_DOMAIN": "stokr.info" };
1
+ const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
2
2
  const _overrides = {};
3
3
  const ENV_KEY_BY_CONFIG = {
4
4
  apiUrl: "VITE_API_URL",
File without changes