dauth-context-react 4.0.4 → 6.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.js CHANGED
@@ -20,11 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.tsx
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ DauthProfileModal: () => DauthProfileModal,
23
24
  DauthProvider: () => DauthProvider,
24
25
  useDauth: () => useDauth
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
27
- var import_react = require("react");
28
+ var import_react2 = require("react");
28
29
 
29
30
  // src/initialDauthState.ts
30
31
  var initialDauthState = {
@@ -38,10 +39,7 @@ var initialDauthState = {
38
39
  },
39
40
  logout: () => {
40
41
  },
41
- getAccessToken: () => Promise.resolve(""),
42
42
  updateUser: () => Promise.resolve(false),
43
- updateUserWithRedirect: () => {
44
- },
45
43
  deleteAccount: () => Promise.resolve(false)
46
44
  };
47
45
  var initialDauthState_default = initialDauthState;
@@ -86,162 +84,95 @@ function userReducer(state, action) {
86
84
  }
87
85
  }
88
86
 
89
- // src/api/utils/config.ts
90
- var apiVersion = "v1";
91
- var serverDomain = "dauth.ovh";
92
- var _dauthUrl;
93
- function setDauthUrl(url) {
94
- _dauthUrl = url?.replace(/\/+$/, "");
95
- }
96
- function checkIsLocalhost() {
97
- if (typeof window === "undefined") return false;
98
- const hostname = window.location.hostname;
99
- return Boolean(
100
- hostname === "localhost" || hostname === "[::1]" || hostname.match(
101
- /(192)\.(168)\.(1)\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/gm
102
- ) || hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
87
+ // src/api/dauth.api.ts
88
+ function getCsrfToken() {
89
+ const match = document.cookie.match(
90
+ /(?:^|;\s*)(?:__Host-csrf|csrf-token)=([^;]*)/
103
91
  );
92
+ if (!match?.[1]) return "";
93
+ try {
94
+ return decodeURIComponent(match[1]);
95
+ } catch {
96
+ return match[1];
97
+ }
104
98
  }
105
- function getServerBasePath() {
106
- if (_dauthUrl) return `${_dauthUrl}/api/${apiVersion}`;
107
- const isLocalhost = checkIsLocalhost();
108
- const serverPort = 4012;
109
- const serverLocalUrl = `${window.location.protocol}//${window.location.hostname}:${serverPort}/api/${apiVersion}`;
110
- const serverProdUrl = `https://${serverDomain}/api/${apiVersion}`;
111
- return isLocalhost ? serverLocalUrl : serverProdUrl;
112
- }
113
- function getClientBasePath() {
114
- if (_dauthUrl) return _dauthUrl;
115
- const isLocalhost = checkIsLocalhost();
116
- const clientPort = 5185;
117
- const clientLocalUrl = `${window.location.protocol}//${window.location.hostname}:${clientPort}`;
118
- const clientProdUrl = `https://${serverDomain}`;
119
- return isLocalhost ? clientLocalUrl : clientProdUrl;
99
+ async function exchangeCodeAPI(basePath, code) {
100
+ const response = await fetch(`${basePath}/exchange-code`, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ credentials: "include",
104
+ body: JSON.stringify({ code })
105
+ });
106
+ const data = await response.json();
107
+ return { response, data };
120
108
  }
121
-
122
- // src/api/dauth.api.ts
123
- var getUserAPI = async (domainName, token) => {
124
- const params = {
109
+ async function getSessionAPI(basePath) {
110
+ const response = await fetch(`${basePath}/session`, {
125
111
  method: "GET",
126
- headers: {
127
- Authorization: token,
128
- "Content-Type": "application/json"
129
- }
130
- };
131
- const response = await fetch(
132
- `${getServerBasePath()}/app/${domainName}/user`,
133
- params
134
- );
112
+ credentials: "include"
113
+ });
135
114
  const data = await response.json();
136
115
  return { response, data };
137
- };
138
- var updateUserAPI = async (domainName, user, token) => {
139
- const params = {
116
+ }
117
+ async function logoutAPI(basePath) {
118
+ const response = await fetch(`${basePath}/logout`, {
119
+ method: "POST",
120
+ headers: {
121
+ "Content-Type": "application/json",
122
+ "X-CSRF-Token": getCsrfToken()
123
+ },
124
+ credentials: "include"
125
+ });
126
+ return { response };
127
+ }
128
+ async function updateUserAPI(basePath, user) {
129
+ const response = await fetch(`${basePath}/user`, {
140
130
  method: "PATCH",
141
131
  headers: {
142
- Authorization: token,
143
- "Content-Type": "application/json"
132
+ "Content-Type": "application/json",
133
+ "X-CSRF-Token": getCsrfToken()
144
134
  },
135
+ credentials: "include",
145
136
  body: JSON.stringify(user)
146
- };
147
- const response = await fetch(
148
- `${getServerBasePath()}/app/${domainName}/user`,
149
- params
150
- );
151
- const data = await response.json();
152
- return { response, data };
153
- };
154
- var refreshTokenAPI = async (domainName, refreshToken) => {
155
- const params = {
156
- method: "POST",
157
- headers: { "Content-Type": "application/json" },
158
- body: JSON.stringify({ refreshToken })
159
- };
160
- const response = await fetch(
161
- `${getServerBasePath()}/app/${domainName}/refresh-token`,
162
- params
163
- );
137
+ });
164
138
  const data = await response.json();
165
139
  return { response, data };
166
- };
167
- var deleteAccountAPI = async (domainName, token) => {
168
- const params = {
140
+ }
141
+ async function deleteAccountAPI(basePath) {
142
+ const response = await fetch(`${basePath}/user`, {
169
143
  method: "DELETE",
170
- headers: {
171
- Authorization: token,
172
- "Content-Type": "application/json"
173
- }
174
- };
175
- const response = await fetch(
176
- `${getServerBasePath()}/app/${domainName}/user`,
177
- params
178
- );
179
- const data = await response.json();
180
- return { response, data };
181
- };
182
- var exchangeCodeAPI = async (domainName, code) => {
183
- const params = {
184
- method: "POST",
185
- headers: { "Content-Type": "application/json" },
186
- body: JSON.stringify({ code })
187
- };
188
- const response = await fetch(
189
- `${getServerBasePath()}/app/${domainName}/exchange-code`,
190
- params
191
- );
144
+ headers: { "X-CSRF-Token": getCsrfToken() },
145
+ credentials: "include"
146
+ });
192
147
  const data = await response.json();
193
148
  return { response, data };
194
- };
195
- var logoutAPI = async (domainName, refreshToken) => {
196
- const params = {
197
- method: "POST",
198
- headers: { "Content-Type": "application/json" },
199
- body: JSON.stringify({ refreshToken })
200
- };
201
- const response = await fetch(
202
- `${getServerBasePath()}/app/${domainName}/logout`,
203
- params
204
- );
205
- return { response };
206
- };
149
+ }
207
150
 
208
151
  // src/reducer/dauth.actions.ts
209
- async function exchangeCodeAction({
210
- dispatch,
211
- code,
212
- domainName,
213
- storageKeys,
214
- onError
215
- }) {
152
+ async function exchangeCodeAction(ctx, code) {
153
+ const { dispatch, authProxyPath, onError } = ctx;
216
154
  dispatch({
217
155
  type: SET_IS_LOADING,
218
156
  payload: { isLoading: true }
219
157
  });
220
158
  try {
221
159
  window.history.replaceState({}, document.title, window.location.pathname);
222
- const exchangeResult = await exchangeCodeAPI(domainName, code);
223
- if (exchangeResult.response.status !== 200) {
224
- return resetUser(dispatch, storageKeys);
225
- }
226
- const { accessToken, refreshToken } = exchangeResult.data;
227
- localStorage.setItem(storageKeys.accessToken, accessToken);
228
- localStorage.setItem(storageKeys.refreshToken, refreshToken);
229
- const getUserFetch = await getUserAPI(domainName, accessToken);
230
- if (getUserFetch.response.status === 200) {
160
+ const result = await exchangeCodeAPI(authProxyPath, code);
161
+ if (result.response.status === 200) {
231
162
  dispatch({
232
163
  type: LOGIN,
233
164
  payload: {
234
- user: getUserFetch.data.user,
235
- domain: getUserFetch.data.domain,
165
+ user: result.data.user,
166
+ domain: result.data.domain,
236
167
  isAuthenticated: true
237
168
  }
238
169
  });
239
170
  return;
240
171
  }
241
- return resetUser(dispatch, storageKeys);
172
+ resetUser(dispatch);
242
173
  } catch (error) {
243
174
  onError(error instanceof Error ? error : new Error(String(error)));
244
- return resetUser(dispatch, storageKeys);
175
+ resetUser(dispatch);
245
176
  } finally {
246
177
  dispatch({
247
178
  type: SET_IS_LOADING,
@@ -249,45 +180,29 @@ async function exchangeCodeAction({
249
180
  });
250
181
  }
251
182
  }
252
- async function setAutoLoginAction({
253
- dispatch,
254
- domainName,
255
- storageKeys,
256
- onError
257
- }) {
258
- dispatch({ type: SET_IS_LOADING, payload: { isLoading: true } });
259
- const storedRefreshToken = localStorage.getItem(storageKeys.refreshToken);
260
- if (!storedRefreshToken) {
261
- dispatch({
262
- type: SET_IS_LOADING,
263
- payload: { isLoading: false }
264
- });
265
- return resetUser(dispatch, storageKeys);
266
- }
183
+ async function autoLoginAction(ctx) {
184
+ const { dispatch, authProxyPath, onError } = ctx;
185
+ dispatch({
186
+ type: SET_IS_LOADING,
187
+ payload: { isLoading: true }
188
+ });
267
189
  try {
268
- const refreshResult = await refreshTokenAPI(domainName, storedRefreshToken);
269
- if (refreshResult.response.status === 200) {
270
- const newAccessToken = refreshResult.data.accessToken;
271
- const newRefreshToken = refreshResult.data.refreshToken;
272
- localStorage.setItem(storageKeys.accessToken, newAccessToken);
273
- localStorage.setItem(storageKeys.refreshToken, newRefreshToken);
274
- const getUserFetch = await getUserAPI(domainName, newAccessToken);
275
- if (getUserFetch.response.status === 200) {
276
- dispatch({
277
- type: LOGIN,
278
- payload: {
279
- user: getUserFetch.data.user,
280
- domain: getUserFetch.data.domain,
281
- isAuthenticated: true
282
- }
283
- });
284
- return;
285
- }
190
+ const result = await getSessionAPI(authProxyPath);
191
+ if (result.response.status === 200) {
192
+ dispatch({
193
+ type: LOGIN,
194
+ payload: {
195
+ user: result.data.user,
196
+ domain: result.data.domain,
197
+ isAuthenticated: true
198
+ }
199
+ });
200
+ return;
286
201
  }
287
- resetUser(dispatch, storageKeys);
202
+ resetUser(dispatch);
288
203
  } catch (error) {
289
204
  onError(error instanceof Error ? error : new Error(String(error)));
290
- resetUser(dispatch, storageKeys);
205
+ resetUser(dispatch);
291
206
  } finally {
292
207
  dispatch({
293
208
  type: SET_IS_LOADING,
@@ -295,19 +210,16 @@ async function setAutoLoginAction({
295
210
  });
296
211
  }
297
212
  }
298
- async function setLogoutAction({
299
- dispatch,
300
- domainName,
301
- storageKeys
302
- }) {
303
- const storedRefreshToken = localStorage.getItem(storageKeys.refreshToken);
304
- if (storedRefreshToken && domainName) {
305
- try {
306
- await logoutAPI(domainName, storedRefreshToken);
307
- } catch (_) {
308
- }
213
+ async function logoutAction(ctx) {
214
+ const { dispatch, authProxyPath } = ctx;
215
+ try {
216
+ await logoutAPI(authProxyPath);
217
+ } catch {
309
218
  }
310
- dispatch({ type: SET_IS_LOADING, payload: { isLoading: true } });
219
+ dispatch({
220
+ type: SET_IS_LOADING,
221
+ payload: { isLoading: true }
222
+ });
311
223
  dispatch({
312
224
  type: LOGIN,
313
225
  payload: {
@@ -318,115 +230,38 @@ async function setLogoutAction({
318
230
  isAuthenticated: false
319
231
  }
320
232
  });
321
- localStorage.removeItem(storageKeys.accessToken);
322
- localStorage.removeItem(storageKeys.refreshToken);
323
- return dispatch({
233
+ dispatch({
324
234
  type: SET_IS_LOADING,
325
235
  payload: { isLoading: false }
326
236
  });
327
237
  }
328
- async function refreshSessionAction({
329
- dispatch,
330
- domainName,
331
- storageKeys,
332
- onError
333
- }) {
334
- const storedRefreshToken = localStorage.getItem(storageKeys.refreshToken);
335
- if (!storedRefreshToken) {
336
- return resetUser(dispatch, storageKeys);
337
- }
338
- try {
339
- const refreshResult = await refreshTokenAPI(domainName, storedRefreshToken);
340
- if (refreshResult.response.status === 200) {
341
- localStorage.setItem(
342
- storageKeys.accessToken,
343
- refreshResult.data.accessToken
344
- );
345
- localStorage.setItem(
346
- storageKeys.refreshToken,
347
- refreshResult.data.refreshToken
348
- );
349
- return;
350
- }
351
- resetUser(dispatch, storageKeys);
352
- } catch (error) {
353
- onError(error instanceof Error ? error : new Error(String(error)));
354
- resetUser(dispatch, storageKeys);
355
- }
356
- }
357
- async function setUpdateUserAction({
358
- dispatch,
359
- domainName,
360
- user,
361
- token,
362
- onError
363
- }) {
238
+ async function updateUserAction(ctx, user) {
239
+ const { dispatch, authProxyPath, onError } = ctx;
364
240
  if (user.language) {
365
241
  window.document.documentElement.setAttribute("lang", user.language);
366
242
  }
367
- if (!token) {
368
- dispatch({
369
- type: UPDATE_USER,
370
- payload: user
371
- });
372
- return false;
373
- }
374
243
  try {
375
- const getUserFetch = await updateUserAPI(domainName, user, token);
376
- if (getUserFetch.response.status === 200) {
244
+ const result = await updateUserAPI(authProxyPath, user);
245
+ if (result.response.status === 200) {
377
246
  dispatch({
378
247
  type: UPDATE_USER,
379
- payload: getUserFetch.data.user
248
+ payload: result.data.user
380
249
  });
381
250
  return true;
382
- } else {
383
- onError(new Error("Update user error: " + getUserFetch.data.message));
384
- return false;
385
251
  }
252
+ onError(new Error("Update user error: " + result.data.message));
253
+ return false;
386
254
  } catch (error) {
387
255
  onError(error instanceof Error ? error : new Error("Update user error"));
388
256
  return false;
389
257
  }
390
258
  }
391
- async function getAccessTokenAction({
392
- dispatch,
393
- domainName,
394
- storageKeys,
395
- onError
396
- }) {
397
- const token_ls = localStorage.getItem(storageKeys.accessToken);
398
- if (!token_ls) return "token-not-found";
399
- try {
400
- const payloadB64 = token_ls.split(".")[1];
401
- if (payloadB64) {
402
- const payload = JSON.parse(atob(payloadB64));
403
- const expiresIn = (payload.exp || 0) * 1e3 - Date.now();
404
- if (expiresIn < 5 * 60 * 1e3) {
405
- await refreshSessionAction({
406
- dispatch,
407
- domainName,
408
- storageKeys,
409
- onError
410
- });
411
- const refreshedToken = localStorage.getItem(storageKeys.accessToken);
412
- return refreshedToken || "token-not-found";
413
- }
414
- }
415
- } catch (_) {
416
- }
417
- return token_ls;
418
- }
419
- async function deleteAccountAction({
420
- dispatch,
421
- domainName,
422
- storageKeys,
423
- onError,
424
- token
425
- }) {
259
+ async function deleteAccountAction(ctx) {
260
+ const { dispatch, authProxyPath, onError } = ctx;
426
261
  try {
427
- const result = await deleteAccountAPI(domainName, token);
262
+ const result = await deleteAccountAPI(authProxyPath);
428
263
  if (result.response.status === 200) {
429
- resetUser(dispatch, storageKeys);
264
+ resetUser(dispatch);
430
265
  return true;
431
266
  }
432
267
  return false;
@@ -435,9 +270,7 @@ async function deleteAccountAction({
435
270
  return false;
436
271
  }
437
272
  }
438
- var resetUser = (dispatch, storageKeys) => {
439
- localStorage.removeItem(storageKeys.accessToken);
440
- localStorage.removeItem(storageKeys.refreshToken);
273
+ var resetUser = (dispatch) => {
441
274
  return dispatch({
442
275
  type: LOGIN,
443
276
  payload: {
@@ -448,120 +281,833 @@ var resetUser = (dispatch, storageKeys) => {
448
281
  });
449
282
  };
450
283
 
284
+ // src/api/utils/config.ts
285
+ var serverDomain = "dauth.ovh";
286
+ var _dauthUrl;
287
+ function setDauthUrl(url) {
288
+ _dauthUrl = url?.replace(/\/+$/, "");
289
+ }
290
+ function checkIsLocalhost() {
291
+ if (typeof window === "undefined") return false;
292
+ const hostname = window.location.hostname;
293
+ return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
294
+ hostname
295
+ ) || /^192\.168(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){2}$/.test(
296
+ hostname
297
+ ) || /^10(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
298
+ hostname
299
+ );
300
+ }
301
+ function getClientBasePath() {
302
+ if (_dauthUrl) return _dauthUrl;
303
+ const isLocalhost = checkIsLocalhost();
304
+ const clientPort = 5185;
305
+ const clientLocalUrl = `${window.location.protocol}//${window.location.hostname}:${clientPort}`;
306
+ const clientProdUrl = `https://${serverDomain}`;
307
+ return isLocalhost ? clientLocalUrl : clientProdUrl;
308
+ }
309
+
451
310
  // src/constants.ts
452
- var TOKEN_LS = "dauth_state";
453
- var REFRESH_TOKEN_LS = "dauth_refresh_token";
454
311
  var AUTH_CODE_PARAM = "code";
455
312
 
456
313
  // src/api/utils/routes.ts
457
314
  var routes = {
458
- signin: "signin",
459
- updateUser: "update-user"
315
+ signin: "signin"
460
316
  };
461
317
 
462
- // src/index.tsx
318
+ // src/DauthProfileModal.tsx
319
+ var import_react = require("react");
320
+ var import_react_dom = require("react-dom");
463
321
  var import_jsx_runtime = require("react/jsx-runtime");
464
- var defaultOnError = (error) => console.error(error);
465
- var DauthProvider = (props) => {
466
- const { domainName, children, storageKey, onError, env, dauthUrl } = props;
467
- const [dauthState, dispatch] = (0, import_react.useReducer)(userReducer, initialDauthState_default);
468
- const refreshTimerRef = (0, import_react.useRef)(null);
469
- (0, import_react.useEffect)(() => {
470
- setDauthUrl(dauthUrl);
471
- }, [dauthUrl]);
472
- const storageKeys = (0, import_react.useMemo)(
473
- () => ({
474
- accessToken: storageKey?.accessToken ?? TOKEN_LS,
475
- refreshToken: storageKey?.refreshToken ?? REFRESH_TOKEN_LS
476
- }),
477
- [storageKey?.accessToken, storageKey?.refreshToken]
322
+ var TRANSITION_MS = 200;
323
+ var MOBILE_TRANSITION_MS = 300;
324
+ var SUCCESS_TIMEOUT_MS = 4e3;
325
+ var CONFIRM_WORD = "DELETE";
326
+ function IconClose() {
327
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
328
+ "svg",
329
+ {
330
+ width: "20",
331
+ height: "20",
332
+ viewBox: "0 0 24 24",
333
+ fill: "none",
334
+ stroke: "currentColor",
335
+ strokeWidth: "2",
336
+ strokeLinecap: "round",
337
+ strokeLinejoin: "round",
338
+ children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
341
+ ]
342
+ }
478
343
  );
479
- const handleError = (0, import_react.useCallback)(
480
- (error) => (onError ?? defaultOnError)(error),
481
- [onError]
344
+ }
345
+ function IconBack() {
346
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
347
+ "svg",
348
+ {
349
+ width: "20",
350
+ height: "20",
351
+ viewBox: "0 0 24 24",
352
+ fill: "none",
353
+ stroke: "currentColor",
354
+ strokeWidth: "2",
355
+ strokeLinecap: "round",
356
+ strokeLinejoin: "round",
357
+ children: [
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
359
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "12 19 5 12 12 5" })
360
+ ]
361
+ }
482
362
  );
483
- const ctx = (0, import_react.useMemo)(
484
- () => ({ dispatch, domainName, storageKeys, onError: handleError }),
485
- [domainName, storageKeys, handleError]
363
+ }
364
+ function Spinner() {
365
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: spinnerStyle, "aria-hidden": "true" });
366
+ }
367
+ function useMediaQuery(query) {
368
+ const [matches, setMatches] = (0, import_react.useState)(
369
+ () => typeof window !== "undefined" && window.matchMedia(query).matches
486
370
  );
487
- const scheduleRefresh = (0, import_react.useCallback)(() => {
488
- if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
489
- const token = localStorage.getItem(storageKeys.accessToken);
490
- if (!token) return;
491
- try {
492
- const payloadB64 = token.split(".")[1];
493
- if (!payloadB64) return;
494
- const payload = JSON.parse(atob(payloadB64));
495
- const expiresIn = (payload.exp || 0) * 1e3 - Date.now();
496
- const refreshIn = Math.max(expiresIn - 5 * 60 * 1e3, 1e4);
497
- refreshTimerRef.current = setTimeout(async () => {
498
- await refreshSessionAction(ctx);
499
- scheduleRefresh();
500
- }, refreshIn);
501
- } catch (_) {
502
- refreshTimerRef.current = setTimeout(
503
- async () => {
504
- await refreshSessionAction(ctx);
505
- scheduleRefresh();
506
- },
507
- 5 * 60 * 1e3
508
- );
371
+ (0, import_react.useEffect)(() => {
372
+ const mq = window.matchMedia(query);
373
+ const handler = (e) => setMatches(e.matches);
374
+ mq.addEventListener("change", handler);
375
+ return () => mq.removeEventListener("change", handler);
376
+ }, [query]);
377
+ return matches;
378
+ }
379
+ function useModalAnimation(open) {
380
+ const [phase, setPhase] = (0, import_react.useState)("exited");
381
+ (0, import_react.useEffect)(() => {
382
+ if (open) {
383
+ setPhase("entering");
384
+ const raf = requestAnimationFrame(() => {
385
+ requestAnimationFrame(() => setPhase("entered"));
386
+ });
387
+ return () => cancelAnimationFrame(raf);
388
+ }
389
+ if (phase === "entered" || phase === "entering") {
390
+ setPhase("exiting");
391
+ const timer = setTimeout(() => setPhase("exited"), MOBILE_TRANSITION_MS);
392
+ return () => clearTimeout(timer);
509
393
  }
510
- }, [ctx, storageKeys.accessToken]);
394
+ return void 0;
395
+ }, [open]);
396
+ return phase;
397
+ }
398
+ function useFocusTrap(containerRef, active, onEscape) {
399
+ const previousFocus = (0, import_react.useRef)(null);
511
400
  (0, import_react.useEffect)(() => {
512
- (async () => {
513
- const queryString = window.location.search;
514
- if (!queryString) return;
515
- const urlParams = new URLSearchParams(queryString);
516
- const code = urlParams.get(AUTH_CODE_PARAM);
517
- if (code && !dauthState.isAuthenticated) {
518
- return exchangeCodeAction({ ...ctx, code });
401
+ if (!active) return;
402
+ previousFocus.current = document.activeElement;
403
+ const container = containerRef.current;
404
+ if (!container) return;
405
+ const focusFirst = () => {
406
+ const firstInput = container.querySelector(
407
+ "input:not([disabled])"
408
+ );
409
+ (firstInput ?? container).focus();
410
+ };
411
+ const raf = requestAnimationFrame(focusFirst);
412
+ const handleKeyDown = (e) => {
413
+ if (e.key === "Escape") {
414
+ e.preventDefault();
415
+ onEscape();
416
+ return;
519
417
  }
520
- })();
521
- }, []);
522
- (0, import_react.useEffect)(() => {
523
- (async () => {
524
- const urlParams = new URLSearchParams(window.location.search);
525
- if (urlParams.get(AUTH_CODE_PARAM)) return;
526
- const refreshToken = localStorage.getItem(storageKeys.refreshToken);
527
- if (refreshToken && !dauthState.isAuthenticated) {
528
- return setAutoLoginAction(ctx);
529
- } else {
530
- return dispatch({
531
- type: SET_IS_LOADING,
532
- payload: { isLoading: false }
533
- });
418
+ if (e.key !== "Tab") return;
419
+ const focusable = container.querySelectorAll(
420
+ 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
421
+ );
422
+ if (focusable.length === 0) return;
423
+ const first = focusable[0];
424
+ const last = focusable[focusable.length - 1];
425
+ if (e.shiftKey && document.activeElement === first) {
426
+ e.preventDefault();
427
+ last.focus();
428
+ } else if (!e.shiftKey && document.activeElement === last) {
429
+ e.preventDefault();
430
+ first.focus();
534
431
  }
535
- })();
536
- }, []);
432
+ };
433
+ document.addEventListener("keydown", handleKeyDown);
434
+ return () => {
435
+ cancelAnimationFrame(raf);
436
+ document.removeEventListener("keydown", handleKeyDown);
437
+ if (previousFocus.current instanceof HTMLElement) {
438
+ previousFocus.current.focus();
439
+ }
440
+ };
441
+ }, [active, containerRef, onEscape]);
442
+ }
443
+ function useScrollLock(active) {
537
444
  (0, import_react.useEffect)(() => {
538
- if (dauthState.isAuthenticated) {
539
- scheduleRefresh();
445
+ if (!active) return;
446
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
447
+ const prevOverflow = document.body.style.overflow;
448
+ const prevPaddingRight = document.body.style.paddingRight;
449
+ document.body.style.overflow = "hidden";
450
+ if (scrollbarWidth > 0) {
451
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
540
452
  }
541
453
  return () => {
542
- if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
454
+ document.body.style.overflow = prevOverflow;
455
+ document.body.style.paddingRight = prevPaddingRight;
543
456
  };
544
- }, [dauthState.isAuthenticated, scheduleRefresh]);
545
- const loginWithRedirect = (0, import_react.useCallback)(() => {
457
+ }, [active]);
458
+ }
459
+ function DauthProfileModal({ open, onClose }) {
460
+ const { user, domain, updateUser, deleteAccount } = useDauth();
461
+ const isDesktop = useMediaQuery("(min-width: 641px)");
462
+ const phase = useModalAnimation(open);
463
+ const modalRef = (0, import_react.useRef)(null);
464
+ const [name, setName] = (0, import_react.useState)("");
465
+ const [lastname, setLastname] = (0, import_react.useState)("");
466
+ const [nickname, setNickname] = (0, import_react.useState)("");
467
+ const [country, setCountry] = (0, import_react.useState)("");
468
+ const [populated, setPopulated] = (0, import_react.useState)(false);
469
+ const [saving, setSaving] = (0, import_react.useState)(false);
470
+ const [status, setStatus] = (0, import_react.useState)(null);
471
+ const [showDelete, setShowDelete] = (0, import_react.useState)(false);
472
+ const [deleteText, setDeleteText] = (0, import_react.useState)("");
473
+ const [deleting, setDeleting] = (0, import_react.useState)(false);
474
+ (0, import_react.useEffect)(() => {
475
+ if (open && user?._id && !populated) {
476
+ setName(user.name || "");
477
+ setLastname(user.lastname || "");
478
+ setNickname(user.nickname || "");
479
+ setCountry(user.country || "");
480
+ setPopulated(true);
481
+ }
482
+ if (!open) {
483
+ setPopulated(false);
484
+ setStatus(null);
485
+ setShowDelete(false);
486
+ setDeleteText("");
487
+ }
488
+ }, [open, user, populated]);
489
+ (0, import_react.useEffect)(() => {
490
+ if (status?.type !== "success") return;
491
+ const timer = setTimeout(() => setStatus(null), SUCCESS_TIMEOUT_MS);
492
+ return () => clearTimeout(timer);
493
+ }, [status]);
494
+ useFocusTrap(modalRef, phase === "entered", onClose);
495
+ useScrollLock(phase !== "exited");
496
+ const hasField = (0, import_react.useCallback)(
497
+ (field) => domain.formFields?.some((f) => f.field === field) ?? false,
498
+ [domain.formFields]
499
+ );
500
+ const isRequired = (0, import_react.useCallback)(
501
+ (field) => domain.formFields?.find((f) => f.field === field)?.required ?? false,
502
+ [domain.formFields]
503
+ );
504
+ const hasChanges = (0, import_react.useMemo)(() => {
505
+ if (!user?._id) return false;
506
+ return name !== (user.name || "") || lastname !== (user.lastname || "") || nickname !== (user.nickname || "") || country !== (user.country || "");
507
+ }, [name, lastname, nickname, country, user]);
508
+ const canSave = name.trim().length > 0 && hasChanges && !saving;
509
+ const handleSave = (0, import_react.useCallback)(async () => {
510
+ setSaving(true);
511
+ setStatus(null);
512
+ const fields = { name };
513
+ if (hasField("lastname")) fields.lastname = lastname;
514
+ if (hasField("nickname")) fields.nickname = nickname;
515
+ if (hasField("country")) fields.country = country;
516
+ const ok = await updateUser(fields);
517
+ setSaving(false);
518
+ if (ok) {
519
+ setStatus({
520
+ type: "success",
521
+ message: "Profile updated successfully"
522
+ });
523
+ } else {
524
+ setStatus({
525
+ type: "error",
526
+ message: "Something went wrong. Please try again."
527
+ });
528
+ }
529
+ }, [name, lastname, nickname, country, hasField, updateUser]);
530
+ const handleDelete = (0, import_react.useCallback)(async () => {
531
+ setDeleting(true);
532
+ const ok = await deleteAccount();
533
+ setDeleting(false);
534
+ if (ok) {
535
+ onClose();
536
+ } else {
537
+ setStatus({
538
+ type: "error",
539
+ message: "Could not delete account. Please try again."
540
+ });
541
+ setShowDelete(false);
542
+ setDeleteText("");
543
+ }
544
+ }, [deleteAccount, onClose]);
545
+ if (phase === "exited") return null;
546
+ const dur = isDesktop ? TRANSITION_MS : MOBILE_TRANSITION_MS;
547
+ const easing = "cubic-bezier(0.16, 1, 0.3, 1)";
548
+ const backdrop = {
549
+ position: "fixed",
550
+ inset: 0,
551
+ zIndex: 2147483647,
552
+ backgroundColor: "var(--dauth-backdrop, rgba(0, 0, 0, 0.6))",
553
+ backdropFilter: "blur(4px)",
554
+ WebkitBackdropFilter: "blur(4px)",
555
+ display: "flex",
556
+ alignItems: "center",
557
+ justifyContent: "center",
558
+ opacity: phase === "entered" ? 1 : 0,
559
+ transition: `opacity ${dur}ms ease-out`
560
+ };
561
+ const modalDesktop = {
562
+ position: "relative",
563
+ width: "100%",
564
+ maxWidth: 480,
565
+ maxHeight: "90vh",
566
+ margin: 16,
567
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
568
+ borderRadius: "var(--dauth-radius, 12px)",
569
+ boxShadow: "var(--dauth-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.5))",
570
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
571
+ display: "flex",
572
+ flexDirection: "column",
573
+ overflow: "hidden",
574
+ fontFamily: "var(--dauth-font-family, system-ui, -apple-system, sans-serif)",
575
+ color: "var(--dauth-text-primary, #e4e4e7)",
576
+ opacity: phase === "entered" ? 1 : 0,
577
+ transform: phase === "entered" ? "translateY(0)" : "translateY(16px)",
578
+ transition: `opacity ${dur}ms ${easing}, transform ${dur}ms ${easing}`
579
+ };
580
+ const modalMobile = {
581
+ position: "fixed",
582
+ inset: 0,
583
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
584
+ display: "flex",
585
+ flexDirection: "column",
586
+ fontFamily: "var(--dauth-font-family, system-ui, -apple-system, sans-serif)",
587
+ color: "var(--dauth-text-primary, #e4e4e7)",
588
+ transform: phase === "entered" ? "translateY(0)" : "translateY(100%)",
589
+ transition: `transform ${dur}ms ${easing}`
590
+ };
591
+ const avatarInitial = (user.name || user.email || "?").charAt(0).toUpperCase();
592
+ return (0, import_react_dom.createPortal)(
593
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
595
+ "style",
596
+ {
597
+ dangerouslySetInnerHTML: {
598
+ __html: "@keyframes dauth-spin{to{transform:rotate(360deg)}}"
599
+ }
600
+ }
601
+ ),
602
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
603
+ "div",
604
+ {
605
+ style: backdrop,
606
+ onClick: isDesktop ? onClose : void 0,
607
+ "data-testid": "dauth-profile-backdrop",
608
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
609
+ "div",
610
+ {
611
+ ref: modalRef,
612
+ role: "dialog",
613
+ "aria-modal": "true",
614
+ "aria-labelledby": "dauth-profile-title",
615
+ style: isDesktop ? modalDesktop : modalMobile,
616
+ onClick: (e) => e.stopPropagation(),
617
+ tabIndex: -1,
618
+ children: [
619
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: headerStyle(isDesktop), children: [
620
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
621
+ "button",
622
+ {
623
+ type: "button",
624
+ onClick: onClose,
625
+ style: closeBtn,
626
+ "aria-label": "Close",
627
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
628
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
629
+ children: isDesktop ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconClose, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconBack, {})
630
+ }
631
+ ),
632
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: "dauth-profile-title", style: titleStyle, children: "Your Profile" }),
633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: 36 } })
634
+ ] }),
635
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: bodyStyle, children: [
636
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: avatarSection, children: [
637
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: avatarCircle, children: user.avatar?.url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
638
+ "img",
639
+ {
640
+ src: user.avatar.url,
641
+ alt: "",
642
+ style: {
643
+ width: "100%",
644
+ height: "100%",
645
+ objectFit: "cover"
646
+ }
647
+ }
648
+ ) : avatarInitial }),
649
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: emailText, children: user.email })
650
+ ] }),
651
+ status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
652
+ "div",
653
+ {
654
+ role: "status",
655
+ "aria-live": "polite",
656
+ style: statusMsg(status.type),
657
+ children: status.message
658
+ }
659
+ ),
660
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
661
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
662
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
664
+ "input",
665
+ {
666
+ id: "dauth-name",
667
+ type: "text",
668
+ value: name,
669
+ onChange: (e) => setName(e.target.value),
670
+ placeholder: "Your name",
671
+ disabled: saving,
672
+ style: input,
673
+ onFocus: inputFocusHandler,
674
+ onBlur: inputBlurHandler
675
+ }
676
+ )
677
+ ] }),
678
+ hasField("lastname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
679
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-lastname", style: label, children: [
680
+ "Last name",
681
+ isRequired("lastname") ? " *" : ""
682
+ ] }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
684
+ "input",
685
+ {
686
+ id: "dauth-lastname",
687
+ type: "text",
688
+ value: lastname,
689
+ onChange: (e) => setLastname(e.target.value),
690
+ placeholder: "Your last name",
691
+ disabled: saving,
692
+ style: input,
693
+ onFocus: inputFocusHandler,
694
+ onBlur: inputBlurHandler
695
+ }
696
+ )
697
+ ] }),
698
+ hasField("nickname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-nickname", style: label, children: [
700
+ "Nickname",
701
+ isRequired("nickname") ? " *" : ""
702
+ ] }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
704
+ "input",
705
+ {
706
+ id: "dauth-nickname",
707
+ type: "text",
708
+ value: nickname,
709
+ onChange: (e) => setNickname(e.target.value),
710
+ placeholder: "Choose a nickname",
711
+ disabled: saving,
712
+ style: input,
713
+ onFocus: inputFocusHandler,
714
+ onBlur: inputBlurHandler
715
+ }
716
+ )
717
+ ] }),
718
+ hasField("country") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
719
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-country", style: label, children: [
720
+ "Country",
721
+ isRequired("country") ? " *" : ""
722
+ ] }),
723
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
724
+ "input",
725
+ {
726
+ id: "dauth-country",
727
+ type: "text",
728
+ value: country,
729
+ onChange: (e) => setCountry(e.target.value),
730
+ placeholder: "Your country",
731
+ disabled: saving,
732
+ style: input,
733
+ onFocus: inputFocusHandler,
734
+ onBlur: inputBlurHandler
735
+ }
736
+ )
737
+ ] })
738
+ ] }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
740
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerTitle, children: "Delete account" }),
742
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
743
+ !showDelete ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
744
+ "button",
745
+ {
746
+ type: "button",
747
+ style: deleteBtn,
748
+ onClick: () => setShowDelete(true),
749
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
750
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
751
+ children: "Delete account"
752
+ }
753
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: deletePanel, children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: deletePanelText, children: [
755
+ "This action is permanent and cannot be undone. Type",
756
+ " ",
757
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: CONFIRM_WORD }),
758
+ " to confirm."
759
+ ] }),
760
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
761
+ "input",
762
+ {
763
+ type: "text",
764
+ value: deleteText,
765
+ onChange: (e) => setDeleteText(e.target.value),
766
+ placeholder: `Type ${CONFIRM_WORD}`,
767
+ style: input,
768
+ onFocus: inputFocusHandler,
769
+ onBlur: inputBlurHandler,
770
+ disabled: deleting
771
+ }
772
+ ),
773
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
774
+ "div",
775
+ {
776
+ style: {
777
+ display: "flex",
778
+ gap: 8,
779
+ marginTop: 12
780
+ },
781
+ children: [
782
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
783
+ "button",
784
+ {
785
+ type: "button",
786
+ style: cancelBtn,
787
+ onClick: () => {
788
+ setShowDelete(false);
789
+ setDeleteText("");
790
+ },
791
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
792
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
793
+ children: "Cancel"
794
+ }
795
+ ),
796
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
797
+ "button",
798
+ {
799
+ type: "button",
800
+ style: {
801
+ ...deleteConfirmBtn,
802
+ opacity: deleteText !== CONFIRM_WORD || deleting ? 0.5 : 1,
803
+ cursor: deleteText !== CONFIRM_WORD || deleting ? "not-allowed" : "pointer"
804
+ },
805
+ disabled: deleteText !== CONFIRM_WORD || deleting,
806
+ onClick: handleDelete,
807
+ children: [
808
+ deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
809
+ "Delete my account"
810
+ ]
811
+ }
812
+ )
813
+ ]
814
+ }
815
+ )
816
+ ] })
817
+ ] })
818
+ ] }),
819
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
820
+ "button",
821
+ {
822
+ type: "button",
823
+ style: {
824
+ ...saveBtn,
825
+ opacity: canSave ? 1 : 0.5,
826
+ cursor: canSave ? "pointer" : "not-allowed"
827
+ },
828
+ disabled: !canSave,
829
+ onClick: handleSave,
830
+ "aria-busy": saving,
831
+ onMouseEnter: (e) => {
832
+ if (canSave)
833
+ e.currentTarget.style.backgroundColor = "var(--dauth-accent-hover, #818cf8)";
834
+ },
835
+ onMouseLeave: (e) => {
836
+ e.currentTarget.style.backgroundColor = "var(--dauth-accent, #6366f1)";
837
+ },
838
+ children: [
839
+ saving && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
840
+ saving ? "Saving..." : "Save changes"
841
+ ]
842
+ }
843
+ ) })
844
+ ]
845
+ }
846
+ )
847
+ }
848
+ )
849
+ ] }),
850
+ document.body
851
+ );
852
+ }
853
+ var headerStyle = (isDesktop) => ({
854
+ display: "flex",
855
+ alignItems: "center",
856
+ justifyContent: "space-between",
857
+ padding: "16px 24px",
858
+ borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
859
+ flexShrink: 0,
860
+ ...!isDesktop ? {
861
+ position: "sticky",
862
+ top: 0,
863
+ zIndex: 1,
864
+ backgroundColor: "var(--dauth-surface, #1a1a2e)"
865
+ } : {}
866
+ });
867
+ var titleStyle = {
868
+ fontSize: "var(--dauth-font-size-lg, 1.25rem)",
869
+ fontWeight: 600,
870
+ margin: 0,
871
+ lineHeight: 1.4,
872
+ textAlign: "center",
873
+ flex: 1
874
+ };
875
+ var closeBtn = {
876
+ display: "flex",
877
+ alignItems: "center",
878
+ justifyContent: "center",
879
+ width: 36,
880
+ height: 36,
881
+ borderRadius: "var(--dauth-radius-sm, 8px)",
882
+ border: "none",
883
+ backgroundColor: "transparent",
884
+ color: "var(--dauth-text-secondary, #a1a1aa)",
885
+ cursor: "pointer",
886
+ transition: "background-color 150ms, color 150ms",
887
+ padding: 0
888
+ };
889
+ var bodyStyle = {
890
+ flex: 1,
891
+ overflowY: "auto",
892
+ padding: 24,
893
+ WebkitOverflowScrolling: "touch"
894
+ };
895
+ var avatarSection = {
896
+ display: "flex",
897
+ flexDirection: "column",
898
+ alignItems: "center",
899
+ marginBottom: 24,
900
+ gap: 8
901
+ };
902
+ var avatarCircle = {
903
+ width: 64,
904
+ height: 64,
905
+ borderRadius: "50%",
906
+ backgroundColor: "var(--dauth-accent, #6366f1)",
907
+ display: "flex",
908
+ alignItems: "center",
909
+ justifyContent: "center",
910
+ overflow: "hidden",
911
+ color: "#ffffff",
912
+ fontSize: "1.5rem",
913
+ fontWeight: 600
914
+ };
915
+ var emailText = {
916
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
917
+ color: "var(--dauth-text-secondary, #a1a1aa)"
918
+ };
919
+ var statusMsg = (type) => ({
920
+ padding: "10px 14px",
921
+ borderRadius: "var(--dauth-radius-sm, 8px)",
922
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
923
+ marginBottom: 16,
924
+ backgroundColor: type === "success" ? "var(--dauth-success-bg, rgba(34, 197, 94, 0.1))" : "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
925
+ color: type === "success" ? "var(--dauth-success, #22c55e)" : "var(--dauth-error, #ef4444)",
926
+ textAlign: "center",
927
+ lineHeight: 1.5
928
+ });
929
+ var fieldGroup = { marginBottom: 16 };
930
+ var label = {
931
+ display: "block",
932
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
933
+ fontWeight: 500,
934
+ color: "var(--dauth-text-primary, #e4e4e7)",
935
+ marginBottom: 6
936
+ };
937
+ var input = {
938
+ width: "100%",
939
+ padding: "10px 14px",
940
+ fontSize: "var(--dauth-font-size-base, 1rem)",
941
+ lineHeight: 1.5,
942
+ color: "var(--dauth-text-primary, #e4e4e7)",
943
+ backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
944
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
945
+ borderRadius: "var(--dauth-radius-input, 8px)",
946
+ outline: "none",
947
+ transition: "border-color 150ms, box-shadow 150ms",
948
+ boxSizing: "border-box",
949
+ fontFamily: "inherit"
950
+ };
951
+ var inputFocusHandler = (e) => {
952
+ e.currentTarget.style.borderColor = "var(--dauth-border-focus, rgba(99, 102, 241, 0.5))";
953
+ e.currentTarget.style.boxShadow = "0 0 0 3px rgba(99, 102, 241, 0.15)";
954
+ };
955
+ var inputBlurHandler = (e) => {
956
+ e.currentTarget.style.borderColor = "var(--dauth-border, rgba(255, 255, 255, 0.08))";
957
+ e.currentTarget.style.boxShadow = "none";
958
+ };
959
+ var separator = {
960
+ height: 1,
961
+ backgroundColor: "var(--dauth-border, rgba(255, 255, 255, 0.08))",
962
+ margin: "24px 0",
963
+ border: "none"
964
+ };
965
+ var dangerTitle = {
966
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
967
+ fontWeight: 600,
968
+ color: "var(--dauth-error, #ef4444)",
969
+ marginBottom: 4
970
+ };
971
+ var dangerDesc = {
972
+ fontSize: "var(--dauth-font-size-xs, 0.75rem)",
973
+ color: "var(--dauth-text-muted, #71717a)",
974
+ marginBottom: 12,
975
+ lineHeight: 1.5
976
+ };
977
+ var deleteBtn = {
978
+ padding: "8px 16px",
979
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
980
+ fontWeight: 500,
981
+ color: "var(--dauth-error, #ef4444)",
982
+ backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
983
+ border: "1px solid rgba(239, 68, 68, 0.2)",
984
+ borderRadius: "var(--dauth-radius-sm, 8px)",
985
+ cursor: "pointer",
986
+ transition: "background-color 150ms, border-color 150ms",
987
+ fontFamily: "inherit"
988
+ };
989
+ var deletePanel = {
990
+ marginTop: 12,
991
+ padding: 16,
992
+ borderRadius: "var(--dauth-radius-sm, 8px)",
993
+ border: "1px solid rgba(239, 68, 68, 0.3)",
994
+ backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))"
995
+ };
996
+ var deletePanelText = {
997
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
998
+ color: "var(--dauth-text-primary, #e4e4e7)",
999
+ marginBottom: 12,
1000
+ lineHeight: 1.5
1001
+ };
1002
+ var cancelBtn = {
1003
+ flex: 1,
1004
+ padding: "8px 16px",
1005
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
1006
+ fontWeight: 500,
1007
+ color: "var(--dauth-text-secondary, #a1a1aa)",
1008
+ backgroundColor: "transparent",
1009
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
1010
+ borderRadius: "var(--dauth-radius-sm, 8px)",
1011
+ cursor: "pointer",
1012
+ transition: "background-color 150ms",
1013
+ fontFamily: "inherit"
1014
+ };
1015
+ var deleteConfirmBtn = {
1016
+ flex: 1,
1017
+ padding: "8px 16px",
1018
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
1019
+ fontWeight: 500,
1020
+ color: "#ffffff",
1021
+ backgroundColor: "var(--dauth-error, #ef4444)",
1022
+ border: "none",
1023
+ borderRadius: "var(--dauth-radius-sm, 8px)",
1024
+ cursor: "pointer",
1025
+ transition: "opacity 150ms",
1026
+ fontFamily: "inherit",
1027
+ display: "flex",
1028
+ alignItems: "center",
1029
+ justifyContent: "center",
1030
+ gap: 8
1031
+ };
1032
+ var footerStyle = (isDesktop) => ({
1033
+ padding: "16px 24px",
1034
+ borderTop: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
1035
+ flexShrink: 0,
1036
+ ...!isDesktop ? {
1037
+ position: "sticky",
1038
+ bottom: 0,
1039
+ zIndex: 1,
1040
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
1041
+ paddingBottom: "max(16px, env(safe-area-inset-bottom))"
1042
+ } : {}
1043
+ });
1044
+ var saveBtn = {
1045
+ width: "100%",
1046
+ padding: "12px 24px",
1047
+ fontSize: "var(--dauth-font-size-base, 1rem)",
1048
+ fontWeight: 600,
1049
+ color: "#ffffff",
1050
+ backgroundColor: "var(--dauth-accent, #6366f1)",
1051
+ border: "none",
1052
+ borderRadius: "var(--dauth-radius-sm, 8px)",
1053
+ transition: "opacity 150ms, background-color 150ms",
1054
+ display: "flex",
1055
+ alignItems: "center",
1056
+ justifyContent: "center",
1057
+ gap: 8,
1058
+ fontFamily: "inherit"
1059
+ };
1060
+ var spinnerStyle = {
1061
+ display: "inline-block",
1062
+ width: 16,
1063
+ height: 16,
1064
+ border: "2px solid rgba(255, 255, 255, 0.3)",
1065
+ borderTopColor: "#ffffff",
1066
+ borderRadius: "50%",
1067
+ animation: "dauth-spin 0.6s linear infinite"
1068
+ };
1069
+
1070
+ // src/index.tsx
1071
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1072
+ var defaultOnError = (error) => console.error(error);
1073
+ var DauthProvider = (props) => {
1074
+ const {
1075
+ domainName,
1076
+ children,
1077
+ authProxyPath = "/api/auth",
1078
+ onError,
1079
+ env,
1080
+ dauthUrl
1081
+ } = props;
1082
+ const [dauthState, dispatch] = (0, import_react2.useReducer)(userReducer, initialDauthState_default);
1083
+ (0, import_react2.useEffect)(() => {
1084
+ setDauthUrl(dauthUrl);
1085
+ }, [dauthUrl]);
1086
+ const handleError = (0, import_react2.useCallback)(
1087
+ (error) => (onError ?? defaultOnError)(error),
1088
+ [onError]
1089
+ );
1090
+ const ctx = (0, import_react2.useMemo)(
1091
+ () => ({ dispatch, authProxyPath, onError: handleError }),
1092
+ [authProxyPath, handleError]
1093
+ );
1094
+ (0, import_react2.useEffect)(() => {
1095
+ const params = new URLSearchParams(window.location.search);
1096
+ const code = params.get(AUTH_CODE_PARAM);
1097
+ if (code) {
1098
+ exchangeCodeAction(ctx, code);
1099
+ } else {
1100
+ autoLoginAction(ctx);
1101
+ }
1102
+ }, []);
1103
+ const loginWithRedirect = (0, import_react2.useCallback)(() => {
546
1104
  const base = `${getClientBasePath()}/${domainName}/${routes.signin}`;
547
1105
  const url = env ? `${base}?env=${encodeURIComponent(env)}` : base;
548
1106
  return window.location.replace(url);
549
1107
  }, [domainName, env]);
550
- const logout = (0, import_react.useCallback)(() => {
551
- if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
552
- return setLogoutAction({
553
- dispatch,
554
- domainName,
555
- storageKeys
556
- });
557
- }, [domainName, storageKeys]);
558
- const getAccessToken = (0, import_react.useCallback)(async () => {
559
- const token = await getAccessTokenAction(ctx);
560
- return token;
561
- }, [ctx]);
562
- const updateUser = (0, import_react.useCallback)(
1108
+ const logout = (0, import_react2.useCallback)(() => logoutAction(ctx), [ctx]);
1109
+ const updateUser = (0, import_react2.useCallback)(
563
1110
  async (fields) => {
564
- const token_ls = localStorage.getItem(storageKeys.accessToken);
565
1111
  const {
566
1112
  name,
567
1113
  lastname,
@@ -586,55 +1132,29 @@ var DauthProvider = (props) => {
586
1132
  country,
587
1133
  metadata
588
1134
  };
589
- return await setUpdateUserAction({
590
- ...ctx,
591
- user,
592
- token: token_ls
593
- });
1135
+ return updateUserAction(ctx, user);
594
1136
  },
595
- [ctx, storageKeys.accessToken]
1137
+ [ctx]
596
1138
  );
597
- const updateUserWithRedirect = (0, import_react.useCallback)(() => {
598
- const token_ls = localStorage.getItem(storageKeys.accessToken);
599
- if (!token_ls) return;
600
- return window.location.replace(
601
- `${getClientBasePath()}/${domainName}/${routes.updateUser}/${token_ls}`
602
- );
603
- }, [domainName, storageKeys.accessToken]);
604
- const deleteAccount = (0, import_react.useCallback)(async () => {
605
- const token_ls = localStorage.getItem(storageKeys.accessToken);
606
- if (!token_ls) return false;
607
- if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
608
- return await deleteAccountAction({
609
- ...ctx,
610
- token: token_ls
611
- });
612
- }, [ctx, storageKeys.accessToken]);
613
- const memoProvider = (0, import_react.useMemo)(
1139
+ const deleteAccount = (0, import_react2.useCallback)(
1140
+ () => deleteAccountAction(ctx),
1141
+ [ctx]
1142
+ );
1143
+ const memoProvider = (0, import_react2.useMemo)(
614
1144
  () => ({
615
1145
  ...dauthState,
616
1146
  loginWithRedirect,
617
1147
  logout,
618
- getAccessToken,
619
1148
  updateUser,
620
- updateUserWithRedirect,
621
1149
  deleteAccount
622
1150
  }),
623
- [
624
- dauthState,
625
- loginWithRedirect,
626
- logout,
627
- getAccessToken,
628
- updateUser,
629
- updateUserWithRedirect,
630
- deleteAccount
631
- ]
1151
+ [dauthState, loginWithRedirect, logout, updateUser, deleteAccount]
632
1152
  );
633
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DauthContext.Provider, { value: memoProvider, children });
1153
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DauthContext.Provider, { value: memoProvider, children });
634
1154
  };
635
- var DauthContext = (0, import_react.createContext)(initialDauthState_default);
1155
+ var DauthContext = (0, import_react2.createContext)(initialDauthState_default);
636
1156
  var useDauth = () => {
637
- const context = (0, import_react.useContext)(DauthContext);
1157
+ const context = (0, import_react2.useContext)(DauthContext);
638
1158
  if (!context) {
639
1159
  throw new Error("useDauth must be used inside DauthProvider");
640
1160
  }
@@ -642,6 +1162,7 @@ var useDauth = () => {
642
1162
  };
643
1163
  // Annotate the CommonJS export names for ESM import in node:
644
1164
  0 && (module.exports = {
1165
+ DauthProfileModal,
645
1166
  DauthProvider,
646
1167
  useDauth
647
1168
  });