@mesob/auth-react 0.0.8 → 0.1.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/components/auth/auth-page-layout.d.ts +1 -3
- package/dist/components/auth/auth-page-layout.js +1 -17
- package/dist/components/auth/auth-page-layout.js.map +1 -1
- package/dist/components/auth/countdown.js +70 -9
- package/dist/components/auth/countdown.js.map +1 -1
- package/dist/components/auth/forgot-password.js +101 -35
- package/dist/components/auth/forgot-password.js.map +1 -1
- package/dist/components/auth/pages/forgot-password-page.d.ts +2 -13
- package/dist/components/auth/pages/forgot-password-page.js +198 -126
- package/dist/components/auth/pages/forgot-password-page.js.map +1 -1
- package/dist/components/auth/pages/reset-password-page.d.ts +1 -12
- package/dist/components/auth/pages/reset-password-page.js +288 -200
- package/dist/components/auth/pages/reset-password-page.js.map +1 -1
- package/dist/components/auth/pages/sign-in-page.d.ts +1 -12
- package/dist/components/auth/pages/sign-in-page.js +352 -230
- package/dist/components/auth/pages/sign-in-page.js.map +1 -1
- package/dist/components/auth/pages/sign-up-page.d.ts +1 -11
- package/dist/components/auth/pages/sign-up-page.js +310 -216
- package/dist/components/auth/pages/sign-up-page.js.map +1 -1
- package/dist/components/auth/pages/verify-email-page.d.ts +2 -12
- package/dist/components/auth/pages/verify-email-page.js +203 -135
- package/dist/components/auth/pages/verify-email-page.js.map +1 -1
- package/dist/components/auth/pages/verify-phone-page.d.ts +1 -11
- package/dist/components/auth/pages/verify-phone-page.js +206 -137
- package/dist/components/auth/pages/verify-phone-page.js.map +1 -1
- package/dist/components/auth/reset-password-form.d.ts +1 -1
- package/dist/components/auth/reset-password-form.js +188 -106
- package/dist/components/auth/reset-password-form.js.map +1 -1
- package/dist/components/auth/sign-in.d.ts +3 -3
- package/dist/components/auth/sign-in.js +228 -109
- package/dist/components/auth/sign-in.js.map +1 -1
- package/dist/components/auth/sign-up.js +210 -122
- package/dist/components/auth/sign-up.js.map +1 -1
- package/dist/components/auth/verification-form.d.ts +1 -1
- package/dist/components/auth/verification-form.js +101 -53
- package/dist/components/auth/verification-form.js.map +1 -1
- package/dist/components/error-boundary.d.ts +27 -0
- package/dist/components/error-boundary.js +49 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/iam/permissions/permissions-page.d.ts +5 -0
- package/dist/components/iam/permissions/permissions-page.js +201 -0
- package/dist/components/iam/permissions/permissions-page.js.map +1 -0
- package/dist/components/iam/roles/roles-page.d.ts +5 -0
- package/dist/components/iam/roles/roles-page.js +199 -0
- package/dist/components/iam/roles/roles-page.js.map +1 -0
- package/dist/components/iam/sessions/sessions-page.d.ts +5 -0
- package/dist/components/iam/sessions/sessions-page.js +202 -0
- package/dist/components/iam/sessions/sessions-page.js.map +1 -0
- package/dist/components/iam/tenants/tenants-page.d.ts +5 -0
- package/dist/components/iam/tenants/tenants-page.js +202 -0
- package/dist/components/iam/tenants/tenants-page.js.map +1 -0
- package/dist/components/iam/users/users-page.d.ts +5 -0
- package/dist/components/iam/users/users-page.js +211 -0
- package/dist/components/iam/users/users-page.js.map +1 -0
- package/dist/components/profile/profile-page.d.ts +8 -0
- package/dist/components/profile/profile-page.js +163 -0
- package/dist/components/profile/profile-page.js.map +1 -0
- package/dist/components/shared/data-table/data-table.d.ts +22 -0
- package/dist/components/shared/data-table/data-table.js +85 -0
- package/dist/components/shared/data-table/data-table.js.map +1 -0
- package/dist/components/skeletons/auth-form-skeleton.d.ts +5 -0
- package/dist/components/skeletons/auth-form-skeleton.js +32 -0
- package/dist/components/skeletons/auth-form-skeleton.js.map +1 -0
- package/dist/components/skeletons/profile-skeleton.d.ts +5 -0
- package/dist/components/skeletons/profile-skeleton.js +33 -0
- package/dist/components/skeletons/profile-skeleton.js.map +1 -0
- package/dist/components/skeletons/table-skeleton.d.ts +9 -0
- package/dist/components/skeletons/table-skeleton.js +39 -0
- package/dist/components/skeletons/table-skeleton.js.map +1 -0
- package/dist/handle-error-BqDMxnQZ.d.ts +8 -0
- package/dist/index.d.ts +75 -208
- package/dist/index.js +2091 -1057
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
- package/dist/handle-error-H0iqQxJ5.d.ts +0 -6
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { A as AuthErrorContent } from '../../handle-error-H0iqQxJ5.js';
|
|
4
3
|
|
|
5
4
|
type AuthPageLayoutProps = {
|
|
6
5
|
title: string;
|
|
7
6
|
description?: string;
|
|
8
7
|
children: ReactNode;
|
|
9
|
-
error?: AuthErrorContent | string | null;
|
|
10
8
|
footer?: ReactNode;
|
|
11
9
|
logoImage?: string;
|
|
12
10
|
};
|
|
13
|
-
declare const AuthPageLayout: ({ title, description, children,
|
|
11
|
+
declare const AuthPageLayout: ({ title, description, children, footer, logoImage, }: AuthPageLayoutProps) => react_jsx_runtime.JSX.Element;
|
|
14
12
|
|
|
15
13
|
export { AuthPageLayout };
|
|
@@ -1,37 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/components/auth/auth-page-layout.tsx
|
|
4
|
-
import {
|
|
5
|
-
Alert,
|
|
6
|
-
AlertDescription,
|
|
7
|
-
AlertTitle
|
|
8
|
-
} from "@mesob/ui/components/alert";
|
|
9
|
-
import { IconAlertCircle } from "@tabler/icons-react";
|
|
10
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
5
|
var AuthPageLayout = ({
|
|
12
6
|
title,
|
|
13
7
|
description,
|
|
14
8
|
children,
|
|
15
|
-
error,
|
|
16
9
|
footer,
|
|
17
10
|
logoImage
|
|
18
11
|
}) => {
|
|
19
|
-
const errorContent = error ? (
|
|
20
|
-
// biome-ignore lint/style/noNestedTernary: <explanation>
|
|
21
|
-
typeof error === "string" ? { title: "Error", description: error } : error
|
|
22
|
-
) : null;
|
|
23
12
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
24
|
-
/* @__PURE__ */ jsx("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx("img", { src: logoImage || "", alt: "
|
|
13
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx("img", { src: logoImage || "", alt: "Mesob", width: 42, height: 42 }) }),
|
|
25
14
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
26
15
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
27
16
|
description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
28
17
|
] }),
|
|
29
18
|
children,
|
|
30
|
-
errorContent && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
|
|
31
|
-
/* @__PURE__ */ jsx(IconAlertCircle, { className: "h-4 w-4" }),
|
|
32
|
-
/* @__PURE__ */ jsx(AlertTitle, { children: errorContent.title }),
|
|
33
|
-
/* @__PURE__ */ jsx(AlertDescription, { children: errorContent.description })
|
|
34
|
-
] }),
|
|
35
19
|
/* @__PURE__ */ jsx("div", { className: "mt-2 w-full", children: footer && /* @__PURE__ */ jsx("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
|
|
36
20
|
] });
|
|
37
21
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/auth/auth-page-layout.tsx"],"sourcesContent":["'use client';\n\nimport
|
|
1
|
+
{"version":3,"sources":["../../../src/components/auth/auth-page-layout.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\n\ntype AuthPageLayoutProps = {\n title: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n logoImage?: string;\n};\n\nexport const AuthPageLayout = ({\n title,\n description,\n children,\n footer,\n logoImage,\n}: AuthPageLayoutProps) => {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex size-8 mb-6 w-full items-center justify-center rounded-md\">\n {/** biome-ignore lint/performance/noImgElement: logo image */}\n <img src={logoImage || ''} alt=\"Mesob\" width={42} height={42} />\n </div>\n <div className=\"text-center\">\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n\n {children}\n\n <div className=\"mt-2 w-full\">\n {footer && (\n <div className=\"w-full text-center text-sm text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"mappings":";;;AAuBQ,cAEF,YAFE;AAXD,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA2B;AACzB,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,SAAI,WAAU,kEAEb,8BAAC,SAAI,KAAK,aAAa,IAAI,KAAI,SAAQ,OAAO,IAAI,QAAQ,IAAI,GAChE;AAAA,IACA,qBAAC,SAAI,WAAU,eACb;AAAA,0BAAC,QAAG,WAAU,qCAAqC,iBAAM;AAAA,MACxD,eACC,oBAAC,OAAE,WAAU,sCAAsC,uBAAY;AAAA,OAEnE;AAAA,IAEC;AAAA,IAED,oBAAC,SAAI,WAAU,eACZ,oBACC,oBAAC,SAAI,WAAU,oDACZ,kBACH,GAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -3,18 +3,79 @@
|
|
|
3
3
|
// src/components/auth/countdown.tsx
|
|
4
4
|
import { Button } from "@mesob/ui/components/button";
|
|
5
5
|
import { Spinner } from "@mesob/ui/components/spinner";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
7
|
+
|
|
8
|
+
// src/lib/translations.ts
|
|
9
|
+
function createTranslator(messages, namespace) {
|
|
10
|
+
return (key, params) => {
|
|
11
|
+
const fullKey = namespace ? `${namespace}.${key}` : key;
|
|
12
|
+
const keys = fullKey.split(".");
|
|
13
|
+
let value = messages;
|
|
14
|
+
for (const k of keys) {
|
|
15
|
+
if (value && typeof value === "object" && value !== null) {
|
|
16
|
+
value = value[k];
|
|
17
|
+
} else {
|
|
18
|
+
return fullKey;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (typeof value !== "string") {
|
|
22
|
+
return fullKey;
|
|
23
|
+
}
|
|
24
|
+
if (params) {
|
|
25
|
+
return value.replace(
|
|
26
|
+
/\{(\w+)\}/g,
|
|
27
|
+
(_, param) => String(params[param] ?? `{${param}}`)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/provider.tsx
|
|
35
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
36
|
+
import { deepmerge } from "deepmerge-ts";
|
|
37
|
+
import createFetchClient from "openapi-fetch";
|
|
38
|
+
import createClient from "openapi-react-query";
|
|
39
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
40
|
+
import { jsx } from "react/jsx-runtime";
|
|
41
|
+
var SessionContext = createContext(null);
|
|
42
|
+
var ApiContext = createContext(null);
|
|
43
|
+
var ConfigContext = createContext(null);
|
|
44
|
+
var queryClient = new QueryClient({
|
|
45
|
+
defaultOptions: {
|
|
46
|
+
queries: {
|
|
47
|
+
staleTime: 1e3 * 60 * 5,
|
|
48
|
+
gcTime: 1e3 * 60 * 10,
|
|
49
|
+
retry: 1,
|
|
50
|
+
refetchOnWindowFocus: false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
function useConfig() {
|
|
55
|
+
const context = useContext(ConfigContext);
|
|
56
|
+
if (!context) {
|
|
57
|
+
throw new Error("useConfig must be used within MesobAuthProvider");
|
|
58
|
+
}
|
|
59
|
+
return context;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/hooks/use-translator.ts
|
|
63
|
+
function useTranslator(namespace) {
|
|
64
|
+
const { config } = useConfig();
|
|
65
|
+
return createTranslator(config.messages || {}, namespace);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/components/auth/countdown.tsx
|
|
69
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
9
70
|
var Countdown = ({
|
|
10
71
|
initialSeconds = 60,
|
|
11
72
|
onResend,
|
|
12
73
|
resending = false
|
|
13
74
|
}) => {
|
|
14
|
-
const t =
|
|
15
|
-
const [seconds, setSeconds] =
|
|
16
|
-
const [isResending, setIsResending] =
|
|
17
|
-
|
|
75
|
+
const t = useTranslator("Common");
|
|
76
|
+
const [seconds, setSeconds] = useState2(initialSeconds);
|
|
77
|
+
const [isResending, setIsResending] = useState2(false);
|
|
78
|
+
useEffect2(() => {
|
|
18
79
|
if (seconds <= 0) {
|
|
19
80
|
return;
|
|
20
81
|
}
|
|
@@ -40,7 +101,7 @@ var Countdown = ({
|
|
|
40
101
|
}
|
|
41
102
|
};
|
|
42
103
|
if (seconds > 0) {
|
|
43
|
-
return /* @__PURE__ */
|
|
104
|
+
return /* @__PURE__ */ jsx2(Button, { variant: "ghost", disabled: true, children: t("resendIn", { seconds }) });
|
|
44
105
|
}
|
|
45
106
|
return /* @__PURE__ */ jsxs(
|
|
46
107
|
Button,
|
|
@@ -49,7 +110,7 @@ var Countdown = ({
|
|
|
49
110
|
onClick: handleResend,
|
|
50
111
|
disabled: isResending || resending,
|
|
51
112
|
children: [
|
|
52
|
-
isResending || resending && /* @__PURE__ */
|
|
113
|
+
isResending || resending && /* @__PURE__ */ jsx2(Spinner, {}),
|
|
53
114
|
t("resend")
|
|
54
115
|
]
|
|
55
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/auth/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@mesob/ui/components/button';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { useTranslations } from 'next-intl';\nimport { useEffect, useState } from 'react';\n\ntype CountdownProps = {\n initialSeconds?: number;\n onResend: () => Promise<void> | void;\n resending?: boolean;\n};\n\nexport const Countdown = ({\n initialSeconds = 60,\n onResend,\n resending = false,\n}: CountdownProps) => {\n const t = useTranslations('Common');\n const [seconds, setSeconds] = useState(initialSeconds);\n const [isResending, setIsResending] = useState(false);\n\n useEffect(() => {\n if (seconds <= 0) {\n return;\n }\n\n const timer = setInterval(() => {\n setSeconds((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [seconds]);\n\n const handleResend = async () => {\n setIsResending(true);\n try {\n await onResend();\n setSeconds(initialSeconds);\n } catch (_error) {\n // Error handling is done by parent\n } finally {\n setIsResending(false);\n }\n };\n\n if (seconds > 0) {\n return (\n <Button variant=\"ghost\" disabled>\n {t('resendIn', { seconds })}\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"ghost\"\n onClick={handleResend}\n disabled={isResending || resending}\n >\n {isResending || (resending && <Spinner />)}\n {t('resend')}\n </Button>\n );\n};\n"],"mappings":";;;AAEA,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,WAAW,gBAAgB;AAiD9B,cAOF,YAPE;AAzCC,IAAM,YAAY,CAAC;AAAA,EACxB,iBAAiB;AAAA,EACjB;AAAA,EACA,YAAY;AACd,MAAsB;AACpB,QAAM,IAAI,gBAAgB,QAAQ;AAClC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,cAAc;AACrD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAEpD,YAAU,MAAM;AACd,QAAI,WAAW,GAAG;AAChB;AAAA,IACF;AAEA,UAAM,QAAQ,YAAY,MAAM;AAC9B,iBAAW,CAAC,SAAS;AACnB,YAAI,QAAQ,GAAG;AACb,wBAAc,KAAK;AACnB,iBAAO;AAAA,QACT;AACA,eAAO,OAAO;AAAA,MAChB,CAAC;AAAA,IACH,GAAG,GAAI;AAEP,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,eAAe,YAAY;AAC/B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,SAAS;AACf,iBAAW,cAAc;AAAA,IAC3B,SAAS,QAAQ;AAAA,IAEjB,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,UAAU,GAAG;AACf,WACE,oBAAC,UAAO,SAAQ,SAAQ,UAAQ,MAC7B,YAAE,YAAY,EAAE,QAAQ,CAAC,GAC5B;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU,eAAe;AAAA,MAExB;AAAA,uBAAgB,aAAa,oBAAC,WAAQ;AAAA,QACtC,EAAE,QAAQ;AAAA;AAAA;AAAA,EACb;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/auth/countdown.tsx","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/hooks/use-translator.ts"],"sourcesContent":["'use client';\n\nimport { Button } from '@mesob/ui/components/button';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { useEffect, useState } from 'react';\nimport { useTranslator } from '../../hooks/use-translator';\n\ntype CountdownProps = {\n initialSeconds?: number;\n onResend: () => Promise<void> | void;\n resending?: boolean;\n};\n\nexport const Countdown = ({\n initialSeconds = 60,\n onResend,\n resending = false,\n}: CountdownProps) => {\n const t = useTranslator('Common');\n const [seconds, setSeconds] = useState(initialSeconds);\n const [isResending, setIsResending] = useState(false);\n\n useEffect(() => {\n if (seconds <= 0) {\n return;\n }\n\n const timer = setInterval(() => {\n setSeconds((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [seconds]);\n\n const handleResend = async () => {\n setIsResending(true);\n try {\n await onResend();\n setSeconds(initialSeconds);\n } catch (_error) {\n // Error handling is done by parent\n } finally {\n setIsResending(false);\n }\n };\n\n if (seconds > 0) {\n return (\n <Button variant=\"ghost\" disabled>\n {t('resendIn', { seconds })}\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"ghost\"\n onClick={handleResend}\n disabled={isResending || resending}\n >\n {isResending || (resending && <Spinner />)}\n {t('resend')}\n </Button>\n );\n};\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { createCustomFetch } from './utils/custom-fetch';\n\ntype OpenApiHooks = any;\n\ntype SessionState = {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n error: Error | null;\n};\n\ntype SessionContextValue = SessionState & {\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5,\n gcTime: 1000 * 60 * 10,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport function useSession() {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi() {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig() {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig;\n\n const api = createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n });\n\n const hooks = createClient(api);\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider config={mergedConfig} hooks={hooks}>\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n children,\n}: AuthStateProviderProps) {\n const [authState, setAuthState] = useState<{\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n error: Error | null;\n }>({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n\n const {\n data: sessionData,\n isLoading: sessionLoading,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: true,\n refetchOnMount: true,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n },\n );\n\n useEffect(() => {\n if (sessionLoading) {\n setAuthState((prev) => ({ ...prev, isLoading: true }));\n return;\n }\n\n if (sessionError) {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: sessionError as Error,\n });\n return;\n }\n\n if (sessionData) {\n setAuthState({\n user: sessionData.user,\n session: sessionData.session,\n isLoading: false,\n error: null,\n });\n return;\n }\n\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n }, [sessionData, sessionLoading, sessionError]);\n\n const refresh = async () => {\n await refetch();\n };\n\n const setAuth = (auth: AuthResponse) => {\n setAuthState({\n user: auth.user,\n session: auth.session,\n isLoading: false,\n error: null,\n });\n };\n\n const clearAuth = () => {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n };\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n const t = createTranslator(config.messages || {});\n\n return (\n <ConfigContext.Provider value={{ config, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user: authState.user,\n session: authState.session,\n isLoading: authState.isLoading,\n isAuthenticated: !!authState.user && !!authState.session,\n error: authState.error,\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const { config } = useConfig();\n return createTranslator(config.messages || {}, namespace);\n}\n"],"mappings":"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","names":["useEffect","useState","jsx","useState","useEffect"]}
|
|
@@ -4,33 +4,88 @@
|
|
|
4
4
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
5
|
import { Button } from "@mesob/ui/components/button";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
FormMessage
|
|
13
|
-
} from "@mesob/ui/components/form";
|
|
7
|
+
Field,
|
|
8
|
+
FieldError,
|
|
9
|
+
FieldGroup,
|
|
10
|
+
FieldLabel
|
|
11
|
+
} from "@mesob/ui/components/field";
|
|
14
12
|
import { Input } from "@mesob/ui/components/input";
|
|
15
13
|
import { Spinner } from "@mesob/ui/components/spinner";
|
|
16
|
-
import {
|
|
17
|
-
import { useMemo } from "react";
|
|
18
|
-
import { useForm } from "react-hook-form";
|
|
14
|
+
import { Controller, useForm } from "react-hook-form";
|
|
19
15
|
import { z } from "zod";
|
|
20
|
-
|
|
16
|
+
|
|
17
|
+
// src/lib/translations.ts
|
|
18
|
+
function createTranslator(messages, namespace) {
|
|
19
|
+
return (key, params) => {
|
|
20
|
+
const fullKey = namespace ? `${namespace}.${key}` : key;
|
|
21
|
+
const keys = fullKey.split(".");
|
|
22
|
+
let value = messages;
|
|
23
|
+
for (const k of keys) {
|
|
24
|
+
if (value && typeof value === "object" && value !== null) {
|
|
25
|
+
value = value[k];
|
|
26
|
+
} else {
|
|
27
|
+
return fullKey;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (typeof value !== "string") {
|
|
31
|
+
return fullKey;
|
|
32
|
+
}
|
|
33
|
+
if (params) {
|
|
34
|
+
return value.replace(
|
|
35
|
+
/\{(\w+)\}/g,
|
|
36
|
+
(_, param) => String(params[param] ?? `{${param}}`)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/provider.tsx
|
|
44
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
45
|
+
import { deepmerge } from "deepmerge-ts";
|
|
46
|
+
import createFetchClient from "openapi-fetch";
|
|
47
|
+
import createClient from "openapi-react-query";
|
|
48
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
49
|
+
import { jsx } from "react/jsx-runtime";
|
|
50
|
+
var SessionContext = createContext(null);
|
|
51
|
+
var ApiContext = createContext(null);
|
|
52
|
+
var ConfigContext = createContext(null);
|
|
53
|
+
var queryClient = new QueryClient({
|
|
54
|
+
defaultOptions: {
|
|
55
|
+
queries: {
|
|
56
|
+
staleTime: 1e3 * 60 * 5,
|
|
57
|
+
gcTime: 1e3 * 60 * 10,
|
|
58
|
+
retry: 1,
|
|
59
|
+
refetchOnWindowFocus: false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
function useConfig() {
|
|
64
|
+
const context = useContext(ConfigContext);
|
|
65
|
+
if (!context) {
|
|
66
|
+
throw new Error("useConfig must be used within MesobAuthProvider");
|
|
67
|
+
}
|
|
68
|
+
return context;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/hooks/use-translator.ts
|
|
72
|
+
function useTranslator(namespace) {
|
|
73
|
+
const { config } = useConfig();
|
|
74
|
+
return createTranslator(config.messages || {}, namespace);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/components/auth/forgot-password.tsx
|
|
78
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
79
|
+
var forgotPasswordSchema = (t) => z.object({
|
|
80
|
+
account: z.string().min(1, t("errors.accountRequired"))
|
|
81
|
+
});
|
|
21
82
|
var ForgotPassword = ({
|
|
22
83
|
onSubmit,
|
|
23
84
|
isLoading = false
|
|
24
85
|
}) => {
|
|
25
|
-
const t =
|
|
26
|
-
const forgotPasswordSchema = useMemo(
|
|
27
|
-
() => z.object({
|
|
28
|
-
account: z.string().min(1, t("errors.accountRequired"))
|
|
29
|
-
}),
|
|
30
|
-
[t]
|
|
31
|
-
);
|
|
86
|
+
const t = useTranslator("Auth.forgotPassword");
|
|
32
87
|
const form = useForm({
|
|
33
|
-
resolver: zodResolver(forgotPasswordSchema),
|
|
88
|
+
resolver: zodResolver(forgotPasswordSchema(t)),
|
|
34
89
|
defaultValues: {
|
|
35
90
|
account: ""
|
|
36
91
|
}
|
|
@@ -38,31 +93,42 @@ var ForgotPassword = ({
|
|
|
38
93
|
const handleSubmit = form.handleSubmit(async (values) => {
|
|
39
94
|
await onSubmit(values);
|
|
40
95
|
});
|
|
41
|
-
return /* @__PURE__ */
|
|
42
|
-
/* @__PURE__ */
|
|
43
|
-
|
|
96
|
+
return /* @__PURE__ */ jsxs("form", { id: "forgot-password-form", onSubmit: handleSubmit, children: [
|
|
97
|
+
/* @__PURE__ */ jsx2(FieldGroup, { children: /* @__PURE__ */ jsx2(
|
|
98
|
+
Controller,
|
|
44
99
|
{
|
|
45
|
-
control: form.control,
|
|
46
100
|
name: "account",
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/* @__PURE__ */
|
|
101
|
+
control: form.control,
|
|
102
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs(Field, { "data-invalid": fieldState.invalid, children: [
|
|
103
|
+
/* @__PURE__ */ jsx2(FieldLabel, { htmlFor: "forgot-password-account", children: t("form.accountLabel") }),
|
|
104
|
+
/* @__PURE__ */ jsx2(
|
|
50
105
|
Input,
|
|
51
106
|
{
|
|
107
|
+
...field,
|
|
108
|
+
id: "forgot-password-account",
|
|
52
109
|
type: "text",
|
|
53
110
|
placeholder: t("form.accountPlaceholder"),
|
|
54
|
-
|
|
111
|
+
"aria-invalid": fieldState.invalid
|
|
55
112
|
}
|
|
56
|
-
)
|
|
57
|
-
/* @__PURE__ */
|
|
113
|
+
),
|
|
114
|
+
fieldState.invalid && /* @__PURE__ */ jsx2(FieldError, { errors: [fieldState.error] })
|
|
58
115
|
] })
|
|
59
116
|
}
|
|
60
|
-
),
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
117
|
+
) }),
|
|
118
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-4", children: /* @__PURE__ */ jsxs(
|
|
119
|
+
Button,
|
|
120
|
+
{
|
|
121
|
+
type: "submit",
|
|
122
|
+
form: "forgot-password-form",
|
|
123
|
+
className: "w-full",
|
|
124
|
+
disabled: isLoading,
|
|
125
|
+
children: [
|
|
126
|
+
isLoading && /* @__PURE__ */ jsx2(Spinner, {}),
|
|
127
|
+
isLoading ? t("form.submitting") : t("form.submit")
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
) })
|
|
131
|
+
] });
|
|
66
132
|
};
|
|
67
133
|
export {
|
|
68
134
|
ForgotPassword
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/auth/forgot-password.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@mesob/ui/components/form';\nimport { Input } from '@mesob/ui/components/input';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { useTranslations } from 'next-intl';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\n\ntype ForgotPasswordFormValues = {\n account: string;\n};\n\ntype ForgotPasswordProps = {\n onSubmit: (values: ForgotPasswordFormValues) => Promise<void> | void;\n isLoading?: boolean;\n onBack?: () => void;\n};\n\nexport const ForgotPassword = ({\n onSubmit,\n isLoading = false,\n}: ForgotPasswordProps) => {\n const t = useTranslations('Auth.forgotPassword');\n const forgotPasswordSchema = useMemo(\n () =>\n z.object({\n account: z.string().min(1, t('errors.accountRequired')),\n }),\n [t],\n );\n\n const form = useForm<ForgotPasswordFormValues>({\n resolver: zodResolver(forgotPasswordSchema),\n defaultValues: {\n account: '',\n },\n });\n\n const handleSubmit = form.handleSubmit(async (values) => {\n await onSubmit(values);\n });\n\n return (\n <Form {...form}>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <FormField\n control={form.control}\n name=\"account\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.accountLabel')}</FormLabel>\n <FormControl>\n <Input\n type=\"text\"\n placeholder={t('form.accountPlaceholder')}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n {isLoading && <Spinner />}\n {isLoading ? t('form.submitting') : t('form.submit')}\n </Button>\n </form>\n </Form>\n );\n};\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,SAAS;AA2CN,SACE,KADF;AA/BL,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA,YAAY;AACd,MAA2B;AACzB,QAAM,IAAI,gBAAgB,qBAAqB;AAC/C,QAAM,uBAAuB;AAAA,IAC3B,MACE,EAAE,OAAO;AAAA,MACP,SAAS,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,wBAAwB,CAAC;AAAA,IACxD,CAAC;AAAA,IACH,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,OAAO,QAAkC;AAAA,IAC7C,UAAU,YAAY,oBAAoB;AAAA,IAC1C,eAAe;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,QAAM,eAAe,KAAK,aAAa,OAAO,WAAW;AACvD,UAAM,SAAS,MAAM;AAAA,EACvB,CAAC;AAED,SACE,oBAAC,QAAM,GAAG,MACR,+BAAC,UAAK,UAAU,cAAc,WAAU,aACtC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,KAAK;AAAA,QACd,MAAK;AAAA,QACL,QAAQ,CAAC,EAAE,MAAM,MACf,qBAAC,YACC;AAAA,8BAAC,aAAW,YAAE,mBAAmB,GAAE;AAAA,UACnC,oBAAC,eACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAa,EAAE,yBAAyB;AAAA,cACvC,GAAG;AAAA;AAAA,UACN,GACF;AAAA,UACA,oBAAC,eAAY;AAAA,WACf;AAAA;AAAA,IAEJ;AAAA,IACA,qBAAC,UAAO,MAAK,UAAS,WAAU,UAAS,UAAU,WAChD;AAAA,mBAAa,oBAAC,WAAQ;AAAA,MACtB,YAAY,EAAE,iBAAiB,IAAI,EAAE,aAAa;AAAA,OACrD;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/auth/forgot-password.tsx","../../../src/lib/translations.ts","../../../src/provider.tsx","../../../src/hooks/use-translator.ts"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport {\n Field,\n FieldError,\n FieldGroup,\n FieldLabel,\n} from '@mesob/ui/components/field';\nimport { Input } from '@mesob/ui/components/input';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { Controller, useForm } from 'react-hook-form';\nimport { z } from 'zod';\nimport { useTranslator } from '../../hooks/use-translator';\n\ntype ForgotPasswordFormValues = {\n account: string;\n};\n\ntype ForgotPasswordProps = {\n onSubmit: (values: ForgotPasswordFormValues) => Promise<void> | void;\n isLoading?: boolean;\n onBack?: () => void;\n};\n\nconst forgotPasswordSchema = (t: (key: string) => string) =>\n z.object({\n account: z.string().min(1, t('errors.accountRequired')),\n });\n\nexport const ForgotPassword = ({\n onSubmit,\n isLoading = false,\n}: ForgotPasswordProps) => {\n const t = useTranslator('Auth.forgotPassword');\n\n const form = useForm<ForgotPasswordFormValues>({\n resolver: zodResolver(forgotPasswordSchema(t)),\n defaultValues: {\n account: '',\n },\n });\n\n const handleSubmit = form.handleSubmit(async (values) => {\n await onSubmit(values);\n });\n\n return (\n <form id=\"forgot-password-form\" onSubmit={handleSubmit}>\n <FieldGroup>\n <Controller\n name=\"account\"\n control={form.control}\n render={({ field, fieldState }) => (\n <Field data-invalid={fieldState.invalid}>\n <FieldLabel htmlFor=\"forgot-password-account\">\n {t('form.accountLabel')}\n </FieldLabel>\n <Input\n {...field}\n id=\"forgot-password-account\"\n type=\"text\"\n placeholder={t('form.accountPlaceholder')}\n aria-invalid={fieldState.invalid}\n />\n {fieldState.invalid && <FieldError errors={[fieldState.error]} />}\n </Field>\n )}\n />\n </FieldGroup>\n <div className=\"mt-4\">\n <Button\n type=\"submit\"\n form=\"forgot-password-form\"\n className=\"w-full\"\n disabled={isLoading}\n >\n {isLoading && <Spinner />}\n {isLoading ? t('form.submitting') : t('form.submit')}\n </Button>\n </div>\n </form>\n );\n};\n","type Messages = Record<string, unknown>;\n\nexport function createTranslator(messages: Messages, namespace?: string) {\n return (key: string, params?: Record<string, string | number>): string => {\n const fullKey = namespace ? `${namespace}.${key}` : key;\n const keys = fullKey.split('.');\n\n let value: unknown = messages;\n for (const k of keys) {\n if (value && typeof value === 'object' && value !== null) {\n value = (value as Record<string, unknown>)[k];\n } else {\n return fullKey;\n }\n }\n\n if (typeof value !== 'string') {\n return fullKey;\n }\n\n // Simple parameter replacement\n if (params) {\n return value.replace(/\\{(\\w+)\\}/g, (_, param) =>\n String(params[param] ?? `{${param}}`),\n );\n }\n\n return value;\n };\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { createCustomFetch } from './utils/custom-fetch';\n\ntype OpenApiHooks = any;\n\ntype SessionState = {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n error: Error | null;\n};\n\ntype SessionContextValue = SessionState & {\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5,\n gcTime: 1000 * 60 * 10,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nexport function useSession() {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi() {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig() {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig;\n\n const api = createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n });\n\n const hooks = createClient(api);\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider config={mergedConfig} hooks={hooks}>\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n children,\n}: AuthStateProviderProps) {\n const [authState, setAuthState] = useState<{\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n error: Error | null;\n }>({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n\n const {\n data: sessionData,\n isLoading: sessionLoading,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: true,\n refetchOnMount: true,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n },\n );\n\n useEffect(() => {\n if (sessionLoading) {\n setAuthState((prev) => ({ ...prev, isLoading: true }));\n return;\n }\n\n if (sessionError) {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: sessionError as Error,\n });\n return;\n }\n\n if (sessionData) {\n setAuthState({\n user: sessionData.user,\n session: sessionData.session,\n isLoading: false,\n error: null,\n });\n return;\n }\n\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n }, [sessionData, sessionLoading, sessionError]);\n\n const refresh = async () => {\n await refetch();\n };\n\n const setAuth = (auth: AuthResponse) => {\n setAuthState({\n user: auth.user,\n session: auth.session,\n isLoading: false,\n error: null,\n });\n };\n\n const clearAuth = () => {\n setAuthState({\n user: null,\n session: null,\n isLoading: false,\n error: null,\n });\n };\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n const t = createTranslator(config.messages || {});\n\n return (\n <ConfigContext.Provider value={{ config, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user: authState.user,\n session: authState.session,\n isLoading: authState.isLoading,\n isAuthenticated: !!authState.user && !!authState.session,\n error: authState.error,\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import { createTranslator } from '../lib/translations';\nimport { useConfig } from '../provider';\n\nexport function useTranslator(namespace?: string) {\n const { config } = useConfig();\n return createTranslator(config.messages || {}, namespace);\n}\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,YAAY,eAAe;AACpC,SAAS,SAAS;;;ACXX,SAAS,iBAAiB,UAAoB,WAAoB;AACvE,SAAO,CAAC,KAAa,WAAqD;AACxE,UAAM,UAAU,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AACpD,UAAM,OAAO,QAAQ,MAAM,GAAG;AAE9B,QAAI,QAAiB;AACrB,eAAW,KAAK,MAAM;AACpB,UAAI,SAAS,OAAO,UAAU,YAAY,UAAU,MAAM;AACxD,gBAAS,MAAkC,CAAC;AAAA,MAC9C,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ;AACV,aAAO,MAAM;AAAA,QAAQ;AAAA,QAAc,CAAC,GAAG,UACrC,OAAO,OAAO,KAAK,KAAK,IAAI,KAAK,GAAG;AAAA,MACtC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC3BA,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB;AAC1B,OAAO,uBAAuB;AAC9B,OAAO,kBAAkB;AAEzB,SAAS,eAAe,YAAY,WAAW,gBAAgB;AAqGzD;AA9DN,IAAM,iBAAiB,cAA0C,IAAI;AACrE,IAAM,aAAa,cAAsC,IAAI;AAC7D,IAAM,gBAAgB,cAAyC,IAAI;AAEnE,IAAM,cAAc,IAAI,YAAY;AAAA,EAClC,gBAAgB;AAAA,IACd,SAAS;AAAA,MACP,WAAW,MAAO,KAAK;AAAA,MACvB,QAAQ,MAAO,KAAK;AAAA,MACpB,OAAO;AAAA,MACP,sBAAsB;AAAA,IACxB;AAAA,EACF;AACF,CAAC;AAkBM,SAAS,YAAY;AAC1B,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,SAAO;AACT;;;AChFO,SAAS,cAAc,WAAoB;AAChD,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,SAAO,iBAAiB,OAAO,YAAY,CAAC,GAAG,SAAS;AAC1D;;;AHiDY,SACE,OAAAA,MADF;AA7BZ,IAAM,uBAAuB,CAAC,MAC5B,EAAE,OAAO;AAAA,EACP,SAAS,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,wBAAwB,CAAC;AACxD,CAAC;AAEI,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA,YAAY;AACd,MAA2B;AACzB,QAAM,IAAI,cAAc,qBAAqB;AAE7C,QAAM,OAAO,QAAkC;AAAA,IAC7C,UAAU,YAAY,qBAAqB,CAAC,CAAC;AAAA,IAC7C,eAAe;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,QAAM,eAAe,KAAK,aAAa,OAAO,WAAW;AACvD,UAAM,SAAS,MAAM;AAAA,EACvB,CAAC;AAED,SACE,qBAAC,UAAK,IAAG,wBAAuB,UAAU,cACxC;AAAA,oBAAAA,KAAC,cACC,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,KAAK;AAAA,QACd,QAAQ,CAAC,EAAE,OAAO,WAAW,MAC3B,qBAAC,SAAM,gBAAc,WAAW,SAC9B;AAAA,0BAAAA,KAAC,cAAW,SAAQ,2BACjB,YAAE,mBAAmB,GACxB;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACE,GAAG;AAAA,cACJ,IAAG;AAAA,cACH,MAAK;AAAA,cACL,aAAa,EAAE,yBAAyB;AAAA,cACxC,gBAAc,WAAW;AAAA;AAAA,UAC3B;AAAA,UACC,WAAW,WAAW,gBAAAA,KAAC,cAAW,QAAQ,CAAC,WAAW,KAAK,GAAG;AAAA,WACjE;AAAA;AAAA,IAEJ,GACF;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,QACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,WAAU;AAAA,QACV,UAAU;AAAA,QAET;AAAA,uBAAa,gBAAAA,KAAC,WAAQ;AAAA,UACtB,YAAY,EAAE,iBAAiB,IAAI,EAAE,aAAa;AAAA;AAAA;AAAA,IACrD,GACF;AAAA,KACF;AAEJ;","names":["jsx"]}
|
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ComponentProps } from 'react';
|
|
3
2
|
|
|
4
|
-
type ForgotPasswordPageProps =
|
|
5
|
-
|
|
6
|
-
onNavigate: (path: string) => void;
|
|
7
|
-
linkComponent?: React.ComponentType<ComponentProps<'a'> & {
|
|
8
|
-
href: string;
|
|
9
|
-
}>;
|
|
10
|
-
links?: {
|
|
11
|
-
signIn?: string;
|
|
12
|
-
};
|
|
13
|
-
logoImage?: string;
|
|
14
|
-
};
|
|
15
|
-
declare const ForgotPasswordPage: ({ onNavigate, linkComponent: Link, links, logoImage, }: ForgotPasswordPageProps) => react_jsx_runtime.JSX.Element;
|
|
3
|
+
type ForgotPasswordPageProps = Record<string, never>;
|
|
4
|
+
declare const ForgotPasswordPage: (_props?: ForgotPasswordPageProps) => react_jsx_runtime.JSX.Element;
|
|
16
5
|
|
|
17
6
|
export { ForgotPasswordPage };
|