dauth-context-react 4.0.3 → 5.0.0
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/dist/index.d.mts +3 -6
- package/dist/index.d.ts +3 -6
- package/dist/index.js +190 -366
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +191 -368
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/api/dauth.api.ts +73 -93
- package/src/api/interfaces/dauth.api.responses.ts +11 -13
- package/src/api/utils/config.ts +3 -11
- package/src/api/utils/routes.ts +0 -1
- package/src/constants.ts +0 -2
- package/src/index.tsx +42 -122
- package/src/initialDauthState.ts +0 -1
- package/src/interfaces.ts +8 -12
- package/src/reducer/dauth.actions.ts +106 -187
package/src/index.tsx
CHANGED
|
@@ -5,21 +5,18 @@ import React, {
|
|
|
5
5
|
useCallback,
|
|
6
6
|
createContext,
|
|
7
7
|
useContext,
|
|
8
|
-
useRef,
|
|
9
8
|
} from 'react';
|
|
10
9
|
import initialDauthState from './initialDauthState';
|
|
11
10
|
import userReducer from './reducer/dauth.reducer';
|
|
12
11
|
import * as action from './reducer/dauth.actions';
|
|
13
12
|
import { getClientBasePath, setDauthUrl } from './api/utils/config';
|
|
14
|
-
import {
|
|
13
|
+
import { AUTH_CODE_PARAM } from './constants';
|
|
15
14
|
import { routes } from './api/utils/routes';
|
|
16
15
|
import type {
|
|
17
16
|
IDauthProviderProps,
|
|
18
|
-
IDauthStorageKeys,
|
|
19
|
-
IDauthUser,
|
|
20
17
|
IDauthAuthMethods,
|
|
18
|
+
IDauthUser,
|
|
21
19
|
} from './interfaces';
|
|
22
|
-
import { SET_IS_LOADING } from './reducer/dauth.types';
|
|
23
20
|
|
|
24
21
|
export type { IDauthProviderProps, IDauthAuthMethods };
|
|
25
22
|
|
|
@@ -28,123 +25,60 @@ const defaultOnError = (error: Error) => console.error(error);
|
|
|
28
25
|
export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
29
26
|
props: IDauthProviderProps
|
|
30
27
|
) => {
|
|
31
|
-
const {
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const {
|
|
29
|
+
domainName,
|
|
30
|
+
children,
|
|
31
|
+
authProxyPath = '/api/auth',
|
|
32
|
+
onError,
|
|
33
|
+
env,
|
|
34
|
+
dauthUrl,
|
|
35
|
+
} = props;
|
|
36
|
+
const [dauthState, dispatch] = useReducer(
|
|
37
|
+
userReducer,
|
|
38
|
+
initialDauthState
|
|
39
|
+
);
|
|
34
40
|
|
|
35
41
|
// Configure custom dauth URL before any API calls
|
|
36
42
|
useEffect(() => {
|
|
37
43
|
setDauthUrl(dauthUrl);
|
|
38
44
|
}, [dauthUrl]);
|
|
39
45
|
|
|
40
|
-
const storageKeys: IDauthStorageKeys = useMemo(
|
|
41
|
-
() => ({
|
|
42
|
-
accessToken: storageKey?.accessToken ?? TOKEN_LS,
|
|
43
|
-
refreshToken: storageKey?.refreshToken ?? REFRESH_TOKEN_LS,
|
|
44
|
-
}),
|
|
45
|
-
[storageKey?.accessToken, storageKey?.refreshToken]
|
|
46
|
-
);
|
|
47
|
-
|
|
48
46
|
const handleError = useCallback(
|
|
49
47
|
(error: Error) => (onError ?? defaultOnError)(error),
|
|
50
48
|
[onError]
|
|
51
49
|
);
|
|
52
50
|
|
|
53
|
-
// Build action context
|
|
54
51
|
const ctx = useMemo(
|
|
55
|
-
() => ({ dispatch,
|
|
56
|
-
[
|
|
52
|
+
() => ({ dispatch, authProxyPath, onError: handleError }),
|
|
53
|
+
[authProxyPath, handleError]
|
|
57
54
|
);
|
|
58
55
|
|
|
59
|
-
//
|
|
60
|
-
const scheduleRefresh = useCallback(() => {
|
|
61
|
-
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
62
|
-
const token = localStorage.getItem(storageKeys.accessToken);
|
|
63
|
-
if (!token) return;
|
|
64
|
-
try {
|
|
65
|
-
const payloadB64 = token.split('.')[1];
|
|
66
|
-
if (!payloadB64) return;
|
|
67
|
-
const payload = JSON.parse(atob(payloadB64));
|
|
68
|
-
const expiresIn = (payload.exp || 0) * 1000 - Date.now();
|
|
69
|
-
// Refresh 5 minutes before expiry, minimum 10 seconds
|
|
70
|
-
const refreshIn = Math.max(expiresIn - 5 * 60 * 1000, 10_000);
|
|
71
|
-
refreshTimerRef.current = setTimeout(async () => {
|
|
72
|
-
await action.refreshSessionAction(ctx);
|
|
73
|
-
scheduleRefresh();
|
|
74
|
-
}, refreshIn);
|
|
75
|
-
} catch (_) {
|
|
76
|
-
// If decode fails, retry in 5 minutes
|
|
77
|
-
refreshTimerRef.current = setTimeout(
|
|
78
|
-
async () => {
|
|
79
|
-
await action.refreshSessionAction(ctx);
|
|
80
|
-
scheduleRefresh();
|
|
81
|
-
},
|
|
82
|
-
5 * 60 * 1000
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
}, [ctx, storageKeys.accessToken]);
|
|
86
|
-
|
|
87
|
-
// Catch login redirect — exchange authorization code for tokens
|
|
56
|
+
// On mount: exchange code or auto-login via session cookie
|
|
88
57
|
useEffect(() => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return action.exchangeCodeAction({ ...ctx, code });
|
|
96
|
-
}
|
|
97
|
-
})();
|
|
98
|
-
}, []);
|
|
99
|
-
|
|
100
|
-
// Auto Login
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
(async () => {
|
|
103
|
-
const refreshToken = localStorage.getItem(storageKeys.refreshToken);
|
|
104
|
-
if (refreshToken && !dauthState.isAuthenticated) {
|
|
105
|
-
return action.setAutoLoginAction(ctx);
|
|
106
|
-
} else {
|
|
107
|
-
return dispatch({
|
|
108
|
-
type: SET_IS_LOADING,
|
|
109
|
-
payload: { isLoading: false },
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
})();
|
|
113
|
-
}, []);
|
|
114
|
-
|
|
115
|
-
// Schedule proactive refresh when authenticated
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
if (dauthState.isAuthenticated) {
|
|
118
|
-
scheduleRefresh();
|
|
58
|
+
const params = new URLSearchParams(window.location.search);
|
|
59
|
+
const code = params.get(AUTH_CODE_PARAM);
|
|
60
|
+
if (code) {
|
|
61
|
+
action.exchangeCodeAction(ctx, code);
|
|
62
|
+
} else {
|
|
63
|
+
action.autoLoginAction(ctx);
|
|
119
64
|
}
|
|
120
|
-
|
|
121
|
-
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
122
|
-
};
|
|
123
|
-
}, [dauthState.isAuthenticated, scheduleRefresh]);
|
|
65
|
+
}, []);
|
|
124
66
|
|
|
125
67
|
const loginWithRedirect = useCallback(() => {
|
|
126
68
|
const base = `${getClientBasePath()}/${domainName}/${routes.signin}`;
|
|
127
|
-
const url = env
|
|
69
|
+
const url = env
|
|
70
|
+
? `${base}?env=${encodeURIComponent(env)}`
|
|
71
|
+
: base;
|
|
128
72
|
return window.location.replace(url);
|
|
129
73
|
}, [domainName, env]);
|
|
130
74
|
|
|
131
|
-
const logout = useCallback(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
domainName,
|
|
136
|
-
storageKeys,
|
|
137
|
-
});
|
|
138
|
-
}, [domainName, storageKeys]);
|
|
139
|
-
|
|
140
|
-
const getAccessToken = useCallback(async () => {
|
|
141
|
-
const token = await action.getAccessTokenAction(ctx);
|
|
142
|
-
return token as string;
|
|
143
|
-
}, [ctx]);
|
|
75
|
+
const logout = useCallback(
|
|
76
|
+
() => action.logoutAction(ctx),
|
|
77
|
+
[ctx]
|
|
78
|
+
);
|
|
144
79
|
|
|
145
80
|
const updateUser = useCallback(
|
|
146
81
|
async (fields: Partial<IDauthUser>) => {
|
|
147
|
-
const token_ls = localStorage.getItem(storageKeys.accessToken);
|
|
148
82
|
const {
|
|
149
83
|
name,
|
|
150
84
|
lastname,
|
|
@@ -169,39 +103,26 @@ export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
|
169
103
|
country,
|
|
170
104
|
metadata,
|
|
171
105
|
} as Partial<IDauthUser>;
|
|
172
|
-
return
|
|
173
|
-
...ctx,
|
|
174
|
-
user,
|
|
175
|
-
token: token_ls,
|
|
176
|
-
})) as boolean;
|
|
106
|
+
return action.updateUserAction(ctx, user);
|
|
177
107
|
},
|
|
178
|
-
[ctx
|
|
108
|
+
[ctx]
|
|
179
109
|
);
|
|
180
110
|
|
|
181
|
-
const updateUserWithRedirect = useCallback(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const token_ls = localStorage.getItem(storageKeys.accessToken);
|
|
191
|
-
if (!token_ls) return false;
|
|
192
|
-
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
193
|
-
return (await action.deleteAccountAction({
|
|
194
|
-
...ctx,
|
|
195
|
-
token: token_ls,
|
|
196
|
-
})) as boolean;
|
|
197
|
-
}, [ctx, storageKeys.accessToken]);
|
|
111
|
+
const updateUserWithRedirect = useCallback(
|
|
112
|
+
() => action.updateUserWithRedirectAction(ctx),
|
|
113
|
+
[ctx]
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const deleteAccount = useCallback(
|
|
117
|
+
() => action.deleteAccountAction(ctx),
|
|
118
|
+
[ctx]
|
|
119
|
+
);
|
|
198
120
|
|
|
199
121
|
const memoProvider = useMemo(
|
|
200
122
|
() => ({
|
|
201
123
|
...dauthState,
|
|
202
124
|
loginWithRedirect,
|
|
203
125
|
logout,
|
|
204
|
-
getAccessToken,
|
|
205
126
|
updateUser,
|
|
206
127
|
updateUserWithRedirect,
|
|
207
128
|
deleteAccount,
|
|
@@ -210,7 +131,6 @@ export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
|
210
131
|
dauthState,
|
|
211
132
|
loginWithRedirect,
|
|
212
133
|
logout,
|
|
213
|
-
getAccessToken,
|
|
214
134
|
updateUser,
|
|
215
135
|
updateUserWithRedirect,
|
|
216
136
|
deleteAccount,
|
package/src/initialDauthState.ts
CHANGED
|
@@ -12,7 +12,6 @@ const initialDauthState: IDauthState = {
|
|
|
12
12
|
isAuthenticated: false,
|
|
13
13
|
loginWithRedirect: () => {},
|
|
14
14
|
logout: () => {},
|
|
15
|
-
getAccessToken: () => Promise.resolve(''),
|
|
16
15
|
updateUser: () => Promise.resolve(false),
|
|
17
16
|
updateUserWithRedirect: () => {},
|
|
18
17
|
deleteAccount: () => Promise.resolve(false),
|
package/src/interfaces.ts
CHANGED
|
@@ -46,7 +46,6 @@ export interface IDauthState {
|
|
|
46
46
|
isAuthenticated: boolean;
|
|
47
47
|
loginWithRedirect: () => void;
|
|
48
48
|
logout: () => void;
|
|
49
|
-
getAccessToken: () => Promise<string>;
|
|
50
49
|
updateUser: (fields: Partial<IDauthUser>) => Promise<boolean>;
|
|
51
50
|
updateUserWithRedirect: () => void;
|
|
52
51
|
deleteAccount: () => Promise<boolean>;
|
|
@@ -56,22 +55,19 @@ export interface IActionStatus {
|
|
|
56
55
|
type: TStatusTypes;
|
|
57
56
|
message: string;
|
|
58
57
|
}
|
|
59
|
-
export type TStatusTypes =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
58
|
+
export type TStatusTypes =
|
|
59
|
+
| 'success'
|
|
60
|
+
| 'error'
|
|
61
|
+
| 'info'
|
|
62
|
+
| 'warning';
|
|
65
63
|
|
|
66
64
|
export interface IDauthProviderProps {
|
|
67
65
|
domainName: string;
|
|
68
66
|
children: React.ReactNode;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
refreshToken?: string;
|
|
72
|
-
};
|
|
67
|
+
/** Base path of the auth proxy on the consumer backend. Default: '/api/auth'. */
|
|
68
|
+
authProxyPath?: string;
|
|
73
69
|
onError?: (error: Error) => void;
|
|
74
70
|
env?: string;
|
|
75
|
-
/** Override the dauth
|
|
71
|
+
/** Override the dauth frontend URL for loginWithRedirect (e.g. 'https://dev.dauth.ovh' for staging) */
|
|
76
72
|
dauthUrl?: string;
|
|
77
73
|
}
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
deleteAccountAPI,
|
|
3
2
|
exchangeCodeAPI,
|
|
4
|
-
|
|
3
|
+
getSessionAPI,
|
|
5
4
|
logoutAPI,
|
|
6
|
-
refreshTokenAPI,
|
|
7
5
|
updateUserAPI,
|
|
6
|
+
deleteAccountAPI,
|
|
7
|
+
profileRedirectAPI,
|
|
8
8
|
} from '../api/dauth.api';
|
|
9
|
-
import {
|
|
10
|
-
IDauthDomainState,
|
|
11
|
-
IDauthStorageKeys,
|
|
12
|
-
IDauthUser,
|
|
13
|
-
} from '../interfaces';
|
|
9
|
+
import { IDauthDomainState, IDauthUser } from '../interfaces';
|
|
14
10
|
import * as DauthTypes from './dauth.types';
|
|
15
11
|
|
|
16
12
|
export interface ActionContext {
|
|
17
13
|
dispatch: React.Dispatch<any>;
|
|
18
|
-
|
|
19
|
-
storageKeys: IDauthStorageKeys;
|
|
14
|
+
authProxyPath: string;
|
|
20
15
|
onError: (error: Error) => void;
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
storageKeys,
|
|
29
|
-
onError,
|
|
30
|
-
}: TExchangeCodeAction) {
|
|
18
|
+
export async function exchangeCodeAction(
|
|
19
|
+
ctx: ActionContext,
|
|
20
|
+
code: string
|
|
21
|
+
) {
|
|
22
|
+
const { dispatch, authProxyPath, onError } = ctx;
|
|
31
23
|
dispatch({
|
|
32
24
|
type: DauthTypes.SET_IS_LOADING,
|
|
33
25
|
payload: { isLoading: true },
|
|
@@ -39,31 +31,24 @@ export async function exchangeCodeAction({
|
|
|
39
31
|
document.title,
|
|
40
32
|
window.location.pathname
|
|
41
33
|
);
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return resetUser(dispatch, storageKeys);
|
|
45
|
-
}
|
|
46
|
-
const { accessToken, refreshToken } = exchangeResult.data;
|
|
47
|
-
localStorage.setItem(storageKeys.accessToken, accessToken);
|
|
48
|
-
localStorage.setItem(storageKeys.refreshToken, refreshToken);
|
|
49
|
-
const getUserFetch = await getUserAPI(domainName, accessToken);
|
|
50
|
-
if (getUserFetch.response.status === 200) {
|
|
34
|
+
const result = await exchangeCodeAPI(authProxyPath, code);
|
|
35
|
+
if (result.response.status === 200) {
|
|
51
36
|
dispatch({
|
|
52
37
|
type: DauthTypes.LOGIN,
|
|
53
38
|
payload: {
|
|
54
|
-
user:
|
|
55
|
-
domain:
|
|
39
|
+
user: result.data.user,
|
|
40
|
+
domain: result.data.domain,
|
|
56
41
|
isAuthenticated: true,
|
|
57
42
|
},
|
|
58
43
|
});
|
|
59
44
|
return;
|
|
60
45
|
}
|
|
61
|
-
|
|
46
|
+
resetUser(dispatch);
|
|
62
47
|
} catch (error) {
|
|
63
48
|
onError(
|
|
64
49
|
error instanceof Error ? error : new Error(String(error))
|
|
65
50
|
);
|
|
66
|
-
|
|
51
|
+
resetUser(dispatch);
|
|
67
52
|
} finally {
|
|
68
53
|
dispatch({
|
|
69
54
|
type: DauthTypes.SET_IS_LOADING,
|
|
@@ -72,46 +57,32 @@ export async function exchangeCodeAction({
|
|
|
72
57
|
}
|
|
73
58
|
}
|
|
74
59
|
|
|
75
|
-
export async function
|
|
76
|
-
dispatch,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
dispatch({ type: DauthTypes.SET_IS_LOADING, payload: { isLoading: true } });
|
|
82
|
-
const storedRefreshToken = localStorage.getItem(storageKeys.refreshToken);
|
|
83
|
-
if (!storedRefreshToken) {
|
|
84
|
-
dispatch({
|
|
85
|
-
type: DauthTypes.SET_IS_LOADING,
|
|
86
|
-
payload: { isLoading: false },
|
|
87
|
-
});
|
|
88
|
-
return resetUser(dispatch, storageKeys);
|
|
89
|
-
}
|
|
60
|
+
export async function autoLoginAction(ctx: ActionContext) {
|
|
61
|
+
const { dispatch, authProxyPath, onError } = ctx;
|
|
62
|
+
dispatch({
|
|
63
|
+
type: DauthTypes.SET_IS_LOADING,
|
|
64
|
+
payload: { isLoading: true },
|
|
65
|
+
});
|
|
90
66
|
try {
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
user: getUserFetch.data.user,
|
|
103
|
-
domain: getUserFetch.data.domain,
|
|
104
|
-
isAuthenticated: true,
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
67
|
+
const result = await getSessionAPI(authProxyPath);
|
|
68
|
+
if (result.response.status === 200) {
|
|
69
|
+
dispatch({
|
|
70
|
+
type: DauthTypes.LOGIN,
|
|
71
|
+
payload: {
|
|
72
|
+
user: result.data.user,
|
|
73
|
+
domain: result.data.domain,
|
|
74
|
+
isAuthenticated: true,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
109
78
|
}
|
|
110
|
-
//
|
|
111
|
-
resetUser(dispatch
|
|
79
|
+
// No session — not authenticated (not an error)
|
|
80
|
+
resetUser(dispatch);
|
|
112
81
|
} catch (error) {
|
|
113
|
-
onError(
|
|
114
|
-
|
|
82
|
+
onError(
|
|
83
|
+
error instanceof Error ? error : new Error(String(error))
|
|
84
|
+
);
|
|
85
|
+
resetUser(dispatch);
|
|
115
86
|
} finally {
|
|
116
87
|
dispatch({
|
|
117
88
|
type: DauthTypes.SET_IS_LOADING,
|
|
@@ -120,168 +91,116 @@ export async function setAutoLoginAction({
|
|
|
120
91
|
}
|
|
121
92
|
}
|
|
122
93
|
|
|
123
|
-
export async function
|
|
124
|
-
dispatch,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (storedRefreshToken && domainName) {
|
|
130
|
-
try {
|
|
131
|
-
await logoutAPI(domainName, storedRefreshToken);
|
|
132
|
-
} catch (_) {
|
|
133
|
-
// Best-effort server-side logout
|
|
134
|
-
}
|
|
94
|
+
export async function logoutAction(ctx: ActionContext) {
|
|
95
|
+
const { dispatch, authProxyPath } = ctx;
|
|
96
|
+
try {
|
|
97
|
+
await logoutAPI(authProxyPath);
|
|
98
|
+
} catch {
|
|
99
|
+
// Best-effort server-side logout
|
|
135
100
|
}
|
|
136
|
-
dispatch({
|
|
101
|
+
dispatch({
|
|
102
|
+
type: DauthTypes.SET_IS_LOADING,
|
|
103
|
+
payload: { isLoading: true },
|
|
104
|
+
});
|
|
137
105
|
dispatch({
|
|
138
106
|
type: DauthTypes.LOGIN,
|
|
139
107
|
payload: {
|
|
140
108
|
user: {
|
|
141
|
-
language:
|
|
109
|
+
language:
|
|
110
|
+
window.document.documentElement.getAttribute('lang') ||
|
|
111
|
+
'es',
|
|
142
112
|
},
|
|
143
113
|
domain: {},
|
|
144
114
|
isAuthenticated: false,
|
|
145
115
|
},
|
|
146
116
|
});
|
|
147
|
-
|
|
148
|
-
localStorage.removeItem(storageKeys.refreshToken);
|
|
149
|
-
return dispatch({
|
|
117
|
+
dispatch({
|
|
150
118
|
type: DauthTypes.SET_IS_LOADING,
|
|
151
119
|
payload: { isLoading: false },
|
|
152
120
|
});
|
|
153
121
|
}
|
|
154
122
|
|
|
155
|
-
export async function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
onError
|
|
160
|
-
}: ActionContext) {
|
|
161
|
-
const storedRefreshToken = localStorage.getItem(storageKeys.refreshToken);
|
|
162
|
-
if (!storedRefreshToken) {
|
|
163
|
-
return resetUser(dispatch, storageKeys);
|
|
164
|
-
}
|
|
165
|
-
try {
|
|
166
|
-
const refreshResult = await refreshTokenAPI(domainName, storedRefreshToken);
|
|
167
|
-
if (refreshResult.response.status === 200) {
|
|
168
|
-
localStorage.setItem(
|
|
169
|
-
storageKeys.accessToken,
|
|
170
|
-
refreshResult.data.accessToken
|
|
171
|
-
);
|
|
172
|
-
localStorage.setItem(
|
|
173
|
-
storageKeys.refreshToken,
|
|
174
|
-
refreshResult.data.refreshToken
|
|
175
|
-
);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
// Refresh failed — revoked or expired
|
|
179
|
-
resetUser(dispatch, storageKeys);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
onError(error instanceof Error ? error : new Error(String(error)));
|
|
182
|
-
resetUser(dispatch, storageKeys);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
type TSetUpdateAction = ActionContext & {
|
|
187
|
-
user: Partial<IDauthUser>;
|
|
188
|
-
token: string | null;
|
|
189
|
-
};
|
|
190
|
-
export async function setUpdateUserAction({
|
|
191
|
-
dispatch,
|
|
192
|
-
domainName,
|
|
193
|
-
user,
|
|
194
|
-
token,
|
|
195
|
-
onError,
|
|
196
|
-
}: TSetUpdateAction) {
|
|
123
|
+
export async function updateUserAction(
|
|
124
|
+
ctx: ActionContext,
|
|
125
|
+
user: Partial<IDauthUser>
|
|
126
|
+
): Promise<boolean> {
|
|
127
|
+
const { dispatch, authProxyPath, onError } = ctx;
|
|
197
128
|
if (user.language) {
|
|
198
|
-
window.document.documentElement.setAttribute(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
type: DauthTypes.UPDATE_USER,
|
|
203
|
-
payload: user,
|
|
204
|
-
});
|
|
205
|
-
return false;
|
|
129
|
+
window.document.documentElement.setAttribute(
|
|
130
|
+
'lang',
|
|
131
|
+
user.language
|
|
132
|
+
);
|
|
206
133
|
}
|
|
207
134
|
try {
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
135
|
+
const result = await updateUserAPI(authProxyPath, user);
|
|
136
|
+
if (result.response.status === 200) {
|
|
210
137
|
dispatch({
|
|
211
138
|
type: DauthTypes.UPDATE_USER,
|
|
212
|
-
payload:
|
|
139
|
+
payload: result.data.user,
|
|
213
140
|
});
|
|
214
141
|
return true;
|
|
215
|
-
} else {
|
|
216
|
-
onError(new Error('Update user error: ' + getUserFetch.data.message));
|
|
217
|
-
return false;
|
|
218
142
|
}
|
|
143
|
+
onError(
|
|
144
|
+
new Error('Update user error: ' + result.data.message)
|
|
145
|
+
);
|
|
146
|
+
return false;
|
|
219
147
|
} catch (error) {
|
|
220
|
-
onError(
|
|
148
|
+
onError(
|
|
149
|
+
error instanceof Error
|
|
150
|
+
? error
|
|
151
|
+
: new Error('Update user error')
|
|
152
|
+
);
|
|
221
153
|
return false;
|
|
222
154
|
}
|
|
223
155
|
}
|
|
224
156
|
|
|
225
|
-
export async function
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
onError,
|
|
230
|
-
}: ActionContext) {
|
|
231
|
-
const token_ls = localStorage.getItem(storageKeys.accessToken);
|
|
232
|
-
if (!token_ls) return 'token-not-found';
|
|
233
|
-
// Decode JWT to check expiry (without verification — that's the server's job)
|
|
157
|
+
export async function updateUserWithRedirectAction(
|
|
158
|
+
ctx: ActionContext
|
|
159
|
+
) {
|
|
160
|
+
const { authProxyPath, onError } = ctx;
|
|
234
161
|
try {
|
|
235
|
-
const
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
dispatch,
|
|
243
|
-
domainName,
|
|
244
|
-
storageKeys,
|
|
245
|
-
onError,
|
|
246
|
-
});
|
|
247
|
-
const refreshedToken = localStorage.getItem(storageKeys.accessToken);
|
|
248
|
-
return refreshedToken || 'token-not-found';
|
|
249
|
-
}
|
|
162
|
+
const result = await profileRedirectAPI(authProxyPath);
|
|
163
|
+
if (
|
|
164
|
+
result.response.status === 200 &&
|
|
165
|
+
result.data.redirectUrl
|
|
166
|
+
) {
|
|
167
|
+
window.location.replace(result.data.redirectUrl);
|
|
168
|
+
return;
|
|
250
169
|
}
|
|
251
|
-
|
|
252
|
-
|
|
170
|
+
onError(
|
|
171
|
+
new Error('Could not generate profile redirect')
|
|
172
|
+
);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
onError(
|
|
175
|
+
error instanceof Error
|
|
176
|
+
? error
|
|
177
|
+
: new Error('Profile redirect error')
|
|
178
|
+
);
|
|
253
179
|
}
|
|
254
|
-
return token_ls;
|
|
255
180
|
}
|
|
256
181
|
|
|
257
|
-
export async function deleteAccountAction(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
onError,
|
|
262
|
-
token,
|
|
263
|
-
}: ActionContext & { token: string }) {
|
|
182
|
+
export async function deleteAccountAction(
|
|
183
|
+
ctx: ActionContext
|
|
184
|
+
): Promise<boolean> {
|
|
185
|
+
const { dispatch, authProxyPath, onError } = ctx;
|
|
264
186
|
try {
|
|
265
|
-
const result = await deleteAccountAPI(
|
|
187
|
+
const result = await deleteAccountAPI(authProxyPath);
|
|
266
188
|
if (result.response.status === 200) {
|
|
267
|
-
resetUser(dispatch
|
|
189
|
+
resetUser(dispatch);
|
|
268
190
|
return true;
|
|
269
191
|
}
|
|
270
192
|
return false;
|
|
271
193
|
} catch (error) {
|
|
272
|
-
onError(
|
|
194
|
+
onError(
|
|
195
|
+
error instanceof Error
|
|
196
|
+
? error
|
|
197
|
+
: new Error('Delete account error')
|
|
198
|
+
);
|
|
273
199
|
return false;
|
|
274
200
|
}
|
|
275
201
|
}
|
|
276
202
|
|
|
277
|
-
|
|
278
|
-
//////////////////////////////////////////
|
|
279
|
-
export const resetUser = (
|
|
280
|
-
dispatch: React.Dispatch<any>,
|
|
281
|
-
storageKeys: IDauthStorageKeys
|
|
282
|
-
) => {
|
|
283
|
-
localStorage.removeItem(storageKeys.accessToken);
|
|
284
|
-
localStorage.removeItem(storageKeys.refreshToken);
|
|
203
|
+
export const resetUser = (dispatch: React.Dispatch<any>) => {
|
|
285
204
|
return dispatch({
|
|
286
205
|
type: DauthTypes.LOGIN,
|
|
287
206
|
payload: {
|