@stokr/components-library 3.0.62 → 3.0.63
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/README.md +166 -166
- package/dist/components/2FA/Connect2FA.js +2 -8
- package/dist/components/2FA/enable-2fa-flow.js +19 -3
- package/dist/components/Footer/Footer.js +32 -17
- package/dist/components/Footer/Footer.styles.js +19 -10
- package/dist/components/StepController/StepController.js +46 -9
- package/dist/components/StepController/StepController.styles.js +1 -0
- package/dist/components/StepController/StepControllerContext.js +4 -4
- package/dist/index.js +2 -2
- package/dist/manifest.json +25 -25
- package/dist/robots.txt +3 -3
- package/dist/runtime-config.js +1 -1
- package/dist/static/fonts/icomoon/icomoon.eot +0 -0
- package/dist/static/fonts/icomoon/icomoon.svg +52 -52
- package/dist/static/fonts/icomoon/icomoon.ttf +0 -0
- package/dist/static/fonts/icomoon/icomoon.woff +0 -0
- package/dist/static/fonts/icomoon/selection.json +0 -0
- package/dist/static/fonts/icomoon/style.css +0 -0
- package/dist/static/images/Glassess.svg +5 -5
- package/dist/static/images/add-folder-icon.svg +4 -4
- package/dist/static/images/arrow-down-black.svg +21 -21
- package/dist/static/images/check-icon.svg +3 -3
- package/dist/static/images/checkmark-circle-icon.svg +3 -3
- package/dist/static/images/close-circle-icon.svg +2 -2
- package/dist/static/images/copy_icon.svg +4 -4
- package/dist/static/images/cross-icon.svg +3 -3
- package/dist/static/images/currency/eth.svg +10 -10
- package/dist/static/images/currency/eth_logo.svg +8 -8
- package/dist/static/images/currency/eur.svg +3 -3
- package/dist/static/images/currency/usdc-logo.svg +5 -5
- package/dist/static/images/doc-icon.svg +3 -3
- package/dist/static/images/download_icon.svg +3 -3
- package/dist/static/images/external-link-icon.svg +3 -3
- package/dist/static/images/filter-icon.svg +6 -6
- package/dist/static/images/globe.svg +15 -15
- package/dist/static/images/mangopay.svg +20 -20
- package/dist/static/images/numbers/number_eight.svg +3 -3
- package/dist/static/images/numbers/number_five.svg +4 -4
- package/dist/static/images/numbers/number_four.svg +3 -3
- package/dist/static/images/numbers/number_nine.svg +4 -4
- package/dist/static/images/numbers/number_one.svg +4 -4
- package/dist/static/images/numbers/number_seven.svg +4 -4
- package/dist/static/images/numbers/number_six.svg +4 -4
- package/dist/static/images/numbers/number_three.svg +3 -3
- package/dist/static/images/numbers/number_two.svg +4 -4
- package/dist/static/images/numbers/number_zero.svg +3 -3
- package/dist/static/images/plus-icon.svg +4 -4
- package/dist/static/images/prof-inv.svg +3 -3
- package/dist/static/images/search-icon.svg +3 -3
- package/dist/static/images/transfer-icon.svg +10 -10
- package/dist/static/images/trash.svg +16 -16
- package/dist/static/images/upload.svg +5 -5
- package/dist/static/images/warning-filled.svg +3 -3
- package/dist/styles/spacing.js +1 -1
- package/package.json +143 -143
package/README.md
CHANGED
|
@@ -1,166 +1,166 @@
|
|
|
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
|
-
- **`accessTokenExpiryMs`** — Cookie TTL when **`Auth.setAccessToken`** runs (default **`DEFAULT_TOKEN_EXPIRY_MS`** = 1 h); not extended by **`getUser`** alone.
|
|
131
|
-
- **`hideInactivityModal`** — Suppress built-in session modal.
|
|
132
|
-
- **`customValidateGetUser(user)`** — Hook after **`user/get`** succeeds (see `src/context/AuthContext.js`).
|
|
133
|
-
|
|
134
|
-
### AuthContext consumer {#authcontext-usecontext}
|
|
135
|
-
|
|
136
|
-
`import { AuthContext } from '…'` then `useContext(AuthContext)`.
|
|
137
|
-
|
|
138
|
-
- **Invalid Firebase guard:** value is **`{ user: null, isFetchingUser: false }`** only (no methods).
|
|
139
|
-
- **State (grouped):** `user` / `firebaseUser`, `isFetchingUser`, `avatar`; MFA (`waitingFor2fa`, `userMfaEnrollment`, `firebaseError`); verify-email (`verifyEmailError`, `isVerifyingEmail`); session UX (`loggedOutDueToInactivity`, `loggedOutDueToCookieExpiry`, `sessionExpiryPendingReason`).
|
|
140
|
-
- **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`**.
|
|
141
|
-
|
|
142
|
-
Use **`AuthConsumer`** for the render-prop pattern.
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## Troubleshooting {#troubleshooting}
|
|
147
|
-
|
|
148
|
-
**`useNavigate` / Router**
|
|
149
|
-
|
|
150
|
-
Add `BrowserRouter` (or **`RouterWrapper`** from this package where the shell has no router). Install `react-router-dom`.
|
|
151
|
-
|
|
152
|
-
**Invalid hook call / duplicated React**
|
|
153
|
-
|
|
154
|
-
Dedupe peers in Vite: `resolve: { dedupe: ['react', 'react-dom', 'styled-components'] }`.
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Development {#development--publishing}
|
|
159
|
-
|
|
160
|
-
| Command | Meaning |
|
|
161
|
-
| -------------------- | -------------------------------- |
|
|
162
|
-
| `npm run storybook` | Local docs / stories |
|
|
163
|
-
| `npm run build:dist` | Library build + static copy |
|
|
164
|
-
| `npm run pub` | Build then publish (`npm login`) |
|
|
165
|
-
|
|
166
|
-
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
|
+
- **`accessTokenExpiryMs`** — Cookie TTL when **`Auth.setAccessToken`** runs (default **`DEFAULT_TOKEN_EXPIRY_MS`** = 1 h); not extended by **`getUser`** alone.
|
|
131
|
+
- **`hideInactivityModal`** — Suppress built-in session modal.
|
|
132
|
+
- **`customValidateGetUser(user)`** — Hook after **`user/get`** succeeds (see `src/context/AuthContext.js`).
|
|
133
|
+
|
|
134
|
+
### AuthContext consumer {#authcontext-usecontext}
|
|
135
|
+
|
|
136
|
+
`import { AuthContext } from '…'` then `useContext(AuthContext)`.
|
|
137
|
+
|
|
138
|
+
- **Invalid Firebase guard:** value is **`{ user: null, isFetchingUser: false }`** only (no methods).
|
|
139
|
+
- **State (grouped):** `user` / `firebaseUser`, `isFetchingUser`, `avatar`; MFA (`waitingFor2fa`, `userMfaEnrollment`, `firebaseError`); verify-email (`verifyEmailError`, `isVerifyingEmail`); session UX (`loggedOutDueToInactivity`, `loggedOutDueToCookieExpiry`, `sessionExpiryPendingReason`).
|
|
140
|
+
- **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`**.
|
|
141
|
+
|
|
142
|
+
Use **`AuthConsumer`** for the render-prop pattern.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Troubleshooting {#troubleshooting}
|
|
147
|
+
|
|
148
|
+
**`useNavigate` / Router**
|
|
149
|
+
|
|
150
|
+
Add `BrowserRouter` (or **`RouterWrapper`** from this package where the shell has no router). Install `react-router-dom`.
|
|
151
|
+
|
|
152
|
+
**Invalid hook call / duplicated React**
|
|
153
|
+
|
|
154
|
+
Dedupe peers in Vite: `resolve: { dedupe: ['react', 'react-dom', 'styled-components'] }`.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Development {#development--publishing}
|
|
159
|
+
|
|
160
|
+
| Command | Meaning |
|
|
161
|
+
| -------------------- | -------------------------------- |
|
|
162
|
+
| `npm run storybook` | Local docs / stories |
|
|
163
|
+
| `npm run build:dist` | Library build + static copy |
|
|
164
|
+
| `npm run pub` | Build then publish (`npm login`) |
|
|
165
|
+
|
|
166
|
+
Release: changelog entry → `npm version` → `npm run pub`. Details: [CHANGELOG.md](CHANGELOG.md).
|
|
@@ -23,13 +23,7 @@ const Connect2FA = (props) => {
|
|
|
23
23
|
] }),
|
|
24
24
|
/* @__PURE__ */ jsx(Column, { part: 8, children: /* @__PURE__ */ jsxs(ModalInner, { children: [
|
|
25
25
|
totpData && /* @__PURE__ */ jsxs(ComponentWrapper, { center: true, noPaddingHorizontal: true, children: [
|
|
26
|
-
!isMobile && /* @__PURE__ */ jsx(
|
|
27
|
-
QRCodeSVG,
|
|
28
|
-
{
|
|
29
|
-
size: 180,
|
|
30
|
-
value: totpData?.totpUri
|
|
31
|
-
}
|
|
32
|
-
),
|
|
26
|
+
!isMobile && /* @__PURE__ */ jsx(QRCodeSVG, { size: 180, value: totpData?.totpUri }),
|
|
33
27
|
/* @__PURE__ */ jsx(
|
|
34
28
|
stdin_default$1,
|
|
35
29
|
{
|
|
@@ -43,7 +37,7 @@ const Connect2FA = (props) => {
|
|
|
43
37
|
}
|
|
44
38
|
)
|
|
45
39
|
] }),
|
|
46
|
-
/* @__PURE__ */ jsx(ComponentWrapper, { noPaddingTop: true, center: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
|
|
40
|
+
/* @__PURE__ */ jsx(ComponentWrapper, { noPaddingTop: true, noPaddingBottom: true, center: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
|
|
47
41
|
Button,
|
|
48
42
|
{
|
|
49
43
|
minWidth: "150px",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useState, useEffect } from "react";
|
|
2
|
+
import { useContext, useState, useRef, useLayoutEffect, useEffect } from "react";
|
|
3
3
|
import { Modal } from "../Modal/Modal.js";
|
|
4
4
|
import stdin_default$2 from "../StepController/StepController.js";
|
|
5
5
|
import { StepControllerProvider, StepControllerConsumer } from "../StepController/StepControllerContext.js";
|
|
@@ -15,10 +15,26 @@ const stepsNames = ["app", "connect", "enter-code"];
|
|
|
15
15
|
const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresRecentLoginError }) => {
|
|
16
16
|
const { user, firebaseUser, enrollUserToTotp, refreshIdToken } = useContext(AuthContext);
|
|
17
17
|
const [showSuccess, setshowSuccess] = useState(false);
|
|
18
|
+
const [flowKey, setFlowKey] = useState(0);
|
|
19
|
+
const prevShowFlowRef = useRef(showFlow);
|
|
20
|
+
const isFirstMountRef = useRef(true);
|
|
18
21
|
const [popupError, setpopupError] = useState({
|
|
19
22
|
popup: void 0,
|
|
20
23
|
message: void 0
|
|
21
24
|
});
|
|
25
|
+
useLayoutEffect(() => {
|
|
26
|
+
if (isFirstMountRef.current) {
|
|
27
|
+
isFirstMountRef.current = false;
|
|
28
|
+
prevShowFlowRef.current = showFlow;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (showFlow && !prevShowFlowRef.current) {
|
|
32
|
+
setFlowKey((key) => key + 1);
|
|
33
|
+
setshowSuccess(false);
|
|
34
|
+
setpopupError({ popup: void 0, message: void 0 });
|
|
35
|
+
}
|
|
36
|
+
prevShowFlowRef.current = showFlow;
|
|
37
|
+
}, [showFlow]);
|
|
22
38
|
const refreshToken = async () => {
|
|
23
39
|
try {
|
|
24
40
|
refreshIdToken();
|
|
@@ -83,7 +99,7 @@ const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresR
|
|
|
83
99
|
subTitleLeft: "Your log in 2FA authentication is now set",
|
|
84
100
|
textRight: "You will now be asked for your 2FA code next time you log in."
|
|
85
101
|
}
|
|
86
|
-
) : /* @__PURE__ */ jsx(StepControllerProvider, { initialStep:
|
|
102
|
+
) : /* @__PURE__ */ jsx(StepControllerProvider, { initialStep: stepsNames[0], children: /* @__PURE__ */ jsx(StepControllerConsumer, { children: (stepController) => {
|
|
87
103
|
const prevStepIndex = stepController.activeStepIndex - 1;
|
|
88
104
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
89
105
|
/* @__PURE__ */ jsx(
|
|
@@ -143,7 +159,7 @@ const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresR
|
|
|
143
159
|
}
|
|
144
160
|
)
|
|
145
161
|
] });
|
|
146
|
-
} }) }) }) });
|
|
162
|
+
} }) }, flowKey) }) });
|
|
147
163
|
};
|
|
148
164
|
var stdin_default = Enable2FAFlow;
|
|
149
165
|
export {
|
|
@@ -2,26 +2,41 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import "react";
|
|
4
4
|
import { Wrapper } from "../Grid/Grid.styles.js";
|
|
5
|
-
import { StyledFooter, FooterInner, PartnerWrap, Partner, LogoWrap, PoweredWrap, Copyright } from "./Footer.styles.js";
|
|
5
|
+
import { StyledFooter, FooterInner, PartnerWrap, Partner, PartnerLine, LogoWrap, PoweredWrap, Copyright } from "./Footer.styles.js";
|
|
6
6
|
import MangoPayLogo from "../../static/images/mangopay.svg.js";
|
|
7
7
|
const Footer = ({ color = "primary", hasSidebar = false, isSidebarExpanded }) => /* @__PURE__ */ jsx(StyledFooter, { color, isSidebarExpanded, hasSidebar, children: /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsxs(FooterInner, { hasSidebar, children: [
|
|
8
8
|
/* @__PURE__ */ jsx(PartnerWrap, { children: /* @__PURE__ */ jsxs(Partner, { children: [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
/* @__PURE__ */ jsxs(PartnerLine, { children: [
|
|
10
|
+
"STOKR is a crypto asset service provider (",
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
"a",
|
|
13
|
+
{
|
|
14
|
+
href: "https://edesk.apps.cssf.lu/search-entities/entite/details/7079114?lng=en&q=&st=advanced&entType=CASP&entDate=2020-08-01",
|
|
15
|
+
title: "CASP",
|
|
16
|
+
target: "_blank",
|
|
17
|
+
rel: "noopener noreferrer",
|
|
18
|
+
style: { textDecoration: "underline", color: "white" },
|
|
19
|
+
children: "CASP"
|
|
20
|
+
}
|
|
21
|
+
),
|
|
22
|
+
")"
|
|
23
|
+
] }),
|
|
24
|
+
/* @__PURE__ */ jsxs(PartnerLine, { children: [
|
|
25
|
+
"and payment institution (",
|
|
26
|
+
/* @__PURE__ */ jsx(
|
|
27
|
+
"a",
|
|
28
|
+
{
|
|
29
|
+
href: "https://edesk.apps.cssf.lu/search-entities/entite/details/7079119?lng=en&q=&st=advanced&entType=PI&entDate=2020-08-01",
|
|
30
|
+
title: "PI",
|
|
31
|
+
target: "_blank",
|
|
32
|
+
rel: "noopener noreferrer",
|
|
33
|
+
style: { textDecoration: "underline", color: "white" },
|
|
34
|
+
children: "PI"
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
"),"
|
|
38
|
+
] }),
|
|
39
|
+
/* @__PURE__ */ jsx(PartnerLine, { children: "registered with the Luxembourg regulator CSSF." })
|
|
25
40
|
] }) }),
|
|
26
41
|
/* @__PURE__ */ jsx(LogoWrap, { children: /* @__PURE__ */ jsx(
|
|
27
42
|
"img",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import styled, { css } from "styled-components";
|
|
2
|
-
import grid from "../../styles/grid.js";
|
|
3
1
|
import rwd from "../../styles/rwd.js";
|
|
2
|
+
import grid from "../../styles/grid.js";
|
|
4
3
|
import { colors } from "../../styles/colors.js";
|
|
4
|
+
import spacing from "../../styles/spacing.js";
|
|
5
|
+
import styled, { css } from "styled-components";
|
|
5
6
|
const StyledFooter = styled.footer.withConfig({
|
|
6
7
|
shouldForwardProp: (props) => !["color", "hasSidebar", "isSidebarExpanded"].includes(props)
|
|
7
8
|
})`
|
|
@@ -23,13 +24,13 @@ const StyledFooter = styled.footer.withConfig({
|
|
|
23
24
|
|
|
24
25
|
${rwd.Medium`
|
|
25
26
|
box-shadow: inset 0 1px 0 0 ${colors.rustyRed};
|
|
26
|
-
padding: 0
|
|
27
|
+
padding: 0 25px;
|
|
27
28
|
`}
|
|
28
29
|
`}
|
|
29
30
|
|
|
30
31
|
${rwd.Medium`
|
|
31
32
|
width: 100%;
|
|
32
|
-
height:
|
|
33
|
+
min-height: ${spacing.footerHeight}px;
|
|
33
34
|
`}
|
|
34
35
|
|
|
35
36
|
@media screen and (max-width: 991px) {
|
|
@@ -56,10 +57,10 @@ const FooterInner = styled.div.withConfig({
|
|
|
56
57
|
`}
|
|
57
58
|
|
|
58
59
|
${rwd.Medium`
|
|
59
|
-
padding:
|
|
60
|
+
padding: 14px 0;
|
|
60
61
|
display: flex;
|
|
61
62
|
align-items: center;
|
|
62
|
-
height:
|
|
63
|
+
min-height: ${spacing.footerHeight}px;
|
|
63
64
|
|
|
64
65
|
${(props) => props.hasSidebar && `
|
|
65
66
|
padding: 20px ${grid(1)};
|
|
@@ -89,8 +90,7 @@ styled.div`
|
|
|
89
90
|
const PartnerWrap = styled.div`
|
|
90
91
|
text-align: center;
|
|
91
92
|
|
|
92
|
-
${rwd.
|
|
93
|
-
// flex: 2;
|
|
93
|
+
${rwd.MLarge`
|
|
94
94
|
text-align: left;
|
|
95
95
|
`}
|
|
96
96
|
|
|
@@ -184,21 +184,29 @@ styled.nav`
|
|
|
184
184
|
}
|
|
185
185
|
`;
|
|
186
186
|
const Partner = styled.span`
|
|
187
|
+
display: block;
|
|
187
188
|
text-transform: uppercase;
|
|
188
189
|
|
|
189
190
|
font-size: 10px;
|
|
190
191
|
font-weight: 400;
|
|
191
192
|
line-height: 1.8;
|
|
192
|
-
letter-spacing:
|
|
193
|
+
letter-spacing: 1.8px;
|
|
193
194
|
|
|
194
195
|
img {
|
|
195
196
|
margin-bottom: 4px;
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
@media screen and (max-width: 560px) {
|
|
199
|
-
line-height:
|
|
200
|
+
line-height: 16px;
|
|
200
201
|
}
|
|
201
202
|
`;
|
|
203
|
+
const PartnerLine = styled.span`
|
|
204
|
+
display: block;
|
|
205
|
+
|
|
206
|
+
${rwd.MLarge`
|
|
207
|
+
white-space: nowrap;
|
|
208
|
+
`}
|
|
209
|
+
`;
|
|
202
210
|
const Copyright = styled.span`
|
|
203
211
|
img {
|
|
204
212
|
margin-bottom: 4px;
|
|
@@ -250,6 +258,7 @@ export {
|
|
|
250
258
|
FooterInner,
|
|
251
259
|
LogoWrap,
|
|
252
260
|
Partner,
|
|
261
|
+
PartnerLine,
|
|
253
262
|
PartnerWrap,
|
|
254
263
|
PoweredWrap,
|
|
255
264
|
StyledFooter
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import React__default, { PureComponent, Fragment } from "react";
|
|
3
2
|
import PropTypes from "prop-types";
|
|
4
|
-
import {
|
|
3
|
+
import { Transition } from "../../utils/transition.js";
|
|
4
|
+
import React__default, { PureComponent, Fragment } from "react";
|
|
5
5
|
import stdin_default$1 from "./StepControllerProgress.js";
|
|
6
|
+
import { StepsProgressContainer, StepContainer } from "./StepController.styles.js";
|
|
7
|
+
const timeout = 300;
|
|
8
|
+
const getTransitionStyles = {
|
|
9
|
+
entering: {
|
|
10
|
+
opacity: 0
|
|
11
|
+
},
|
|
12
|
+
entered: {
|
|
13
|
+
transition: `opacity ${timeout}ms ease-in-out`,
|
|
14
|
+
opacity: 1
|
|
15
|
+
},
|
|
16
|
+
exiting: {
|
|
17
|
+
transition: `opacity ${timeout}ms ease-in-out`,
|
|
18
|
+
opacity: 0
|
|
19
|
+
}
|
|
20
|
+
};
|
|
6
21
|
class StepController extends PureComponent {
|
|
7
22
|
componentDidMount() {
|
|
8
23
|
const { changeStep, stepsProgressList, currentStep } = this.props;
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
const firstStepId = stepsProgressList[0]?.id;
|
|
25
|
+
if (firstStepId && currentStep !== firstStepId) {
|
|
26
|
+
changeStep(firstStepId, 0, []);
|
|
11
27
|
}
|
|
12
28
|
}
|
|
13
29
|
render() {
|
|
@@ -22,12 +38,33 @@ class StepController extends PureComponent {
|
|
|
22
38
|
stepsProgressList
|
|
23
39
|
}
|
|
24
40
|
) }),
|
|
25
|
-
/* @__PURE__ */ jsx(StepContainer, { children: /* @__PURE__ */ jsx(
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
/* @__PURE__ */ jsx(StepContainer, { children: /* @__PURE__ */ jsx(
|
|
42
|
+
Transition,
|
|
43
|
+
{
|
|
44
|
+
timeout: {
|
|
45
|
+
enter: timeout,
|
|
46
|
+
exit: timeout
|
|
47
|
+
},
|
|
48
|
+
nodeRef: this.stepRef,
|
|
49
|
+
children: (status) => /* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
ref: this.stepRef,
|
|
53
|
+
style: {
|
|
54
|
+
width: "100%",
|
|
55
|
+
height: "100%",
|
|
56
|
+
...getTransitionStyles[status]
|
|
57
|
+
},
|
|
58
|
+
children: React__default.Children.map(children, (child) => {
|
|
59
|
+
if (child.props.id === currentStep && React__default.isValidElement(child)) {
|
|
60
|
+
return /* @__PURE__ */ jsx(Fragment, { children: child }, child.props.id);
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
)
|
|
28
66
|
}
|
|
29
|
-
|
|
30
|
-
}) }) })
|
|
67
|
+
) })
|
|
31
68
|
] });
|
|
32
69
|
}
|
|
33
70
|
}
|
|
@@ -19,16 +19,16 @@ class StepControllerProvider extends Component {
|
|
|
19
19
|
const { activeStepIndex, doneStepsIndexes, touchedStepsIndexes } = this.state;
|
|
20
20
|
const nextActiveStep = activeStep === null ? activeStepIndex : activeStep;
|
|
21
21
|
const nextDoneStepIndexes = doneStepsIndexes.slice();
|
|
22
|
-
|
|
22
|
+
let nextTouchedStepsIndexes = touchedStepsIndexes.slice();
|
|
23
23
|
let emptyDoneStep;
|
|
24
24
|
if (doneStep !== null && !nextDoneStepIndexes.includes(doneStep)) {
|
|
25
25
|
nextDoneStepIndexes.push(doneStep);
|
|
26
26
|
}
|
|
27
|
-
if (!nextTouchedStepsIndexes.includes(nextActiveStep)) {
|
|
28
|
-
nextTouchedStepsIndexes.push(nextActiveStep);
|
|
29
|
-
}
|
|
30
27
|
if (Array.isArray(doneStep) && doneStep.length === 0) {
|
|
31
28
|
emptyDoneStep = [];
|
|
29
|
+
nextTouchedStepsIndexes = [nextActiveStep];
|
|
30
|
+
} else if (!nextTouchedStepsIndexes.includes(nextActiveStep)) {
|
|
31
|
+
nextTouchedStepsIndexes.push(nextActiveStep);
|
|
32
32
|
}
|
|
33
33
|
this.setState(() => ({
|
|
34
34
|
currentStep: stepName,
|