spry-apps-dropdown 3.0.0 → 3.0.2
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 +272 -276
- package/dist/SpryAuthProvider.d.ts +1 -2
- package/dist/constants.d.ts +5 -0
- package/dist/index.cjs +15 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1593 -1576
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,71 +1,17 @@
|
|
|
1
1
|
# spry-apps-dropdown
|
|
2
|
-
## Integration Guide
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
This package requires OIDC authentication. Use `react-oidc-context` or `@react-keycloak/web` for best results.
|
|
7
|
-
|
|
8
|
-
**Example OIDC config:**
|
|
9
|
-
|
|
10
|
-
```tsx
|
|
11
|
-
const oidcConfig = {
|
|
12
|
-
authority: 'https://auth.sprylogin.com/realms/sprylogin',
|
|
13
|
-
client_id: 'my-app-client',
|
|
14
|
-
redirect_uri: window.location.origin,
|
|
15
|
-
post_logout_redirect_uri: window.location.origin,
|
|
16
|
-
onSigninCallback: () => {
|
|
17
|
-
window.history.replaceState({}, document.title, window.location.pathname)
|
|
18
|
-
},
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### 2. Multi-Account Management
|
|
23
|
-
|
|
24
|
-
The package supports multi-account switching, add-account, and soft logout. All account state is stored in localStorage for cross-app/iframe sync.
|
|
25
|
-
|
|
26
|
-
**Syncing across apps/iframe:**
|
|
27
|
-
- Use the same localStorage key (`spry_accounts`) in all apps.
|
|
28
|
-
- When an account is added, removed, or switched, update localStorage and reload state in all apps.
|
|
29
|
-
- For iframe/bridge integration, use a shared localStorage or a custom syncBridge client.
|
|
30
|
-
|
|
31
|
-
### 3. Add Another Account Flow
|
|
32
|
-
|
|
33
|
-
When adding another account:
|
|
34
|
-
- A flag (`spry_add_account_pending`) is set in localStorage.
|
|
35
|
-
- After soft logout, the app checks this flag and triggers OIDC login for the new account.
|
|
36
|
-
- On callback, the new account is added and set as active.
|
|
37
|
-
|
|
38
|
-
### 4. Cross-App Sync
|
|
39
|
-
|
|
40
|
-
To sync active account and account removal across apps:
|
|
41
|
-
- Listen for changes to `spry_accounts` in localStorage (using the `storage` event or polling).
|
|
42
|
-
- When the accounts state changes, update your app's state and UI.
|
|
43
|
-
- If using an iframe bridge, ensure the bridge propagates account changes to all connected apps.
|
|
44
|
-
|
|
45
|
-
### 5. Troubleshooting
|
|
46
|
-
|
|
47
|
-
- If new accounts are not added after login, ensure your OIDC provider updates the user context before the callback runs.
|
|
48
|
-
- If cross-app sync is not working, check that all apps use the same localStorage key and listen for changes.
|
|
49
|
-
- For CORS or redirect issues, verify your OIDC config and Keycloak setup.
|
|
50
|
-
|
|
51
|
-
### 6. Example Integration
|
|
52
|
-
|
|
53
|
-
See the Quick Start and Usage sections below for full code examples.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
A React component library for displaying Spry apps dropdown and profile menu with dynamic API integration. Features a Google-style UI with beautiful animations.
|
|
3
|
+
A React component library for Spry apps dropdown and profile menu with **multi-account switching**. Features a Google-style UI with beautiful animations and automatic Keycloak authentication.
|
|
57
4
|
|
|
58
5
|
## Features
|
|
59
6
|
|
|
60
7
|
- 🎨 Beautiful Material-UI design with smooth animations (Google-inspired)
|
|
61
|
-
-
|
|
62
|
-
-
|
|
8
|
+
- 👥 **Multi-account switching** - Users can log into multiple accounts and switch between them
|
|
9
|
+
- 🔄 Automatic data fetching from API with caching
|
|
10
|
+
- 🔐 Built-in Keycloak/OIDC authentication via react-oidc-context
|
|
63
11
|
- ⚡ Loading and error states
|
|
64
12
|
- 📱 Responsive layout
|
|
65
13
|
- 🎯 TypeScript support
|
|
66
|
-
- 🔌 Easy integration
|
|
67
|
-
- 👤 Profile menu with avatar, account management, and sign out (always shows Manage your Account)
|
|
68
|
-
- 🎛️ Combined TopBar component with both apps dropdown and profile menu
|
|
14
|
+
- 🔌 Easy integration - Just 3 steps!
|
|
69
15
|
|
|
70
16
|
## Installation
|
|
71
17
|
|
|
@@ -73,18 +19,28 @@ A React component library for displaying Spry apps dropdown and profile menu wit
|
|
|
73
19
|
npm install spry-apps-dropdown react-oidc-context oidc-client-ts
|
|
74
20
|
```
|
|
75
21
|
|
|
76
|
-
|
|
22
|
+
**Peer Dependencies:**
|
|
23
|
+
- `react` ^18.0.0 || ^19.0.0
|
|
24
|
+
- `react-dom` ^18.0.0 || ^19.0.0
|
|
25
|
+
- `react-oidc-context` ^3.3.0
|
|
26
|
+
- `oidc-client-ts` ^1.0.0
|
|
27
|
+
|
|
28
|
+
---
|
|
77
29
|
|
|
78
|
-
##
|
|
30
|
+
## Quick Start (3 Steps)
|
|
31
|
+
|
|
32
|
+
### Step 1: Wrap Your App with `SpryAuthProvider`
|
|
79
33
|
|
|
80
34
|
```tsx
|
|
35
|
+
// main.tsx or index.tsx
|
|
81
36
|
import React from 'react'
|
|
82
37
|
import ReactDOM from 'react-dom/client'
|
|
83
|
-
import { SpryAuthProvider
|
|
38
|
+
import { SpryAuthProvider } from 'spry-apps-dropdown'
|
|
39
|
+
import App from './App'
|
|
84
40
|
|
|
85
41
|
const oidcConfig = {
|
|
86
42
|
authority: 'https://auth.sprylogin.com/realms/sprylogin',
|
|
87
|
-
client_id: '
|
|
43
|
+
client_id: 'your-client-id',
|
|
88
44
|
redirect_uri: window.location.origin,
|
|
89
45
|
post_logout_redirect_uri: window.location.origin,
|
|
90
46
|
onSigninCallback: () => {
|
|
@@ -92,17 +48,6 @@ const oidcConfig = {
|
|
|
92
48
|
},
|
|
93
49
|
}
|
|
94
50
|
|
|
95
|
-
function App() {
|
|
96
|
-
const accountManager = useSpryAccountManager()
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<TopBar
|
|
100
|
-
apiUrl="https://your-api.com"
|
|
101
|
-
accountManager={accountManager}
|
|
102
|
-
/>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
51
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
107
52
|
<React.StrictMode>
|
|
108
53
|
<SpryAuthProvider config={oidcConfig}>
|
|
@@ -112,253 +57,252 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
112
57
|
)
|
|
113
58
|
```
|
|
114
59
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### TopBar Component (Easiest - Recommended for v2.0+)
|
|
118
|
-
|
|
119
|
-
The `TopBar` component combines both apps dropdown and profile menu in a single component, just like Google's interface:
|
|
60
|
+
### Step 2: Use `useSpryAccountManager` Hook
|
|
120
61
|
|
|
121
62
|
```tsx
|
|
122
|
-
|
|
63
|
+
// App.tsx
|
|
64
|
+
import { useSpryAccountManager } from 'spry-apps-dropdown'
|
|
65
|
+
|
|
66
|
+
function App() {
|
|
67
|
+
const accountManager = useSpryAccountManager()
|
|
123
68
|
|
|
124
|
-
function MyAppBar() {
|
|
125
69
|
return (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
My App
|
|
130
|
-
</Typography>
|
|
131
|
-
|
|
132
|
-
<TopBar
|
|
133
|
-
apiUrl="https://your-api.com"
|
|
134
|
-
onSignOut={() => handleLogout()}
|
|
135
|
-
getAuthToken={() => yourAuthToken}
|
|
136
|
-
appsRefetchInterval={30000} // 30 seconds
|
|
137
|
-
appsCacheTime={30000}
|
|
138
|
-
profileRefetchInterval={5 * 60 * 1000} // 5 minutes
|
|
139
|
-
profileCacheTime={5 * 60 * 1000}
|
|
140
|
-
/>
|
|
141
|
-
</Toolbar>
|
|
142
|
-
</AppBar>
|
|
70
|
+
<div>
|
|
71
|
+
{/* Your app content */}
|
|
72
|
+
</div>
|
|
143
73
|
)
|
|
144
74
|
}
|
|
145
75
|
```
|
|
146
76
|
|
|
147
|
-
###
|
|
148
|
-
|
|
149
|
-
Use just the profile menu component:
|
|
77
|
+
### Step 3: Add the TopBar Component
|
|
150
78
|
|
|
151
79
|
```tsx
|
|
152
|
-
|
|
80
|
+
// App.tsx
|
|
81
|
+
import { TopBar, useSpryAuth, useSpryAccountManager } from 'spry-apps-dropdown'
|
|
82
|
+
|
|
83
|
+
function App() {
|
|
84
|
+
const auth = useSpryAuth()
|
|
85
|
+
const accountManager = useSpryAccountManager()
|
|
153
86
|
|
|
154
|
-
function MyComponent() {
|
|
155
87
|
return (
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
88
|
+
<div>
|
|
89
|
+
<AppBar>
|
|
90
|
+
<Toolbar>
|
|
91
|
+
<Typography variant="h6" sx={{ flexGrow: 1 }}>
|
|
92
|
+
My App
|
|
93
|
+
</Typography>
|
|
94
|
+
|
|
95
|
+
<TopBar
|
|
96
|
+
apiUrl="https://sprylogin.com/apps-api"
|
|
97
|
+
onSignOut={() => auth.signoutRedirect()}
|
|
98
|
+
getAuthToken={() => auth.user?.access_token || null}
|
|
99
|
+
accountManager={accountManager}
|
|
100
|
+
/>
|
|
101
|
+
</Toolbar>
|
|
102
|
+
</AppBar>
|
|
103
|
+
|
|
104
|
+
{/* Your app content */}
|
|
105
|
+
</div>
|
|
163
106
|
)
|
|
164
107
|
}
|
|
165
108
|
```
|
|
166
109
|
|
|
167
|
-
|
|
110
|
+
**That's it!** Your app now has:
|
|
111
|
+
- ✅ Multi-account switching
|
|
112
|
+
- ✅ Apps dropdown
|
|
113
|
+
- ✅ Profile menu
|
|
114
|
+
- ✅ Automatic authentication
|
|
168
115
|
|
|
169
|
-
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Using Auth Token in Your API Calls
|
|
119
|
+
|
|
120
|
+
Get the current user's token using `useSpryAuth()`:
|
|
170
121
|
|
|
171
122
|
```tsx
|
|
172
|
-
import {
|
|
173
|
-
import { IconButton } from '@mui/material'
|
|
174
|
-
import { Apps } from '@mui/icons-material'
|
|
175
|
-
import { AppsDropdownConnected } from 'spry-apps-dropdown'
|
|
123
|
+
import { useSpryAuth } from 'spry-apps-dropdown'
|
|
176
124
|
|
|
177
125
|
function MyComponent() {
|
|
178
|
-
const
|
|
179
|
-
const appsButtonRef = useRef<HTMLButtonElement>(null)
|
|
126
|
+
const auth = useSpryAuth()
|
|
180
127
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<AppsDropdownConnected
|
|
191
|
-
apiUrl="http://localhost:3002"
|
|
192
|
-
open={appsMenuOpen}
|
|
193
|
-
onClose={() => setAppsMenuOpen(false)}
|
|
194
|
-
buttonRef={appsButtonRef}
|
|
195
|
-
/>
|
|
196
|
-
</>
|
|
197
|
-
)
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const token = auth.user?.access_token
|
|
130
|
+
|
|
131
|
+
fetch('/api/data', {
|
|
132
|
+
headers: {
|
|
133
|
+
'Authorization': `Bearer ${token}`
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}, [auth.user])
|
|
198
137
|
}
|
|
199
138
|
```
|
|
200
139
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
Use `AppsDropdown` directly with custom data source:
|
|
140
|
+
**For React Query:**
|
|
204
141
|
|
|
205
142
|
```tsx
|
|
206
|
-
import {
|
|
143
|
+
import { useSpryAuth } from 'spry-apps-dropdown'
|
|
144
|
+
import { useQuery } from '@tanstack/react-query'
|
|
207
145
|
|
|
208
146
|
function MyComponent() {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
147
|
+
const auth = useSpryAuth()
|
|
148
|
+
|
|
149
|
+
const { data } = useQuery({
|
|
150
|
+
queryKey: ['data'],
|
|
151
|
+
queryFn: async () => {
|
|
152
|
+
const token = auth.user?.access_token
|
|
153
|
+
const res = await fetch('/api/data', {
|
|
154
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
155
|
+
})
|
|
156
|
+
return res.json()
|
|
157
|
+
},
|
|
158
|
+
enabled: !!auth.user,
|
|
216
159
|
})
|
|
217
|
-
|
|
218
|
-
return (
|
|
219
|
-
<>
|
|
220
|
-
<IconButton ref={appsButtonRef} onClick={() => setAppsMenuOpen(!appsMenuOpen)}>
|
|
221
|
-
<Apps />
|
|
222
|
-
</IconButton>
|
|
223
|
-
|
|
224
|
-
<AppsDropdown
|
|
225
|
-
apps={apps}
|
|
226
|
-
open={appsMenuOpen}
|
|
227
|
-
onClose={() => setAppsMenuOpen(false)}
|
|
228
|
-
buttonRef={appsButtonRef}
|
|
229
|
-
isLoading={isLoading}
|
|
230
|
-
error={error}
|
|
231
|
-
onRetry={refetch}
|
|
232
|
-
/>
|
|
233
|
-
</>
|
|
234
|
-
)
|
|
235
160
|
}
|
|
236
161
|
```
|
|
237
162
|
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Multi-Account Switching
|
|
166
|
+
|
|
167
|
+
The package automatically handles multi-account switching:
|
|
168
|
+
|
|
169
|
+
1. **User clicks "Add Another Account"** in ProfileMenu
|
|
170
|
+
2. **Redirects to Keycloak** for login (with `prompt=login`)
|
|
171
|
+
3. **New account is added** to localStorage
|
|
172
|
+
4. **User can switch** between accounts from ProfileMenu
|
|
173
|
+
5. **API calls automatically use** the active account's token
|
|
174
|
+
|
|
175
|
+
**No manual code needed** - it just works!
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
238
179
|
## API Reference
|
|
239
180
|
|
|
240
|
-
### `TopBar`
|
|
181
|
+
### `TopBar` Component
|
|
241
182
|
|
|
242
|
-
Combined
|
|
183
|
+
Combined apps dropdown + profile menu (recommended).
|
|
243
184
|
|
|
244
185
|
#### Props
|
|
245
186
|
|
|
246
187
|
| Prop | Type | Required | Default | Description |
|
|
247
188
|
|------|------|----------|---------|-------------|
|
|
248
189
|
| `apiUrl` | `string` | Yes | - | Base URL for apps API |
|
|
190
|
+
| `accountManager` | `UseAccountManagerReturn` | Yes | - | Account manager from `useSpryAccountManager()` |
|
|
249
191
|
| `profileApiUrl` | `string` | No | Same as `apiUrl` | Base URL for profile API |
|
|
250
192
|
| `onSignOut` | `() => void` | No | - | Callback when user signs out |
|
|
251
|
-
| `getAuthToken` | `() => string \| null
|
|
193
|
+
| `getAuthToken` | `() => string \| null` | No | - | Function to get auth token |
|
|
252
194
|
| `profileHeaders` | `Record<string, string>` | No | - | Custom headers for profile API |
|
|
253
195
|
| `showAppsDropdown` | `boolean` | No | `true` | Show apps dropdown |
|
|
254
196
|
| `showProfileMenu` | `boolean` | No | `true` | Show profile menu |
|
|
255
|
-
| `appsRefetchInterval` | `number` | No | `300000` (5 min) | Apps refetch interval
|
|
256
|
-
| `appsCacheTime` | `number` | No | `300000` (5 min) | Apps cache duration
|
|
257
|
-
| `profileRefetchInterval` | `number` | No | `300000` (5 min) | Profile refetch interval
|
|
258
|
-
| `profileCacheTime` | `number` | No | `300000` (5 min) | Profile cache duration
|
|
259
|
-
|
|
260
|
-
### `ProfileMenuConnected` (New in v2.0)
|
|
261
|
-
|
|
262
|
-
Profile menu component with automatic API integration.
|
|
263
|
-
|
|
264
|
-
#### Props
|
|
265
|
-
|
|
266
|
-
| Prop | Type | Required | Default | Description |
|
|
267
|
-
|------|------|----------|---------|-------------|
|
|
268
|
-
| `apiUrl` | `string` | Yes | - | Base URL for profile API |
|
|
269
|
-
| `onSignOut` | `() => void` | No | - | Callback when user signs out |
|
|
270
|
-
| `onManageAccount` | `() => void` | No | - | Callback for Manage your Account button. If not provided, it redirects to `https://sprylogin.com/my-account/` |
|
|
271
|
-
| `getAuthToken` | `() => string \| null \| Promise<string \| null>` | No | - | Function to get auth token |
|
|
272
|
-
| `headers` | `Record<string, string>` | No | - | Custom headers for API requests |
|
|
273
|
-
| `refetchInterval` | `number` | No | `300000` (5 min) | Auto-refetch interval in ms |
|
|
274
|
-
| `cacheTime` | `number` | No | `300000` (5 min) | Cache duration in ms |
|
|
197
|
+
| `appsRefetchInterval` | `number` | No | `300000` (5 min) | Apps refetch interval (ms) |
|
|
198
|
+
| `appsCacheTime` | `number` | No | `300000` (5 min) | Apps cache duration (ms) |
|
|
199
|
+
| `profileRefetchInterval` | `number` | No | `300000` (5 min) | Profile refetch interval (ms) |
|
|
200
|
+
| `profileCacheTime` | `number` | No | `300000` (5 min) | Profile cache duration (ms) |
|
|
275
201
|
|
|
276
|
-
|
|
202
|
+
---
|
|
277
203
|
|
|
278
|
-
|
|
204
|
+
### `SpryAuthProvider` Component
|
|
279
205
|
|
|
280
|
-
|
|
281
|
-
2. `profile.manageAccountUrl` (if present)
|
|
282
|
-
3. Default: `https://sprylogin.com/my-account/`
|
|
283
|
-
|
|
284
|
-
### `AppsDropdownConnected`
|
|
285
|
-
|
|
286
|
-
The main component with automatic API integration.
|
|
206
|
+
Wraps your app with Keycloak/OIDC authentication.
|
|
287
207
|
|
|
288
208
|
#### Props
|
|
289
209
|
|
|
290
|
-
| Prop | Type | Required |
|
|
291
|
-
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `onClose` | `() => void` | Yes | - | Callback when dropdown closes |
|
|
295
|
-
| `buttonRef` | `React.RefObject<HTMLButtonElement>` | No | - | Ref for positioning |
|
|
296
|
-
| `refetchInterval` | `number` | No | `300000` (5 min) | Auto-refetch interval in ms |
|
|
297
|
-
| `cacheTime` | `number` | No | `300000` (5 min) | Cache duration in ms |
|
|
298
|
-
|
|
299
|
-
### `AppsDropdown`
|
|
210
|
+
| Prop | Type | Required | Description |
|
|
211
|
+
|------|------|----------|-------------|
|
|
212
|
+
| `config` | `UserManagerSettings` | Yes | OIDC configuration object |
|
|
213
|
+
| `children` | `ReactNode` | Yes | Your app components |
|
|
300
214
|
|
|
301
|
-
|
|
215
|
+
**Example config:**
|
|
302
216
|
|
|
303
|
-
|
|
217
|
+
```tsx
|
|
218
|
+
const oidcConfig = {
|
|
219
|
+
authority: 'https://auth.sprylogin.com/realms/sprylogin',
|
|
220
|
+
client_id: 'my-app-client',
|
|
221
|
+
redirect_uri: window.location.origin,
|
|
222
|
+
post_logout_redirect_uri: window.location.origin,
|
|
223
|
+
onSigninCallback: () => {
|
|
224
|
+
window.history.replaceState({}, document.title, window.location.pathname)
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
```
|
|
304
228
|
|
|
305
|
-
|
|
306
|
-
|------|------|----------|---------|-------------|
|
|
307
|
-
| `apps` | `App[]` | Yes | - | Array of apps to display |
|
|
308
|
-
| `open` | `boolean` | Yes | - | Whether the dropdown is open |
|
|
309
|
-
| `onClose` | `() => void` | Yes | - | Callback when dropdown closes |
|
|
310
|
-
| `buttonRef` | `React.RefObject<HTMLButtonElement>` | No | - | Ref for positioning |
|
|
311
|
-
| `isLoading` | `boolean` | No | `false` | Loading state |
|
|
312
|
-
| `error` | `string \| null` | No | `null` | Error message |
|
|
313
|
-
| `onRetry` | `() => void` | No | - | Retry callback |
|
|
229
|
+
---
|
|
314
230
|
|
|
315
|
-
### `
|
|
231
|
+
### `useSpryAccountManager()` Hook
|
|
316
232
|
|
|
317
|
-
|
|
233
|
+
Returns account manager for multi-account switching.
|
|
318
234
|
|
|
319
|
-
####
|
|
235
|
+
#### Returns
|
|
320
236
|
|
|
321
237
|
```typescript
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
238
|
+
{
|
|
239
|
+
accounts: StoredAccount[] // All logged-in accounts
|
|
240
|
+
activeAccount: StoredAccount // Currently active account
|
|
241
|
+
switchAccount: (id: string) => Promise<void>
|
|
242
|
+
addNewAccount: () => Promise<void>
|
|
243
|
+
removeAccount: (id: string) => Promise<void>
|
|
244
|
+
refreshAccountToken: (id: string) => Promise<void>
|
|
245
|
+
}
|
|
326
246
|
```
|
|
327
247
|
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
### `useSpryAuth()` Hook
|
|
251
|
+
|
|
252
|
+
Returns the current authentication state (alias for `useAuth()` from react-oidc-context).
|
|
253
|
+
|
|
328
254
|
#### Returns
|
|
329
255
|
|
|
330
256
|
```typescript
|
|
331
257
|
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
258
|
+
user: User | null // Current user object
|
|
259
|
+
isAuthenticated: boolean // Is user logged in
|
|
260
|
+
isLoading: boolean // Is auth loading
|
|
261
|
+
signinRedirect: () => Promise<void>
|
|
262
|
+
signoutRedirect: () => Promise<void>
|
|
263
|
+
// ... other react-oidc-context methods
|
|
336
264
|
}
|
|
337
265
|
```
|
|
338
266
|
|
|
339
|
-
|
|
267
|
+
---
|
|
340
268
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
269
|
+
## Advanced: Handling Account Switches
|
|
270
|
+
|
|
271
|
+
If you're using React Query and want to refetch data when accounts switch:
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
import { useSpryAccountManager } from 'spry-apps-dropdown'
|
|
275
|
+
import { useQueryClient } from '@tanstack/react-query'
|
|
276
|
+
import { useEffect } from 'react'
|
|
277
|
+
|
|
278
|
+
function useMultiAccountManager() {
|
|
279
|
+
const queryClient = useQueryClient()
|
|
280
|
+
const accountManager = useSpryAccountManager()
|
|
281
|
+
|
|
282
|
+
// Listen for account switches and invalidate queries
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
const handleAccountSwitch = () => {
|
|
285
|
+
queryClient.invalidateQueries() // Refetch all data
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
window.addEventListener('auth:account-switched', handleAccountSwitch)
|
|
289
|
+
return () => window.removeEventListener('auth:account-switched', handleAccountSwitch)
|
|
290
|
+
}, [queryClient])
|
|
291
|
+
|
|
292
|
+
return accountManager
|
|
352
293
|
}
|
|
353
294
|
```
|
|
354
295
|
|
|
296
|
+
---
|
|
297
|
+
|
|
355
298
|
## Backend API Requirements
|
|
356
299
|
|
|
357
|
-
|
|
300
|
+
Your backend should expose these endpoints:
|
|
358
301
|
|
|
359
302
|
### `GET /api/apps`
|
|
360
303
|
|
|
361
|
-
Returns
|
|
304
|
+
Returns list of apps for the dropdown.
|
|
305
|
+
|
|
362
306
|
```json
|
|
363
307
|
{
|
|
364
308
|
"apps": [
|
|
@@ -378,26 +322,17 @@ Returns:
|
|
|
378
322
|
}
|
|
379
323
|
```
|
|
380
324
|
|
|
381
|
-
### `GET /api/profile`
|
|
325
|
+
### `GET /api/profile`
|
|
382
326
|
|
|
383
|
-
Returns user profile information
|
|
327
|
+
Returns user profile information (requires Bearer token).
|
|
384
328
|
|
|
385
|
-
**Option 1: JWT Token (via Authorization header)**
|
|
386
329
|
```http
|
|
387
330
|
GET /api/profile
|
|
388
331
|
Authorization: Bearer <jwt-token>
|
|
389
332
|
```
|
|
390
333
|
|
|
391
|
-
**Option 2: Custom Headers**
|
|
392
|
-
```http
|
|
393
|
-
GET /api/profile
|
|
394
|
-
X-User-Email: user@example.com
|
|
395
|
-
X-User-FirstName: John
|
|
396
|
-
X-User-LastName: Doe
|
|
397
|
-
X-User-Avatar: https://example.com/avatar.jpg
|
|
398
|
-
```
|
|
399
|
-
|
|
400
334
|
**Response:**
|
|
335
|
+
|
|
401
336
|
```json
|
|
402
337
|
{
|
|
403
338
|
"email": "user@example.com",
|
|
@@ -408,52 +343,113 @@ X-User-Avatar: https://example.com/avatar.jpg
|
|
|
408
343
|
}
|
|
409
344
|
```
|
|
410
345
|
|
|
411
|
-
|
|
346
|
+
---
|
|
412
347
|
|
|
413
|
-
##
|
|
348
|
+
## Customization
|
|
414
349
|
|
|
415
|
-
|
|
350
|
+
### Custom Theme
|
|
416
351
|
|
|
417
352
|
```tsx
|
|
418
353
|
import { ThemeProvider, createTheme } from '@mui/material/styles'
|
|
419
354
|
|
|
420
355
|
const theme = createTheme({
|
|
421
|
-
|
|
356
|
+
palette: {
|
|
357
|
+
primary: {
|
|
358
|
+
main: '#1a73e8',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
422
361
|
})
|
|
423
362
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
<
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
)
|
|
430
|
-
}
|
|
363
|
+
<ThemeProvider theme={theme}>
|
|
364
|
+
<SpryAuthProvider config={oidcConfig}>
|
|
365
|
+
<App />
|
|
366
|
+
</SpryAuthProvider>
|
|
367
|
+
</ThemeProvider>
|
|
431
368
|
```
|
|
432
369
|
|
|
433
|
-
|
|
370
|
+
### Hide Apps Dropdown or Profile Menu
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
<TopBar
|
|
374
|
+
apiUrl="https://sprylogin.com/apps-api"
|
|
375
|
+
showAppsDropdown={false} // Hide apps dropdown
|
|
376
|
+
showProfileMenu={true} // Show only profile menu
|
|
377
|
+
accountManager={accountManager}
|
|
378
|
+
/>
|
|
379
|
+
```
|
|
434
380
|
|
|
435
|
-
|
|
381
|
+
---
|
|
436
382
|
|
|
437
|
-
##
|
|
383
|
+
## Troubleshooting
|
|
438
384
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
385
|
+
### "User not authenticated" error
|
|
386
|
+
|
|
387
|
+
Make sure you wrapped your app with `SpryAuthProvider`:
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
<SpryAuthProvider config={oidcConfig}>
|
|
391
|
+
<App />
|
|
392
|
+
</SpryAuthProvider>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Account switching doesn't work
|
|
396
|
+
|
|
397
|
+
Pass the `accountManager` prop to `TopBar`:
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
const accountManager = useSpryAccountManager()
|
|
401
|
+
|
|
402
|
+
<TopBar accountManager={accountManager} {...otherProps} />
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### API calls use wrong token after switching
|
|
406
|
+
|
|
407
|
+
Use `useSpryAuth()` to get the current token:
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
const auth = useSpryAuth()
|
|
411
|
+
const token = auth.user?.access_token
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## TypeScript Support
|
|
417
|
+
|
|
418
|
+
Full TypeScript support included. Types are automatically available:
|
|
419
|
+
|
|
420
|
+
```tsx
|
|
421
|
+
import type {
|
|
422
|
+
UseAccountManagerReturn,
|
|
423
|
+
StoredAccount,
|
|
424
|
+
OIDCUser,
|
|
425
|
+
TopBarProps
|
|
426
|
+
} from 'spry-apps-dropdown'
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
442
430
|
|
|
443
431
|
## Browser Support
|
|
444
432
|
|
|
445
433
|
- Modern browsers with ES2020 support
|
|
446
434
|
- Requires localStorage API
|
|
447
435
|
|
|
436
|
+
---
|
|
437
|
+
|
|
448
438
|
## License
|
|
449
439
|
|
|
450
440
|
MIT
|
|
451
441
|
|
|
452
|
-
|
|
442
|
+
---
|
|
453
443
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
## Related
|
|
444
|
+
## Related Documentation
|
|
457
445
|
|
|
446
|
+
- [INTEGRATION.md](./INTEGRATION.md) - Detailed multi-account integration guide
|
|
458
447
|
- [Spry Apps Server](https://github.com/your-org/spry-apps-server) - Backend API server
|
|
459
|
-
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Support
|
|
452
|
+
|
|
453
|
+
For issues or questions:
|
|
454
|
+
- Open an issue on GitHub
|
|
455
|
+
- Check INTEGRATION.md for detailed guides
|