@mesob/auth-react 0.0.3
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-card.d.ts +9 -0
- package/dist/components/auth-card.js +11 -0
- package/dist/components/auth-card.js.map +1 -0
- package/dist/components/auth-page-layout.d.ts +14 -0
- package/dist/components/auth-page-layout.js +28 -0
- package/dist/components/auth-page-layout.js.map +1 -0
- package/dist/components/countdown.d.ts +10 -0
- package/dist/components/countdown.js +57 -0
- package/dist/components/countdown.js.map +1 -0
- package/dist/components/forgot-password.d.ts +13 -0
- package/dist/components/forgot-password.js +67 -0
- package/dist/components/forgot-password.js.map +1 -0
- package/dist/components/pages/forgot-password-page.d.ts +17 -0
- package/dist/components/pages/forgot-password-page.js +224 -0
- package/dist/components/pages/forgot-password-page.js.map +1 -0
- package/dist/components/pages/reset-password-page.d.ts +19 -0
- package/dist/components/pages/reset-password-page.js +357 -0
- package/dist/components/pages/reset-password-page.js.map +1 -0
- package/dist/components/pages/sign-in-page.d.ts +19 -0
- package/dist/components/pages/sign-in-page.js +343 -0
- package/dist/components/pages/sign-in-page.js.map +1 -0
- package/dist/components/pages/sign-up-page.d.ts +18 -0
- package/dist/components/pages/sign-up-page.js +360 -0
- package/dist/components/pages/sign-up-page.js.map +1 -0
- package/dist/components/pages/verify-email-page.d.ts +19 -0
- package/dist/components/pages/verify-email-page.js +356 -0
- package/dist/components/pages/verify-email-page.js.map +1 -0
- package/dist/components/pages/verify-phone-page.d.ts +20 -0
- package/dist/components/pages/verify-phone-page.js +368 -0
- package/dist/components/pages/verify-phone-page.js.map +1 -0
- package/dist/components/reset-password-form.d.ts +16 -0
- package/dist/components/reset-password-form.js +142 -0
- package/dist/components/reset-password-form.js.map +1 -0
- package/dist/components/sign-in.d.ts +16 -0
- package/dist/components/sign-in.js +128 -0
- package/dist/components/sign-in.js.map +1 -0
- package/dist/components/sign-up.d.ts +17 -0
- package/dist/components/sign-up.js +179 -0
- package/dist/components/sign-up.js.map +1 -0
- package/dist/components/verification-form.d.ts +15 -0
- package/dist/components/verification-form.js +155 -0
- package/dist/components/verification-form.js.map +1 -0
- package/dist/index.d.ts +222 -0
- package/dist/index.js +1640 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/auth-card.tsx
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var AuthCard = ({ children }) => {
|
|
6
|
+
return /* @__PURE__ */ jsx("div", { className: "flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 p-4 dark:from-slate-900 dark:to-slate-800", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-card p-8 shadow-lg", children }) }) });
|
|
7
|
+
};
|
|
8
|
+
export {
|
|
9
|
+
AuthCard
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=auth-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/auth-card.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\n\ntype AuthCardProps = {\n children: ReactNode;\n};\n\nexport const AuthCard = ({ children }: AuthCardProps) => {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 p-4 dark:from-slate-900 dark:to-slate-800\">\n <div className=\"w-full max-w-md\">\n <div className=\"rounded-xl border bg-card p-8 shadow-lg\">\n {children}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;AAYQ;AAJD,IAAM,WAAW,CAAC,EAAE,SAAS,MAAqB;AACvD,SACE,oBAAC,SAAI,WAAU,wIACb,8BAAC,SAAI,WAAU,mBACb,8BAAC,SAAI,WAAU,2CACZ,UACH,GACF,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type AuthPageLayoutProps = {
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
error?: string | null;
|
|
9
|
+
footer?: ReactNode;
|
|
10
|
+
logoImage?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const AuthPageLayout: ({ title, description, children, error, footer, logoImage, }: AuthPageLayoutProps) => react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
export { AuthPageLayout };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/auth-page-layout.tsx
|
|
4
|
+
import { Alert, AlertDescription } from "@mesob/ui/components/alert";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var AuthPageLayout = ({
|
|
7
|
+
title,
|
|
8
|
+
description,
|
|
9
|
+
children,
|
|
10
|
+
error,
|
|
11
|
+
footer,
|
|
12
|
+
logoImage
|
|
13
|
+
}) => {
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
15
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx("img", { src: logoImage || "", alt: "Jiret", width: 42, height: 42 }) }),
|
|
16
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
17
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
18
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
19
|
+
] }),
|
|
20
|
+
children,
|
|
21
|
+
error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
|
|
22
|
+
/* @__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 }) })
|
|
23
|
+
] });
|
|
24
|
+
};
|
|
25
|
+
export {
|
|
26
|
+
AuthPageLayout
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=auth-page-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/auth-page-layout.tsx"],"sourcesContent":["'use client';\n\nimport { Alert, AlertDescription } from '@mesob/ui/components/alert';\nimport type { ReactNode } from 'react';\n\ntype AuthPageLayoutProps = {\n title: string;\n description?: string;\n children: ReactNode;\n error?: string | null;\n footer?: ReactNode;\n logoImage?: string;\n};\n\nexport const AuthPageLayout = ({\n title,\n description,\n children,\n error,\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=\"Jiret\" 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 {error && (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\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":";;;AAEA,SAAS,OAAO,wBAAwB;AAwBhC,cAEF,YAFE;AAZD,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;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,IAEA,SACC,oBAAC,SAAM,SAAQ,eACb,8BAAC,oBAAkB,iBAAM,GAC3B;AAAA,IAEF,oBAAC,SAAI,WAAU,eACZ,oBACC,oBAAC,SAAI,WAAU,oDACZ,kBACH,GAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type CountdownProps = {
|
|
4
|
+
initialSeconds?: number;
|
|
5
|
+
onResend: () => Promise<void> | void;
|
|
6
|
+
resending?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare const Countdown: ({ initialSeconds, onResend, resending, }: CountdownProps) => react_jsx_runtime.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { Countdown };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/countdown.tsx
|
|
4
|
+
import { Button } from "@mesob/ui/components/button";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var Countdown = ({
|
|
9
|
+
initialSeconds = 60,
|
|
10
|
+
onResend,
|
|
11
|
+
resending = false
|
|
12
|
+
}) => {
|
|
13
|
+
const t = useTranslations("Common");
|
|
14
|
+
const [seconds, setSeconds] = useState(initialSeconds);
|
|
15
|
+
const [isResending, setIsResending] = useState(false);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (seconds <= 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const timer = setInterval(() => {
|
|
21
|
+
setSeconds((prev) => {
|
|
22
|
+
if (prev <= 1) {
|
|
23
|
+
clearInterval(timer);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
return prev - 1;
|
|
27
|
+
});
|
|
28
|
+
}, 1e3);
|
|
29
|
+
return () => clearInterval(timer);
|
|
30
|
+
}, [seconds]);
|
|
31
|
+
const handleResend = async () => {
|
|
32
|
+
setIsResending(true);
|
|
33
|
+
try {
|
|
34
|
+
await onResend();
|
|
35
|
+
setSeconds(initialSeconds);
|
|
36
|
+
} catch (_error) {
|
|
37
|
+
} finally {
|
|
38
|
+
setIsResending(false);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
if (seconds > 0) {
|
|
42
|
+
return /* @__PURE__ */ jsx(Button, { variant: "ghost", disabled: true, children: t("resendIn", { seconds }) });
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
Button,
|
|
46
|
+
{
|
|
47
|
+
variant: "ghost",
|
|
48
|
+
onClick: handleResend,
|
|
49
|
+
disabled: isResending || resending,
|
|
50
|
+
children: isResending || resending ? t("resending") : t("resend")
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
Countdown
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=countdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/countdown.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@mesob/ui/components/button';\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 ? t('resending') : t('resend')}\n </Button>\n );\n};\n"],"mappings":";;;AAEA,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,WAAW,gBAAgB;AAiD9B;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,yBAAe,YAAY,EAAE,WAAW,IAAI,EAAE,QAAQ;AAAA;AAAA,EACzD;AAEJ;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type ForgotPasswordFormValues = {
|
|
4
|
+
account: string;
|
|
5
|
+
};
|
|
6
|
+
type ForgotPasswordProps = {
|
|
7
|
+
onSubmit: (values: ForgotPasswordFormValues) => Promise<void> | void;
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
onBack?: () => void;
|
|
10
|
+
};
|
|
11
|
+
declare const ForgotPassword: ({ onSubmit, isLoading, onBack, }: ForgotPasswordProps) => react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { ForgotPassword };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/forgot-password.tsx
|
|
4
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
|
+
import { Button } from "@mesob/ui/components/button";
|
|
6
|
+
import {
|
|
7
|
+
Form,
|
|
8
|
+
FormControl,
|
|
9
|
+
FormField,
|
|
10
|
+
FormItem,
|
|
11
|
+
FormLabel,
|
|
12
|
+
FormMessage
|
|
13
|
+
} from "@mesob/ui/components/form";
|
|
14
|
+
import { Input } from "@mesob/ui/components/input";
|
|
15
|
+
import { useTranslations } from "next-intl";
|
|
16
|
+
import { useMemo } from "react";
|
|
17
|
+
import { useForm } from "react-hook-form";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var ForgotPassword = ({
|
|
21
|
+
onSubmit,
|
|
22
|
+
isLoading = false,
|
|
23
|
+
onBack
|
|
24
|
+
}) => {
|
|
25
|
+
const t = useTranslations("Auth.forgotPassword");
|
|
26
|
+
const forgotPasswordSchema = useMemo(
|
|
27
|
+
() => z.object({
|
|
28
|
+
account: z.string().min(1, t("errors.accountRequired"))
|
|
29
|
+
}),
|
|
30
|
+
[t]
|
|
31
|
+
);
|
|
32
|
+
const form = useForm({
|
|
33
|
+
resolver: zodResolver(forgotPasswordSchema),
|
|
34
|
+
defaultValues: {
|
|
35
|
+
account: ""
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
39
|
+
await onSubmit(values);
|
|
40
|
+
});
|
|
41
|
+
return /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
|
|
42
|
+
/* @__PURE__ */ jsx(
|
|
43
|
+
FormField,
|
|
44
|
+
{
|
|
45
|
+
control: form.control,
|
|
46
|
+
name: "account",
|
|
47
|
+
render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
|
|
48
|
+
/* @__PURE__ */ jsx(FormLabel, { children: t("form.accountLabel") }),
|
|
49
|
+
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
|
|
50
|
+
Input,
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
placeholder: t("form.accountPlaceholder"),
|
|
54
|
+
...field
|
|
55
|
+
}
|
|
56
|
+
) }),
|
|
57
|
+
/* @__PURE__ */ jsx(FormMessage, {})
|
|
58
|
+
] })
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.submit") })
|
|
62
|
+
] }) });
|
|
63
|
+
};
|
|
64
|
+
export {
|
|
65
|
+
ForgotPassword
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=forgot-password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/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 { 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 onBack,\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-5\">\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 ? 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,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,SAAS;AA4CN,SACE,KADF;AAhCL,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA,YAAY;AAAA,EACZ;AACF,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,oBAAC,UAAO,MAAK,UAAS,WAAU,UAAS,UAAU,WAChD,sBAAY,EAAE,iBAAiB,IAAI,EAAE,aAAa,GACrD;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
|
|
4
|
+
type ForgotPasswordPageProps = {
|
|
5
|
+
locale?: string;
|
|
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;
|
|
16
|
+
|
|
17
|
+
export { ForgotPasswordPage };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/pages/forgot-password-page.tsx
|
|
4
|
+
import { useTranslations as useTranslations2 } from "next-intl";
|
|
5
|
+
import { useState as useState2 } from "react";
|
|
6
|
+
|
|
7
|
+
// src/context/auth-provider.tsx
|
|
8
|
+
import {
|
|
9
|
+
createContext,
|
|
10
|
+
useCallback,
|
|
11
|
+
useContext,
|
|
12
|
+
useEffect,
|
|
13
|
+
useState
|
|
14
|
+
} from "react";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
var AuthContext = createContext(null);
|
|
17
|
+
var useAuth = () => {
|
|
18
|
+
const context = useContext(AuthContext);
|
|
19
|
+
if (!context) {
|
|
20
|
+
throw new Error("useAuth must be used within AuthProvider");
|
|
21
|
+
}
|
|
22
|
+
return context;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/client.ts
|
|
26
|
+
var AuthError = class extends Error {
|
|
27
|
+
code;
|
|
28
|
+
status;
|
|
29
|
+
details;
|
|
30
|
+
constructor(message, code, status, details) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "AuthError";
|
|
33
|
+
this.code = code;
|
|
34
|
+
this.status = status;
|
|
35
|
+
this.details = details;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/constants/auth.error.codes.ts
|
|
40
|
+
var validCodes = [
|
|
41
|
+
"USER_NOT_FOUND",
|
|
42
|
+
"INVALID_PASSWORD",
|
|
43
|
+
"USER_EXISTS",
|
|
44
|
+
"VERIFICATION_EXPIRED",
|
|
45
|
+
"VERIFICATION_MISMATCH",
|
|
46
|
+
"VERIFICATION_NOT_FOUND",
|
|
47
|
+
"TOO_MANY_ATTEMPTS",
|
|
48
|
+
"REQUIRES_VERIFICATION",
|
|
49
|
+
"UNAUTHORIZED",
|
|
50
|
+
"ACCESS_DENIED",
|
|
51
|
+
"HAS_NO_PASSWORD"
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// src/utils/handle-error.ts
|
|
55
|
+
var handleError = (err, setError, t) => {
|
|
56
|
+
if (err instanceof AuthError) {
|
|
57
|
+
let errorKey = "errors.fallback";
|
|
58
|
+
if (err.code) {
|
|
59
|
+
errorKey = `errors.${err.code.toLowerCase()}`;
|
|
60
|
+
} else if (err.message) {
|
|
61
|
+
const messageUpper = err.message.toUpperCase().trim();
|
|
62
|
+
if (validCodes.includes(messageUpper)) {
|
|
63
|
+
errorKey = `errors.${messageUpper.toLowerCase()}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
setError(t(errorKey, { defaultValue: err.message }));
|
|
67
|
+
} else {
|
|
68
|
+
setError(err instanceof Error ? err.message : t("errors.fallback"));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/components/auth-page-layout.tsx
|
|
73
|
+
import { Alert, AlertDescription } from "@mesob/ui/components/alert";
|
|
74
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
75
|
+
var AuthPageLayout = ({
|
|
76
|
+
title,
|
|
77
|
+
description,
|
|
78
|
+
children,
|
|
79
|
+
error,
|
|
80
|
+
footer,
|
|
81
|
+
logoImage
|
|
82
|
+
}) => {
|
|
83
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
84
|
+
/* @__PURE__ */ jsx2("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx2("img", { src: logoImage || "", alt: "Jiret", width: 42, height: 42 }) }),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
86
|
+
/* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
87
|
+
description && /* @__PURE__ */ jsx2("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
88
|
+
] }),
|
|
89
|
+
children,
|
|
90
|
+
error && /* @__PURE__ */ jsx2(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx2(AlertDescription, { children: error }) }),
|
|
91
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-2 w-full", children: footer && /* @__PURE__ */ jsx2("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
|
|
92
|
+
] });
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/components/forgot-password.tsx
|
|
96
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
97
|
+
import { Button } from "@mesob/ui/components/button";
|
|
98
|
+
import {
|
|
99
|
+
Form,
|
|
100
|
+
FormControl,
|
|
101
|
+
FormField,
|
|
102
|
+
FormItem,
|
|
103
|
+
FormLabel,
|
|
104
|
+
FormMessage
|
|
105
|
+
} from "@mesob/ui/components/form";
|
|
106
|
+
import { Input } from "@mesob/ui/components/input";
|
|
107
|
+
import { useTranslations } from "next-intl";
|
|
108
|
+
import { useMemo } from "react";
|
|
109
|
+
import { useForm } from "react-hook-form";
|
|
110
|
+
import { z } from "zod";
|
|
111
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
112
|
+
var ForgotPassword = ({
|
|
113
|
+
onSubmit,
|
|
114
|
+
isLoading = false,
|
|
115
|
+
onBack
|
|
116
|
+
}) => {
|
|
117
|
+
const t = useTranslations("Auth.forgotPassword");
|
|
118
|
+
const forgotPasswordSchema = useMemo(
|
|
119
|
+
() => z.object({
|
|
120
|
+
account: z.string().min(1, t("errors.accountRequired"))
|
|
121
|
+
}),
|
|
122
|
+
[t]
|
|
123
|
+
);
|
|
124
|
+
const form = useForm({
|
|
125
|
+
resolver: zodResolver(forgotPasswordSchema),
|
|
126
|
+
defaultValues: {
|
|
127
|
+
account: ""
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
131
|
+
await onSubmit(values);
|
|
132
|
+
});
|
|
133
|
+
return /* @__PURE__ */ jsx3(Form, { ...form, children: /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
|
|
134
|
+
/* @__PURE__ */ jsx3(
|
|
135
|
+
FormField,
|
|
136
|
+
{
|
|
137
|
+
control: form.control,
|
|
138
|
+
name: "account",
|
|
139
|
+
render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
|
|
140
|
+
/* @__PURE__ */ jsx3(FormLabel, { children: t("form.accountLabel") }),
|
|
141
|
+
/* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsx3(
|
|
142
|
+
Input,
|
|
143
|
+
{
|
|
144
|
+
type: "text",
|
|
145
|
+
placeholder: t("form.accountPlaceholder"),
|
|
146
|
+
...field
|
|
147
|
+
}
|
|
148
|
+
) }),
|
|
149
|
+
/* @__PURE__ */ jsx3(FormMessage, {})
|
|
150
|
+
] })
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
/* @__PURE__ */ jsx3(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.submit") })
|
|
154
|
+
] }) });
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/components/pages/forgot-password-page.tsx
|
|
158
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
159
|
+
var ForgotPasswordPage = ({
|
|
160
|
+
onNavigate,
|
|
161
|
+
linkComponent: Link,
|
|
162
|
+
links,
|
|
163
|
+
logoImage
|
|
164
|
+
}) => {
|
|
165
|
+
const t = useTranslations2("Auth.forgotPassword");
|
|
166
|
+
const { client } = useAuth();
|
|
167
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
168
|
+
const [error, setError] = useState2(null);
|
|
169
|
+
const signInLink = links?.signIn || "/auth/sign-in";
|
|
170
|
+
const handleSubmit = async (values) => {
|
|
171
|
+
setIsLoading(true);
|
|
172
|
+
setError(null);
|
|
173
|
+
try {
|
|
174
|
+
const res = await client.forgotPassword({ identifier: values.account });
|
|
175
|
+
if ("verificationId" in res && res.verificationId) {
|
|
176
|
+
onNavigate(`/auth/reset-password?verificationId=${res.verificationId}`);
|
|
177
|
+
} else {
|
|
178
|
+
onNavigate(
|
|
179
|
+
`/auth/reset-password?identifier=${encodeURIComponent(values.account)}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
} catch (err) {
|
|
183
|
+
handleError(err, setError, t);
|
|
184
|
+
} finally {
|
|
185
|
+
setIsLoading(false);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const handleBack = () => {
|
|
189
|
+
onNavigate(signInLink);
|
|
190
|
+
};
|
|
191
|
+
return /* @__PURE__ */ jsx4(
|
|
192
|
+
AuthPageLayout,
|
|
193
|
+
{
|
|
194
|
+
title: t("title"),
|
|
195
|
+
description: t("description"),
|
|
196
|
+
error,
|
|
197
|
+
logoImage,
|
|
198
|
+
footer: Link ? /* @__PURE__ */ jsx4(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }) : /* @__PURE__ */ jsx4(
|
|
199
|
+
"a",
|
|
200
|
+
{
|
|
201
|
+
href: signInLink,
|
|
202
|
+
onClick: (e) => {
|
|
203
|
+
e.preventDefault();
|
|
204
|
+
onNavigate(signInLink);
|
|
205
|
+
},
|
|
206
|
+
className: "text-primary hover:underline",
|
|
207
|
+
children: t("footer.backToSignIn")
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
children: /* @__PURE__ */ jsx4(
|
|
211
|
+
ForgotPassword,
|
|
212
|
+
{
|
|
213
|
+
onSubmit: handleSubmit,
|
|
214
|
+
isLoading,
|
|
215
|
+
onBack: handleBack
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
};
|
|
221
|
+
export {
|
|
222
|
+
ForgotPasswordPage
|
|
223
|
+
};
|
|
224
|
+
//# sourceMappingURL=forgot-password-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/pages/forgot-password-page.tsx","../../../src/context/auth-provider.tsx","../../../src/client.ts","../../../src/constants/auth.error.codes.ts","../../../src/utils/handle-error.ts","../../../src/components/auth-page-layout.tsx","../../../src/components/forgot-password.tsx"],"sourcesContent":["'use client';\n\nimport { useTranslations } from 'next-intl';\nimport type { ComponentProps } from 'react';\nimport { useState } from 'react';\nimport { useAuth } from '../../context/auth-provider';\nimport { handleError } from '../../utils/handle-error';\nimport { AuthPageLayout } from '../auth-page-layout';\nimport { ForgotPassword } from '../forgot-password';\n\ntype ForgotPasswordPageProps = {\n locale?: string;\n onNavigate: (path: string) => void;\n linkComponent?: React.ComponentType<ComponentProps<'a'> & { href: string }>;\n links?: {\n signIn?: string;\n };\n logoImage?: string;\n};\n\nexport const ForgotPasswordPage = ({\n onNavigate,\n linkComponent: Link,\n links,\n logoImage,\n}: ForgotPasswordPageProps) => {\n const t = useTranslations('Auth.forgotPassword');\n const { client } = useAuth();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const signInLink = links?.signIn || '/auth/sign-in';\n\n const handleSubmit = async (values: { account: string }) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const res = await client.forgotPassword({ identifier: values.account });\n\n if ('verificationId' in res && res.verificationId) {\n onNavigate(`/auth/reset-password?verificationId=${res.verificationId}`);\n } else {\n onNavigate(\n `/auth/reset-password?identifier=${encodeURIComponent(values.account)}`,\n );\n }\n } catch (err) {\n handleError(err, setError, t);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleBack = () => {\n onNavigate(signInLink);\n };\n\n return (\n <AuthPageLayout\n title={t('title')}\n description={t('description')}\n error={error}\n logoImage={logoImage}\n footer={\n Link ? (\n <Link href={signInLink} className=\"text-primary hover:underline\">\n {t('footer.backToSignIn')}\n </Link>\n ) : (\n <a\n href={signInLink}\n onClick={(e) => {\n e.preventDefault();\n onNavigate(signInLink);\n }}\n className=\"text-primary hover:underline\"\n >\n {t('footer.backToSignIn')}\n </a>\n )\n }\n >\n <ForgotPassword\n onSubmit={handleSubmit}\n isLoading={isLoading}\n onBack={handleBack}\n />\n </AuthPageLayout>\n );\n};\n","'use client';\n\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport type { AuthClient } from '../client';\nimport type { AuthResponse, Session, User } from '../types';\n\ntype AuthContextValue = {\n user: User | null;\n session: Session | null;\n loading: boolean;\n error: Error | null;\n client: AuthClient;\n refresh: () => Promise<void>;\n setAuth: (data: AuthResponse) => void;\n};\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\nexport const useAuth = () => {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuth must be used within AuthProvider');\n }\n return context;\n};\n\ntype AuthProviderProps = {\n client: AuthClient;\n children: ReactNode;\n};\n\nexport const AuthProvider = ({ client, children }: AuthProviderProps) => {\n const [user, setUser] = useState<User | null>(null);\n const [session, setSession] = useState<Session | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n const data = await client.getSession();\n setUser(data.user);\n setSession(data.session);\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to fetch session'),\n );\n setUser(null);\n setSession(null);\n } finally {\n setLoading(false);\n }\n }, [client]);\n\n const setAuth = useCallback((data: AuthResponse) => {\n setUser(data.user);\n setSession(data.session);\n setError(null);\n setLoading(false);\n }, []);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return (\n <AuthContext.Provider\n value={{\n user,\n session,\n loading,\n error,\n client,\n refresh,\n setAuth,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n","import type {\n AuthErrorCode,\n AuthErrorResponse,\n AuthResponse,\n SessionResponse,\n User,\n VerificationResponse,\n} from './types';\n\n// Backend returns error code in 'error' field (AUTH_ERRORS values)\n// or in 'code' field, message in 'message' or 'error' field\nconst validErrorCodes: readonly AuthErrorCode[] = [\n 'USER_NOT_FOUND',\n 'INVALID_PASSWORD',\n 'USER_EXISTS',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'REQUIRES_VERIFICATION',\n 'UNAUTHORIZED',\n 'ACCESS_DENIED',\n 'HAS_NO_PASSWORD',\n] as const;\n\nexport class AuthError extends Error {\n code?: AuthErrorCode;\n status?: number;\n details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code?: AuthErrorCode,\n status?: number,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport type AuthClientConfig = {\n baseURL: string;\n};\n\nexport class AuthClient {\n private baseURL: string;\n\n constructor(config: AuthClientConfig) {\n this.baseURL = config.baseURL.replace(/\\/$/, '');\n }\n\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseURL}${endpoint}`;\n const response = await fetch(url, {\n ...options,\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n if (!response.ok) {\n const text = await response.text();\n let errorData: AuthErrorResponse;\n try {\n errorData = JSON.parse(text);\n } catch {\n errorData = { error: 'Unknown error', message: text };\n }\n\n // Extract error code from code, error, or message field\n // Backend returns error codes in 'error' field (e.g., { error: 'INVALID_PASSWORD' })\n const potentialCode =\n errorData.code ||\n (typeof errorData.error === 'string' ? errorData.error : null) ||\n (typeof errorData.message === 'string' ? errorData.message : null);\n const upperCode = potentialCode?.toUpperCase().trim();\n const errorCode =\n upperCode && validErrorCodes.includes(upperCode as AuthErrorCode)\n ? (upperCode as AuthErrorCode)\n : undefined;\n const errorMessage =\n errorData.message || errorData.error || 'Request failed';\n\n throw new AuthError(\n errorMessage,\n errorCode as AuthErrorCode | undefined,\n response.status,\n errorData.details,\n );\n }\n\n const data = await response.json();\n return data;\n }\n\n signUpWithEmail(data: {\n email: string;\n password: string;\n fullName: string;\n handle?: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-up', {\n method: 'POST',\n body: JSON.stringify({\n email: data.email,\n password: data.password,\n fullName: data.fullName,\n handle: data.handle,\n }),\n });\n }\n\n signUpWithPhone(data: {\n phone: string;\n password: string;\n fullName: string;\n handle?: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-up', {\n method: 'POST',\n body: JSON.stringify({\n phone: data.phone,\n password: data.password,\n fullName: data.fullName,\n handle: data.handle,\n }),\n });\n }\n\n checkUser(data: { identifier: string }): Promise<{ exists: boolean }> {\n return this.request<{ exists: boolean }>('/check-user', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n signInWithPassword(data: {\n identifier: string;\n password: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-in', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n signOut(): Promise<{ message: string }> {\n return this.request<{ message: string }>('/sign-out', {\n method: 'POST',\n });\n }\n\n requestEmailVerification(data?: {\n email?: string;\n }): Promise<{ verificationId: string }> {\n return this.request<{ verificationId: string }>(\n '/email/verification/request',\n {\n method: 'POST',\n body: JSON.stringify(data || {}),\n },\n );\n }\n\n verifyEmail(data: {\n verificationId: string;\n code: string;\n }): Promise<AuthResponse> {\n return this.request<AuthResponse>('/email/verification/confirm', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n resendVerification(_verificationId: string): Promise<{\n verificationId: string;\n }> {\n // For email, request new verification\n return this.requestEmailVerification();\n }\n\n requestPhoneOtp(data: {\n phone: string;\n context: 'sign-up' | 'sign-in' | 'change-phone';\n }): Promise<{ verificationId: string }> {\n return this.request<{ verificationId: string }>(\n '/phone/verification/request',\n {\n method: 'POST',\n body: JSON.stringify(data),\n },\n );\n }\n\n verifyPhoneOtp(data: {\n verificationId: string;\n code: string;\n context: 'sign-up' | 'sign-in' | 'change-phone';\n }): Promise<\n AuthResponse | { user: User | null; session: null; verified: boolean }\n > {\n return this.request('/phone/verification/confirm', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n forgotPassword(data: { identifier: string }): Promise<{\n message: string;\n }> {\n return this.request<{ message: string }>('/password/forgot', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n resetPassword(data: {\n verificationId: string;\n code: string;\n password: string;\n }): Promise<AuthResponse> {\n return this.request<AuthResponse>('/password/reset', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n changePassword(data: {\n currentPassword: string;\n newPassword: string;\n }): Promise<{ message: string }> {\n return this.request<{ message: string }>('/password/change', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n getSession(): Promise<SessionResponse> {\n return this.request<SessionResponse>('/session', {\n method: 'GET',\n });\n }\n}\n","export const validCodes = [\n 'USER_NOT_FOUND',\n 'INVALID_PASSWORD',\n 'USER_EXISTS',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'REQUIRES_VERIFICATION',\n 'UNAUTHORIZED',\n 'ACCESS_DENIED',\n 'HAS_NO_PASSWORD',\n];\n","import type { _Translator } from 'next-intl';\nimport { AuthError } from '../client';\nimport { validCodes } from '../constants/auth.error.codes';\n\nexport const handleError = (\n err: any,\n setError: (error: string | null) => void,\n t: _Translator<Record<string, any>, string>,\n) => {\n if (err instanceof AuthError) {\n let errorKey = 'errors.fallback';\n if (err.code) {\n errorKey = `errors.${err.code.toLowerCase()}`;\n } else if (err.message) {\n // Fallback: try to extract error code from message\n const messageUpper = err.message.toUpperCase().trim();\n\n if (validCodes.includes(messageUpper)) {\n errorKey = `errors.${messageUpper.toLowerCase()}`;\n }\n }\n setError(t(errorKey, { defaultValue: err.message }));\n } else {\n setError(err instanceof Error ? err.message : t('errors.fallback'));\n }\n};\n","'use client';\n\nimport { Alert, AlertDescription } from '@mesob/ui/components/alert';\nimport type { ReactNode } from 'react';\n\ntype AuthPageLayoutProps = {\n title: string;\n description?: string;\n children: ReactNode;\n error?: string | null;\n footer?: ReactNode;\n logoImage?: string;\n};\n\nexport const AuthPageLayout = ({\n title,\n description,\n children,\n error,\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=\"Jiret\" 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 {error && (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\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","'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 { 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 onBack,\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-5\">\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 ? t('form.submitting') : t('form.submit')}\n </Button>\n </form>\n </Form>\n );\n};\n"],"mappings":"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","names":["useTranslations","useState","jsx","jsx","jsxs","jsx","useTranslations","useState"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
|
|
4
|
+
type ResetPasswordPageProps = {
|
|
5
|
+
locale?: string;
|
|
6
|
+
verificationId: string;
|
|
7
|
+
onNavigate: (path: string) => void;
|
|
8
|
+
linkComponent?: React.ComponentType<ComponentProps<'a'> & {
|
|
9
|
+
href: string;
|
|
10
|
+
}>;
|
|
11
|
+
links?: {
|
|
12
|
+
signIn?: string;
|
|
13
|
+
forgotPassword?: string;
|
|
14
|
+
};
|
|
15
|
+
logoImage?: string;
|
|
16
|
+
};
|
|
17
|
+
declare const ResetPasswordPage: ({ verificationId, onNavigate, linkComponent: Link, links, logoImage, }: ResetPasswordPageProps) => react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { ResetPasswordPage };
|