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