@caseparts-org/casecore 0.0.3 → 0.0.5
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 +60 -60
- package/dist/environment.d.ts +3 -0
- package/dist/environment.js +2 -0
- package/dist/src/App.d.ts +3 -0
- package/dist/src/App.js +46 -0
- package/dist/src/lib/authentication/AuthContext.d.ts +34 -0
- package/dist/src/lib/authentication/AuthContext.js +252 -0
- package/dist/src/lib/authentication/AuthContext.test.js +214 -0
- package/dist/src/lib/authentication/AuthTypes.d.ts +82 -0
- package/dist/src/lib/authentication/AuthTypes.js +1 -0
- package/dist/src/lib/hooks/useLocalStorage.d.ts +14 -0
- package/dist/src/lib/hooks/useLocalStorage.js +41 -0
- package/dist/src/lib/hooks/useMicroFlex.d.ts +28 -0
- package/dist/src/lib/hooks/useMicroFlex.js +138 -0
- package/dist/src/lib/index.d.ts +6 -0
- package/dist/src/lib/index.js +6 -0
- package/dist/src/lib/utils/ClaimsUtils.d.ts +16 -0
- package/dist/src/lib/utils/ClaimsUtils.js +76 -0
- package/dist/src/lib/utils/SessionUtils.d.ts +7 -0
- package/dist/src/lib/utils/SessionUtils.js +18 -0
- package/dist/src/local/impersonate/Impersonate.d.ts +1 -0
- package/dist/src/local/impersonate/Impersonate.js +62 -0
- package/dist/src/local/layout/Layout.d.ts +4 -0
- package/dist/src/local/layout/Layout.js +33 -0
- package/dist/src/local/login/Login.d.ts +1 -0
- package/dist/src/local/login/Login.js +53 -0
- package/dist/src/local/microflex/MicroFlex.d.ts +1 -0
- package/dist/src/local/microflex/MicroFlex.js +47 -0
- package/dist/src/local/util/AppSettings.d.ts +109 -0
- package/dist/src/local/util/AppSettings.js +138 -0
- package/dist/src/main.d.ts +1 -0
- package/dist/src/main.js +6 -0
- package/package.json +54 -53
- package/dist/authentication/AuthContext.d.ts +0 -14
- package/dist/authentication/AuthContext.helpers.d.ts +0 -0
- package/dist/authentication/AuthContext.helpers.js +0 -1
- package/dist/authentication/AuthContext.js +0 -21
- package/dist/authentication/AuthContext.test.js +0 -29
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -1
- /package/dist/{authentication → src/lib/authentication}/AuthContext.test.d.ts +0 -0
- /package/dist/{test → src/lib/test}/setup.d.ts +0 -0
- /package/dist/{test → src/lib/test}/setup.js +0 -0
package/README.md
CHANGED
@@ -1,60 +1,60 @@
|
|
1
|
-
# CaseCore React Component & Logic Library
|
2
|
-
|
3
|
-
This project is a reusable logic and component library for React and Next.js applications, designed to house all core business logic for our front-end apps, decoupled from any specific UI. While it currently focuses on authentication, claims, and session management, it is intended to grow into a central place for all shared business logic, utilities, and core functionality needed across our projects.
|
4
|
-
|
5
|
-
## Project Structure
|
6
|
-
|
7
|
-
- **/lib/**
|
8
|
-
- Contains all code intended for export as part of the library.
|
9
|
-
- Includes authentication context/provider, hooks, utility functions, and type definitions.
|
10
|
-
- The main entry point for consumers is `lib/index.ts`.
|
11
|
-
- **/src/App.tsx**
|
12
|
-
- Local demo/test app for development, not included in the library build.
|
13
|
-
- Useful for running and testing components locally with `npm run dev`.
|
14
|
-
- **/public/**
|
15
|
-
- Static assets for local development/demo.
|
16
|
-
- **/index.html**
|
17
|
-
- Entry point for local development with Vite.
|
18
|
-
|
19
|
-
## Key Features
|
20
|
-
|
21
|
-
- **Authentication Context (`AuthProvider`)**
|
22
|
-
- Provides authentication state, login/logout/impersonate methods, and claims to your app via React context.
|
23
|
-
- Handles JWT parsing, localStorage/sessionStorage, and API integration.
|
24
|
-
- **Claims & Session Utilities**
|
25
|
-
- `buildClaimsFromPayload`: Normalizes JWT payloads into a consistent claims object.
|
26
|
-
- `getSessionId`: Manages session IDs in sessionStorage.
|
27
|
-
- `useLocalStorage`: React hook for persistent state with automatic key prefixing.
|
28
|
-
- **TypeScript-first**
|
29
|
-
- All types and interfaces are defined in `lib/authentication/AuthTypes.ts` for strong typing and IDE support.
|
30
|
-
- **Testing**
|
31
|
-
- Tests are colocated with their modules (e.g., `AuthContext.test.tsx`).
|
32
|
-
- Mocks for fetch and JWT decoding are used to simulate authentication flows.
|
33
|
-
|
34
|
-
## Usage
|
35
|
-
|
36
|
-
- **As a library:**
|
37
|
-
- Import from `lib/index.ts` in your consuming app:
|
38
|
-
```ts
|
39
|
-
import { AuthProvider, useAuthContext } from 'casecore/lib';
|
40
|
-
```
|
41
|
-
- **For local development:**
|
42
|
-
- Run `npm run dev` to start the Vite dev server and use the demo app in `src/App.tsx`.
|
43
|
-
- **To run tests locally:**
|
44
|
-
- Run `npm test` or `npx vitest run` to execute all tests.
|
45
|
-
- For watch mode (auto-re-run on file changes), use:
|
46
|
-
```sh
|
47
|
-
npx vitest
|
48
|
-
```
|
49
|
-
- Test files are colocated with their modules (e.g., `AuthContext.test.tsx`).
|
50
|
-
|
51
|
-
## Contributing
|
52
|
-
|
53
|
-
- Add new core logic, hooks, or components to `/lib`.
|
54
|
-
- Add or update exports in `lib/index.ts`.
|
55
|
-
- Use `/src` and `/public` for local-only demo/testing code.
|
56
|
-
- Write and run tests for all exported logic.
|
57
|
-
|
58
|
-
## License
|
59
|
-
|
60
|
-
MIT
|
1
|
+
# CaseCore React Component & Logic Library
|
2
|
+
|
3
|
+
This project is a reusable logic and component library for React and Next.js applications, designed to house all core business logic for our front-end apps, decoupled from any specific UI. While it currently focuses on authentication, claims, and session management, it is intended to grow into a central place for all shared business logic, utilities, and core functionality needed across our projects.
|
4
|
+
|
5
|
+
## Project Structure
|
6
|
+
|
7
|
+
- **/lib/**
|
8
|
+
- Contains all code intended for export as part of the library.
|
9
|
+
- Includes authentication context/provider, hooks, utility functions, and type definitions.
|
10
|
+
- The main entry point for consumers is `lib/index.ts`.
|
11
|
+
- **/src/App.tsx**
|
12
|
+
- Local demo/test app for development, not included in the library build.
|
13
|
+
- Useful for running and testing components locally with `npm run dev`.
|
14
|
+
- **/public/**
|
15
|
+
- Static assets for local development/demo.
|
16
|
+
- **/index.html**
|
17
|
+
- Entry point for local development with Vite.
|
18
|
+
|
19
|
+
## Key Features
|
20
|
+
|
21
|
+
- **Authentication Context (`AuthProvider`)**
|
22
|
+
- Provides authentication state, login/logout/impersonate methods, and claims to your app via React context.
|
23
|
+
- Handles JWT parsing, localStorage/sessionStorage, and API integration.
|
24
|
+
- **Claims & Session Utilities**
|
25
|
+
- `buildClaimsFromPayload`: Normalizes JWT payloads into a consistent claims object.
|
26
|
+
- `getSessionId`: Manages session IDs in sessionStorage.
|
27
|
+
- `useLocalStorage`: React hook for persistent state with automatic key prefixing.
|
28
|
+
- **TypeScript-first**
|
29
|
+
- All types and interfaces are defined in `lib/authentication/AuthTypes.ts` for strong typing and IDE support.
|
30
|
+
- **Testing**
|
31
|
+
- Tests are colocated with their modules (e.g., `AuthContext.test.tsx`).
|
32
|
+
- Mocks for fetch and JWT decoding are used to simulate authentication flows.
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
- **As a library:**
|
37
|
+
- Import from `lib/index.ts` in your consuming app:
|
38
|
+
```ts
|
39
|
+
import { AuthProvider, useAuthContext } from 'casecore/lib';
|
40
|
+
```
|
41
|
+
- **For local development:**
|
42
|
+
- Run `npm run dev` to start the Vite dev server and use the demo app in `src/App.tsx`.
|
43
|
+
- **To run tests locally:**
|
44
|
+
- Run `npm test` or `npx vitest run` to execute all tests.
|
45
|
+
- For watch mode (auto-re-run on file changes), use:
|
46
|
+
```sh
|
47
|
+
npx vitest
|
48
|
+
```
|
49
|
+
- Test files are colocated with their modules (e.g., `AuthContext.test.tsx`).
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
- Add new core logic, hooks, or components to `/lib`.
|
54
|
+
- Add or update exports in `lib/index.ts`.
|
55
|
+
- Use `/src` and `/public` for local-only demo/testing code.
|
56
|
+
- Write and run tests for all exported logic.
|
57
|
+
|
58
|
+
## License
|
59
|
+
|
60
|
+
MIT
|
package/dist/src/App.js
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import './App.css';
|
3
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
4
|
+
import AuthProvider from './lib/authentication/AuthContext';
|
5
|
+
import Login from './local/login/Login';
|
6
|
+
import Impersonate from './local/impersonate/Impersonate';
|
7
|
+
import AppSettings from './local/util/AppSettings';
|
8
|
+
import Layout from './local/layout/Layout';
|
9
|
+
import MicroFlex from './local/microflex/MicroFlex';
|
10
|
+
function App() {
|
11
|
+
// You can define your AuthProvider props here or import them
|
12
|
+
const urls = {
|
13
|
+
Login: AppSettings.Authentication.Login,
|
14
|
+
Logout: AppSettings.Authentication.Logout,
|
15
|
+
Impersonate: (email) => AppSettings.Authentication.Impersonate(email),
|
16
|
+
};
|
17
|
+
const apiKey = import.meta.env.VITE_APIKEY;
|
18
|
+
const sessionClientId = 'casecore';
|
19
|
+
return (_jsx(AuthProvider, { urls: urls, apiKey: apiKey, sessionClientId: sessionClientId, children: _jsx(BrowserRouter, { children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(Home, {}) }), _jsx(Route, { path: "/login", element: _jsx(Login, {}) }), _jsx(Route, { path: "/impersonate", element: _jsx(Impersonate, {}) }), _jsx(Route, { path: "/microflex", element: _jsx(MicroFlex, {}) })] }) }) }));
|
20
|
+
}
|
21
|
+
function Home() {
|
22
|
+
return (_jsx(Layout, { children: _jsx("h1", { children: "Home" }) }));
|
23
|
+
}
|
24
|
+
// const urls = {
|
25
|
+
// Login: '/api/login',
|
26
|
+
// Logout: '/api/logout',
|
27
|
+
// Impersonate: (email: string) => `/api/impersonate/${email}`,
|
28
|
+
// };
|
29
|
+
// const apiKey = 'test-api-key';
|
30
|
+
// const sessionClientId = 'test-session-id';
|
31
|
+
// function TestConsumer() {
|
32
|
+
// const ctx = useAuthContext();
|
33
|
+
// if (!ctx) return <div>no context</div>;
|
34
|
+
// return (
|
35
|
+
// <div>
|
36
|
+
// <div data-testid="initialized">{ctx.initialized}</div>
|
37
|
+
// <div data-testid="email">{ctx.email}</div>
|
38
|
+
// <div data-testid="userType">{ctx.userType}</div>
|
39
|
+
// <div data-testid="claims">{JSON.stringify(ctx.claims)}</div>
|
40
|
+
// <button onClick={() => ctx.login('test@example.com', 'pw')}>Login</button>
|
41
|
+
// <button onClick={() => ctx.logout()}>Logout</button>
|
42
|
+
// <button onClick={() => ctx.impersonate('imp@example.com')}>Impersonate</button>
|
43
|
+
// </div>
|
44
|
+
// );
|
45
|
+
// }
|
46
|
+
export default App;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React, { ReactNode } from "react";
|
2
|
+
import { Claims } from "./AuthTypes";
|
3
|
+
export type AuthUrls = {
|
4
|
+
Login: string;
|
5
|
+
Logout: string;
|
6
|
+
Impersonate: (_email: string | null) => string;
|
7
|
+
};
|
8
|
+
export type AuthProviderProps = {
|
9
|
+
children: ReactNode;
|
10
|
+
urls: AuthUrls;
|
11
|
+
apiKey: string;
|
12
|
+
sessionClientId: string;
|
13
|
+
};
|
14
|
+
export type AuthContextType = {
|
15
|
+
initialized: string;
|
16
|
+
claims: Claims | null;
|
17
|
+
email: string;
|
18
|
+
discountLevel: string;
|
19
|
+
userType: string;
|
20
|
+
login: (_email?: string, _password?: string) => Promise<unknown>;
|
21
|
+
logout: () => Promise<boolean>;
|
22
|
+
impersonate: (_email: string | null) => Promise<string | null>;
|
23
|
+
fetch: (_url: string, _options?: RequestInit) => Promise<Response | null>;
|
24
|
+
hasRight: (_right: string) => boolean;
|
25
|
+
token: string | null;
|
26
|
+
sessionId: string;
|
27
|
+
};
|
28
|
+
export type Credentials = {
|
29
|
+
email: string;
|
30
|
+
password: string;
|
31
|
+
};
|
32
|
+
export declare const AuthContext: React.Context<AuthContextType | undefined>;
|
33
|
+
export declare const useAuthContext: () => AuthContextType | undefined;
|
34
|
+
export default function AuthProvider({ children, urls, apiKey, sessionClientId }: AuthProviderProps): import("react/jsx-runtime").JSX.Element;
|
@@ -0,0 +1,252 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import React, { useContext, useState, useEffect, createContext } from "react";
|
3
|
+
import { jwtDecode } from "jwt-decode";
|
4
|
+
import useLocalStorage from "../hooks/useLocalStorage";
|
5
|
+
import { getSessionId } from '../utils/SessionUtils';
|
6
|
+
import { buildClaimsFromPayload } from "../utils/ClaimsUtils";
|
7
|
+
export const AuthContext = createContext(undefined);
|
8
|
+
export const useAuthContext = () => {
|
9
|
+
return useContext(AuthContext);
|
10
|
+
};
|
11
|
+
export default function AuthProvider({ children, urls, apiKey, sessionClientId }) {
|
12
|
+
const [token, setToken] = useState(null);
|
13
|
+
const [initialized, setInitialized] = useState("");
|
14
|
+
const [claims, setClaims] = useState(null);
|
15
|
+
const [localToken, setLocalToken] = useLocalStorage("token", "");
|
16
|
+
const credentialsRef = React.useRef(null);
|
17
|
+
const sessionId = getSessionId(sessionClientId);
|
18
|
+
useEffect(() => {
|
19
|
+
if (token)
|
20
|
+
return;
|
21
|
+
// Logs in using local storage token if present or cookies. If neither exist, API will return a Guest token.
|
22
|
+
login()
|
23
|
+
.catch(e => setInitialized(e.message));
|
24
|
+
// eslint-disable-next-line
|
25
|
+
}, [token]); // Triggers login when setting token in `logout` to obtain a Guest token.
|
26
|
+
//#region Fetch extensions
|
27
|
+
class FetchError extends Error {
|
28
|
+
statusCode;
|
29
|
+
constructor(statusCode, message) {
|
30
|
+
super(message);
|
31
|
+
this.name = "FetchError";
|
32
|
+
this.statusCode = statusCode;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
function defaultErrorMessage(status, url) {
|
36
|
+
switch (status) {
|
37
|
+
case 401: return "You are not authenticated";
|
38
|
+
case 403: return "You do not have permission to access this page";
|
39
|
+
case 404: return "Page does not exist: " + url;
|
40
|
+
default: return "Unexpected Error";
|
41
|
+
}
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Performs a fetch request and throws a FetchError for HTTP errors (except 500).
|
45
|
+
*
|
46
|
+
* - Returns the response for successful requests (status < 400) and for status 500.
|
47
|
+
* - For other error statuses, reads the response text and throws a FetchError with a normalized message.
|
48
|
+
* - Handles network or parsing errors by rethrowing them.
|
49
|
+
*
|
50
|
+
* @param url - The URL to fetch.
|
51
|
+
* @param options - Optional fetch options (method, headers, body, etc).
|
52
|
+
* @returns {Promise<Response>} The fetch response if successful.
|
53
|
+
* @throws {FetchError} If the response status is an error (except 500).
|
54
|
+
*/
|
55
|
+
const fancyFetch = (url, options) => {
|
56
|
+
return fetch(url, options)
|
57
|
+
.then(async (res) => {
|
58
|
+
if (res.status < 400) {
|
59
|
+
return res;
|
60
|
+
}
|
61
|
+
else if (res.status === 500) {
|
62
|
+
return res;
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
const text = await res.text();
|
66
|
+
const message = text ? String(text).replace(/['"]+/g, '')
|
67
|
+
: res.statusText ? res.statusText
|
68
|
+
: defaultErrorMessage(res.status, url);
|
69
|
+
throw new FetchError(res.status, message);
|
70
|
+
}
|
71
|
+
})
|
72
|
+
.catch(e => { throw e; });
|
73
|
+
};
|
74
|
+
/**
|
75
|
+
* Performs a fetch request with authentication and automatic retry on 401 errors.
|
76
|
+
*
|
77
|
+
* - Adds Authorization and X-Session-ID headers if available.
|
78
|
+
* - On a 401 response, attempts to re-authenticate by calling login(), updates the Authorization header, and retries the request once.
|
79
|
+
* - Throws for other errors or if re-authentication fails.
|
80
|
+
*
|
81
|
+
* @param url - The URL to fetch.
|
82
|
+
* @param options - Optional fetch options (method, headers, body, etc).
|
83
|
+
* @returns {Promise<Response>} The fetch response if successful.
|
84
|
+
* @throws {FetchError} If the request fails or re-authentication fails.
|
85
|
+
*/
|
86
|
+
const fancyFetchWithRetry = (url, options) => {
|
87
|
+
const opts = { ...options };
|
88
|
+
opts.method = opts.method || 'GET';
|
89
|
+
opts.headers = { ...(opts.headers || {}) };
|
90
|
+
if (token)
|
91
|
+
opts.headers.Authorization = "Bearer " + token;
|
92
|
+
opts.headers['X-Session-ID'] = sessionId;
|
93
|
+
opts.credentials = 'include';
|
94
|
+
return fancyFetch(url, opts)
|
95
|
+
.catch(e => {
|
96
|
+
if (e.statusCode === 401) {
|
97
|
+
return login()
|
98
|
+
.then(fetchTokenResult => {
|
99
|
+
opts.headers.Authorization = "Bearer " + fetchTokenResult.token;
|
100
|
+
})
|
101
|
+
.then(() => fancyFetch(url, opts))
|
102
|
+
.catch(loginError => { throw loginError; });
|
103
|
+
}
|
104
|
+
else {
|
105
|
+
throw e;
|
106
|
+
}
|
107
|
+
});
|
108
|
+
};
|
109
|
+
//#endregion
|
110
|
+
//#region Login/Logout with related helpers
|
111
|
+
/**
|
112
|
+
* Authenticates the user and returns a token/claims object.
|
113
|
+
*
|
114
|
+
* The login logic attempts authentication in the following order:
|
115
|
+
* 1. If running locally and no email is provided, but credentials are stored in memory, it uses those credentials to fetch a token.
|
116
|
+
* 2. If running locally and a JWT exists in local storage (and no email is provided), it uses that token and parses claims from it.
|
117
|
+
* 3. Otherwise, it calls fetchToken with the provided email and password (or undefined for guest login).
|
118
|
+
*
|
119
|
+
* This function is used both for explicit user login and for automatic login (e.g., after logout or on mount) to obtain a guest or user token as needed.
|
120
|
+
*
|
121
|
+
* @param email - Optional email/username for login. If omitted, attempts to use stored credentials or local storage.
|
122
|
+
* @param password - Optional password for login.
|
123
|
+
* @returns {Promise<FetchTokenResult>} A promise resolving to the token and claims.
|
124
|
+
*/
|
125
|
+
const login = (email, password) => {
|
126
|
+
// const localTokenJson = window.localStorage.getItem("CPC.token")
|
127
|
+
// const localToken = localTokenJson ? JSON.parse(localTokenJson) : null
|
128
|
+
if (isLocal() && !email && credentialsRef.current) { // Has logged in using credentials and stored in state
|
129
|
+
return fetchToken(credentialsRef.current.email, credentialsRef.current.password);
|
130
|
+
}
|
131
|
+
if (isLocal() && localToken && !email) { // Local storage jwt exists on localhost
|
132
|
+
const claims = assignToken(localToken);
|
133
|
+
return Promise.resolve({ token: localToken, claims });
|
134
|
+
}
|
135
|
+
return fetchToken(email, password);
|
136
|
+
};
|
137
|
+
/**
|
138
|
+
* Logs out the current user and resets authentication state.
|
139
|
+
*
|
140
|
+
* - Calls the logout API endpoint to invalidate the session on the server.
|
141
|
+
* - Clears any stored credentials in memory.
|
142
|
+
* - Sets the token to null, which triggers a re-authentication as a guest via useEffect.
|
143
|
+
* - Clears claims state.
|
144
|
+
*
|
145
|
+
* @returns {Promise<boolean>} Resolves to true when logout is complete.
|
146
|
+
*/
|
147
|
+
const logout = () => {
|
148
|
+
if (isLocal())
|
149
|
+
setLocalToken();
|
150
|
+
return fancyFetch(urls.Logout, { method: 'POST', credentials: 'include' })
|
151
|
+
.then(() => {
|
152
|
+
credentialsRef.current = null;
|
153
|
+
setToken(null); // Setting token null triggers useEffect to reauthenticate as an anonymous user
|
154
|
+
setClaims(null);
|
155
|
+
return true;
|
156
|
+
});
|
157
|
+
};
|
158
|
+
/**
|
159
|
+
* Impersonates another user by email, updating authentication state with the new user's claims.
|
160
|
+
*
|
161
|
+
* - Calls the impersonate API endpoint with the provided email.
|
162
|
+
* - Parses and assigns the returned JWT as the current authentication token and claims.
|
163
|
+
* - If running locally, stores the new JWT in local storage.
|
164
|
+
*
|
165
|
+
* @param email - The email address of the user to impersonate.
|
166
|
+
* @returns {Promise<string | null>} Resolves to the new JWT string if successful, or null otherwise.
|
167
|
+
*/
|
168
|
+
const impersonate = (email) => {
|
169
|
+
return fancyFetchWithRetry(urls.Impersonate(email))
|
170
|
+
.then(res => res ? res.text() : null)
|
171
|
+
.then(jwt => jwt ? jwt.replace(/['"]+/g, '') : null)
|
172
|
+
.then(jwt => {
|
173
|
+
assignToken(jwt);
|
174
|
+
if (isLocal() && jwt)
|
175
|
+
setLocalToken(jwt);
|
176
|
+
return jwt;
|
177
|
+
});
|
178
|
+
};
|
179
|
+
function isLocal() {
|
180
|
+
const hostname = window.location.hostname;
|
181
|
+
return hostname === "localhost" || hostname === "127.0.0.1";
|
182
|
+
}
|
183
|
+
const assignToken = (jwt) => {
|
184
|
+
if (!jwt) {
|
185
|
+
throw Error("Cannot parse null");
|
186
|
+
}
|
187
|
+
const decoded = jwtDecode(jwt);
|
188
|
+
const claims = buildClaimsFromPayload(decoded);
|
189
|
+
setInitialized("OK");
|
190
|
+
setToken(jwt);
|
191
|
+
setClaims(claims);
|
192
|
+
return claims;
|
193
|
+
};
|
194
|
+
async function fetchToken(email, password) {
|
195
|
+
const options = {
|
196
|
+
method: 'POST',
|
197
|
+
credentials: 'include',
|
198
|
+
headers: {
|
199
|
+
'Accept': 'application/json',
|
200
|
+
'Content-Type': 'application/json',
|
201
|
+
'ApiKey': apiKey
|
202
|
+
}
|
203
|
+
};
|
204
|
+
if (email) {
|
205
|
+
options.body = JSON.stringify({
|
206
|
+
UserName: email,
|
207
|
+
Password: password,
|
208
|
+
RememberMe: false
|
209
|
+
});
|
210
|
+
}
|
211
|
+
return fancyFetch(urls.Login, options)
|
212
|
+
.then(res => res ? res.text() : null)
|
213
|
+
.then(jwt => jwt ? jwt.replace(/['"]+/g, '') : null)
|
214
|
+
.then(jwt => {
|
215
|
+
const decoded = assignToken(jwt);
|
216
|
+
if (isLocal() && email && password) {
|
217
|
+
credentialsRef.current = { email, password };
|
218
|
+
}
|
219
|
+
if (isLocal() && decoded.UserType !== "Guest" && jwt) {
|
220
|
+
setLocalToken(jwt); // Store token in Local Storage
|
221
|
+
}
|
222
|
+
return { token: jwt, claims: decoded };
|
223
|
+
});
|
224
|
+
}
|
225
|
+
//#endregion
|
226
|
+
const hasRight = (right) => {
|
227
|
+
const claimsType = claims;
|
228
|
+
if (claimsType.UserType === "Guest")
|
229
|
+
return false;
|
230
|
+
if (claimsType.Customer && claimsType.Customer.Rights) {
|
231
|
+
return claimsType.Customer.Rights.includes(right);
|
232
|
+
}
|
233
|
+
if (claimsType.Employee && claimsType.Employee.Rights) {
|
234
|
+
return claimsType.Employee.Rights.includes(right);
|
235
|
+
}
|
236
|
+
return false;
|
237
|
+
};
|
238
|
+
return (_jsx(AuthContext.Provider, { value: {
|
239
|
+
initialized,
|
240
|
+
claims,
|
241
|
+
email: claims?.Customer?.UserName || claims?.Employee?.UserName || "",
|
242
|
+
discountLevel: claims?.Customer?.CustClass || "EndUser",
|
243
|
+
userType: claims?.UserType || "",
|
244
|
+
login,
|
245
|
+
logout,
|
246
|
+
impersonate,
|
247
|
+
fetch: fancyFetchWithRetry,
|
248
|
+
hasRight,
|
249
|
+
token,
|
250
|
+
sessionId
|
251
|
+
}, children: children }));
|
252
|
+
}
|