thecore-auth 0.0.214 → 0.0.215
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 +1318 -128
- package/dist/thecore-auth.cjs.js +39 -39
- package/dist/thecore-auth.css +1 -1
- package/dist/thecore-auth.esm.js +4963 -4765
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,195 +1,1385 @@
|
|
|
1
|
-
#
|
|
1
|
+
# thecore-auth — Documentation (English)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> 🇮🇹 [Documentazione in Italiano](https://github.com/SantiGalvan/thecore-auth/blob/main/DOCUMENTATION_IT.md) | 🇪🇸 [Documentación en Español](https://github.com/SantiGalvan/thecore-auth/blob/main/DOCUMENTATION_ES.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Version: 0.0.214 | License: MIT | Author: Santiago Galvan
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is thecore-auth?
|
|
10
|
+
|
|
11
|
+
**thecore-auth** is a React library that provides a complete authentication system based on **JWT (JSON Web Tokens)**, integrated with **React Router** and built for the **thecore** architecture pattern.
|
|
12
|
+
|
|
13
|
+
It ships ready-to-use:
|
|
14
|
+
- JWT login / logout with automatic token refresh
|
|
15
|
+
- Context providers for auth, loading, alerts, modals, forms, and routing
|
|
16
|
+
- A set of UI components (login form, modal, inputs, loaders, alerts)
|
|
17
|
+
- Utility hooks for device detection, form management, calendar, IndexedDB, and more
|
|
18
|
+
- Re-exports of the most common React Router APIs so you only import from one place
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
### 1. Create a new React project with Vite
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm create vite@latest my-app -- --template react
|
|
28
|
+
cd my-app
|
|
29
|
+
npm install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Install thecore-auth
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install thecore-auth
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. Import the CSS
|
|
39
|
+
|
|
40
|
+
In your main CSS file (e.g. `src/index.css`) add:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@import url('../node_modules/thecore-auth/dist/thecore-auth.css');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or in `src/main.jsx`:
|
|
47
|
+
|
|
48
|
+
```jsx
|
|
49
|
+
import 'thecore-auth/dist/thecore-auth.css';
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Required Configuration
|
|
55
|
+
|
|
56
|
+
Create a file `public/config.json` in your project. This file is loaded at runtime and drives the entire auth system:
|
|
9
57
|
|
|
10
|
-
### Example:
|
|
11
58
|
```json
|
|
12
59
|
{
|
|
13
|
-
"baseUri": "",
|
|
14
|
-
"authenticatedEndpoint": "",
|
|
15
|
-
"usersEndpoint": "",
|
|
16
|
-
"heartbeatEndpoint": "",
|
|
17
|
-
"firstPrivatePath": "/dashboard
|
|
60
|
+
"baseUri": "https://api.myapp.com",
|
|
61
|
+
"authenticatedEndpoint": "/auth/login",
|
|
62
|
+
"usersEndpoint": "/auth/me",
|
|
63
|
+
"heartbeatEndpoint": "/auth/refresh",
|
|
64
|
+
"firstPrivatePath": "/dashboard",
|
|
18
65
|
"firstPrivateTitle": "Dashboard",
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"alertTimeout": 5000,
|
|
24
|
-
"axiosTimeout": 3000,
|
|
66
|
+
"defaultTitle": "My App",
|
|
67
|
+
"infiniteSession": false,
|
|
68
|
+
"timeDeducted": 60000,
|
|
69
|
+
"alertTimeout": 4000,
|
|
25
70
|
"axiosErrors": {
|
|
26
|
-
"unauthorized": "
|
|
27
|
-
"notFound": "
|
|
28
|
-
"defaultMessage": "
|
|
71
|
+
"unauthorized": "Session expired. Please log in again.",
|
|
72
|
+
"notFound": "Resource not found.",
|
|
73
|
+
"defaultMessage": "An unexpected error occurred."
|
|
29
74
|
},
|
|
30
75
|
"clearLoginFormOnError": true,
|
|
31
76
|
"autoLogin": false,
|
|
32
|
-
"backendToken": "
|
|
33
|
-
"isDebug":
|
|
77
|
+
"backendToken": "",
|
|
78
|
+
"isDebug": false,
|
|
79
|
+
"tokenLog": false,
|
|
80
|
+
"isDevelopment": false,
|
|
81
|
+
"hasSessionKey": false,
|
|
82
|
+
"appKey": "myapp",
|
|
83
|
+
"showHeaderButton": false,
|
|
84
|
+
"useCustomLoginTimeout": false,
|
|
85
|
+
"customLoginTimeout": 10000,
|
|
86
|
+
"stopLoaderOnFinish": true,
|
|
87
|
+
"timerInfiniteSession": "",
|
|
88
|
+
"customDeviceType": "",
|
|
89
|
+
"sileoToastEnabled": false,
|
|
90
|
+
"sileoToastConfig": {
|
|
91
|
+
"position": "bottom-center",
|
|
92
|
+
"options": {
|
|
93
|
+
"fill": "#000000",
|
|
94
|
+
"duration": 2000,
|
|
95
|
+
"styles": {
|
|
96
|
+
"title": "text-white font-semibold",
|
|
97
|
+
"description": "text-white/75",
|
|
98
|
+
"badge": "bg-white/20"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"pwa": {
|
|
103
|
+
"enabled": false,
|
|
104
|
+
"promptOnLoad": false,
|
|
105
|
+
"customPrompt": false
|
|
106
|
+
},
|
|
107
|
+
"routes": [
|
|
108
|
+
{ "path": "/dashboard", "title": "Dashboard" },
|
|
109
|
+
{ "path": "/profile", "title": "Profile" }
|
|
110
|
+
],
|
|
111
|
+
"configRoutes": []
|
|
34
112
|
}
|
|
35
113
|
```
|
|
36
114
|
|
|
37
|
-
|
|
115
|
+
| Key | Type | Description |
|
|
116
|
+
|-----|------|-------------|
|
|
117
|
+
| `baseUri` | `string` | Base URL of the backend API |
|
|
118
|
+
| `authenticatedEndpoint` | `string` | Login endpoint path |
|
|
119
|
+
| `usersEndpoint` | `string` | Endpoint to fetch the authenticated user |
|
|
120
|
+
| `heartbeatEndpoint` | `string` | Endpoint to refresh the JWT token |
|
|
121
|
+
| `firstPrivatePath` | `string` | Redirect path after successful login |
|
|
122
|
+
| `firstPrivateTitle` | `string` | Title of the first private page |
|
|
123
|
+
| `infiniteSession` | `boolean` | If `true`, session never expires |
|
|
124
|
+
| `timeDeducted` | `number` | Milliseconds to subtract from token expiry for early refresh |
|
|
125
|
+
| `alertTimeout` | `number` | Duration (ms) to show alert notifications |
|
|
126
|
+
| `axiosErrors` | `object` | Custom error messages for 401, 404, and generic errors |
|
|
127
|
+
| `clearLoginFormOnError` | `boolean` | Clear login form fields when an error occurs |
|
|
128
|
+
| `autoLogin` | `boolean` | Enable machine-to-machine auto-login |
|
|
129
|
+
| `backendToken` | `string` | Token used for auto-login |
|
|
130
|
+
| `isDebug` | `boolean` | Enable debug logging to console |
|
|
131
|
+
| `sileoToastEnabled` | `boolean` | Enable Sileo mobile toast notifications |
|
|
132
|
+
| `sileoToastConfig` | `object` | Sileo toast options: `position`, `options.fill`, `options.duration`, `options.styles` |
|
|
133
|
+
| `hasSessionKey` | `boolean` | Generate a unique session key per browser tab |
|
|
134
|
+
| `appKey` | `string` | App prefix for the session key |
|
|
135
|
+
| `isDevelopment` | `boolean` | Development mode flag |
|
|
136
|
+
| `defaultTitle` | `string` | Default browser tab title |
|
|
137
|
+
| `routes` | `array` | Array of `{ path, title }` for automatic page title updates |
|
|
138
|
+
| `configRoutes` | `array` | Additional custom routes injected by the package |
|
|
139
|
+
| `tokenLog` | `boolean` | Log JWT token details to the console (debug) |
|
|
140
|
+
| `showHeaderButton` | `boolean` | Show a logout button in the default header |
|
|
141
|
+
| `useCustomLoginTimeout` | `boolean` | Enable a custom timeout for the login request |
|
|
142
|
+
| `customLoginTimeout` | `number` | Timeout (ms) for the login request when `useCustomLoginTimeout` is `true` |
|
|
143
|
+
| `stopLoaderOnFinish` | `boolean` | Stop the global loader when SmartLogin finishes its intro animation |
|
|
144
|
+
| `timerInfiniteSession` | `string` | Cron-like string for infinite-session heartbeat scheduling |
|
|
145
|
+
| `customDeviceType` | `string` | Override the detected device type (`'mobile'`, `'tablet'`, `'desktop'`) |
|
|
146
|
+
| `pwa` | `object` | PWA install prompt config: `enabled`, `promptOnLoad`, `customPrompt` |
|
|
147
|
+
|
|
148
|
+
---
|
|
38
149
|
|
|
39
|
-
|
|
40
|
-
- `authenticatedEndpoint`: The endpoint for user login and authentication. This URL is used to send the authentication request.
|
|
41
|
-
- `usersEndpoint`: The endpoint to retrieve user information, such as the user list or details of the authenticated user.
|
|
42
|
-
- `heartbeatEndpoint`: The endpoint for renewing the authentication token (heartbeat). This URL is used to keep the session active, preventing the token from expiring.
|
|
43
|
-
- `firstPrivatePath`: The path to the first private route that the user sees after logging in. For example, it might be a page like the dashboard.
|
|
44
|
-
- `firstPrivateTitle`: The title to display for the first private page, useful for defining the page name in the layout.
|
|
45
|
-
- `configRoutes`: A list of new customizable routes to add to the application. Each route contains a `path` (URL), a `title` (title to display on the page), and an `element` (the element defining the route content, such as a React component).
|
|
46
|
-
- `infiniteSession`: The number of milliseconds to subtract from the authentication token's expiration time to determine when the session should be considered expired and therefore renewed.
|
|
47
|
-
- `alertTimeout`: The time, in milliseconds, for how long an alert (e.g., an on-screen notification) should remain visible.
|
|
48
|
-
- `axiosTimeout`: The maximum duration (in milliseconds) that an Axios request can take before it times out.
|
|
49
|
-
- `axiosErrors`: An object containing custom messages to display for specific Axios errors:
|
|
50
|
-
- `unauthorized`: The message displayed when error code 401 (access denied) is returned from the request.
|
|
51
|
-
- `notFound`: The message displayed when error code 404 (resource not found) is returned from the request.
|
|
52
|
-
- `defaultMessage`: A generic message displayed for unspecified errors.
|
|
53
|
-
- `clearLoginFormOnError`: A flag that indicates whether the login form data should be cleared in case of an error.
|
|
54
|
-
- `autoLogin`: A flag that enables or disables auto-login. When set to true, the app will automatically log in with predefined credentials.
|
|
55
|
-
- `backendToken`: The token for auto-login, used for automatic login in "machine-to-machine" mode or without user interaction.
|
|
56
|
-
- `isDebug`: A flag that, when set to true, enables the display of debug logs (console.log) to assist with application debugging.
|
|
150
|
+
## Quick Start — Complete Setup
|
|
57
151
|
|
|
58
|
-
|
|
152
|
+
### `src/main.jsx`
|
|
59
153
|
|
|
60
154
|
```jsx
|
|
61
|
-
|
|
155
|
+
import { StrictMode } from 'react';
|
|
156
|
+
import { createRoot } from 'react-dom/client';
|
|
157
|
+
import { BrowserRouter } from 'thecore-auth';
|
|
158
|
+
import App from './App.jsx';
|
|
159
|
+
import 'thecore-auth/dist/thecore-auth.css';
|
|
160
|
+
import './index.css';
|
|
161
|
+
|
|
162
|
+
createRoot(document.getElementById('root')).render(
|
|
163
|
+
<StrictMode>
|
|
164
|
+
<BrowserRouter>
|
|
165
|
+
<App />
|
|
166
|
+
</BrowserRouter>
|
|
167
|
+
</StrictMode>
|
|
168
|
+
);
|
|
62
169
|
```
|
|
63
170
|
|
|
64
|
-
|
|
171
|
+
### `src/App.jsx`
|
|
65
172
|
|
|
66
|
-
|
|
173
|
+
```jsx
|
|
174
|
+
import {
|
|
175
|
+
PackageRoutes,
|
|
176
|
+
ConfigProvider,
|
|
177
|
+
AuthProvider,
|
|
178
|
+
LoadingProvider,
|
|
179
|
+
AlertProvider,
|
|
180
|
+
LoginFormProvider,
|
|
181
|
+
ModalProvider,
|
|
182
|
+
RouteProvider
|
|
183
|
+
} from 'thecore-auth';
|
|
67
184
|
|
|
68
|
-
|
|
185
|
+
// Your private pages
|
|
186
|
+
import Dashboard from './pages/Dashboard';
|
|
69
187
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
188
|
+
// Define your private routes
|
|
189
|
+
const privateRoutes = [
|
|
190
|
+
{ path: '/dashboard', element: <Dashboard /> }
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
export default function App() {
|
|
194
|
+
return (
|
|
195
|
+
<ConfigProvider>
|
|
74
196
|
<LoadingProvider>
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
197
|
+
<AlertProvider>
|
|
198
|
+
<AuthProvider>
|
|
199
|
+
<LoginFormProvider>
|
|
200
|
+
<ModalProvider>
|
|
201
|
+
<RouteProvider privateRoutes={privateRoutes} publicRoutes={[]}>
|
|
202
|
+
<PackageRoutes
|
|
203
|
+
firstPrivateElement={<Dashboard />}
|
|
204
|
+
/>
|
|
205
|
+
</RouteProvider>
|
|
206
|
+
</ModalProvider>
|
|
207
|
+
</LoginFormProvider>
|
|
208
|
+
</AuthProvider>
|
|
209
|
+
</AlertProvider>
|
|
84
210
|
</LoadingProvider>
|
|
85
|
-
</
|
|
86
|
-
|
|
87
|
-
|
|
211
|
+
</ConfigProvider>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
88
214
|
```
|
|
89
215
|
|
|
90
|
-
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Context Providers & Hooks
|
|
219
|
+
|
|
220
|
+
### ConfigProvider / useConfig
|
|
221
|
+
|
|
222
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/ConfigProvider.md)
|
|
223
|
+
|
|
224
|
+
Loads and exposes the runtime `config.json` configuration. Also provides IndexedDB utilities and the current date helper.
|
|
91
225
|
|
|
92
226
|
```jsx
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
227
|
+
import { useConfig } from 'thecore-auth';
|
|
228
|
+
|
|
229
|
+
function MyComponent() {
|
|
230
|
+
const { config, version, setCurrentDate, getDataIndexedDB } = useConfig();
|
|
231
|
+
|
|
232
|
+
return <p>API base: {config.baseUri}</p>;
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Returned values:**
|
|
237
|
+
|
|
238
|
+
| Name | Type | Description |
|
|
239
|
+
|------|------|-------------|
|
|
240
|
+
| `config` | `object` | All values from `config.json` |
|
|
241
|
+
| `version` | `string` | Package version |
|
|
242
|
+
| `setCurrentDate()` | `function` | Returns current date as `dd/mm/yyyy hh:mm:ss` |
|
|
243
|
+
| `openIndexedDB(db, store)` | `function` | Open an IndexedDB connection |
|
|
244
|
+
| `getDataIndexedDB(db, store, key)` | `function` | Read a value from IndexedDB |
|
|
245
|
+
| `setDataIndexedDB(db, store, data)` | `function` | Write a value to IndexedDB |
|
|
246
|
+
| `generateUniqueId(db, store)` | `function` | Generate a unique numeric ID |
|
|
247
|
+
| `setDataWithAutoId(db, store, data)` | `function` | Save data with an auto-generated ID |
|
|
248
|
+
| `activity` | `object` | User activity info (visibility, focus) |
|
|
249
|
+
| `sessionKey` | `string \| undefined` | Unique session key (if `hasSessionKey: true`) |
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### AuthProvider / useAuth
|
|
254
|
+
|
|
255
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/AuthProvider.md)
|
|
256
|
+
|
|
257
|
+
Manages JWT authentication state, token refresh, and login/logout.
|
|
258
|
+
|
|
259
|
+
```jsx
|
|
260
|
+
import { useAuth } from 'thecore-auth';
|
|
261
|
+
|
|
262
|
+
function Header() {
|
|
263
|
+
const { isAuthenticated, logout } = useAuth();
|
|
264
|
+
|
|
265
|
+
return isAuthenticated
|
|
266
|
+
? <button onClick={logout}>Logout</button>
|
|
267
|
+
: <p>Not logged in</p>;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Returned values:**
|
|
272
|
+
|
|
273
|
+
| Name | Type | Description |
|
|
274
|
+
|------|------|-------------|
|
|
275
|
+
| `isAuthenticated` | `boolean \| null` | Auth state (`null` = loading) |
|
|
276
|
+
| `login(e?, formData)` | `function` | Submit login credentials |
|
|
277
|
+
| `logout()` | `function` | Clear session and redirect to login |
|
|
278
|
+
| `createAxiosInstances(...)` | `function` | Create axios instance with Bearer token |
|
|
279
|
+
| `fetchHeartbeat()` | `function` | Manually refresh the JWT token |
|
|
280
|
+
| `getTokenExpiry(token?)` | `function` | Get remaining ms before token expires |
|
|
281
|
+
| `checkTokenValidity(token)` | `function` | Returns `true` if token is still valid |
|
|
282
|
+
| `timeoutToken` | `number` | Ms until next token refresh |
|
|
283
|
+
| `sessionTimeout` | `number` | Ms until session expires |
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### LoadingProvider / useLoading
|
|
288
|
+
|
|
289
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/LoadingProvider.md)
|
|
290
|
+
|
|
291
|
+
Global loading spinner visible over the entire application.
|
|
292
|
+
|
|
293
|
+
```jsx
|
|
294
|
+
import { useLoading } from 'thecore-auth';
|
|
295
|
+
|
|
296
|
+
function SaveButton() {
|
|
297
|
+
const { setIsLoading } = useLoading();
|
|
298
|
+
|
|
299
|
+
const handleSave = async () => {
|
|
300
|
+
setIsLoading(true);
|
|
301
|
+
await saveData();
|
|
302
|
+
setIsLoading(false);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
return <button onClick={handleSave}>Save</button>;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Returned values:**
|
|
310
|
+
|
|
311
|
+
| Name | Type | Description |
|
|
312
|
+
|------|------|-------------|
|
|
313
|
+
| `isLoading` | `boolean` | Current loading state |
|
|
314
|
+
| `setIsLoading(bool)` | `function` | Show or hide the spinner |
|
|
315
|
+
| `showLoadingFor(ms?, props?)` | `function` | Show spinner for a fixed duration |
|
|
316
|
+
| `loadingProps` | `object` | Props passed to `Loading` component |
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### AlertProvider / useAlert
|
|
321
|
+
|
|
322
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/AlertProvider.md)
|
|
323
|
+
|
|
324
|
+
Displays in-app notifications of type `danger`, `info`, `success`, or `warning`.
|
|
325
|
+
|
|
326
|
+
```jsx
|
|
327
|
+
import { useAlert } from 'thecore-auth';
|
|
328
|
+
|
|
329
|
+
function SubmitForm() {
|
|
330
|
+
const { activeAlert } = useAlert();
|
|
331
|
+
|
|
332
|
+
const handleSubmit = async () => {
|
|
333
|
+
try {
|
|
334
|
+
await submitData();
|
|
335
|
+
activeAlert('success', 'Data saved successfully!');
|
|
336
|
+
} catch {
|
|
337
|
+
activeAlert('danger', 'Something went wrong.');
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
return <button onClick={handleSubmit}>Submit</button>;
|
|
342
|
+
}
|
|
106
343
|
```
|
|
107
344
|
|
|
108
|
-
|
|
345
|
+
**Returned values:**
|
|
109
346
|
|
|
110
|
-
|
|
347
|
+
| Name | Type | Description |
|
|
348
|
+
|------|------|-------------|
|
|
349
|
+
| `showAlert` | `boolean` | Whether the alert is visible |
|
|
350
|
+
| `typeAlert` | `string` | Alert type (`danger`, `info`, `success`, `warning`) |
|
|
351
|
+
| `messageAlert` | `string` | Alert message text |
|
|
352
|
+
| `activeAlert(type, message)` | `function` | Show an alert |
|
|
353
|
+
| `closeAlert()` | `function` | Dismiss the current alert |
|
|
111
354
|
|
|
112
|
-
|
|
355
|
+
---
|
|
113
356
|
|
|
114
|
-
|
|
357
|
+
### ModalProvider / useModal
|
|
115
358
|
|
|
116
|
-
|
|
359
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/ModalProvider.md)
|
|
117
360
|
|
|
118
|
-
|
|
361
|
+
Centralized modal system supporting `submit`, `delete`, and `custom` modal types.
|
|
119
362
|
|
|
120
363
|
```jsx
|
|
364
|
+
import { useModal } from 'thecore-auth';
|
|
365
|
+
|
|
366
|
+
function UserList() {
|
|
367
|
+
const { openModal, closeModal } = useModal();
|
|
368
|
+
|
|
369
|
+
const handleDelete = (user) => {
|
|
370
|
+
openModal({
|
|
371
|
+
type: 'delete',
|
|
372
|
+
title: 'Delete user',
|
|
373
|
+
item: user,
|
|
374
|
+
onConfirm: async () => {
|
|
375
|
+
await deleteUser(user.id);
|
|
376
|
+
closeModal();
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
return <button onClick={() => handleDelete(user)}>Delete</button>;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**`openModal` options:**
|
|
386
|
+
|
|
387
|
+
| Property | Type | Description |
|
|
388
|
+
|----------|------|-------------|
|
|
389
|
+
| `type` | `'submit' \| 'delete' \| 'custom'` | Modal behavior type |
|
|
390
|
+
| `title` | `string` | Modal header title |
|
|
391
|
+
| `component` | `ReactNode` | Content to render inside the modal |
|
|
392
|
+
| `modalData` | `object` | Initial form data |
|
|
393
|
+
| `onConfirm` | `function` | Confirm callback |
|
|
394
|
+
| `onCancel` | `function` | Cancel callback |
|
|
395
|
+
| `formId` | `string` | ID of the form inside the modal |
|
|
396
|
+
| `item` | `any` | Entity the modal is acting upon |
|
|
397
|
+
| `style` | `object` | Custom styles |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
### LoginFormProvider / useLoginForm
|
|
402
|
+
|
|
403
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/LoginFormProvider.md)
|
|
404
|
+
|
|
405
|
+
Manages the login form state and customization options.
|
|
406
|
+
|
|
407
|
+
```jsx
|
|
408
|
+
import { LoginFormProvider } from 'thecore-auth';
|
|
409
|
+
|
|
410
|
+
<LoginFormProvider
|
|
411
|
+
title="Sign In"
|
|
412
|
+
label="Email address"
|
|
413
|
+
buttonText="Log in"
|
|
414
|
+
LogoImg={MyLogo}
|
|
415
|
+
>
|
|
416
|
+
{/* children */}
|
|
417
|
+
</LoginFormProvider>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Provider props:**
|
|
421
|
+
|
|
422
|
+
| Prop | Type | Default | Description |
|
|
423
|
+
|------|------|---------|-------------|
|
|
424
|
+
| `title` | `string` | `'Accedi'` | Form card title |
|
|
425
|
+
| `label` | `string` | `'Email'` | Email field label |
|
|
426
|
+
| `type` | `string` | `'email'` | Email field input type |
|
|
427
|
+
| `placeholder` | `string` | — | Email field placeholder |
|
|
428
|
+
| `buttonText` | `string` | `'Accedi'` | Submit button text |
|
|
429
|
+
| `LogoImg` | `ReactNode` | — | Logo component |
|
|
430
|
+
| `styleCardForm` | `object` | — | Card container styles |
|
|
431
|
+
| `styleLogo` | `object` | — | Logo styles |
|
|
432
|
+
| `overrideStyle` | `object` | — | CSS override object |
|
|
433
|
+
| `customVersion` | `string` | — | Custom version string |
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### RouteProvider / useRoutesInjection
|
|
438
|
+
|
|
439
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/contexts/RouteProvider.md)
|
|
440
|
+
|
|
441
|
+
Registers public and private routes to be rendered by `PackageRoutes`.
|
|
442
|
+
|
|
443
|
+
```jsx
|
|
444
|
+
import { RouteProvider } from 'thecore-auth';
|
|
445
|
+
|
|
121
446
|
const privateRoutes = [
|
|
122
|
-
{ path: '
|
|
447
|
+
{ path: '/profile', element: <ProfilePage /> },
|
|
448
|
+
{ path: '/settings', element: <SettingsPage /> }
|
|
123
449
|
];
|
|
450
|
+
|
|
124
451
|
const publicRoutes = [
|
|
125
|
-
{ path: '
|
|
452
|
+
{ path: '/about', element: <AboutPage /> }
|
|
126
453
|
];
|
|
127
454
|
|
|
128
455
|
<RouteProvider privateRoutes={privateRoutes} publicRoutes={publicRoutes}>
|
|
129
|
-
<PackageRoutes />
|
|
456
|
+
<PackageRoutes firstPrivateElement={<Dashboard />} />
|
|
130
457
|
</RouteProvider>
|
|
131
458
|
```
|
|
132
459
|
|
|
133
|
-
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Components
|
|
463
|
+
|
|
464
|
+
### PackageRoutes
|
|
465
|
+
|
|
466
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/routing/PackageRoutes.md)
|
|
467
|
+
|
|
468
|
+
The main routing component. Renders public routes, the login page, and wraps private routes with authentication guards.
|
|
469
|
+
|
|
470
|
+
```jsx
|
|
471
|
+
<PackageRoutes
|
|
472
|
+
firstPrivateElement={<Dashboard />}
|
|
473
|
+
globalLayout={MyLayout}
|
|
474
|
+
headerComponent={MyHeader}
|
|
475
|
+
footerComponent={MyFooter}
|
|
476
|
+
showHeaderOnLogin={false}
|
|
477
|
+
showFooterOnLogin={false}
|
|
478
|
+
headerExcludedRoutes={['/settings']}
|
|
479
|
+
footerExcludedRoutes={[]}
|
|
480
|
+
/>
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
| Prop | Type | Description |
|
|
484
|
+
|------|------|-------------|
|
|
485
|
+
| `firstPrivateElement` | `ReactNode` | Component for the first private route |
|
|
486
|
+
| `globalLayout` | `ReactNode` | Custom layout wrapper component |
|
|
487
|
+
| `headerComponent` | `ReactNode` | Header component |
|
|
488
|
+
| `footerComponent` | `ReactNode` | Footer component |
|
|
489
|
+
| `showHeaderOnLogin` | `boolean` | Show header on the login page |
|
|
490
|
+
| `showFooterOnLogin` | `boolean` | Show footer on the login page |
|
|
491
|
+
| `headerExcludedRoutes` | `string[]` | Paths where the header is hidden |
|
|
492
|
+
| `footerExcludedRoutes` | `string[]` | Paths where the footer is hidden |
|
|
493
|
+
| `privateProvider` | `ReactNode` | Extra provider wrapping private routes |
|
|
494
|
+
| `customProvider` | `ReactNode` | Extra provider wrapping all routes |
|
|
495
|
+
| `promptComponent` | `ReactNode` | Navigation prompt component |
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
### Login
|
|
500
|
+
|
|
501
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/pages/Login.md)
|
|
502
|
+
|
|
503
|
+
Pre-built login page. Automatically used by `PackageRoutes` at the `/` path.
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
### SmartLogin
|
|
508
|
+
|
|
509
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/pages/SmartLogin.md)
|
|
510
|
+
|
|
511
|
+
PWA-ready login page with advanced features. Drop-in replacement for `Login` with full
|
|
512
|
+
customization, accessibility improvements, and better mobile support.
|
|
513
|
+
|
|
514
|
+
```jsx
|
|
515
|
+
import { SmartLogin } from 'thecore-auth';
|
|
516
|
+
|
|
517
|
+
<SmartLogin
|
|
518
|
+
Logo={MyLogo}
|
|
519
|
+
backgroundSrc="/images/bg.jpg"
|
|
520
|
+
overlayOpacity={0.5}
|
|
521
|
+
overlayColor="#f1f1f1"
|
|
522
|
+
cardVariant="glass"
|
|
523
|
+
cardPosition="center"
|
|
524
|
+
logoPosition="left"
|
|
525
|
+
showPasswordToggle={true}
|
|
526
|
+
animateEntrance={true}
|
|
527
|
+
/>
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
| Prop | Type | Default | Description |
|
|
531
|
+
|------|------|---------|-------------|
|
|
532
|
+
| `Logo` | `ComponentType` | — | SVG logo component |
|
|
533
|
+
| `backgroundSrc` | `string` | `undefined` | Custom background image URL |
|
|
534
|
+
| `overlayOpacity` | `number` | `0.5` | Background overlay opacity (0.0–1.0) |
|
|
535
|
+
| `overlayColor` | `string` | `'#f1f1f1'` | Background overlay base color |
|
|
536
|
+
| `cardVariant` | `'solid' \| 'glass' \| 'minimal'` | `'solid'` | Card style variant |
|
|
537
|
+
| `cardPosition` | `'center' \| 'left' \| 'right'` | `'center'` | Horizontal card position |
|
|
538
|
+
| `logoPosition` | `'left' \| 'top'` | `'left'` | Logo position on desktop |
|
|
539
|
+
| `showPasswordToggle` | `boolean` | `true` | Show password visibility toggle |
|
|
540
|
+
| `animateEntrance` | `boolean` | `true` | Animate card on mount |
|
|
541
|
+
|
|
542
|
+
All `overrideStyle` values from `LoginFormProvider` continue to work with `SmartLogin`.
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
### LoginForm
|
|
547
|
+
|
|
548
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/LoginForm.md)
|
|
549
|
+
|
|
550
|
+
Login form UI built on top of `LoginFormProvider`. Can be used standalone inside a custom layout.
|
|
551
|
+
|
|
552
|
+
```jsx
|
|
553
|
+
import { LoginForm } from 'thecore-auth';
|
|
554
|
+
|
|
555
|
+
<LoginForm />
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
### DefaultLayout
|
|
561
|
+
|
|
562
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/layouts/DefaultLayout.md)
|
|
563
|
+
|
|
564
|
+
Layout wrapper that renders `Loading`, `Alert`, `Modal`, and an optional toast layer alongside the page content.
|
|
565
|
+
|
|
566
|
+
```jsx
|
|
567
|
+
import { DefaultLayout } from 'thecore-auth';
|
|
568
|
+
|
|
569
|
+
<DefaultLayout
|
|
570
|
+
headerComponent={<MyHeader />}
|
|
571
|
+
footerComponent={<MyFooter />}
|
|
572
|
+
isMain={true}
|
|
573
|
+
/>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
### Input / InputLabel
|
|
579
|
+
|
|
580
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/Input.md) | [InputLabel](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/InputLabel.md)
|
|
581
|
+
|
|
582
|
+
Basic form input and label components.
|
|
583
|
+
|
|
584
|
+
```jsx
|
|
585
|
+
import { Input, InputLabel } from 'thecore-auth';
|
|
586
|
+
|
|
587
|
+
<InputLabel label="Name" labelId="name" />
|
|
588
|
+
<Input
|
|
589
|
+
inputId="name"
|
|
590
|
+
inputType="text"
|
|
591
|
+
inputValue={name}
|
|
592
|
+
inputChange={(e) => setName(e.target.value)}
|
|
593
|
+
inputPlaceholder="Enter your name"
|
|
594
|
+
/>
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
### InputDate / InputStartEndDate
|
|
600
|
+
|
|
601
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/InputDate.md) | [InputStartEndDate](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/InputStartEndDate.md)
|
|
602
|
+
|
|
603
|
+
Date picker and date range picker components.
|
|
604
|
+
|
|
605
|
+
```jsx
|
|
606
|
+
import { InputDate, InputStartEndDate } from 'thecore-auth';
|
|
607
|
+
|
|
608
|
+
// Single date
|
|
609
|
+
<InputDate
|
|
610
|
+
id="date"
|
|
611
|
+
name="date"
|
|
612
|
+
value={date}
|
|
613
|
+
onChange={(e) => setDate(e.target.value)}
|
|
614
|
+
title="Select date"
|
|
615
|
+
/>
|
|
616
|
+
|
|
617
|
+
// Date range
|
|
618
|
+
<InputStartEndDate
|
|
619
|
+
startId="start"
|
|
620
|
+
endId="end"
|
|
621
|
+
startValue={startDate}
|
|
622
|
+
endValue={endDate}
|
|
623
|
+
onChange={handleChange}
|
|
624
|
+
startTitle="From"
|
|
625
|
+
endTitle="To"
|
|
626
|
+
/>
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
### FileDropzone
|
|
632
|
+
|
|
633
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/FileDropzone.md)
|
|
634
|
+
|
|
635
|
+
Drag-and-drop file upload area.
|
|
636
|
+
|
|
637
|
+
```jsx
|
|
638
|
+
import { FileDropzone } from 'thecore-auth';
|
|
639
|
+
|
|
640
|
+
<FileDropzone
|
|
641
|
+
id="upload"
|
|
642
|
+
onFilesSelect={(files) => console.log(files)}
|
|
643
|
+
/>
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
### SwitchRadio
|
|
649
|
+
|
|
650
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/SwitchRadio.md)
|
|
651
|
+
|
|
652
|
+
A toggle switch (controlled or uncontrolled).
|
|
653
|
+
|
|
654
|
+
```jsx
|
|
655
|
+
import { SwitchRadio } from 'thecore-auth';
|
|
656
|
+
|
|
657
|
+
<SwitchRadio value={active} onChange={(val) => setActive(val)} />
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
### SingleSelect / MultiSelect
|
|
663
|
+
|
|
664
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/SingleSelect.md) | [MultiSelect](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/MultiSelect.md)
|
|
665
|
+
|
|
666
|
+
Dropdown select components.
|
|
667
|
+
|
|
668
|
+
```jsx
|
|
669
|
+
import { SingleSelect, MultiSelect } from 'thecore-auth';
|
|
670
|
+
|
|
671
|
+
// Single
|
|
672
|
+
<SingleSelect
|
|
673
|
+
options={[{ label: 'Italy', value: 'IT' }, { label: 'France', value: 'FR' }]}
|
|
674
|
+
value={selected}
|
|
675
|
+
onChange={setSelected}
|
|
676
|
+
/>
|
|
677
|
+
|
|
678
|
+
// Multi
|
|
679
|
+
<MultiSelect
|
|
680
|
+
label="Countries"
|
|
681
|
+
items={countries}
|
|
682
|
+
value={selectedCountries}
|
|
683
|
+
displayKey="label"
|
|
684
|
+
valueKey="value"
|
|
685
|
+
idKey="id"
|
|
686
|
+
updateFilter={setSelectedCountries}
|
|
687
|
+
/>
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
### Loading / LoadingComponent / Loader / LogoLoader
|
|
693
|
+
|
|
694
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/Loading.md) | [LoadingComponent](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/LoadingComponent.md) | [Loader](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/Loader.md) | [LogoLoader](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/LogoLoader.md)
|
|
695
|
+
|
|
696
|
+
Loading state components.
|
|
697
|
+
|
|
698
|
+
```jsx
|
|
699
|
+
import { Loader } from 'thecore-auth';
|
|
700
|
+
|
|
701
|
+
<Loader
|
|
702
|
+
Logo={MyLogo}
|
|
703
|
+
spinnerColor="#3b82f6"
|
|
704
|
+
containerSize="100vh"
|
|
705
|
+
/>
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
### Alert
|
|
711
|
+
|
|
712
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/components/Alert.md)
|
|
713
|
+
|
|
714
|
+
Notification banner controlled by `AlertProvider`. Renders automatically when `activeAlert` is called.
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
### AuthPage / AuthAdmin
|
|
719
|
+
|
|
720
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/middlewares/AuthPage.md) | [AuthAdmin](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/middlewares/AuthAdmin.md)
|
|
721
|
+
|
|
722
|
+
Route guards for authentication and admin roles.
|
|
723
|
+
|
|
724
|
+
```jsx
|
|
725
|
+
import { AuthPage, AuthAdmin } from 'thecore-auth';
|
|
726
|
+
|
|
727
|
+
// In your routes:
|
|
728
|
+
{ path: '/dashboard', element: <AuthPage><Dashboard /></AuthPage> }
|
|
729
|
+
{ path: '/admin', element: <AuthAdmin><AdminPanel /></AuthAdmin> }
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## Hooks
|
|
735
|
+
|
|
736
|
+
### useStorage
|
|
737
|
+
|
|
738
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useStorage.md)
|
|
739
|
+
|
|
740
|
+
State synchronized with `localStorage`.
|
|
741
|
+
|
|
742
|
+
```jsx
|
|
743
|
+
import { useStorage } from 'thecore-auth';
|
|
744
|
+
|
|
745
|
+
const [theme, setTheme, removeTheme] = useStorage('light', 'app-theme');
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
| Parameter | Type | Description |
|
|
749
|
+
|-----------|------|-------------|
|
|
750
|
+
| `initialValue` | `any` | Default value if key is not in storage |
|
|
751
|
+
| `itemKey` | `string` | localStorage key |
|
|
752
|
+
|
|
753
|
+
Returns `[state, setState, remove]`.
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
### useAuthStorage
|
|
758
|
+
|
|
759
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useAuthStorage.md)
|
|
760
|
+
|
|
761
|
+
Manages `accessToken` and `user` in localStorage.
|
|
762
|
+
|
|
763
|
+
```jsx
|
|
764
|
+
import { useAuthStorage } from 'thecore-auth';
|
|
765
|
+
|
|
766
|
+
const { token, user, setToken, setUser, storageLogout } = useAuthStorage();
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
---
|
|
770
|
+
|
|
771
|
+
### useIndexedDB
|
|
772
|
+
|
|
773
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useIndexedDB.md)
|
|
774
|
+
|
|
775
|
+
Full CRUD operations on an IndexedDB object store.
|
|
776
|
+
|
|
777
|
+
```jsx
|
|
778
|
+
import { useIndexedDB } from 'thecore-auth';
|
|
779
|
+
|
|
780
|
+
const db = useIndexedDB('myDatabase', 'myStore');
|
|
781
|
+
|
|
782
|
+
await db.set({ id: 1, name: 'Item' });
|
|
783
|
+
const item = await db.get(1);
|
|
784
|
+
await db.remove(1);
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
| Method | Description |
|
|
788
|
+
|--------|-------------|
|
|
789
|
+
| `get(key)` | Read a record by key |
|
|
790
|
+
| `getAll()` | Read all records |
|
|
791
|
+
| `set(data)` | Write a record |
|
|
792
|
+
| `setWithAutoId(data)` | Write with auto-generated ID |
|
|
793
|
+
| `remove(id)` | Delete a record by ID |
|
|
794
|
+
| `clear()` | Delete all records |
|
|
795
|
+
| `isReady` | `boolean` — DB is ready to use |
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
### useForm
|
|
800
|
+
|
|
801
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useForm.md)
|
|
802
|
+
|
|
803
|
+
Form state management with file upload support.
|
|
804
|
+
|
|
805
|
+
```jsx
|
|
806
|
+
import { useForm } from 'thecore-auth';
|
|
807
|
+
|
|
808
|
+
const { values, handleChange, files, addFiles, resetForm } = useForm({
|
|
809
|
+
name: '',
|
|
810
|
+
email: ''
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
<input
|
|
814
|
+
value={values.name}
|
|
815
|
+
onChange={(e) => handleChange('name', e.target.value)}
|
|
816
|
+
/>
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
| Returned value | Type | Description |
|
|
820
|
+
|----------------|------|-------------|
|
|
821
|
+
| `values` | `object` | Current form values |
|
|
822
|
+
| `handleChange(field, value)` | `function` | Update a field value |
|
|
823
|
+
| `files` | `object` | File inputs by field name |
|
|
824
|
+
| `previews` | `object` | Preview URLs for image files |
|
|
825
|
+
| `addFiles(field, fileList)` | `function` | Append files to a field |
|
|
826
|
+
| `replaceFiles(field, fileList)` | `function` | Replace files in a field |
|
|
827
|
+
| `removeFile(field, index)` | `function` | Remove a file by index |
|
|
828
|
+
| `setValues` | `function` | Override the entire form state |
|
|
829
|
+
| `resetForm()` | `function` | Reset to initial values |
|
|
830
|
+
|
|
831
|
+
---
|
|
832
|
+
|
|
833
|
+
### useDevice
|
|
834
|
+
|
|
835
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useDevice.md)
|
|
836
|
+
|
|
837
|
+
Detect the user's device type, OS, and browser.
|
|
838
|
+
|
|
839
|
+
```jsx
|
|
840
|
+
import { useDevice } from 'thecore-auth';
|
|
841
|
+
|
|
842
|
+
const { isMobile, isDesktop, os, browser } = useDevice();
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
| Returned value | Type | Description |
|
|
846
|
+
|----------------|------|-------------|
|
|
847
|
+
| `type` | `string` | `'mobile'`, `'tablet'`, or `'desktop'` |
|
|
848
|
+
| `os` | `string` | Operating system name |
|
|
849
|
+
| `browser` | `string` | Browser name |
|
|
850
|
+
| `vendor` | `string` | Device manufacturer |
|
|
851
|
+
| `model` | `string` | Device model |
|
|
852
|
+
| `isMobile` | `boolean` | — |
|
|
853
|
+
| `isTablet` | `boolean` | — |
|
|
854
|
+
| `isDesktop` | `boolean` | — |
|
|
855
|
+
| `isIPhone` | `boolean` | — |
|
|
856
|
+
| `isIPad` | `boolean` | — |
|
|
857
|
+
| `isAndroid` | `boolean` | — |
|
|
858
|
+
|
|
859
|
+
---
|
|
860
|
+
|
|
861
|
+
### useOrientation
|
|
862
|
+
|
|
863
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useOrientation.md)
|
|
864
|
+
|
|
865
|
+
Detect portrait or landscape orientation.
|
|
866
|
+
|
|
867
|
+
```jsx
|
|
868
|
+
import { useOrientation } from 'thecore-auth';
|
|
869
|
+
|
|
870
|
+
const orientation = useOrientation(); // 'portrait' | 'landscape'
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
---
|
|
874
|
+
|
|
875
|
+
### useViewportHeight
|
|
876
|
+
|
|
877
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useViewportHeight.md)
|
|
878
|
+
|
|
879
|
+
Reads the actual viewport height and exposes it as a CSS variable `--vh`.
|
|
880
|
+
|
|
881
|
+
```jsx
|
|
882
|
+
import { useViewportHeight } from 'thecore-auth';
|
|
883
|
+
|
|
884
|
+
const { height, vh } = useViewportHeight({ getValues: true });
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
### useSafeArea
|
|
890
|
+
|
|
891
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useSafeArea.md)
|
|
892
|
+
|
|
893
|
+
Adds the `with-safe-area` class to `<body>` when on devices with a notch or safe area insets (iPhone X+, etc.).
|
|
894
|
+
|
|
895
|
+
```jsx
|
|
896
|
+
import { useSafeArea } from 'thecore-auth';
|
|
897
|
+
|
|
898
|
+
useSafeArea(['/login']); // exclude these paths
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
---
|
|
134
902
|
|
|
135
|
-
|
|
136
|
-
| ---------------------- | --------- | --------------- | ----------------------------------------------------------- |
|
|
137
|
-
| `firstPrivateElement` | Component | `<Dashboard />` | First component of the private route |
|
|
138
|
-
| `firstPrivatePath` | String | `/dashboard/` | Path of the first private route (configurable in `config.json`) |
|
|
139
|
-
| `logoImg` | Component | `MyWharehouse` | SVG component for the login logo |
|
|
140
|
-
| `globalLayout` | Component | `null` | Custom global layout |
|
|
141
|
-
| `isMain` | Boolean | `false` | Keeps the `main` tag in `DefaultLayout` |
|
|
142
|
-
| `headerComponent` | Component | `null` | Header component |
|
|
143
|
-
| `showHeaderOnLogin` | Boolean | `false` | Displays the header on the login page |
|
|
144
|
-
| `headerExcludedRoutes` | Array | `[]` | Routes where the header should not be displayed |
|
|
145
|
-
| `footerComponent` | Component | `null` | Footer component |
|
|
146
|
-
| `showFooterOnLogin` | Boolean | `false` | Displays the footer on the login page |
|
|
147
|
-
| `footerExcludedRoutes` | Array | `[]` | Routes where the footer should not be displayed |
|
|
903
|
+
### useClickOutside
|
|
148
904
|
|
|
149
|
-
|
|
905
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useClickOutside.md)
|
|
150
906
|
|
|
151
|
-
|
|
907
|
+
Fire a callback when the user clicks outside a referenced element.
|
|
152
908
|
|
|
153
|
-
|
|
909
|
+
```jsx
|
|
910
|
+
import { useClickOutside } from 'thecore-auth';
|
|
911
|
+
import { useRef } from 'react';
|
|
154
912
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
- `headerExcludedRoutes`: Array of routes where the header should not appear
|
|
913
|
+
const ref = useRef();
|
|
914
|
+
useClickOutside(ref, () => setOpen(false));
|
|
158
915
|
|
|
159
|
-
|
|
916
|
+
<div ref={ref}>...</div>
|
|
917
|
+
```
|
|
160
918
|
|
|
161
|
-
|
|
162
|
-
- `showFooterOnLogin`: Boolean flag to show the footer on the login page
|
|
163
|
-
- `footerExcludedRoutes`: Array of routes where the footer should not appear
|
|
919
|
+
---
|
|
164
920
|
|
|
165
|
-
|
|
921
|
+
### UsePageTitle
|
|
166
922
|
|
|
167
|
-
|
|
923
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/UsePageTitle.md)
|
|
168
924
|
|
|
169
|
-
|
|
170
|
-
```javascript
|
|
171
|
-
const { setButtonText, setOverrideStyle } = useLoginForm();
|
|
925
|
+
Update `document.title` automatically based on the current route.
|
|
172
926
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
form: 'flex items-center justify-center flex-col basis-1/2'
|
|
179
|
-
});
|
|
180
|
-
}, []);
|
|
927
|
+
```jsx
|
|
928
|
+
import { UsePageTitle } from 'thecore-auth';
|
|
929
|
+
|
|
930
|
+
// Inside your layout component:
|
|
931
|
+
UsePageTitle(routes, 'My App');
|
|
181
932
|
```
|
|
182
933
|
|
|
183
|
-
|
|
184
|
-
|
|
934
|
+
---
|
|
935
|
+
|
|
936
|
+
### useToast
|
|
937
|
+
|
|
938
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useToast.md)
|
|
939
|
+
|
|
940
|
+
Mobile-optimized toast notifications via the Sileo library.
|
|
941
|
+
|
|
942
|
+
```jsx
|
|
943
|
+
import { useToast } from 'thecore-auth';
|
|
944
|
+
|
|
945
|
+
const toast = useToast();
|
|
946
|
+
|
|
947
|
+
toast.success('Saved!', 'Your changes have been saved.');
|
|
948
|
+
toast.error('Error', 'Something went wrong.');
|
|
949
|
+
toast.info('Notice', 'Please review the form.');
|
|
950
|
+
toast.warning('Warning', 'This action cannot be undone.');
|
|
951
|
+
|
|
952
|
+
// Promise toast
|
|
953
|
+
toast.promise(fetchData(), {
|
|
954
|
+
loading: 'Loading...',
|
|
955
|
+
success: 'Done!',
|
|
956
|
+
error: 'Failed'
|
|
957
|
+
});
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
---
|
|
961
|
+
|
|
962
|
+
### useCalendar
|
|
963
|
+
|
|
964
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/hooks/useCalendar.md)
|
|
965
|
+
|
|
966
|
+
Calendar utilities with public holiday detection.
|
|
967
|
+
|
|
968
|
+
```jsx
|
|
969
|
+
import { useCalendar } from 'thecore-auth';
|
|
970
|
+
|
|
971
|
+
const { isTodayHoliday, isHoliday, getDaysInMonth } = useCalendar(2025, 'IT');
|
|
972
|
+
|
|
973
|
+
const isHol = isTodayHoliday();
|
|
974
|
+
const days = getDaysInMonth(0, 2025); // January 2025
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
| Returned value | Description |
|
|
978
|
+
|----------------|-------------|
|
|
979
|
+
| `holidays` | Array of holiday objects |
|
|
980
|
+
| `holidayMap` | Map for O(1) holiday lookup |
|
|
981
|
+
| `isTodayHoliday()` | `true` if today is a holiday |
|
|
982
|
+
| `isHoliday(date)` | `true` if the given date is a holiday |
|
|
983
|
+
| `getWeekDays(date)` | 7-day week starting from Monday |
|
|
984
|
+
| `getWeeksInMonth(month, year)` | Weeks in the given month |
|
|
985
|
+
| `getDaysInMonth(month, year)` | All days in the given month |
|
|
986
|
+
| `getDaysInMonths(start, year, n)` | Days across `n` months from `start` |
|
|
987
|
+
| `getDaysInYear(year)` | All days in the given year |
|
|
988
|
+
|
|
989
|
+
---
|
|
990
|
+
|
|
991
|
+
## Utility Functions
|
|
992
|
+
|
|
993
|
+
### Date Utilities
|
|
994
|
+
|
|
995
|
+
[→ Full reference](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/utils/dateUtils.md) | [fetchAxiosConfig](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/utils/fetchAxiosConfig.md)
|
|
996
|
+
|
|
997
|
+
```jsx
|
|
998
|
+
import {
|
|
999
|
+
toDatetimeLocalValue,
|
|
1000
|
+
setTime,
|
|
1001
|
+
subtractDays,
|
|
1002
|
+
parseUtcToLocal,
|
|
1003
|
+
toDateValue
|
|
1004
|
+
} from 'thecore-auth';
|
|
1005
|
+
|
|
1006
|
+
toDatetimeLocalValue(new Date()); // "2025-01-15T14:30"
|
|
1007
|
+
toDateValue(new Date()); // "2025-01-15"
|
|
1008
|
+
setTime(new Date(), 9, 0, 0); // Date at 09:00:00
|
|
1009
|
+
subtractDays(new Date(), 7); // 7 days ago
|
|
1010
|
+
parseUtcToLocal('2025-01-15T12:00:00Z'); // Local Date object
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
---
|
|
1014
|
+
|
|
1015
|
+
## React Router Re-exports
|
|
1016
|
+
|
|
1017
|
+
You do not need to install `react-router-dom` separately. Import everything from `thecore-auth`:
|
|
1018
|
+
|
|
1019
|
+
```jsx
|
|
1020
|
+
import {
|
|
1021
|
+
BrowserRouter,
|
|
1022
|
+
Routes,
|
|
1023
|
+
Route,
|
|
1024
|
+
Outlet,
|
|
1025
|
+
Link,
|
|
1026
|
+
NavLink,
|
|
1027
|
+
useLocation,
|
|
1028
|
+
useNavigate,
|
|
1029
|
+
useParams,
|
|
1030
|
+
useMatch
|
|
1031
|
+
} from 'thecore-auth';
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
---
|
|
1035
|
+
|
|
1036
|
+
## CSS Customization
|
|
1037
|
+
|
|
1038
|
+
Override the package's design tokens in your own CSS file:
|
|
1039
|
+
|
|
1040
|
+
```css
|
|
1041
|
+
:root {
|
|
1042
|
+
/* Brand colors */
|
|
1043
|
+
--color-primary: #3b82f6;
|
|
1044
|
+
--color-primary-hover: #2563eb;
|
|
1045
|
+
--color-primary-text: #ffffff;
|
|
1046
|
+
|
|
1047
|
+
/* Alert colors */
|
|
1048
|
+
--color-danger: #ef4444;
|
|
1049
|
+
--color-success: #22c55e;
|
|
1050
|
+
--color-warning: #f59e0b;
|
|
1051
|
+
--color-info: #3b82f6;
|
|
1052
|
+
|
|
1053
|
+
/* Login form sizing */
|
|
1054
|
+
--height-card-form: auto;
|
|
1055
|
+
--width-card-form: 400px;
|
|
1056
|
+
--max-width-card-form: 90vw;
|
|
1057
|
+
--padding-input: 0.75rem 1rem;
|
|
1058
|
+
--input-radius: 0.5rem;
|
|
1059
|
+
|
|
1060
|
+
/* Buttons */
|
|
1061
|
+
--padding-primary-button: 0.75rem 1.5rem;
|
|
1062
|
+
--radius-primary-button: 0.5rem;
|
|
1063
|
+
}
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
---
|
|
1067
|
+
|
|
1068
|
+
## Complete React App Example
|
|
1069
|
+
|
|
1070
|
+
Below is a minimal but complete example of a React application using `thecore-auth`.
|
|
1071
|
+
|
|
1072
|
+
### File structure
|
|
1073
|
+
|
|
1074
|
+
```
|
|
1075
|
+
my-app/
|
|
1076
|
+
├── public/
|
|
1077
|
+
│ └── config.json
|
|
1078
|
+
├── src/
|
|
1079
|
+
│ ├── pages/
|
|
1080
|
+
│ │ ├── Dashboard.jsx
|
|
1081
|
+
│ │ └── Profile.jsx
|
|
1082
|
+
│ ├── components/
|
|
1083
|
+
│ │ └── Header.jsx
|
|
1084
|
+
│ ├── App.jsx
|
|
1085
|
+
│ ├── main.jsx
|
|
1086
|
+
│ └── index.css
|
|
1087
|
+
└── package.json
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
### `public/config.json`
|
|
1091
|
+
|
|
1092
|
+
```json
|
|
1093
|
+
{
|
|
1094
|
+
"baseUri": "https://api.example.com",
|
|
1095
|
+
"authenticatedEndpoint": "/auth/login",
|
|
1096
|
+
"usersEndpoint": "/auth/me",
|
|
1097
|
+
"heartbeatEndpoint": "/auth/refresh",
|
|
1098
|
+
"firstPrivatePath": "/dashboard",
|
|
1099
|
+
"firstPrivateTitle": "Dashboard",
|
|
1100
|
+
"defaultTitle": "My App",
|
|
1101
|
+
"infiniteSession": false,
|
|
1102
|
+
"timeDeducted": 60000,
|
|
1103
|
+
"alertTimeout": 4000,
|
|
1104
|
+
"axiosErrors": {
|
|
1105
|
+
"unauthorized": "Your session has expired.",
|
|
1106
|
+
"notFound": "Page not found.",
|
|
1107
|
+
"defaultMessage": "An error occurred."
|
|
1108
|
+
},
|
|
1109
|
+
"clearLoginFormOnError": true,
|
|
1110
|
+
"autoLogin": false,
|
|
1111
|
+
"backendToken": "",
|
|
1112
|
+
"isDebug": false,
|
|
1113
|
+
"tokenLog": false,
|
|
1114
|
+
"isDevelopment": false,
|
|
1115
|
+
"hasSessionKey": false,
|
|
1116
|
+
"appKey": "myapp",
|
|
1117
|
+
"showHeaderButton": false,
|
|
1118
|
+
"useCustomLoginTimeout": false,
|
|
1119
|
+
"customLoginTimeout": 10000,
|
|
1120
|
+
"stopLoaderOnFinish": true,
|
|
1121
|
+
"timerInfiniteSession": "",
|
|
1122
|
+
"customDeviceType": "",
|
|
1123
|
+
"sileoToastEnabled": false,
|
|
1124
|
+
"sileoToastConfig": {
|
|
1125
|
+
"position": "bottom-center",
|
|
1126
|
+
"options": {
|
|
1127
|
+
"fill": "#000000",
|
|
1128
|
+
"duration": 2000,
|
|
1129
|
+
"styles": {
|
|
1130
|
+
"title": "text-white font-semibold",
|
|
1131
|
+
"description": "text-white/75",
|
|
1132
|
+
"badge": "bg-white/20"
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
"pwa": {
|
|
1137
|
+
"enabled": false,
|
|
1138
|
+
"promptOnLoad": false,
|
|
1139
|
+
"customPrompt": false
|
|
1140
|
+
},
|
|
1141
|
+
"routes": [
|
|
1142
|
+
{ "path": "/dashboard", "title": "Dashboard" },
|
|
1143
|
+
{ "path": "/profile", "title": "Profile" }
|
|
1144
|
+
],
|
|
1145
|
+
"configRoutes": []
|
|
1146
|
+
}
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
### `src/index.css`
|
|
185
1150
|
|
|
186
1151
|
```css
|
|
187
|
-
@import url(../node_modules
|
|
1152
|
+
@import url('../node_modules/thecore-auth/dist/thecore-auth.css');
|
|
1153
|
+
|
|
1154
|
+
:root {
|
|
1155
|
+
--color-primary: #6366f1;
|
|
1156
|
+
--color-primary-hover: #4f46e5;
|
|
1157
|
+
--color-primary-text: #ffffff;
|
|
1158
|
+
}
|
|
188
1159
|
```
|
|
189
1160
|
|
|
190
|
-
|
|
1161
|
+
### `src/main.jsx`
|
|
1162
|
+
|
|
1163
|
+
```jsx
|
|
1164
|
+
import { StrictMode } from 'react';
|
|
1165
|
+
import { createRoot } from 'react-dom/client';
|
|
1166
|
+
import { BrowserRouter } from 'thecore-auth';
|
|
1167
|
+
import App from './App.jsx';
|
|
1168
|
+
import './index.css';
|
|
1169
|
+
|
|
1170
|
+
createRoot(document.getElementById('root')).render(
|
|
1171
|
+
<StrictMode>
|
|
1172
|
+
<BrowserRouter>
|
|
1173
|
+
<App />
|
|
1174
|
+
</BrowserRouter>
|
|
1175
|
+
</StrictMode>
|
|
1176
|
+
);
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
### `src/App.jsx`
|
|
1180
|
+
|
|
1181
|
+
```jsx
|
|
1182
|
+
import {
|
|
1183
|
+
PackageRoutes,
|
|
1184
|
+
ConfigProvider,
|
|
1185
|
+
AuthProvider,
|
|
1186
|
+
LoadingProvider,
|
|
1187
|
+
AlertProvider,
|
|
1188
|
+
LoginFormProvider,
|
|
1189
|
+
ModalProvider,
|
|
1190
|
+
RouteProvider
|
|
1191
|
+
} from 'thecore-auth';
|
|
1192
|
+
|
|
1193
|
+
import Dashboard from './pages/Dashboard';
|
|
1194
|
+
import Profile from './pages/Profile';
|
|
1195
|
+
import Header from './components/Header';
|
|
1196
|
+
|
|
1197
|
+
const privateRoutes = [
|
|
1198
|
+
{ path: '/profile', element: <Profile /> }
|
|
1199
|
+
];
|
|
1200
|
+
|
|
1201
|
+
export default function App() {
|
|
1202
|
+
return (
|
|
1203
|
+
<ConfigProvider>
|
|
1204
|
+
<LoadingProvider>
|
|
1205
|
+
<AlertProvider>
|
|
1206
|
+
<AuthProvider>
|
|
1207
|
+
<LoginFormProvider
|
|
1208
|
+
title="Welcome back"
|
|
1209
|
+
label="Email address"
|
|
1210
|
+
buttonText="Sign in"
|
|
1211
|
+
>
|
|
1212
|
+
<ModalProvider>
|
|
1213
|
+
<RouteProvider privateRoutes={privateRoutes} publicRoutes={[]}>
|
|
1214
|
+
<PackageRoutes
|
|
1215
|
+
firstPrivateElement={<Dashboard />}
|
|
1216
|
+
headerComponent={<Header />}
|
|
1217
|
+
showHeaderOnLogin={false}
|
|
1218
|
+
/>
|
|
1219
|
+
</RouteProvider>
|
|
1220
|
+
</ModalProvider>
|
|
1221
|
+
</LoginFormProvider>
|
|
1222
|
+
</AuthProvider>
|
|
1223
|
+
</AlertProvider>
|
|
1224
|
+
</LoadingProvider>
|
|
1225
|
+
</ConfigProvider>
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
### `src/components/Header.jsx`
|
|
1231
|
+
|
|
1232
|
+
```jsx
|
|
1233
|
+
import { useAuth, useNavigate, Link } from 'thecore-auth';
|
|
1234
|
+
|
|
1235
|
+
export default function Header() {
|
|
1236
|
+
const { isAuthenticated, logout } = useAuth();
|
|
1237
|
+
const navigate = useNavigate();
|
|
1238
|
+
|
|
1239
|
+
const handleLogout = () => {
|
|
1240
|
+
logout();
|
|
1241
|
+
navigate('/');
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
return (
|
|
1245
|
+
<header style={{ padding: '1rem', display: 'flex', justifyContent: 'space-between' }}>
|
|
1246
|
+
<Link to="/dashboard">My App</Link>
|
|
1247
|
+
{isAuthenticated && (
|
|
1248
|
+
<nav style={{ display: 'flex', gap: '1rem' }}>
|
|
1249
|
+
<Link to="/profile">Profile</Link>
|
|
1250
|
+
<button onClick={handleLogout}>Logout</button>
|
|
1251
|
+
</nav>
|
|
1252
|
+
)}
|
|
1253
|
+
</header>
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
### `src/pages/Dashboard.jsx`
|
|
1259
|
+
|
|
1260
|
+
```jsx
|
|
1261
|
+
import { useAuth, useAlert, useLoading, useConfig } from 'thecore-auth';
|
|
1262
|
+
|
|
1263
|
+
export default function Dashboard() {
|
|
1264
|
+
const { isAuthenticated } = useAuth();
|
|
1265
|
+
const { activeAlert } = useAlert();
|
|
1266
|
+
const { setIsLoading } = useLoading();
|
|
1267
|
+
const { config } = useConfig();
|
|
1268
|
+
|
|
1269
|
+
const handleAction = async () => {
|
|
1270
|
+
setIsLoading(true);
|
|
1271
|
+
try {
|
|
1272
|
+
// simulate API call
|
|
1273
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
1274
|
+
activeAlert('success', 'Action completed successfully!');
|
|
1275
|
+
} catch {
|
|
1276
|
+
activeAlert('danger', 'Something went wrong.');
|
|
1277
|
+
} finally {
|
|
1278
|
+
setIsLoading(false);
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
if (!isAuthenticated) return null;
|
|
1283
|
+
|
|
1284
|
+
return (
|
|
1285
|
+
<main style={{ padding: '2rem' }}>
|
|
1286
|
+
<h1>Dashboard</h1>
|
|
1287
|
+
<p>API: {config.baseUri}</p>
|
|
1288
|
+
<button onClick={handleAction}>Run action</button>
|
|
1289
|
+
</main>
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
```
|
|
1293
|
+
|
|
1294
|
+
### `src/pages/Profile.jsx`
|
|
1295
|
+
|
|
1296
|
+
```jsx
|
|
1297
|
+
import { useForm, useAlert, useAuth } from 'thecore-auth';
|
|
1298
|
+
|
|
1299
|
+
export default function Profile() {
|
|
1300
|
+
const { values, handleChange, resetForm } = useForm({ name: '', bio: '' });
|
|
1301
|
+
const { activeAlert } = useAlert();
|
|
1302
|
+
const { createAxiosInstances } = useAuth();
|
|
1303
|
+
|
|
1304
|
+
const handleSubmit = async (e) => {
|
|
1305
|
+
e.preventDefault();
|
|
1306
|
+
const axios = createAxiosInstances();
|
|
1307
|
+
try {
|
|
1308
|
+
await axios.put('/profile', values);
|
|
1309
|
+
activeAlert('success', 'Profile updated!');
|
|
1310
|
+
} catch {
|
|
1311
|
+
activeAlert('danger', 'Failed to update profile.');
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
return (
|
|
1316
|
+
<main style={{ padding: '2rem' }}>
|
|
1317
|
+
<h1>Profile</h1>
|
|
1318
|
+
<form onSubmit={handleSubmit}>
|
|
1319
|
+
<div>
|
|
1320
|
+
<label>Name</label>
|
|
1321
|
+
<input
|
|
1322
|
+
value={values.name}
|
|
1323
|
+
onChange={(e) => handleChange('name', e.target.value)}
|
|
1324
|
+
/>
|
|
1325
|
+
</div>
|
|
1326
|
+
<div>
|
|
1327
|
+
<label>Bio</label>
|
|
1328
|
+
<textarea
|
|
1329
|
+
value={values.bio}
|
|
1330
|
+
onChange={(e) => handleChange('bio', e.target.value)}
|
|
1331
|
+
/>
|
|
1332
|
+
</div>
|
|
1333
|
+
<button type="submit">Save</button>
|
|
1334
|
+
<button type="button" onClick={resetForm}>Reset</button>
|
|
1335
|
+
</form>
|
|
1336
|
+
</main>
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
---
|
|
1342
|
+
|
|
1343
|
+
## CSS Variables
|
|
1344
|
+
|
|
1345
|
+
All visual aspects of the package are controlled through CSS custom properties.
|
|
1346
|
+
Override them in your own `:root {}` block after importing the package CSS.
|
|
1347
|
+
|
|
1348
|
+
| Language | Link |
|
|
1349
|
+
|----------|------|
|
|
1350
|
+
| 🇬🇧 English | [docs/en/css/css-variables.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/css/css-variables.md) |
|
|
1351
|
+
| 🇮🇹 Italiano | [docs/it/css-variables.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/it/css-variables.md) |
|
|
1352
|
+
| 🇪🇸 Español | [docs/es/css-variables.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/es/css-variables.md) |
|
|
1353
|
+
|
|
1354
|
+
Quick reference — most commonly overridden:
|
|
1355
|
+
|
|
1356
|
+
```css
|
|
1357
|
+
:root {
|
|
1358
|
+
--color-primary: #6366f1; /* brand color */
|
|
1359
|
+
--color-primary-hover: #4f46e5; /* brand color on hover */
|
|
1360
|
+
--color-primary-text: #ffffff; /* text on brand-colored elements */
|
|
1361
|
+
--height-card-form: 65vh; /* login card height */
|
|
1362
|
+
--form-radius: 1.5rem; /* login card border radius */
|
|
1363
|
+
--input-radius: 0.5rem; /* input border radius */
|
|
1364
|
+
--color-spinner: #6366f1; /* loading spinner color */
|
|
1365
|
+
}
|
|
1366
|
+
```
|
|
191
1367
|
|
|
192
1368
|
---
|
|
193
1369
|
|
|
194
|
-
##
|
|
195
|
-
|
|
1370
|
+
## Modal System
|
|
1371
|
+
|
|
1372
|
+
Full API reference, style override guide, and usage examples for the centralized modal system (`useModal`, `openModal`, `closeModal`).
|
|
1373
|
+
|
|
1374
|
+
| Language | Link |
|
|
1375
|
+
|----------|------|
|
|
1376
|
+
| 🇬🇧 English | [docs/en/modal.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/en/modal.md) |
|
|
1377
|
+
| 🇮🇹 Italiano | [docs/it/modal.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/it/modal.md) |
|
|
1378
|
+
| 🇪🇸 Español | [docs/es/modal.md](https://github.com/SantiGalvan/thecore-auth/blob/main/docs/es/modal.md) |
|
|
1379
|
+
|
|
1380
|
+
---
|
|
1381
|
+
|
|
1382
|
+
## Repository
|
|
1383
|
+
|
|
1384
|
+
- GitHub: [https://github.com/SantiGalvan/thecore-auth](https://github.com/SantiGalvan/thecore-auth)
|
|
1385
|
+
- npm: `npm install thecore-auth`
|