@mesob/auth-react 0.0.7 → 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
package/dist/index.js
CHANGED
|
@@ -1,428 +1,260 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// src/client.ts
|
|
4
|
-
var validErrorCodes = [
|
|
5
|
-
"USER_NOT_FOUND",
|
|
6
|
-
"INVALID_PASSWORD",
|
|
7
|
-
"USER_EXISTS",
|
|
8
|
-
"VERIFICATION_EXPIRED",
|
|
9
|
-
"VERIFICATION_MISMATCH",
|
|
10
|
-
"VERIFICATION_NOT_FOUND",
|
|
11
|
-
"TOO_MANY_ATTEMPTS",
|
|
12
|
-
"REQUIRES_VERIFICATION",
|
|
13
|
-
"UNAUTHORIZED",
|
|
14
|
-
"ACCESS_DENIED",
|
|
15
|
-
"HAS_NO_PASSWORD"
|
|
16
|
-
];
|
|
17
|
-
var AuthError = class extends Error {
|
|
18
|
-
code;
|
|
19
|
-
status;
|
|
20
|
-
details;
|
|
21
|
-
constructor(message, code, status, details) {
|
|
22
|
-
super(message);
|
|
23
|
-
this.name = "AuthError";
|
|
24
|
-
this.code = code;
|
|
25
|
-
this.status = status;
|
|
26
|
-
this.details = details;
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var AuthClient = class {
|
|
30
|
-
baseURL;
|
|
31
|
-
constructor(config) {
|
|
32
|
-
this.baseURL = config.baseURL.replace(/\/$/, "");
|
|
33
|
-
}
|
|
34
|
-
async request(endpoint, options = {}) {
|
|
35
|
-
const url = `${this.baseURL}${endpoint}`;
|
|
36
|
-
const response = await fetch(url, {
|
|
37
|
-
...options,
|
|
38
|
-
credentials: "include",
|
|
39
|
-
headers: {
|
|
40
|
-
"Content-Type": "application/json",
|
|
41
|
-
...options.headers
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
const text = await response.text();
|
|
46
|
-
let errorData;
|
|
47
|
-
try {
|
|
48
|
-
errorData = JSON.parse(text);
|
|
49
|
-
} catch {
|
|
50
|
-
errorData = { error: "Unknown error", message: text };
|
|
51
|
-
}
|
|
52
|
-
const potentialCode = errorData.code || (typeof errorData.error === "string" ? errorData.error : null) || (typeof errorData.message === "string" ? errorData.message : null);
|
|
53
|
-
const upperCode = potentialCode?.toUpperCase().trim();
|
|
54
|
-
const errorCode = upperCode && validErrorCodes.includes(upperCode) ? upperCode : void 0;
|
|
55
|
-
const errorMessage = errorData.message || errorData.error || "Request failed";
|
|
56
|
-
throw new AuthError(
|
|
57
|
-
errorMessage,
|
|
58
|
-
errorCode,
|
|
59
|
-
response.status,
|
|
60
|
-
errorData.details
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
const data = await response.json();
|
|
64
|
-
return data;
|
|
65
|
-
}
|
|
66
|
-
signUpWithEmail(data) {
|
|
67
|
-
return this.request("/sign-up", {
|
|
68
|
-
method: "POST",
|
|
69
|
-
body: JSON.stringify({
|
|
70
|
-
email: data.email,
|
|
71
|
-
password: data.password,
|
|
72
|
-
fullName: data.fullName,
|
|
73
|
-
handle: data.handle
|
|
74
|
-
})
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
signUpWithPhone(data) {
|
|
78
|
-
return this.request("/sign-up", {
|
|
79
|
-
method: "POST",
|
|
80
|
-
body: JSON.stringify({
|
|
81
|
-
phone: data.phone,
|
|
82
|
-
password: data.password,
|
|
83
|
-
fullName: data.fullName,
|
|
84
|
-
handle: data.handle
|
|
85
|
-
})
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
checkUser(data) {
|
|
89
|
-
return this.request("/check-user", {
|
|
90
|
-
method: "POST",
|
|
91
|
-
body: JSON.stringify(data)
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
signInWithPassword(data) {
|
|
95
|
-
return this.request("/sign-in", {
|
|
96
|
-
method: "POST",
|
|
97
|
-
body: JSON.stringify(data)
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
signOut() {
|
|
101
|
-
return this.request("/sign-out", {
|
|
102
|
-
method: "POST"
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
requestEmailVerification(data) {
|
|
106
|
-
return this.request(
|
|
107
|
-
"/email/verification/request",
|
|
108
|
-
{
|
|
109
|
-
method: "POST",
|
|
110
|
-
body: JSON.stringify(data || {})
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
verifyEmail(data) {
|
|
115
|
-
return this.request("/email/verification/confirm", {
|
|
116
|
-
method: "POST",
|
|
117
|
-
body: JSON.stringify(data)
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
resendVerification(_verificationId) {
|
|
121
|
-
return this.requestEmailVerification();
|
|
122
|
-
}
|
|
123
|
-
requestPhoneOtp(data) {
|
|
124
|
-
return this.request(
|
|
125
|
-
"/phone/verification/request",
|
|
126
|
-
{
|
|
127
|
-
method: "POST",
|
|
128
|
-
body: JSON.stringify(data)
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
verifyPhoneOtp(data) {
|
|
133
|
-
return this.request("/phone/verification/confirm", {
|
|
134
|
-
method: "POST",
|
|
135
|
-
body: JSON.stringify(data)
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
forgotPassword(data) {
|
|
139
|
-
return this.request("/password/forgot", {
|
|
140
|
-
method: "POST",
|
|
141
|
-
body: JSON.stringify(data)
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
resetPassword(data) {
|
|
145
|
-
return this.request("/password/reset", {
|
|
146
|
-
method: "POST",
|
|
147
|
-
body: JSON.stringify(data)
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
verifyPassword(data) {
|
|
151
|
-
return this.request("/password/verify", {
|
|
152
|
-
method: "POST",
|
|
153
|
-
body: JSON.stringify(data)
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
changePassword(data) {
|
|
157
|
-
return this.request("/password/change", {
|
|
158
|
-
method: "POST",
|
|
159
|
-
body: JSON.stringify(data)
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
getSession() {
|
|
163
|
-
return this.request("/session", {
|
|
164
|
-
method: "GET"
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
getPendingAccountChange() {
|
|
168
|
-
return this.request(
|
|
169
|
-
"/account-change/pending",
|
|
170
|
-
{
|
|
171
|
-
method: "GET"
|
|
172
|
-
}
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
updateProfile(data) {
|
|
176
|
-
return this.request("/profile", {
|
|
177
|
-
method: "PUT",
|
|
178
|
-
body: JSON.stringify(data)
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
updateEmail(data) {
|
|
182
|
-
return this.request("/profile/email", {
|
|
183
|
-
method: "PUT",
|
|
184
|
-
body: JSON.stringify(data)
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
updatePhone(data) {
|
|
188
|
-
return this.request("/profile/phone", {
|
|
189
|
-
method: "PUT",
|
|
190
|
-
body: JSON.stringify(data)
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
3
|
// src/components/auth/auth-card.tsx
|
|
196
4
|
import { jsx } from "react/jsx-runtime";
|
|
197
5
|
var AuthCard = ({ children }) => {
|
|
198
6
|
return /* @__PURE__ */ jsx("div", { className: "flex min-h-screen p-4 items-center justify-center", 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 }) }) });
|
|
199
7
|
};
|
|
200
8
|
|
|
201
|
-
// src/components/auth/
|
|
9
|
+
// src/components/auth/pages/forgot-password-page.tsx
|
|
202
10
|
import {
|
|
203
11
|
Alert,
|
|
204
12
|
AlertDescription,
|
|
205
13
|
AlertTitle
|
|
206
14
|
} from "@mesob/ui/components/alert";
|
|
15
|
+
import { toast } from "@mesob/ui/components/sonner";
|
|
207
16
|
import { IconAlertCircle } from "@tabler/icons-react";
|
|
208
|
-
import {
|
|
209
|
-
var AuthPageLayout = ({
|
|
210
|
-
title,
|
|
211
|
-
description,
|
|
212
|
-
children,
|
|
213
|
-
error,
|
|
214
|
-
footer,
|
|
215
|
-
logoImage
|
|
216
|
-
}) => {
|
|
217
|
-
const errorContent = error ? (
|
|
218
|
-
// biome-ignore lint/style/noNestedTernary: <explanation>
|
|
219
|
-
typeof error === "string" ? { title: "Error", description: error } : error
|
|
220
|
-
) : null;
|
|
221
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
222
|
-
/* @__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 }) }),
|
|
223
|
-
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
224
|
-
/* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
225
|
-
description && /* @__PURE__ */ jsx2("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
226
|
-
] }),
|
|
227
|
-
children,
|
|
228
|
-
errorContent && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
|
|
229
|
-
/* @__PURE__ */ jsx2(IconAlertCircle, { className: "h-4 w-4" }),
|
|
230
|
-
/* @__PURE__ */ jsx2(AlertTitle, { children: errorContent.title }),
|
|
231
|
-
/* @__PURE__ */ jsx2(AlertDescription, { children: errorContent.description })
|
|
232
|
-
] }),
|
|
233
|
-
/* @__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 }) })
|
|
234
|
-
] });
|
|
235
|
-
};
|
|
17
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
236
18
|
|
|
237
|
-
// src/
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const [seconds, setSeconds] = useState(initialSeconds);
|
|
250
|
-
const [isResending, setIsResending] = useState(false);
|
|
251
|
-
useEffect(() => {
|
|
252
|
-
if (seconds <= 0) {
|
|
253
|
-
return;
|
|
19
|
+
// src/lib/translations.ts
|
|
20
|
+
function createTranslator(messages, namespace) {
|
|
21
|
+
return (key, params) => {
|
|
22
|
+
const fullKey = namespace ? `${namespace}.${key}` : key;
|
|
23
|
+
const keys = fullKey.split(".");
|
|
24
|
+
let value = messages;
|
|
25
|
+
for (const k of keys) {
|
|
26
|
+
if (value && typeof value === "object" && value !== null) {
|
|
27
|
+
value = value[k];
|
|
28
|
+
} else {
|
|
29
|
+
return fullKey;
|
|
30
|
+
}
|
|
254
31
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (prev <= 1) {
|
|
258
|
-
clearInterval(timer);
|
|
259
|
-
return 0;
|
|
260
|
-
}
|
|
261
|
-
return prev - 1;
|
|
262
|
-
});
|
|
263
|
-
}, 1e3);
|
|
264
|
-
return () => clearInterval(timer);
|
|
265
|
-
}, [seconds]);
|
|
266
|
-
const handleResend = async () => {
|
|
267
|
-
setIsResending(true);
|
|
268
|
-
try {
|
|
269
|
-
await onResend();
|
|
270
|
-
setSeconds(initialSeconds);
|
|
271
|
-
} catch (_error) {
|
|
272
|
-
} finally {
|
|
273
|
-
setIsResending(false);
|
|
32
|
+
if (typeof value !== "string") {
|
|
33
|
+
return fullKey;
|
|
274
34
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Button,
|
|
281
|
-
{
|
|
282
|
-
variant: "ghost",
|
|
283
|
-
onClick: handleResend,
|
|
284
|
-
disabled: isResending || resending,
|
|
285
|
-
children: [
|
|
286
|
-
isResending || resending && /* @__PURE__ */ jsx3(Spinner, {}),
|
|
287
|
-
t("resend")
|
|
288
|
-
]
|
|
35
|
+
if (params) {
|
|
36
|
+
return value.replace(
|
|
37
|
+
/\{(\w+)\}/g,
|
|
38
|
+
(_, param) => String(params[param] ?? `{${param}}`)
|
|
39
|
+
);
|
|
289
40
|
}
|
|
290
|
-
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/provider.tsx
|
|
46
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
47
|
+
import { deepmerge } from "deepmerge-ts";
|
|
48
|
+
import createFetchClient from "openapi-fetch";
|
|
49
|
+
import createClient from "openapi-react-query";
|
|
50
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
51
|
+
|
|
52
|
+
// src/types.ts
|
|
53
|
+
var defaultAuthClientConfig = {
|
|
54
|
+
features: {
|
|
55
|
+
enableSignup: true,
|
|
56
|
+
enablePasswordReset: true,
|
|
57
|
+
enableEmailSignup: true,
|
|
58
|
+
enablePhoneSignup: true,
|
|
59
|
+
enableSocialSignup: false,
|
|
60
|
+
socialProviders: []
|
|
61
|
+
},
|
|
62
|
+
navigation: {
|
|
63
|
+
locale: "en"
|
|
64
|
+
},
|
|
65
|
+
cookiePrefix: "msb"
|
|
291
66
|
};
|
|
292
67
|
|
|
293
|
-
// src/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
import { Input } from "@mesob/ui/components/input";
|
|
305
|
-
import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
|
|
306
|
-
import { useTranslations as useTranslations2 } from "next-intl";
|
|
307
|
-
import { useMemo } from "react";
|
|
308
|
-
import { useForm } from "react-hook-form";
|
|
309
|
-
import { z } from "zod";
|
|
310
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
311
|
-
var ForgotPassword = ({
|
|
312
|
-
onSubmit,
|
|
313
|
-
isLoading = false
|
|
314
|
-
}) => {
|
|
315
|
-
const t = useTranslations2("Auth.forgotPassword");
|
|
316
|
-
const forgotPasswordSchema = useMemo(
|
|
317
|
-
() => z.object({
|
|
318
|
-
account: z.string().min(1, t("errors.accountRequired"))
|
|
319
|
-
}),
|
|
320
|
-
[t]
|
|
321
|
-
);
|
|
322
|
-
const form = useForm({
|
|
323
|
-
resolver: zodResolver(forgotPasswordSchema),
|
|
324
|
-
defaultValues: {
|
|
325
|
-
account: ""
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
const handleSubmit = form.handleSubmit(async (values) => {
|
|
329
|
-
await onSubmit(values);
|
|
330
|
-
});
|
|
331
|
-
return /* @__PURE__ */ jsx4(Form, { ...form, children: /* @__PURE__ */ jsxs3("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
332
|
-
/* @__PURE__ */ jsx4(
|
|
333
|
-
FormField,
|
|
334
|
-
{
|
|
335
|
-
control: form.control,
|
|
336
|
-
name: "account",
|
|
337
|
-
render: ({ field }) => /* @__PURE__ */ jsxs3(FormItem, { children: [
|
|
338
|
-
/* @__PURE__ */ jsx4(FormLabel, { children: t("form.accountLabel") }),
|
|
339
|
-
/* @__PURE__ */ jsx4(FormControl, { children: /* @__PURE__ */ jsx4(
|
|
340
|
-
Input,
|
|
341
|
-
{
|
|
342
|
-
type: "text",
|
|
343
|
-
placeholder: t("form.accountPlaceholder"),
|
|
344
|
-
...field
|
|
345
|
-
}
|
|
346
|
-
) }),
|
|
347
|
-
/* @__PURE__ */ jsx4(FormMessage, {})
|
|
348
|
-
] })
|
|
68
|
+
// src/utils/custom-fetch.ts
|
|
69
|
+
var createCustomFetch = (config) => {
|
|
70
|
+
return (input, init) => {
|
|
71
|
+
const baseUrl = config.baseURL;
|
|
72
|
+
if (input instanceof Request) {
|
|
73
|
+
const originalUrl = input.url;
|
|
74
|
+
const fullUrl2 = originalUrl.startsWith("http") ? originalUrl : `${baseUrl}${originalUrl}`;
|
|
75
|
+
if (originalUrl === fullUrl2) {
|
|
76
|
+
return fetch(input, {
|
|
77
|
+
credentials: "include"
|
|
78
|
+
});
|
|
349
79
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
80
|
+
const clonedRequest = input.clone();
|
|
81
|
+
const requestInit = {
|
|
82
|
+
method: clonedRequest.method,
|
|
83
|
+
headers: clonedRequest.headers,
|
|
84
|
+
credentials: "include"
|
|
85
|
+
};
|
|
86
|
+
if (clonedRequest.body !== null) {
|
|
87
|
+
requestInit.body = clonedRequest.body;
|
|
88
|
+
requestInit.duplex = "half";
|
|
89
|
+
}
|
|
90
|
+
return fetch(fullUrl2, requestInit);
|
|
91
|
+
}
|
|
92
|
+
const urlString = typeof input === "string" ? input : input.toString();
|
|
93
|
+
const fullUrl = urlString.startsWith("http") ? urlString : `${baseUrl}${urlString}`;
|
|
94
|
+
return fetch(fullUrl, {
|
|
95
|
+
...init,
|
|
96
|
+
headers: {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
...init?.headers
|
|
99
|
+
},
|
|
100
|
+
credentials: "include"
|
|
101
|
+
});
|
|
102
|
+
};
|
|
356
103
|
};
|
|
357
104
|
|
|
358
|
-
// src/
|
|
359
|
-
import {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
105
|
+
// src/provider.tsx
|
|
106
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
107
|
+
var SessionContext = createContext(null);
|
|
108
|
+
var ApiContext = createContext(null);
|
|
109
|
+
var ConfigContext = createContext(null);
|
|
110
|
+
var queryClient = new QueryClient({
|
|
111
|
+
defaultOptions: {
|
|
112
|
+
queries: {
|
|
113
|
+
staleTime: 1e3 * 60 * 5,
|
|
114
|
+
gcTime: 1e3 * 60 * 10,
|
|
115
|
+
retry: 1,
|
|
116
|
+
refetchOnWindowFocus: false
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
function useSession() {
|
|
121
|
+
const context = useContext(SessionContext);
|
|
374
122
|
if (!context) {
|
|
375
|
-
throw new Error("
|
|
123
|
+
throw new Error("useSession must be used within MesobAuthProvider");
|
|
376
124
|
}
|
|
377
125
|
return context;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
126
|
+
}
|
|
127
|
+
function useApi() {
|
|
128
|
+
const context = useContext(ApiContext);
|
|
129
|
+
if (!context) {
|
|
130
|
+
throw new Error("useApi must be used within MesobAuthProvider");
|
|
131
|
+
}
|
|
132
|
+
return context;
|
|
133
|
+
}
|
|
134
|
+
function useConfig() {
|
|
135
|
+
const context = useContext(ConfigContext);
|
|
136
|
+
if (!context) {
|
|
137
|
+
throw new Error("useConfig must be used within MesobAuthProvider");
|
|
138
|
+
}
|
|
139
|
+
return context;
|
|
140
|
+
}
|
|
141
|
+
function MesobAuthProvider({
|
|
142
|
+
config,
|
|
143
|
+
children
|
|
144
|
+
}) {
|
|
145
|
+
const mergedConfig = deepmerge(
|
|
146
|
+
{ ...defaultAuthClientConfig },
|
|
147
|
+
config
|
|
148
|
+
);
|
|
149
|
+
const api = createFetchClient({
|
|
150
|
+
baseUrl: mergedConfig.baseURL,
|
|
151
|
+
fetch: createCustomFetch(mergedConfig)
|
|
152
|
+
});
|
|
153
|
+
const hooks = createClient(api);
|
|
154
|
+
return /* @__PURE__ */ jsx2(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx2(AuthStateProvider, { config: mergedConfig, hooks, children }) });
|
|
155
|
+
}
|
|
156
|
+
function AuthStateProvider({
|
|
157
|
+
config,
|
|
158
|
+
hooks,
|
|
159
|
+
children
|
|
160
|
+
}) {
|
|
161
|
+
const [authState, setAuthState] = useState({
|
|
162
|
+
user: null,
|
|
163
|
+
session: null,
|
|
164
|
+
isLoading: false,
|
|
165
|
+
error: null
|
|
166
|
+
});
|
|
167
|
+
const {
|
|
168
|
+
data: sessionData,
|
|
169
|
+
isLoading: sessionLoading,
|
|
170
|
+
error: sessionError,
|
|
171
|
+
refetch
|
|
172
|
+
} = hooks.useQuery(
|
|
173
|
+
"get",
|
|
174
|
+
"/session",
|
|
175
|
+
{},
|
|
176
|
+
{
|
|
177
|
+
enabled: true,
|
|
178
|
+
refetchOnMount: true,
|
|
179
|
+
refetchOnWindowFocus: false,
|
|
180
|
+
refetchOnReconnect: false,
|
|
181
|
+
retry: false
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (sessionLoading) {
|
|
186
|
+
setAuthState((prev) => ({ ...prev, isLoading: true }));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (sessionError) {
|
|
190
|
+
setAuthState({
|
|
191
|
+
user: null,
|
|
192
|
+
session: null,
|
|
193
|
+
isLoading: false,
|
|
194
|
+
error: sessionError
|
|
195
|
+
});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (sessionData) {
|
|
199
|
+
setAuthState({
|
|
200
|
+
user: sessionData.user,
|
|
201
|
+
session: sessionData.session,
|
|
202
|
+
isLoading: false,
|
|
203
|
+
error: null
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
setAuthState({
|
|
208
|
+
user: null,
|
|
209
|
+
session: null,
|
|
210
|
+
isLoading: false,
|
|
211
|
+
error: null
|
|
212
|
+
});
|
|
213
|
+
}, [sessionData, sessionLoading, sessionError]);
|
|
214
|
+
const refresh = async () => {
|
|
215
|
+
await refetch();
|
|
216
|
+
};
|
|
217
|
+
const setAuth = (auth) => {
|
|
218
|
+
setAuthState({
|
|
219
|
+
user: auth.user,
|
|
220
|
+
session: auth.session,
|
|
221
|
+
isLoading: false,
|
|
222
|
+
error: null
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
const clearAuth = () => {
|
|
226
|
+
setAuthState({
|
|
227
|
+
user: null,
|
|
228
|
+
session: null,
|
|
229
|
+
isLoading: false,
|
|
230
|
+
error: null
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
const signOutMutation = hooks.useMutation("post", "/sign-out");
|
|
234
|
+
const signOut = async () => {
|
|
385
235
|
try {
|
|
386
|
-
|
|
387
|
-
setError(null);
|
|
388
|
-
const data = await client.getSession();
|
|
389
|
-
setUser(data.user);
|
|
390
|
-
setSession(data.session);
|
|
391
|
-
} catch (err) {
|
|
392
|
-
setError(
|
|
393
|
-
err instanceof Error ? err : new Error("Failed to fetch session")
|
|
394
|
-
);
|
|
395
|
-
setUser(null);
|
|
396
|
-
setSession(null);
|
|
236
|
+
await signOutMutation.mutateAsync({});
|
|
397
237
|
} finally {
|
|
398
|
-
|
|
238
|
+
clearAuth();
|
|
399
239
|
}
|
|
400
|
-
}
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
setError(null);
|
|
405
|
-
setLoading(false);
|
|
406
|
-
}, []);
|
|
407
|
-
useEffect2(() => {
|
|
408
|
-
refresh();
|
|
409
|
-
}, [refresh]);
|
|
410
|
-
return /* @__PURE__ */ jsx5(
|
|
411
|
-
AuthContext.Provider,
|
|
240
|
+
};
|
|
241
|
+
const t = createTranslator(config.messages || {});
|
|
242
|
+
return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value: { config, t }, children: /* @__PURE__ */ jsx2(ApiContext.Provider, { value: { hooks, setAuth, clearAuth, refresh }, children: /* @__PURE__ */ jsx2(
|
|
243
|
+
SessionContext.Provider,
|
|
412
244
|
{
|
|
413
245
|
value: {
|
|
414
|
-
user,
|
|
415
|
-
session,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
246
|
+
user: authState.user,
|
|
247
|
+
session: authState.session,
|
|
248
|
+
isLoading: authState.isLoading,
|
|
249
|
+
isAuthenticated: !!authState.user && !!authState.session,
|
|
250
|
+
error: authState.error,
|
|
419
251
|
refresh,
|
|
420
|
-
|
|
252
|
+
signOut
|
|
421
253
|
},
|
|
422
254
|
children
|
|
423
255
|
}
|
|
424
|
-
);
|
|
425
|
-
}
|
|
256
|
+
) }) });
|
|
257
|
+
}
|
|
426
258
|
|
|
427
259
|
// src/constants/auth.error.codes.ts
|
|
428
260
|
var AUTH_ERROR_MAPPING = {
|
|
@@ -474,57 +306,181 @@ var AUTH_ERROR_MAPPING = {
|
|
|
474
306
|
var validCodes = Object.keys(AUTH_ERROR_MAPPING);
|
|
475
307
|
|
|
476
308
|
// src/utils/handle-error.ts
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
|
|
489
|
-
const mapping = AUTH_ERROR_MAPPING[errorCode];
|
|
490
|
-
setError({
|
|
491
|
-
title: mapping.title,
|
|
492
|
-
description: mapping.description
|
|
493
|
-
});
|
|
494
|
-
return;
|
|
309
|
+
function isAuthError(err) {
|
|
310
|
+
return typeof err === "object" && err !== null && "message" in err && typeof err.message === "string";
|
|
311
|
+
}
|
|
312
|
+
function extractErrorCode(err) {
|
|
313
|
+
if (err.code && validCodes.includes(err.code)) {
|
|
314
|
+
return err.code;
|
|
315
|
+
}
|
|
316
|
+
if (err.message) {
|
|
317
|
+
const messageUpper = err.message.toUpperCase().trim();
|
|
318
|
+
if (validCodes.includes(messageUpper)) {
|
|
319
|
+
return messageUpper;
|
|
495
320
|
}
|
|
321
|
+
}
|
|
322
|
+
return "";
|
|
323
|
+
}
|
|
324
|
+
function handleAuthError(err, setError, t) {
|
|
325
|
+
const errorCode = extractErrorCode(err);
|
|
326
|
+
if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
|
|
327
|
+
const mapping = AUTH_ERROR_MAPPING[errorCode];
|
|
496
328
|
setError({
|
|
497
|
-
title:
|
|
498
|
-
|
|
499
|
-
description: err.message || t("errors.fallback")
|
|
329
|
+
title: mapping.title,
|
|
330
|
+
description: mapping.description
|
|
500
331
|
});
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
setError({
|
|
335
|
+
title: t("errors.fallback"),
|
|
336
|
+
description: err.message || t("errors.fallback")
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
function handleGenericError(err, setError, t) {
|
|
340
|
+
const message = err instanceof Error ? err.message : t("errors.fallback");
|
|
341
|
+
setError({
|
|
342
|
+
title: "Error",
|
|
343
|
+
description: message
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
var handleError = (err, setError, t) => {
|
|
347
|
+
if (isAuthError(err)) {
|
|
348
|
+
handleAuthError(err, setError, t);
|
|
501
349
|
} else {
|
|
502
|
-
|
|
503
|
-
setError({
|
|
504
|
-
title: "Error",
|
|
505
|
-
description: message
|
|
506
|
-
});
|
|
350
|
+
handleGenericError(err, setError, t);
|
|
507
351
|
}
|
|
508
352
|
};
|
|
509
353
|
|
|
510
|
-
// src/components/auth/
|
|
511
|
-
import { jsx as
|
|
512
|
-
var
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
354
|
+
// src/components/auth/auth-page-layout.tsx
|
|
355
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
356
|
+
var AuthPageLayout = ({
|
|
357
|
+
title,
|
|
358
|
+
description,
|
|
359
|
+
children,
|
|
360
|
+
footer,
|
|
516
361
|
logoImage
|
|
517
362
|
}) => {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
363
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
364
|
+
/* @__PURE__ */ jsx3("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx3("img", { src: logoImage || "", alt: "Mesob", width: 42, height: 42 }) }),
|
|
365
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
366
|
+
/* @__PURE__ */ jsx3("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
367
|
+
description && /* @__PURE__ */ jsx3("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
368
|
+
] }),
|
|
369
|
+
children,
|
|
370
|
+
/* @__PURE__ */ jsx3("div", { className: "mt-2 w-full", children: footer && /* @__PURE__ */ jsx3("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
|
|
371
|
+
] });
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// src/components/auth/forgot-password.tsx
|
|
375
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
376
|
+
import { Button } from "@mesob/ui/components/button";
|
|
377
|
+
import {
|
|
378
|
+
Field,
|
|
379
|
+
FieldError,
|
|
380
|
+
FieldGroup,
|
|
381
|
+
FieldLabel
|
|
382
|
+
} from "@mesob/ui/components/field";
|
|
383
|
+
import { Input } from "@mesob/ui/components/input";
|
|
384
|
+
import { Spinner } from "@mesob/ui/components/spinner";
|
|
385
|
+
import { Controller, useForm } from "react-hook-form";
|
|
386
|
+
import { z } from "zod";
|
|
387
|
+
|
|
388
|
+
// src/hooks/use-translator.ts
|
|
389
|
+
function useTranslator(namespace) {
|
|
390
|
+
const { config } = useConfig();
|
|
391
|
+
return createTranslator(config.messages || {}, namespace);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/components/auth/forgot-password.tsx
|
|
395
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
396
|
+
var forgotPasswordSchema = (t) => z.object({
|
|
397
|
+
account: z.string().min(1, t("errors.accountRequired"))
|
|
398
|
+
});
|
|
399
|
+
var ForgotPassword = ({
|
|
400
|
+
onSubmit,
|
|
401
|
+
isLoading = false
|
|
402
|
+
}) => {
|
|
403
|
+
const t = useTranslator("Auth.forgotPassword");
|
|
404
|
+
const form = useForm({
|
|
405
|
+
resolver: zodResolver(forgotPasswordSchema(t)),
|
|
406
|
+
defaultValues: {
|
|
407
|
+
account: ""
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
411
|
+
await onSubmit(values);
|
|
412
|
+
});
|
|
413
|
+
return /* @__PURE__ */ jsxs2("form", { id: "forgot-password-form", onSubmit: handleSubmit, children: [
|
|
414
|
+
/* @__PURE__ */ jsx4(FieldGroup, { children: /* @__PURE__ */ jsx4(
|
|
415
|
+
Controller,
|
|
416
|
+
{
|
|
417
|
+
name: "account",
|
|
418
|
+
control: form.control,
|
|
419
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
|
|
420
|
+
/* @__PURE__ */ jsx4(FieldLabel, { htmlFor: "forgot-password-account", children: t("form.accountLabel") }),
|
|
421
|
+
/* @__PURE__ */ jsx4(
|
|
422
|
+
Input,
|
|
423
|
+
{
|
|
424
|
+
...field,
|
|
425
|
+
id: "forgot-password-account",
|
|
426
|
+
type: "text",
|
|
427
|
+
placeholder: t("form.accountPlaceholder"),
|
|
428
|
+
"aria-invalid": fieldState.invalid
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
fieldState.invalid && /* @__PURE__ */ jsx4(FieldError, { errors: [fieldState.error] })
|
|
432
|
+
] })
|
|
433
|
+
}
|
|
434
|
+
) }),
|
|
435
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-4", children: /* @__PURE__ */ jsxs2(
|
|
436
|
+
Button,
|
|
437
|
+
{
|
|
438
|
+
type: "submit",
|
|
439
|
+
form: "forgot-password-form",
|
|
440
|
+
className: "w-full",
|
|
441
|
+
disabled: isLoading,
|
|
442
|
+
children: [
|
|
443
|
+
isLoading && /* @__PURE__ */ jsx4(Spinner, {}),
|
|
444
|
+
isLoading ? t("form.submitting") : t("form.submit")
|
|
445
|
+
]
|
|
446
|
+
}
|
|
447
|
+
) })
|
|
448
|
+
] });
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// src/components/auth/pages/forgot-password-page.tsx
|
|
452
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
453
|
+
var ForgotPasswordPage = (_props = {}) => {
|
|
454
|
+
const { hooks } = useApi();
|
|
455
|
+
const { config } = useConfig();
|
|
456
|
+
const t = createTranslator(config.messages || {}, "Auth.forgotPassword");
|
|
457
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
458
|
+
const [error, setError] = useState2(null);
|
|
459
|
+
const forgotPasswordMutation = hooks.useMutation("post", "/password/forgot");
|
|
460
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
461
|
+
const Link = config.navigation?.linkComponent;
|
|
462
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
463
|
+
if (typeof window !== "undefined") {
|
|
464
|
+
window.location.href = path;
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
const logoImage = config.ui.logoImage;
|
|
468
|
+
useEffect2(() => {
|
|
469
|
+
if (error) {
|
|
470
|
+
toast.error(error.title || "Error", {
|
|
471
|
+
description: error.description
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}, [error]);
|
|
523
475
|
const handleSubmit = async (values) => {
|
|
524
476
|
setIsLoading(true);
|
|
525
477
|
setError(null);
|
|
526
478
|
try {
|
|
527
|
-
const res = await
|
|
479
|
+
const res = await forgotPasswordMutation.mutateAsync({
|
|
480
|
+
body: {
|
|
481
|
+
identifier: values.account
|
|
482
|
+
}
|
|
483
|
+
});
|
|
528
484
|
if ("verificationId" in res && res.verificationId) {
|
|
529
485
|
onNavigate(`/auth/reset-password?verificationId=${res.verificationId}`);
|
|
530
486
|
} else {
|
|
@@ -541,14 +497,21 @@ var ForgotPasswordPage = ({
|
|
|
541
497
|
const handleBack = () => {
|
|
542
498
|
onNavigate(signInLink);
|
|
543
499
|
};
|
|
544
|
-
|
|
500
|
+
let errorContent = null;
|
|
501
|
+
if (error) {
|
|
502
|
+
if (typeof error === "string") {
|
|
503
|
+
errorContent = { title: "Error", description: error };
|
|
504
|
+
} else {
|
|
505
|
+
errorContent = error;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return /* @__PURE__ */ jsxs3(
|
|
545
509
|
AuthPageLayout,
|
|
546
510
|
{
|
|
547
511
|
title: t("title"),
|
|
548
512
|
description: t("description"),
|
|
549
|
-
error,
|
|
550
513
|
logoImage,
|
|
551
|
-
footer: Link ? /* @__PURE__ */
|
|
514
|
+
footer: Link ? /* @__PURE__ */ jsx5(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }) : /* @__PURE__ */ jsx5(
|
|
552
515
|
"a",
|
|
553
516
|
{
|
|
554
517
|
href: signInLink,
|
|
@@ -560,65 +523,72 @@ var ForgotPasswordPage = ({
|
|
|
560
523
|
children: t("footer.backToSignIn")
|
|
561
524
|
}
|
|
562
525
|
),
|
|
563
|
-
children:
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
526
|
+
children: [
|
|
527
|
+
/* @__PURE__ */ jsx5(
|
|
528
|
+
ForgotPassword,
|
|
529
|
+
{
|
|
530
|
+
onSubmit: handleSubmit,
|
|
531
|
+
isLoading: isLoading || forgotPasswordMutation.isPending,
|
|
532
|
+
onBack: handleBack
|
|
533
|
+
}
|
|
534
|
+
),
|
|
535
|
+
errorContent && /* @__PURE__ */ jsxs3(Alert, { variant: "destructive", className: "mt-4", children: [
|
|
536
|
+
/* @__PURE__ */ jsx5(IconAlertCircle, { className: "h-4 w-4" }),
|
|
537
|
+
/* @__PURE__ */ jsx5(AlertTitle, { children: errorContent.title }),
|
|
538
|
+
/* @__PURE__ */ jsx5(AlertDescription, { children: errorContent.description })
|
|
539
|
+
] })
|
|
540
|
+
]
|
|
571
541
|
}
|
|
572
542
|
);
|
|
573
543
|
};
|
|
574
544
|
|
|
575
545
|
// src/components/auth/pages/reset-password-page.tsx
|
|
576
|
-
import {
|
|
577
|
-
|
|
546
|
+
import {
|
|
547
|
+
Alert as Alert2,
|
|
548
|
+
AlertDescription as AlertDescription2,
|
|
549
|
+
AlertTitle as AlertTitle2
|
|
550
|
+
} from "@mesob/ui/components/alert";
|
|
551
|
+
import { toast as toast2 } from "@mesob/ui/components/sonner";
|
|
552
|
+
import { IconAlertCircle as IconAlertCircle2 } from "@tabler/icons-react";
|
|
553
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
578
554
|
|
|
579
555
|
// src/components/auth/reset-password-form.tsx
|
|
580
556
|
import { zodResolver as zodResolver2 } from "@hookform/resolvers/zod";
|
|
581
|
-
import { Button as
|
|
557
|
+
import { Button as Button2 } from "@mesob/ui/components/button";
|
|
582
558
|
import {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
FormMessage as FormMessage2
|
|
589
|
-
} from "@mesob/ui/components/form";
|
|
559
|
+
Field as Field2,
|
|
560
|
+
FieldError as FieldError2,
|
|
561
|
+
FieldGroup as FieldGroup2,
|
|
562
|
+
FieldLabel as FieldLabel2
|
|
563
|
+
} from "@mesob/ui/components/field";
|
|
590
564
|
import { Input as Input2 } from "@mesob/ui/components/input";
|
|
591
565
|
import {
|
|
592
566
|
InputOTP,
|
|
593
567
|
InputOTPGroup,
|
|
594
568
|
InputOTPSlot
|
|
595
569
|
} from "@mesob/ui/components/input-otp";
|
|
596
|
-
import { Spinner as
|
|
570
|
+
import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
|
|
597
571
|
import { IconEye, IconEyeOff } from "@tabler/icons-react";
|
|
598
|
-
import {
|
|
599
|
-
import {
|
|
600
|
-
import { useForm as useForm2 } from "react-hook-form";
|
|
572
|
+
import { useState as useState3 } from "react";
|
|
573
|
+
import { Controller as Controller2, useForm as useForm2 } from "react-hook-form";
|
|
601
574
|
import { z as z2 } from "zod";
|
|
602
|
-
import { jsx as
|
|
575
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
576
|
+
var resetPasswordSchema = (t) => z2.object({
|
|
577
|
+
code: z2.string().length(6, t("errors.codeLength")),
|
|
578
|
+
password: z2.string().min(8, t("errors.passwordLength")),
|
|
579
|
+
confirmPassword: z2.string()
|
|
580
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
581
|
+
message: t("errors.passwordsMismatch"),
|
|
582
|
+
path: ["confirmPassword"]
|
|
583
|
+
});
|
|
603
584
|
var ResetPasswordForm = ({
|
|
604
585
|
onSubmit,
|
|
605
586
|
isLoading = false
|
|
606
587
|
}) => {
|
|
607
|
-
const t =
|
|
608
|
-
const [showPassword, setShowPassword] =
|
|
609
|
-
const resetPasswordSchema = useMemo2(
|
|
610
|
-
() => z2.object({
|
|
611
|
-
code: z2.string().length(6, t("errors.codeLength")),
|
|
612
|
-
password: z2.string().min(8, t("errors.passwordLength")),
|
|
613
|
-
confirmPassword: z2.string()
|
|
614
|
-
}).refine((data) => data.password === data.confirmPassword, {
|
|
615
|
-
message: t("errors.passwordsMismatch"),
|
|
616
|
-
path: ["confirmPassword"]
|
|
617
|
-
}),
|
|
618
|
-
[t]
|
|
619
|
-
);
|
|
588
|
+
const t = useTranslator("Auth.resetPassword");
|
|
589
|
+
const [showPassword, setShowPassword] = useState3(false);
|
|
620
590
|
const form = useForm2({
|
|
621
|
-
resolver: zodResolver2(resetPasswordSchema),
|
|
591
|
+
resolver: zodResolver2(resetPasswordSchema(t)),
|
|
622
592
|
defaultValues: {
|
|
623
593
|
code: "",
|
|
624
594
|
password: "",
|
|
@@ -628,110 +598,149 @@ var ResetPasswordForm = ({
|
|
|
628
598
|
const handleSubmit = form.handleSubmit(async (values) => {
|
|
629
599
|
await onSubmit(values);
|
|
630
600
|
});
|
|
631
|
-
return /* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
|
|
642
|
-
/* @__PURE__ */ jsx7(InputOTPSlot, { className: "h-12", index: 2 }),
|
|
643
|
-
/* @__PURE__ */ jsx7(InputOTPSlot, { className: "h-12", index: 3 }),
|
|
644
|
-
/* @__PURE__ */ jsx7(InputOTPSlot, { className: "h-12", index: 4 }),
|
|
645
|
-
/* @__PURE__ */ jsx7(InputOTPSlot, { className: "h-12", index: 5 })
|
|
646
|
-
] }) }) }) }),
|
|
647
|
-
/* @__PURE__ */ jsx7(FormMessage2, {})
|
|
648
|
-
] })
|
|
649
|
-
}
|
|
650
|
-
),
|
|
651
|
-
/* @__PURE__ */ jsx7(
|
|
652
|
-
FormField2,
|
|
653
|
-
{
|
|
654
|
-
control: form.control,
|
|
655
|
-
name: "password",
|
|
656
|
-
render: ({ field }) => /* @__PURE__ */ jsxs4(FormItem2, { children: [
|
|
657
|
-
/* @__PURE__ */ jsx7(FormLabel2, { children: t("form.passwordLabel") }),
|
|
658
|
-
/* @__PURE__ */ jsx7(FormControl2, { children: /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
659
|
-
/* @__PURE__ */ jsx7(
|
|
660
|
-
Input2,
|
|
661
|
-
{
|
|
662
|
-
type: showPassword ? "text" : "password",
|
|
663
|
-
placeholder: t("form.passwordPlaceholder"),
|
|
664
|
-
...field
|
|
665
|
-
}
|
|
666
|
-
),
|
|
667
|
-
/* @__PURE__ */ jsx7(
|
|
668
|
-
"button",
|
|
601
|
+
return /* @__PURE__ */ jsxs4("form", { id: "reset-password-form", onSubmit: handleSubmit, children: [
|
|
602
|
+
/* @__PURE__ */ jsxs4(FieldGroup2, { children: [
|
|
603
|
+
/* @__PURE__ */ jsx6(
|
|
604
|
+
Controller2,
|
|
605
|
+
{
|
|
606
|
+
name: "code",
|
|
607
|
+
control: form.control,
|
|
608
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs4(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
609
|
+
/* @__PURE__ */ jsx6("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx6(FieldLabel2, { children: t("form.codeLabel") }) }),
|
|
610
|
+
/* @__PURE__ */ jsx6("div", { className: "flex mt-2 justify-center", children: /* @__PURE__ */ jsx6(
|
|
611
|
+
InputOTP,
|
|
669
612
|
{
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
613
|
+
maxLength: 6,
|
|
614
|
+
value: field.value,
|
|
615
|
+
onChange: field.onChange,
|
|
616
|
+
onBlur: field.onBlur,
|
|
617
|
+
containerClassName: "gap-4",
|
|
618
|
+
"aria-invalid": fieldState.invalid,
|
|
619
|
+
children: /* @__PURE__ */ jsxs4(InputOTPGroup, { className: "gap-3 *:data-[slot=input-otp-slot]:h-12 *:data-[slot=input-otp-slot]:w-12 *:data-[slot=input-otp-slot]:rounded-md *:data-[slot=input-otp-slot]:border *:data-[slot=input-otp-slot]:text-xl", children: [
|
|
620
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 0 }),
|
|
621
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 1 }),
|
|
622
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 2 }),
|
|
623
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 3 }),
|
|
624
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 4 }),
|
|
625
|
+
/* @__PURE__ */ jsx6(InputOTPSlot, { className: "h-12", index: 5 })
|
|
626
|
+
] })
|
|
674
627
|
}
|
|
675
|
-
)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
628
|
+
) }),
|
|
629
|
+
fieldState.invalid && /* @__PURE__ */ jsx6(FieldError2, { errors: [fieldState.error] })
|
|
630
|
+
] })
|
|
631
|
+
}
|
|
632
|
+
),
|
|
633
|
+
/* @__PURE__ */ jsx6(
|
|
634
|
+
Controller2,
|
|
635
|
+
{
|
|
636
|
+
name: "password",
|
|
637
|
+
control: form.control,
|
|
638
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs4(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
639
|
+
/* @__PURE__ */ jsx6(FieldLabel2, { htmlFor: "reset-password-password", children: t("form.passwordLabel") }),
|
|
640
|
+
/* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
641
|
+
/* @__PURE__ */ jsx6(
|
|
642
|
+
Input2,
|
|
643
|
+
{
|
|
644
|
+
...field,
|
|
645
|
+
id: "reset-password-password",
|
|
646
|
+
type: showPassword ? "text" : "password",
|
|
647
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
648
|
+
"aria-invalid": fieldState.invalid
|
|
649
|
+
}
|
|
650
|
+
),
|
|
651
|
+
/* @__PURE__ */ jsx6(
|
|
652
|
+
"button",
|
|
653
|
+
{
|
|
654
|
+
type: "button",
|
|
655
|
+
onClick: () => setShowPassword(!showPassword),
|
|
656
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
657
|
+
children: showPassword ? /* @__PURE__ */ jsx6(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx6(IconEye, { className: "h-4 w-4" })
|
|
658
|
+
}
|
|
659
|
+
)
|
|
660
|
+
] }),
|
|
661
|
+
fieldState.invalid && /* @__PURE__ */ jsx6(FieldError2, { errors: [fieldState.error] })
|
|
662
|
+
] })
|
|
663
|
+
}
|
|
664
|
+
),
|
|
665
|
+
/* @__PURE__ */ jsx6(
|
|
666
|
+
Controller2,
|
|
667
|
+
{
|
|
668
|
+
name: "confirmPassword",
|
|
669
|
+
control: form.control,
|
|
670
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs4(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
671
|
+
/* @__PURE__ */ jsx6(FieldLabel2, { htmlFor: "reset-password-confirmPassword", children: t("form.confirmPasswordLabel") }),
|
|
672
|
+
/* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
673
|
+
/* @__PURE__ */ jsx6(
|
|
674
|
+
Input2,
|
|
675
|
+
{
|
|
676
|
+
...field,
|
|
677
|
+
id: "reset-password-confirmPassword",
|
|
678
|
+
type: showPassword ? "text" : "password",
|
|
679
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
680
|
+
"aria-invalid": fieldState.invalid
|
|
681
|
+
}
|
|
682
|
+
),
|
|
683
|
+
/* @__PURE__ */ jsx6(
|
|
684
|
+
"button",
|
|
685
|
+
{
|
|
686
|
+
type: "button",
|
|
687
|
+
onClick: () => setShowPassword(!showPassword),
|
|
688
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
689
|
+
children: showPassword ? /* @__PURE__ */ jsx6(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx6(IconEye, { className: "h-4 w-4" })
|
|
690
|
+
}
|
|
691
|
+
)
|
|
692
|
+
] }),
|
|
693
|
+
fieldState.invalid && /* @__PURE__ */ jsx6(FieldError2, { errors: [fieldState.error] })
|
|
694
|
+
] })
|
|
695
|
+
}
|
|
696
|
+
)
|
|
697
|
+
] }),
|
|
698
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsxs4(
|
|
699
|
+
Button2,
|
|
683
700
|
{
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
type: showPassword ? "text" : "password",
|
|
693
|
-
placeholder: t("form.passwordPlaceholder"),
|
|
694
|
-
...field
|
|
695
|
-
}
|
|
696
|
-
),
|
|
697
|
-
/* @__PURE__ */ jsx7(
|
|
698
|
-
"button",
|
|
699
|
-
{
|
|
700
|
-
type: "button",
|
|
701
|
-
onClick: () => setShowPassword(!showPassword),
|
|
702
|
-
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
703
|
-
children: showPassword ? /* @__PURE__ */ jsx7(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(IconEye, { className: "h-4 w-4" })
|
|
704
|
-
}
|
|
705
|
-
)
|
|
706
|
-
] }) }),
|
|
707
|
-
/* @__PURE__ */ jsx7(FormMessage2, {})
|
|
708
|
-
] })
|
|
701
|
+
type: "submit",
|
|
702
|
+
form: "reset-password-form",
|
|
703
|
+
className: "w-full",
|
|
704
|
+
disabled: isLoading,
|
|
705
|
+
children: [
|
|
706
|
+
isLoading && /* @__PURE__ */ jsx6(Spinner2, {}),
|
|
707
|
+
isLoading ? t("form.submitting") : t("form.submit")
|
|
708
|
+
]
|
|
709
709
|
}
|
|
710
|
-
)
|
|
711
|
-
|
|
712
|
-
isLoading && /* @__PURE__ */ jsx7(Spinner3, {}),
|
|
713
|
-
isLoading ? t("form.submitting") : t("form.submit")
|
|
714
|
-
] })
|
|
715
|
-
] }) });
|
|
710
|
+
) })
|
|
711
|
+
] });
|
|
716
712
|
};
|
|
717
713
|
|
|
718
714
|
// src/components/auth/pages/reset-password-page.tsx
|
|
719
|
-
import { jsx as
|
|
715
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
720
716
|
var ResetPasswordPage = ({
|
|
721
717
|
verificationId,
|
|
722
|
-
onNavigate,
|
|
723
|
-
linkComponent: Link,
|
|
724
|
-
links,
|
|
725
|
-
logoImage,
|
|
726
718
|
redirectUrl
|
|
727
719
|
}) => {
|
|
728
|
-
const
|
|
729
|
-
const
|
|
730
|
-
const
|
|
731
|
-
const
|
|
732
|
-
const [
|
|
733
|
-
const
|
|
734
|
-
const
|
|
720
|
+
const { hooks, refresh } = useApi();
|
|
721
|
+
const { config } = useConfig();
|
|
722
|
+
const t = createTranslator(config.messages || {}, "Auth.resetPassword");
|
|
723
|
+
const common = createTranslator(config.messages || {}, "Common");
|
|
724
|
+
const [isLoading, setIsLoading] = useState4(false);
|
|
725
|
+
const [error, setError] = useState4(null);
|
|
726
|
+
const resetPasswordMutation = hooks.useMutation("post", "/password/reset");
|
|
727
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
728
|
+
const forgotPasswordLink = config.navigation?.links?.forgotPassword || "/auth/forgot-password";
|
|
729
|
+
const Link = config.navigation?.linkComponent;
|
|
730
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
731
|
+
if (typeof window !== "undefined") {
|
|
732
|
+
window.location.href = path;
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
const logoImage = config.ui.logoImage;
|
|
736
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
737
|
+
useEffect3(() => {
|
|
738
|
+
if (error) {
|
|
739
|
+
toast2.error(error.title || "Error", {
|
|
740
|
+
description: error.description
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
}, [error]);
|
|
735
744
|
const handleSubmit = async (values) => {
|
|
736
745
|
if (!verificationId) {
|
|
737
746
|
setError({
|
|
@@ -743,13 +752,15 @@ var ResetPasswordPage = ({
|
|
|
743
752
|
setIsLoading(true);
|
|
744
753
|
setError(null);
|
|
745
754
|
try {
|
|
746
|
-
await
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
755
|
+
await resetPasswordMutation.mutateAsync({
|
|
756
|
+
body: {
|
|
757
|
+
verificationId,
|
|
758
|
+
code: values.code,
|
|
759
|
+
password: values.password
|
|
760
|
+
}
|
|
750
761
|
});
|
|
751
762
|
await refresh();
|
|
752
|
-
onNavigate(
|
|
763
|
+
onNavigate(defaultRedirect);
|
|
753
764
|
} catch (err) {
|
|
754
765
|
handleError(err, setError, t);
|
|
755
766
|
} finally {
|
|
@@ -757,20 +768,20 @@ var ResetPasswordPage = ({
|
|
|
757
768
|
}
|
|
758
769
|
};
|
|
759
770
|
if (!verificationId) {
|
|
760
|
-
return /* @__PURE__ */
|
|
771
|
+
return /* @__PURE__ */ jsx7(
|
|
761
772
|
AuthPageLayout,
|
|
762
773
|
{
|
|
763
774
|
title: common("invalidLinkTitle"),
|
|
764
775
|
description: common("invalidLinkDescription"),
|
|
765
776
|
logoImage,
|
|
766
|
-
footer: Link ? /* @__PURE__ */
|
|
777
|
+
footer: Link ? /* @__PURE__ */ jsx7(
|
|
767
778
|
Link,
|
|
768
779
|
{
|
|
769
780
|
href: forgotPasswordLink,
|
|
770
781
|
className: "text-primary hover:underline",
|
|
771
782
|
children: t("footer.requestNew")
|
|
772
783
|
}
|
|
773
|
-
) : /* @__PURE__ */
|
|
784
|
+
) : /* @__PURE__ */ jsx7(
|
|
774
785
|
"a",
|
|
775
786
|
{
|
|
776
787
|
href: forgotPasswordLink,
|
|
@@ -782,20 +793,27 @@ var ResetPasswordPage = ({
|
|
|
782
793
|
children: t("footer.requestNew")
|
|
783
794
|
}
|
|
784
795
|
),
|
|
785
|
-
children: /* @__PURE__ */
|
|
796
|
+
children: /* @__PURE__ */ jsx7("div", {})
|
|
786
797
|
}
|
|
787
798
|
);
|
|
788
799
|
}
|
|
789
|
-
|
|
800
|
+
let errorContent = null;
|
|
801
|
+
if (error) {
|
|
802
|
+
if (typeof error === "string") {
|
|
803
|
+
errorContent = { title: "Error", description: error };
|
|
804
|
+
} else {
|
|
805
|
+
errorContent = error;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return /* @__PURE__ */ jsxs5(
|
|
790
809
|
AuthPageLayout,
|
|
791
810
|
{
|
|
792
811
|
title: t("title"),
|
|
793
812
|
description: t("description"),
|
|
794
|
-
error,
|
|
795
813
|
logoImage,
|
|
796
814
|
footer: Link ? /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between w-full gap-2", children: [
|
|
797
|
-
/* @__PURE__ */
|
|
798
|
-
/* @__PURE__ */
|
|
815
|
+
/* @__PURE__ */ jsx7(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }),
|
|
816
|
+
/* @__PURE__ */ jsx7(
|
|
799
817
|
Link,
|
|
800
818
|
{
|
|
801
819
|
href: forgotPasswordLink,
|
|
@@ -804,7 +822,7 @@ var ResetPasswordPage = ({
|
|
|
804
822
|
}
|
|
805
823
|
)
|
|
806
824
|
] }) : /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between w-full gap-2", children: [
|
|
807
|
-
/* @__PURE__ */
|
|
825
|
+
/* @__PURE__ */ jsx7(
|
|
808
826
|
"a",
|
|
809
827
|
{
|
|
810
828
|
href: forgotPasswordLink,
|
|
@@ -816,7 +834,7 @@ var ResetPasswordPage = ({
|
|
|
816
834
|
children: t("footer.backToSignIn")
|
|
817
835
|
}
|
|
818
836
|
),
|
|
819
|
-
/* @__PURE__ */
|
|
837
|
+
/* @__PURE__ */ jsx7(
|
|
820
838
|
"a",
|
|
821
839
|
{
|
|
822
840
|
href: forgotPasswordLink,
|
|
@@ -829,40 +847,50 @@ var ResetPasswordPage = ({
|
|
|
829
847
|
}
|
|
830
848
|
)
|
|
831
849
|
] }),
|
|
832
|
-
children:
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
850
|
+
children: [
|
|
851
|
+
/* @__PURE__ */ jsx7(
|
|
852
|
+
ResetPasswordForm,
|
|
853
|
+
{
|
|
854
|
+
verificationId,
|
|
855
|
+
onSubmit: handleSubmit,
|
|
856
|
+
isLoading: isLoading || resetPasswordMutation.isPending,
|
|
857
|
+
error
|
|
858
|
+
}
|
|
859
|
+
),
|
|
860
|
+
errorContent && /* @__PURE__ */ jsxs5(Alert2, { variant: "destructive", className: "mt-4", children: [
|
|
861
|
+
/* @__PURE__ */ jsx7(IconAlertCircle2, { className: "h-4 w-4" }),
|
|
862
|
+
/* @__PURE__ */ jsx7(AlertTitle2, { children: errorContent.title }),
|
|
863
|
+
/* @__PURE__ */ jsx7(AlertDescription2, { children: errorContent.description })
|
|
864
|
+
] })
|
|
865
|
+
]
|
|
841
866
|
}
|
|
842
867
|
);
|
|
843
868
|
};
|
|
844
869
|
|
|
845
870
|
// src/components/auth/pages/sign-in-page.tsx
|
|
846
|
-
import {
|
|
847
|
-
|
|
871
|
+
import {
|
|
872
|
+
Alert as Alert3,
|
|
873
|
+
AlertDescription as AlertDescription3,
|
|
874
|
+
AlertTitle as AlertTitle3
|
|
875
|
+
} from "@mesob/ui/components/alert";
|
|
876
|
+
import { toast as toast3 } from "@mesob/ui/components/sonner";
|
|
877
|
+
import { IconAlertCircle as IconAlertCircle3 } from "@tabler/icons-react";
|
|
878
|
+
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
848
879
|
|
|
849
880
|
// src/components/auth/sign-in.tsx
|
|
850
881
|
import { zodResolver as zodResolver3 } from "@hookform/resolvers/zod";
|
|
851
|
-
import { Button as
|
|
882
|
+
import { Button as Button3 } from "@mesob/ui/components/button";
|
|
852
883
|
import {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
FormMessage as FormMessage3
|
|
859
|
-
} from "@mesob/ui/components/form";
|
|
884
|
+
Field as Field3,
|
|
885
|
+
FieldError as FieldError3,
|
|
886
|
+
FieldGroup as FieldGroup3,
|
|
887
|
+
FieldLabel as FieldLabel3
|
|
888
|
+
} from "@mesob/ui/components/field";
|
|
860
889
|
import { Input as Input3 } from "@mesob/ui/components/input";
|
|
861
|
-
import { Spinner as
|
|
890
|
+
import { Spinner as Spinner3 } from "@mesob/ui/components/spinner";
|
|
862
891
|
import { IconEye as IconEye2, IconEyeOff as IconEyeOff2 } from "@tabler/icons-react";
|
|
863
|
-
import {
|
|
864
|
-
import {
|
|
865
|
-
import { useForm as useForm3 } from "react-hook-form";
|
|
892
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
893
|
+
import { Controller as Controller3, useForm as useForm3 } from "react-hook-form";
|
|
866
894
|
import { z as z3 } from "zod";
|
|
867
895
|
|
|
868
896
|
// src/utils/normalize-phone.ts
|
|
@@ -884,183 +912,256 @@ function normalizePhone(phone) {
|
|
|
884
912
|
}
|
|
885
913
|
|
|
886
914
|
// src/components/auth/sign-in.tsx
|
|
887
|
-
import { jsx as
|
|
915
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
916
|
+
var identifierSchema = (t) => z3.object({
|
|
917
|
+
identifier: z3.string().trim().min(1, { message: t("errors.requiredField") }).refine(
|
|
918
|
+
(val) => {
|
|
919
|
+
const isEmail = z3.email().safeParse(val).success;
|
|
920
|
+
const phoneRegex = /^(\+2519|2519|09)\d{8}$/;
|
|
921
|
+
const isPhone4 = phoneRegex.test(val);
|
|
922
|
+
return isEmail || isPhone4;
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
message: t("errors.invalidEmailOrPhone")
|
|
926
|
+
}
|
|
927
|
+
)
|
|
928
|
+
});
|
|
929
|
+
var passwordSchema = (t) => z3.object({
|
|
930
|
+
password: z3.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError"))
|
|
931
|
+
});
|
|
888
932
|
var SignIn = ({
|
|
889
933
|
onSubmit,
|
|
890
934
|
isLoading = false,
|
|
891
|
-
identifier = "",
|
|
935
|
+
identifier: initialIdentifier = "",
|
|
892
936
|
step = "identifier",
|
|
893
937
|
onBack: _onBack
|
|
894
938
|
}) => {
|
|
895
|
-
const
|
|
896
|
-
const
|
|
897
|
-
const
|
|
898
|
-
|
|
899
|
-
account: z3.string().trim().min(1, { message: t("errors.requiredField") }).refine(
|
|
900
|
-
(val) => {
|
|
901
|
-
const isEmail = z3.string().email().safeParse(val).success;
|
|
902
|
-
const phoneRegex = /^(\+2519|2519|09)\d{8}$/;
|
|
903
|
-
const isPhone4 = phoneRegex.test(val);
|
|
904
|
-
return isEmail || isPhone4;
|
|
905
|
-
},
|
|
906
|
-
{
|
|
907
|
-
message: t("errors.invalidEmailOrPhone")
|
|
908
|
-
}
|
|
909
|
-
)
|
|
910
|
-
}),
|
|
911
|
-
[t]
|
|
912
|
-
);
|
|
913
|
-
const passwordSchema = useMemo3(
|
|
914
|
-
() => z3.object({
|
|
915
|
-
password: z3.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError"))
|
|
916
|
-
}),
|
|
917
|
-
[t]
|
|
918
|
-
);
|
|
939
|
+
const { hooks } = useApi();
|
|
940
|
+
const t = useTranslator("Auth.signIn");
|
|
941
|
+
const [showPassword, setShowPassword] = useState5(false);
|
|
942
|
+
const [currentIdentifier, setCurrentIdentifier] = useState5(initialIdentifier);
|
|
919
943
|
const identifierForm = useForm3({
|
|
920
|
-
resolver: zodResolver3(identifierSchema),
|
|
944
|
+
resolver: zodResolver3(identifierSchema(t)),
|
|
921
945
|
defaultValues: {
|
|
922
|
-
|
|
923
|
-
}
|
|
946
|
+
identifier: initialIdentifier
|
|
947
|
+
},
|
|
948
|
+
mode: "onChange"
|
|
924
949
|
});
|
|
925
950
|
const passwordForm = useForm3({
|
|
926
|
-
resolver: zodResolver3(passwordSchema),
|
|
951
|
+
resolver: zodResolver3(passwordSchema(t)),
|
|
927
952
|
defaultValues: {
|
|
928
953
|
password: ""
|
|
929
|
-
}
|
|
954
|
+
},
|
|
955
|
+
mode: "onChange"
|
|
930
956
|
});
|
|
931
|
-
const
|
|
957
|
+
const signInMutation = hooks.useMutation("post", "/sign-in");
|
|
958
|
+
useEffect4(() => {
|
|
959
|
+
if (initialIdentifier) {
|
|
960
|
+
identifierForm.setValue("identifier", initialIdentifier);
|
|
961
|
+
setCurrentIdentifier(initialIdentifier);
|
|
962
|
+
}
|
|
963
|
+
}, [initialIdentifier, identifierForm]);
|
|
964
|
+
const handleIdentifierSubmit = async (values) => {
|
|
932
965
|
const phoneRegex = /^(\+2519|2519|09)\d{8}$/;
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
const handlePasswordSubmit = passwordForm.handleSubmit(async (values) => {
|
|
966
|
+
const normalizedIdentifier = phoneRegex.test(values.identifier) ? normalizePhone(values.identifier) : values.identifier;
|
|
967
|
+
setCurrentIdentifier(normalizedIdentifier);
|
|
968
|
+
identifierForm.setValue("identifier", normalizedIdentifier);
|
|
937
969
|
await onSubmit(
|
|
938
|
-
{
|
|
939
|
-
"
|
|
970
|
+
{ identifier: normalizedIdentifier, password: "" },
|
|
971
|
+
"identifier"
|
|
940
972
|
);
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
973
|
+
};
|
|
974
|
+
const handlePasswordSubmit = async (values) => {
|
|
975
|
+
try {
|
|
976
|
+
await signInMutation.mutateAsync({
|
|
977
|
+
body: {
|
|
978
|
+
identifier: currentIdentifier || identifierForm.getValues("identifier"),
|
|
979
|
+
password: values.password
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
await onSubmit(
|
|
950
983
|
{
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
984
|
+
identifier: currentIdentifier || identifierForm.getValues("identifier"),
|
|
985
|
+
password: values.password
|
|
986
|
+
},
|
|
987
|
+
"password"
|
|
988
|
+
);
|
|
989
|
+
} catch {
|
|
990
|
+
await onSubmit(
|
|
991
|
+
{
|
|
992
|
+
identifier: currentIdentifier || identifierForm.getValues("identifier"),
|
|
993
|
+
password: values.password
|
|
994
|
+
},
|
|
995
|
+
"password"
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
const isPasswordStep = step === "password";
|
|
1000
|
+
const isSubmitting = isLoading || signInMutation.isPending;
|
|
1001
|
+
if (isPasswordStep) {
|
|
1002
|
+
return /* @__PURE__ */ jsxs6(
|
|
1003
|
+
"form",
|
|
1004
|
+
{
|
|
1005
|
+
id: "sign-in-password-form",
|
|
1006
|
+
onSubmit: passwordForm.handleSubmit(handlePasswordSubmit),
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ jsxs6(FieldGroup3, { children: [
|
|
1009
|
+
/* @__PURE__ */ jsxs6("div", { className: "text-center", children: [
|
|
1010
|
+
/* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground mb-2", children: t("form.enterPasswordFor") }),
|
|
1011
|
+
/* @__PURE__ */ jsx8("p", { className: "font-bold", children: currentIdentifier || identifierForm.getValues("identifier") })
|
|
1012
|
+
] }),
|
|
1013
|
+
/* @__PURE__ */ jsx8(
|
|
1014
|
+
Controller3,
|
|
1015
|
+
{
|
|
1016
|
+
name: "password",
|
|
1017
|
+
control: passwordForm.control,
|
|
1018
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs6(Field3, { "data-invalid": fieldState.invalid, children: [
|
|
1019
|
+
/* @__PURE__ */ jsx8(FieldLabel3, { htmlFor: "sign-in-password", children: t("form.passwordLabel") }),
|
|
1020
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative", children: [
|
|
1021
|
+
/* @__PURE__ */ jsx8(
|
|
1022
|
+
Input3,
|
|
1023
|
+
{
|
|
1024
|
+
...field,
|
|
1025
|
+
id: "sign-in-password",
|
|
1026
|
+
type: showPassword ? "text" : "password",
|
|
1027
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1028
|
+
autoComplete: "current-password",
|
|
1029
|
+
"aria-invalid": fieldState.invalid
|
|
1030
|
+
}
|
|
1031
|
+
),
|
|
1032
|
+
/* @__PURE__ */ jsx8(
|
|
1033
|
+
"button",
|
|
1034
|
+
{
|
|
1035
|
+
type: "button",
|
|
1036
|
+
onClick: () => setShowPassword(!showPassword),
|
|
1037
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1038
|
+
children: showPassword ? /* @__PURE__ */ jsx8(IconEyeOff2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx8(IconEye2, { className: "h-4 w-4" })
|
|
1039
|
+
}
|
|
1040
|
+
)
|
|
1041
|
+
] }),
|
|
1042
|
+
fieldState.invalid && /* @__PURE__ */ jsx8(FieldError3, { errors: [fieldState.error] })
|
|
1043
|
+
] })
|
|
1044
|
+
}
|
|
1045
|
+
)
|
|
1046
|
+
] }),
|
|
1047
|
+
/* @__PURE__ */ jsx8("div", { className: "mt-4", children: /* @__PURE__ */ jsxs6(Button3, { type: "submit", className: "w-full", disabled: isSubmitting, children: [
|
|
1048
|
+
isSubmitting && /* @__PURE__ */ jsx8(Spinner3, {}),
|
|
1049
|
+
isSubmitting ? t("form.submitting") : t("form.submit")
|
|
1050
|
+
] }) })
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
return /* @__PURE__ */ jsxs6(
|
|
1056
|
+
"form",
|
|
1057
|
+
{
|
|
1058
|
+
id: "sign-in-identifier-form",
|
|
1059
|
+
onSubmit: identifierForm.handleSubmit(handleIdentifierSubmit),
|
|
1060
|
+
children: [
|
|
1061
|
+
/* @__PURE__ */ jsx8(FieldGroup3, { children: /* @__PURE__ */ jsx8(
|
|
1062
|
+
Controller3,
|
|
1063
|
+
{
|
|
1064
|
+
name: "identifier",
|
|
1065
|
+
control: identifierForm.control,
|
|
1066
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs6(Field3, { "data-invalid": fieldState.invalid, children: [
|
|
1067
|
+
/* @__PURE__ */ jsx8(FieldLabel3, { htmlFor: "sign-in-identifier", children: t("form.accountLabel") }),
|
|
1068
|
+
/* @__PURE__ */ jsx8(
|
|
957
1069
|
Input3,
|
|
958
1070
|
{
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1071
|
+
...field,
|
|
1072
|
+
id: "sign-in-identifier",
|
|
1073
|
+
type: "text",
|
|
1074
|
+
placeholder: t("form.accountPlaceholder"),
|
|
1075
|
+
autoComplete: "username",
|
|
1076
|
+
"aria-invalid": fieldState.invalid
|
|
963
1077
|
}
|
|
964
1078
|
),
|
|
965
|
-
/* @__PURE__ */
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
] })
|
|
977
|
-
}
|
|
978
|
-
),
|
|
979
|
-
/* @__PURE__ */ jsx9(Button4, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.submit") })
|
|
980
|
-
] }) });
|
|
981
|
-
}
|
|
982
|
-
return /* @__PURE__ */ jsx9(Form3, { ...identifierForm, children: /* @__PURE__ */ jsxs6("form", { onSubmit: handleIdentifierSubmit, className: "space-y-4", children: [
|
|
983
|
-
/* @__PURE__ */ jsx9(
|
|
984
|
-
FormField3,
|
|
985
|
-
{
|
|
986
|
-
control: identifierForm.control,
|
|
987
|
-
name: "account",
|
|
988
|
-
render: ({ field }) => /* @__PURE__ */ jsxs6(FormItem3, { children: [
|
|
989
|
-
/* @__PURE__ */ jsx9(FormLabel3, { children: t("form.accountLabel") }),
|
|
990
|
-
/* @__PURE__ */ jsx9(FormControl3, { children: /* @__PURE__ */ jsx9(
|
|
991
|
-
Input3,
|
|
992
|
-
{
|
|
993
|
-
type: "text",
|
|
994
|
-
placeholder: t("form.accountPlaceholder"),
|
|
995
|
-
...field
|
|
996
|
-
}
|
|
997
|
-
) }),
|
|
998
|
-
/* @__PURE__ */ jsx9(FormMessage3, {})
|
|
999
|
-
] })
|
|
1000
|
-
}
|
|
1001
|
-
),
|
|
1002
|
-
/* @__PURE__ */ jsxs6(Button4, { type: "submit", className: "w-full", disabled: isLoading, children: [
|
|
1003
|
-
isLoading && /* @__PURE__ */ jsx9(Spinner4, {}),
|
|
1004
|
-
isLoading ? t("form.submitting") : t("form.continue")
|
|
1005
|
-
] })
|
|
1006
|
-
] }) });
|
|
1079
|
+
fieldState.invalid && /* @__PURE__ */ jsx8(FieldError3, { errors: [fieldState.error] })
|
|
1080
|
+
] })
|
|
1081
|
+
}
|
|
1082
|
+
) }),
|
|
1083
|
+
/* @__PURE__ */ jsx8("div", { className: "mt-4", children: /* @__PURE__ */ jsxs6(Button3, { type: "submit", className: "w-full", disabled: isSubmitting, children: [
|
|
1084
|
+
isSubmitting && /* @__PURE__ */ jsx8(Spinner3, {}),
|
|
1085
|
+
isSubmitting ? t("form.submitting") : t("form.continue")
|
|
1086
|
+
] }) })
|
|
1087
|
+
]
|
|
1088
|
+
}
|
|
1089
|
+
);
|
|
1007
1090
|
};
|
|
1008
1091
|
|
|
1009
1092
|
// src/components/auth/pages/sign-in-page.tsx
|
|
1010
|
-
import { jsx as
|
|
1093
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1011
1094
|
var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1012
|
-
var SignInPage = ({
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const
|
|
1020
|
-
const
|
|
1021
|
-
const
|
|
1022
|
-
const
|
|
1023
|
-
const
|
|
1024
|
-
const
|
|
1025
|
-
const
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1095
|
+
var SignInPage = ({ redirectUrl } = {}) => {
|
|
1096
|
+
const { hooks, setAuth } = useApi();
|
|
1097
|
+
const { config } = useConfig();
|
|
1098
|
+
const t = createTranslator(config.messages || {}, "Auth.signIn");
|
|
1099
|
+
const [isLoading, setIsLoading] = useState6(false);
|
|
1100
|
+
const [error, setError] = useState6(null);
|
|
1101
|
+
const [step, setStep] = useState6("identifier");
|
|
1102
|
+
const [identifier, setIdentifier] = useState6("");
|
|
1103
|
+
const checkUserMutation = hooks.useMutation("post", "/check-user");
|
|
1104
|
+
const signInMutation = hooks.useMutation("post", "/sign-in");
|
|
1105
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/dashboard";
|
|
1106
|
+
const forgotPasswordLink = config.navigation?.links?.forgotPassword || "/auth/forgot-password";
|
|
1107
|
+
const signUpLink = config.navigation?.links?.signUp || "/auth/sign-up";
|
|
1108
|
+
const Link = config.navigation?.linkComponent;
|
|
1109
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1110
|
+
if (typeof window !== "undefined") {
|
|
1111
|
+
window.location.href = path;
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
const logoImage = config.ui.logoImage;
|
|
1115
|
+
useEffect5(() => {
|
|
1116
|
+
if (error) {
|
|
1117
|
+
toast3.error(error.title || "Error", {
|
|
1118
|
+
description: error.description
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
}, [error]);
|
|
1122
|
+
const handleIdentifierStep = async (identifierValue) => {
|
|
1123
|
+
const checkResult = await checkUserMutation.mutateAsync({
|
|
1124
|
+
body: {
|
|
1125
|
+
identifier: identifierValue
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
if (checkResult.exists) {
|
|
1129
|
+
setIdentifier(identifierValue);
|
|
1130
|
+
setStep("password");
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
const email = isPhone(identifierValue) ? "" : identifierValue;
|
|
1134
|
+
if (email) {
|
|
1135
|
+
onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);
|
|
1136
|
+
} else {
|
|
1137
|
+
onNavigate(`${signUpLink}?phone=${encodeURIComponent(identifierValue)}`);
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
const handlePasswordStep = async (passwordValue) => {
|
|
1141
|
+
const res = await signInMutation.mutateAsync({
|
|
1142
|
+
body: {
|
|
1143
|
+
identifier,
|
|
1144
|
+
password: passwordValue
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
if ("verificationId" in res && res.verificationId) {
|
|
1148
|
+
const verifyPath = isPhone(identifier) ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(identifier)}` : `/auth/verify-email?verificationId=${res.verificationId}`;
|
|
1149
|
+
onNavigate(verifyPath);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
if ("user" in res && "session" in res) {
|
|
1153
|
+
setAuth(res);
|
|
1154
|
+
}
|
|
1155
|
+
onNavigate(defaultRedirect);
|
|
1156
|
+
};
|
|
1028
1157
|
const handleSubmit = async (values, currentStep) => {
|
|
1029
1158
|
setIsLoading(true);
|
|
1030
1159
|
setError(null);
|
|
1031
1160
|
try {
|
|
1032
1161
|
if (currentStep === "identifier") {
|
|
1033
|
-
|
|
1034
|
-
identifier: values.account
|
|
1035
|
-
});
|
|
1036
|
-
if (checkResult.exists) {
|
|
1037
|
-
setIdentifier(values.account);
|
|
1038
|
-
setStep("password");
|
|
1039
|
-
} else {
|
|
1040
|
-
const email = isPhone(values.account) ? "" : values.account;
|
|
1041
|
-
if (email) {
|
|
1042
|
-
onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);
|
|
1043
|
-
} else {
|
|
1044
|
-
onNavigate(
|
|
1045
|
-
`${signUpLink}?phone=${encodeURIComponent(values.account)}`
|
|
1046
|
-
);
|
|
1047
|
-
}
|
|
1048
|
-
return;
|
|
1049
|
-
}
|
|
1162
|
+
await handleIdentifierStep(values.identifier);
|
|
1050
1163
|
} else {
|
|
1051
|
-
|
|
1052
|
-
identifier,
|
|
1053
|
-
password: values.password
|
|
1054
|
-
});
|
|
1055
|
-
if ("verificationId" in res && res.verificationId) {
|
|
1056
|
-
const verifyPath = isPhone(identifier) ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(identifier)}` : `/auth/verify-email?verificationId=${res.verificationId}`;
|
|
1057
|
-
onNavigate(verifyPath);
|
|
1058
|
-
return;
|
|
1059
|
-
}
|
|
1060
|
-
if ("user" in res && "session" in res) {
|
|
1061
|
-
setAuth(res);
|
|
1062
|
-
}
|
|
1063
|
-
onNavigate(defaultRedirect);
|
|
1164
|
+
await handlePasswordStep(values.password || "");
|
|
1064
1165
|
}
|
|
1065
1166
|
} catch (err) {
|
|
1066
1167
|
handleError(err, setError, t);
|
|
@@ -1068,18 +1169,26 @@ var SignInPage = ({
|
|
|
1068
1169
|
setIsLoading(false);
|
|
1069
1170
|
}
|
|
1070
1171
|
};
|
|
1172
|
+
const isSubmitting = isLoading || checkUserMutation.isPending || signInMutation.isPending;
|
|
1071
1173
|
const handleBack = () => {
|
|
1072
1174
|
setStep("identifier");
|
|
1073
1175
|
setIdentifier("");
|
|
1074
1176
|
setError(null);
|
|
1075
1177
|
};
|
|
1076
1178
|
const isStepPassword = step === "password";
|
|
1077
|
-
|
|
1179
|
+
let errorContent = null;
|
|
1180
|
+
if (error) {
|
|
1181
|
+
if (typeof error === "string") {
|
|
1182
|
+
errorContent = { title: "Error", description: error };
|
|
1183
|
+
} else {
|
|
1184
|
+
errorContent = error;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return /* @__PURE__ */ jsx9("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs7(
|
|
1078
1188
|
AuthPageLayout,
|
|
1079
1189
|
{
|
|
1080
1190
|
title: t("title"),
|
|
1081
1191
|
description: isStepPassword ? void 0 : t("description"),
|
|
1082
|
-
error,
|
|
1083
1192
|
logoImage,
|
|
1084
1193
|
footer: /* @__PURE__ */ jsxs7(
|
|
1085
1194
|
"div",
|
|
@@ -1090,7 +1199,7 @@ var SignInPage = ({
|
|
|
1090
1199
|
},
|
|
1091
1200
|
children: [
|
|
1092
1201
|
isStepPassword && // biome-ignore lint/a11y/useKeyWithClickEvents: change account
|
|
1093
|
-
/* @__PURE__ */
|
|
1202
|
+
/* @__PURE__ */ jsx9(
|
|
1094
1203
|
"p",
|
|
1095
1204
|
{
|
|
1096
1205
|
className: "text-primary inline-block cursor-pointer hover:underline",
|
|
@@ -1098,14 +1207,14 @@ var SignInPage = ({
|
|
|
1098
1207
|
children: t("changeAccount")
|
|
1099
1208
|
}
|
|
1100
1209
|
),
|
|
1101
|
-
Link ? /* @__PURE__ */
|
|
1210
|
+
Link ? /* @__PURE__ */ jsx9(
|
|
1102
1211
|
Link,
|
|
1103
1212
|
{
|
|
1104
1213
|
href: forgotPasswordLink,
|
|
1105
1214
|
className: "text-primary inline-block hover:underline",
|
|
1106
1215
|
children: t("footer.forgotPassword")
|
|
1107
1216
|
}
|
|
1108
|
-
) : /* @__PURE__ */
|
|
1217
|
+
) : /* @__PURE__ */ jsx9(
|
|
1109
1218
|
"a",
|
|
1110
1219
|
{
|
|
1111
1220
|
href: forgotPasswordLink,
|
|
@@ -1116,75 +1225,82 @@ var SignInPage = ({
|
|
|
1116
1225
|
]
|
|
1117
1226
|
}
|
|
1118
1227
|
),
|
|
1119
|
-
children:
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1228
|
+
children: [
|
|
1229
|
+
/* @__PURE__ */ jsx9(
|
|
1230
|
+
SignIn,
|
|
1231
|
+
{
|
|
1232
|
+
onSubmit: handleSubmit,
|
|
1233
|
+
isLoading: isSubmitting,
|
|
1234
|
+
identifier,
|
|
1235
|
+
step
|
|
1236
|
+
}
|
|
1237
|
+
),
|
|
1238
|
+
errorContent && /* @__PURE__ */ jsxs7(Alert3, { variant: "destructive", className: "mt-4", children: [
|
|
1239
|
+
/* @__PURE__ */ jsx9(IconAlertCircle3, { className: "h-4 w-4" }),
|
|
1240
|
+
/* @__PURE__ */ jsx9(AlertTitle3, { children: errorContent.title }),
|
|
1241
|
+
/* @__PURE__ */ jsx9(AlertDescription3, { children: errorContent.description })
|
|
1242
|
+
] })
|
|
1243
|
+
]
|
|
1128
1244
|
}
|
|
1129
1245
|
) });
|
|
1130
1246
|
};
|
|
1131
1247
|
|
|
1132
1248
|
// src/components/auth/pages/sign-up-page.tsx
|
|
1133
|
-
import {
|
|
1134
|
-
|
|
1249
|
+
import {
|
|
1250
|
+
Alert as Alert4,
|
|
1251
|
+
AlertDescription as AlertDescription4,
|
|
1252
|
+
AlertTitle as AlertTitle4
|
|
1253
|
+
} from "@mesob/ui/components/alert";
|
|
1254
|
+
import { toast as toast4 } from "@mesob/ui/components/sonner";
|
|
1255
|
+
import { IconAlertCircle as IconAlertCircle4 } from "@tabler/icons-react";
|
|
1256
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
1135
1257
|
|
|
1136
1258
|
// src/components/auth/sign-up.tsx
|
|
1137
1259
|
import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
|
|
1138
|
-
import { Button as
|
|
1260
|
+
import { Button as Button4 } from "@mesob/ui/components/button";
|
|
1139
1261
|
import {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
FormMessage as FormMessage4
|
|
1146
|
-
} from "@mesob/ui/components/form";
|
|
1262
|
+
Field as Field4,
|
|
1263
|
+
FieldError as FieldError4,
|
|
1264
|
+
FieldGroup as FieldGroup4,
|
|
1265
|
+
FieldLabel as FieldLabel4
|
|
1266
|
+
} from "@mesob/ui/components/field";
|
|
1147
1267
|
import { Input as Input4 } from "@mesob/ui/components/input";
|
|
1148
1268
|
import { IconEye as IconEye3, IconEyeOff as IconEyeOff3 } from "@tabler/icons-react";
|
|
1149
|
-
import {
|
|
1150
|
-
import {
|
|
1151
|
-
import { useForm as useForm4 } from "react-hook-form";
|
|
1269
|
+
import { useEffect as useEffect6, useState as useState7 } from "react";
|
|
1270
|
+
import { Controller as Controller4, useForm as useForm4 } from "react-hook-form";
|
|
1152
1271
|
import { z as z4 } from "zod";
|
|
1153
|
-
import { jsx as
|
|
1272
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1154
1273
|
var isPhone2 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1274
|
+
var signUpSchema = (t) => z4.object({
|
|
1275
|
+
fullName: z4.string().min(1, t("errors.fullNameRequired")),
|
|
1276
|
+
identifier: z4.string().min(1, t("errors.contactRequired")).refine(
|
|
1277
|
+
(val) => {
|
|
1278
|
+
if (!val) {
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
return val.includes("@") || isPhone2(val);
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
message: t("errors.invalidEmailOrPhone")
|
|
1285
|
+
}
|
|
1286
|
+
),
|
|
1287
|
+
password: z4.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
|
|
1288
|
+
confirmPassword: z4.string()
|
|
1289
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
1290
|
+
message: t("errors.passwordsMismatch"),
|
|
1291
|
+
path: ["confirmPassword"]
|
|
1292
|
+
});
|
|
1155
1293
|
var SignUp = ({
|
|
1156
1294
|
onSubmit,
|
|
1157
1295
|
isLoading = false,
|
|
1158
1296
|
initialIdentifier
|
|
1159
1297
|
}) => {
|
|
1160
|
-
const t =
|
|
1298
|
+
const t = useTranslator("Auth.signUp");
|
|
1161
1299
|
const hasInitialIdentifier = !!initialIdentifier;
|
|
1162
|
-
const [showPassword, setShowPassword] =
|
|
1163
|
-
const [showConfirmPassword, setShowConfirmPassword] =
|
|
1164
|
-
const signUpSchema = useMemo4(
|
|
1165
|
-
() => z4.object({
|
|
1166
|
-
fullName: z4.string().min(1, t("errors.fullNameRequired")),
|
|
1167
|
-
identifier: z4.string().min(1, t("errors.contactRequired")).refine(
|
|
1168
|
-
(val) => {
|
|
1169
|
-
if (!val) {
|
|
1170
|
-
return false;
|
|
1171
|
-
}
|
|
1172
|
-
return val.includes("@") || isPhone2(val);
|
|
1173
|
-
},
|
|
1174
|
-
{
|
|
1175
|
-
message: t("errors.invalidEmailOrPhone")
|
|
1176
|
-
}
|
|
1177
|
-
),
|
|
1178
|
-
password: z4.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
|
|
1179
|
-
confirmPassword: z4.string()
|
|
1180
|
-
}).refine((data) => data.password === data.confirmPassword, {
|
|
1181
|
-
message: t("errors.passwordsMismatch"),
|
|
1182
|
-
path: ["confirmPassword"]
|
|
1183
|
-
}),
|
|
1184
|
-
[t]
|
|
1185
|
-
);
|
|
1300
|
+
const [showPassword, setShowPassword] = useState7(false);
|
|
1301
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState7(false);
|
|
1186
1302
|
const form = useForm4({
|
|
1187
|
-
resolver: zodResolver4(signUpSchema),
|
|
1303
|
+
resolver: zodResolver4(signUpSchema(t)),
|
|
1188
1304
|
defaultValues: {
|
|
1189
1305
|
fullName: "",
|
|
1190
1306
|
identifier: initialIdentifier || "",
|
|
@@ -1192,7 +1308,7 @@ var SignUp = ({
|
|
|
1192
1308
|
confirmPassword: ""
|
|
1193
1309
|
}
|
|
1194
1310
|
});
|
|
1195
|
-
|
|
1311
|
+
useEffect6(() => {
|
|
1196
1312
|
if (initialIdentifier) {
|
|
1197
1313
|
form.setValue("identifier", initialIdentifier);
|
|
1198
1314
|
}
|
|
@@ -1210,135 +1326,182 @@ var SignUp = ({
|
|
|
1210
1326
|
return t("form.phoneLabel");
|
|
1211
1327
|
};
|
|
1212
1328
|
const identifierLabel = getIdentifierLabel();
|
|
1213
|
-
return /* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
/* @__PURE__ */
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
] })
|
|
1224
|
-
}
|
|
1225
|
-
),
|
|
1226
|
-
/* @__PURE__ */ jsx11(
|
|
1227
|
-
FormField4,
|
|
1228
|
-
{
|
|
1229
|
-
control: form.control,
|
|
1230
|
-
name: "identifier",
|
|
1231
|
-
render: ({ field }) => /* @__PURE__ */ jsxs8(FormItem4, { children: [
|
|
1232
|
-
/* @__PURE__ */ jsx11(FormLabel4, { className: hasInitialIdentifier ? "block" : void 0, children: identifierLabel }),
|
|
1233
|
-
/* @__PURE__ */ jsx11(FormControl4, { children: /* @__PURE__ */ jsx11(
|
|
1234
|
-
Input4,
|
|
1235
|
-
{
|
|
1236
|
-
type: field.value.includes("@") ? "email" : "tel",
|
|
1237
|
-
placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
|
|
1238
|
-
...field,
|
|
1239
|
-
disabled: hasInitialIdentifier
|
|
1240
|
-
}
|
|
1241
|
-
) }),
|
|
1242
|
-
/* @__PURE__ */ jsx11(FormMessage4, {})
|
|
1243
|
-
] })
|
|
1244
|
-
}
|
|
1245
|
-
),
|
|
1246
|
-
/* @__PURE__ */ jsx11(
|
|
1247
|
-
FormField4,
|
|
1248
|
-
{
|
|
1249
|
-
control: form.control,
|
|
1250
|
-
name: "password",
|
|
1251
|
-
render: ({ field }) => /* @__PURE__ */ jsxs8(FormItem4, { children: [
|
|
1252
|
-
/* @__PURE__ */ jsx11(FormLabel4, { children: t("form.passwordLabel") }),
|
|
1253
|
-
/* @__PURE__ */ jsx11(FormControl4, { children: /* @__PURE__ */ jsxs8("div", { className: "relative", children: [
|
|
1254
|
-
/* @__PURE__ */ jsx11(
|
|
1329
|
+
return /* @__PURE__ */ jsxs8("form", { id: "sign-up-form", onSubmit: handleSubmit, children: [
|
|
1330
|
+
/* @__PURE__ */ jsxs8(FieldGroup4, { children: [
|
|
1331
|
+
/* @__PURE__ */ jsx10(
|
|
1332
|
+
Controller4,
|
|
1333
|
+
{
|
|
1334
|
+
name: "fullName",
|
|
1335
|
+
control: form.control,
|
|
1336
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs8(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1337
|
+
/* @__PURE__ */ jsx10(FieldLabel4, { htmlFor: "sign-up-fullName", children: t("form.fullNameLabel") }),
|
|
1338
|
+
/* @__PURE__ */ jsx10(
|
|
1255
1339
|
Input4,
|
|
1256
1340
|
{
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1341
|
+
...field,
|
|
1342
|
+
id: "sign-up-fullName",
|
|
1343
|
+
placeholder: t("form.fullNamePlaceholder"),
|
|
1344
|
+
"aria-invalid": fieldState.invalid
|
|
1260
1345
|
}
|
|
1261
1346
|
),
|
|
1262
|
-
/* @__PURE__ */
|
|
1263
|
-
|
|
1347
|
+
fieldState.invalid && /* @__PURE__ */ jsx10(FieldError4, { errors: [fieldState.error] })
|
|
1348
|
+
] })
|
|
1349
|
+
}
|
|
1350
|
+
),
|
|
1351
|
+
/* @__PURE__ */ jsx10(
|
|
1352
|
+
Controller4,
|
|
1353
|
+
{
|
|
1354
|
+
name: "identifier",
|
|
1355
|
+
control: form.control,
|
|
1356
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs8(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1357
|
+
/* @__PURE__ */ jsx10(
|
|
1358
|
+
FieldLabel4,
|
|
1264
1359
|
{
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
children: showPassword ? /* @__PURE__ */ jsx11(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx11(IconEye3, { className: "h-4 w-4" })
|
|
1360
|
+
htmlFor: "sign-up-identifier",
|
|
1361
|
+
className: hasInitialIdentifier ? "block" : void 0,
|
|
1362
|
+
children: identifierLabel
|
|
1269
1363
|
}
|
|
1270
|
-
)
|
|
1271
|
-
|
|
1272
|
-
/* @__PURE__ */ jsx11(FormMessage4, {})
|
|
1273
|
-
] })
|
|
1274
|
-
}
|
|
1275
|
-
),
|
|
1276
|
-
/* @__PURE__ */ jsx11(
|
|
1277
|
-
FormField4,
|
|
1278
|
-
{
|
|
1279
|
-
control: form.control,
|
|
1280
|
-
name: "confirmPassword",
|
|
1281
|
-
render: ({ field }) => /* @__PURE__ */ jsxs8(FormItem4, { children: [
|
|
1282
|
-
/* @__PURE__ */ jsx11(FormLabel4, { children: t("form.confirmPasswordLabel") }),
|
|
1283
|
-
/* @__PURE__ */ jsx11(FormControl4, { children: /* @__PURE__ */ jsxs8("div", { className: "relative", children: [
|
|
1284
|
-
/* @__PURE__ */ jsx11(
|
|
1364
|
+
),
|
|
1365
|
+
/* @__PURE__ */ jsx10(
|
|
1285
1366
|
Input4,
|
|
1286
1367
|
{
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1368
|
+
...field,
|
|
1369
|
+
id: "sign-up-identifier",
|
|
1370
|
+
type: field.value.includes("@") ? "email" : "tel",
|
|
1371
|
+
placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
|
|
1372
|
+
disabled: hasInitialIdentifier,
|
|
1373
|
+
"aria-invalid": fieldState.invalid
|
|
1290
1374
|
}
|
|
1291
1375
|
),
|
|
1292
|
-
/* @__PURE__ */
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1376
|
+
fieldState.invalid && /* @__PURE__ */ jsx10(FieldError4, { errors: [fieldState.error] })
|
|
1377
|
+
] })
|
|
1378
|
+
}
|
|
1379
|
+
),
|
|
1380
|
+
/* @__PURE__ */ jsx10(
|
|
1381
|
+
Controller4,
|
|
1382
|
+
{
|
|
1383
|
+
name: "password",
|
|
1384
|
+
control: form.control,
|
|
1385
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs8(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1386
|
+
/* @__PURE__ */ jsx10(FieldLabel4, { htmlFor: "sign-up-password", children: t("form.passwordLabel") }),
|
|
1387
|
+
/* @__PURE__ */ jsxs8("div", { className: "relative", children: [
|
|
1388
|
+
/* @__PURE__ */ jsx10(
|
|
1389
|
+
Input4,
|
|
1390
|
+
{
|
|
1391
|
+
...field,
|
|
1392
|
+
id: "sign-up-password",
|
|
1393
|
+
type: showPassword ? "text" : "password",
|
|
1394
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1395
|
+
"aria-invalid": fieldState.invalid
|
|
1396
|
+
}
|
|
1397
|
+
),
|
|
1398
|
+
/* @__PURE__ */ jsx10(
|
|
1399
|
+
"button",
|
|
1400
|
+
{
|
|
1401
|
+
type: "button",
|
|
1402
|
+
onClick: () => setShowPassword(!showPassword),
|
|
1403
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1404
|
+
children: showPassword ? /* @__PURE__ */ jsx10(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx10(IconEye3, { className: "h-4 w-4" })
|
|
1405
|
+
}
|
|
1406
|
+
)
|
|
1407
|
+
] }),
|
|
1408
|
+
fieldState.invalid && /* @__PURE__ */ jsx10(FieldError4, { errors: [fieldState.error] })
|
|
1409
|
+
] })
|
|
1410
|
+
}
|
|
1411
|
+
),
|
|
1412
|
+
/* @__PURE__ */ jsx10(
|
|
1413
|
+
Controller4,
|
|
1414
|
+
{
|
|
1415
|
+
name: "confirmPassword",
|
|
1416
|
+
control: form.control,
|
|
1417
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs8(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1418
|
+
/* @__PURE__ */ jsx10(FieldLabel4, { htmlFor: "sign-up-confirmPassword", children: t("form.confirmPasswordLabel") }),
|
|
1419
|
+
/* @__PURE__ */ jsxs8("div", { className: "relative", children: [
|
|
1420
|
+
/* @__PURE__ */ jsx10(
|
|
1421
|
+
Input4,
|
|
1422
|
+
{
|
|
1423
|
+
...field,
|
|
1424
|
+
id: "sign-up-confirmPassword",
|
|
1425
|
+
type: showConfirmPassword ? "text" : "password",
|
|
1426
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1427
|
+
"aria-invalid": fieldState.invalid
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
/* @__PURE__ */ jsx10(
|
|
1431
|
+
"button",
|
|
1432
|
+
{
|
|
1433
|
+
type: "button",
|
|
1434
|
+
onClick: () => setShowConfirmPassword(!showConfirmPassword),
|
|
1435
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1436
|
+
children: showConfirmPassword ? /* @__PURE__ */ jsx10(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx10(IconEye3, { className: "h-4 w-4" })
|
|
1437
|
+
}
|
|
1438
|
+
)
|
|
1439
|
+
] }),
|
|
1440
|
+
fieldState.invalid && /* @__PURE__ */ jsx10(FieldError4, { errors: [fieldState.error] })
|
|
1441
|
+
] })
|
|
1442
|
+
}
|
|
1443
|
+
)
|
|
1444
|
+
] }),
|
|
1445
|
+
/* @__PURE__ */ jsx10("div", { className: "mt-4", children: /* @__PURE__ */ jsx10(
|
|
1446
|
+
Button4,
|
|
1447
|
+
{
|
|
1448
|
+
type: "submit",
|
|
1449
|
+
form: "sign-up-form",
|
|
1450
|
+
className: "w-full",
|
|
1451
|
+
disabled: isLoading,
|
|
1452
|
+
children: isLoading ? t("form.submitting") : t("form.submit")
|
|
1304
1453
|
}
|
|
1305
|
-
)
|
|
1306
|
-
|
|
1307
|
-
] }) });
|
|
1454
|
+
) })
|
|
1455
|
+
] });
|
|
1308
1456
|
};
|
|
1309
1457
|
|
|
1310
1458
|
// src/components/auth/pages/sign-up-page.tsx
|
|
1311
|
-
import { jsx as
|
|
1459
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1312
1460
|
var isPhone3 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1313
1461
|
var SignUpPage = ({
|
|
1314
1462
|
redirectUrl,
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
const
|
|
1322
|
-
const
|
|
1323
|
-
const
|
|
1324
|
-
const
|
|
1325
|
-
const
|
|
1463
|
+
initialIdentifier
|
|
1464
|
+
} = {}) => {
|
|
1465
|
+
const { hooks, setAuth } = useApi();
|
|
1466
|
+
const { config } = useConfig();
|
|
1467
|
+
const t = createTranslator(config.messages || {}, "Auth.signUp");
|
|
1468
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1469
|
+
const [error, setError] = useState8(null);
|
|
1470
|
+
const signUpMutation = hooks.useMutation("post", "/sign-up");
|
|
1471
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1472
|
+
const Link = config.navigation?.linkComponent;
|
|
1473
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1474
|
+
if (typeof window !== "undefined") {
|
|
1475
|
+
window.location.href = path;
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
const logoImage = config.ui.logoImage;
|
|
1479
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1480
|
+
useEffect7(() => {
|
|
1481
|
+
if (error) {
|
|
1482
|
+
toast4.error(error.title || "Error", {
|
|
1483
|
+
description: error.description
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
}, [error]);
|
|
1326
1487
|
const handleSubmit = async (values) => {
|
|
1327
1488
|
setIsLoading(true);
|
|
1328
1489
|
setError(null);
|
|
1329
1490
|
try {
|
|
1330
1491
|
const identifier = values.identifier;
|
|
1331
1492
|
const usingPhone = isPhone3(identifier);
|
|
1332
|
-
const res =
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1493
|
+
const res = await signUpMutation.mutateAsync({
|
|
1494
|
+
body: usingPhone ? {
|
|
1495
|
+
phone: identifier,
|
|
1496
|
+
password: values.password,
|
|
1497
|
+
fullName: values.fullName,
|
|
1498
|
+
handle: values.handle
|
|
1499
|
+
} : {
|
|
1500
|
+
email: identifier,
|
|
1501
|
+
password: values.password,
|
|
1502
|
+
fullName: values.fullName,
|
|
1503
|
+
handle: values.handle
|
|
1504
|
+
}
|
|
1342
1505
|
});
|
|
1343
1506
|
if ("verificationId" in res && res.verificationId) {
|
|
1344
1507
|
if (usingPhone) {
|
|
@@ -1355,24 +1518,31 @@ var SignUpPage = ({
|
|
|
1355
1518
|
if ("user" in res && "session" in res) {
|
|
1356
1519
|
setAuth(res);
|
|
1357
1520
|
}
|
|
1358
|
-
onNavigate(
|
|
1521
|
+
onNavigate(defaultRedirect);
|
|
1359
1522
|
} catch (err) {
|
|
1360
1523
|
handleError(err, setError, t);
|
|
1361
1524
|
} finally {
|
|
1362
1525
|
setIsLoading(false);
|
|
1363
1526
|
}
|
|
1364
1527
|
};
|
|
1365
|
-
|
|
1528
|
+
let errorContent = null;
|
|
1529
|
+
if (error) {
|
|
1530
|
+
if (typeof error === "string") {
|
|
1531
|
+
errorContent = { title: "Error", description: error };
|
|
1532
|
+
} else {
|
|
1533
|
+
errorContent = error;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return /* @__PURE__ */ jsxs9(
|
|
1366
1537
|
AuthPageLayout,
|
|
1367
1538
|
{
|
|
1368
1539
|
title: t("title"),
|
|
1369
1540
|
description: t("description"),
|
|
1370
|
-
error,
|
|
1371
1541
|
logoImage,
|
|
1372
1542
|
footer: /* @__PURE__ */ jsxs9("p", { children: [
|
|
1373
1543
|
t("footer.hasAccount"),
|
|
1374
1544
|
" ",
|
|
1375
|
-
Link ? /* @__PURE__ */
|
|
1545
|
+
Link ? /* @__PURE__ */ jsx11(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.signInCta") }) : /* @__PURE__ */ jsx11(
|
|
1376
1546
|
"a",
|
|
1377
1547
|
{
|
|
1378
1548
|
href: signInLink,
|
|
@@ -1385,69 +1555,131 @@ var SignUpPage = ({
|
|
|
1385
1555
|
}
|
|
1386
1556
|
)
|
|
1387
1557
|
] }),
|
|
1388
|
-
children:
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1558
|
+
children: [
|
|
1559
|
+
/* @__PURE__ */ jsx11(
|
|
1560
|
+
SignUp,
|
|
1561
|
+
{
|
|
1562
|
+
onSubmit: handleSubmit,
|
|
1563
|
+
isLoading: isLoading || signUpMutation.isPending,
|
|
1564
|
+
initialIdentifier
|
|
1565
|
+
}
|
|
1566
|
+
),
|
|
1567
|
+
errorContent && /* @__PURE__ */ jsxs9(Alert4, { variant: "destructive", className: "mt-4", children: [
|
|
1568
|
+
/* @__PURE__ */ jsx11(IconAlertCircle4, { className: "h-4 w-4" }),
|
|
1569
|
+
/* @__PURE__ */ jsx11(AlertTitle4, { children: errorContent.title }),
|
|
1570
|
+
/* @__PURE__ */ jsx11(AlertDescription4, { children: errorContent.description })
|
|
1571
|
+
] })
|
|
1572
|
+
]
|
|
1396
1573
|
}
|
|
1397
1574
|
);
|
|
1398
1575
|
};
|
|
1399
1576
|
|
|
1400
1577
|
// src/components/auth/pages/verify-email-page.tsx
|
|
1401
|
-
import {
|
|
1402
|
-
|
|
1578
|
+
import {
|
|
1579
|
+
Alert as Alert5,
|
|
1580
|
+
AlertDescription as AlertDescription5,
|
|
1581
|
+
AlertTitle as AlertTitle5
|
|
1582
|
+
} from "@mesob/ui/components/alert";
|
|
1583
|
+
import { toast as toast5 } from "@mesob/ui/components/sonner";
|
|
1584
|
+
import { IconAlertCircle as IconAlertCircle5 } from "@tabler/icons-react";
|
|
1585
|
+
import { useEffect as useEffect9, useState as useState10 } from "react";
|
|
1403
1586
|
|
|
1404
1587
|
// src/components/auth/verification-form.tsx
|
|
1405
1588
|
import { zodResolver as zodResolver5 } from "@hookform/resolvers/zod";
|
|
1406
1589
|
import { Button as Button6 } from "@mesob/ui/components/button";
|
|
1407
|
-
import {
|
|
1408
|
-
Form as Form5,
|
|
1409
|
-
FormControl as FormControl5,
|
|
1410
|
-
FormField as FormField5,
|
|
1411
|
-
FormItem as FormItem5,
|
|
1412
|
-
FormMessage as FormMessage5
|
|
1413
|
-
} from "@mesob/ui/components/form";
|
|
1590
|
+
import { Field as Field5, FieldError as FieldError5, FieldGroup as FieldGroup5 } from "@mesob/ui/components/field";
|
|
1414
1591
|
import {
|
|
1415
1592
|
InputOTP as InputOTP2,
|
|
1416
1593
|
InputOTPGroup as InputOTPGroup2,
|
|
1417
1594
|
InputOTPSlot as InputOTPSlot2
|
|
1418
1595
|
} from "@mesob/ui/components/input-otp";
|
|
1419
1596
|
import { Spinner as Spinner5 } from "@mesob/ui/components/spinner";
|
|
1420
|
-
import {
|
|
1421
|
-
import { useMemo as useMemo5 } from "react";
|
|
1422
|
-
import { useForm as useForm5 } from "react-hook-form";
|
|
1597
|
+
import { Controller as Controller5, useForm as useForm5 } from "react-hook-form";
|
|
1423
1598
|
import { z as z5 } from "zod";
|
|
1424
|
-
|
|
1599
|
+
|
|
1600
|
+
// src/components/auth/countdown.tsx
|
|
1601
|
+
import { Button as Button5 } from "@mesob/ui/components/button";
|
|
1602
|
+
import { Spinner as Spinner4 } from "@mesob/ui/components/spinner";
|
|
1603
|
+
import { useEffect as useEffect8, useState as useState9 } from "react";
|
|
1604
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1605
|
+
var Countdown = ({
|
|
1606
|
+
initialSeconds = 60,
|
|
1607
|
+
onResend,
|
|
1608
|
+
resending = false
|
|
1609
|
+
}) => {
|
|
1610
|
+
const t = useTranslator("Common");
|
|
1611
|
+
const [seconds, setSeconds] = useState9(initialSeconds);
|
|
1612
|
+
const [isResending, setIsResending] = useState9(false);
|
|
1613
|
+
useEffect8(() => {
|
|
1614
|
+
if (seconds <= 0) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
const timer = setInterval(() => {
|
|
1618
|
+
setSeconds((prev) => {
|
|
1619
|
+
if (prev <= 1) {
|
|
1620
|
+
clearInterval(timer);
|
|
1621
|
+
return 0;
|
|
1622
|
+
}
|
|
1623
|
+
return prev - 1;
|
|
1624
|
+
});
|
|
1625
|
+
}, 1e3);
|
|
1626
|
+
return () => clearInterval(timer);
|
|
1627
|
+
}, [seconds]);
|
|
1628
|
+
const handleResend = async () => {
|
|
1629
|
+
setIsResending(true);
|
|
1630
|
+
try {
|
|
1631
|
+
await onResend();
|
|
1632
|
+
setSeconds(initialSeconds);
|
|
1633
|
+
} catch (_error) {
|
|
1634
|
+
} finally {
|
|
1635
|
+
setIsResending(false);
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
if (seconds > 0) {
|
|
1639
|
+
return /* @__PURE__ */ jsx12(Button5, { variant: "ghost", disabled: true, children: t("resendIn", { seconds }) });
|
|
1640
|
+
}
|
|
1641
|
+
return /* @__PURE__ */ jsxs10(
|
|
1642
|
+
Button5,
|
|
1643
|
+
{
|
|
1644
|
+
variant: "ghost",
|
|
1645
|
+
onClick: handleResend,
|
|
1646
|
+
disabled: isResending || resending,
|
|
1647
|
+
children: [
|
|
1648
|
+
isResending || resending && /* @__PURE__ */ jsx12(Spinner4, {}),
|
|
1649
|
+
t("resend")
|
|
1650
|
+
]
|
|
1651
|
+
}
|
|
1652
|
+
);
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
// src/components/auth/verification-form.tsx
|
|
1656
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1657
|
+
var verificationSchema = (t) => z5.object({
|
|
1658
|
+
code: z5.string().length(6, t("form.codeLength"))
|
|
1659
|
+
});
|
|
1425
1660
|
var VerificationForm = ({
|
|
1426
1661
|
onSubmit,
|
|
1427
1662
|
onResend,
|
|
1428
1663
|
isLoading = false
|
|
1429
1664
|
}) => {
|
|
1430
|
-
const t =
|
|
1431
|
-
const verificationSchema = useMemo5(
|
|
1432
|
-
() => z5.object({
|
|
1433
|
-
code: z5.string().length(6, t("form.codeLength"))
|
|
1434
|
-
}),
|
|
1435
|
-
[t]
|
|
1436
|
-
);
|
|
1665
|
+
const t = useTranslator("Auth.verification");
|
|
1437
1666
|
const form = useForm5({
|
|
1438
|
-
resolver: zodResolver5(verificationSchema),
|
|
1667
|
+
resolver: zodResolver5(verificationSchema(t)),
|
|
1439
1668
|
defaultValues: {
|
|
1440
1669
|
code: ""
|
|
1441
1670
|
}
|
|
1442
1671
|
});
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1672
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1673
|
+
await onSubmit(values);
|
|
1674
|
+
});
|
|
1675
|
+
return /* @__PURE__ */ jsxs11("form", { id: "verification-form", onSubmit: handleSubmit, children: [
|
|
1676
|
+
/* @__PURE__ */ jsx13(FieldGroup5, { children: /* @__PURE__ */ jsx13(
|
|
1677
|
+
Controller5,
|
|
1446
1678
|
{
|
|
1447
|
-
control: form.control,
|
|
1448
1679
|
name: "code",
|
|
1449
|
-
|
|
1450
|
-
|
|
1680
|
+
control: form.control,
|
|
1681
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs11(Field5, { "data-invalid": fieldState.invalid, children: [
|
|
1682
|
+
/* @__PURE__ */ jsx13("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx13(
|
|
1451
1683
|
InputOTP2,
|
|
1452
1684
|
{
|
|
1453
1685
|
maxLength: 6,
|
|
@@ -1457,7 +1689,8 @@ var VerificationForm = ({
|
|
|
1457
1689
|
onChange: field.onChange,
|
|
1458
1690
|
onBlur: field.onBlur,
|
|
1459
1691
|
containerClassName: "gap-4 justify-center mb-2 flex items-center",
|
|
1460
|
-
|
|
1692
|
+
"aria-invalid": fieldState.invalid,
|
|
1693
|
+
children: /* @__PURE__ */ jsxs11(InputOTPGroup2, { className: "gap-3 *:data-[slot=input-otp-slot]:h-12 *:data-[slot=input-otp-slot]:w-12 *:data-[slot=input-otp-slot]:rounded-md *:data-[slot=input-otp-slot]:border *:data-[slot=input-otp-slot]:text-xl", children: [
|
|
1461
1694
|
/* @__PURE__ */ jsx13(InputOTPSlot2, { className: "h-12", index: 0 }),
|
|
1462
1695
|
/* @__PURE__ */ jsx13(InputOTPSlot2, { className: "h-12", index: 1 }),
|
|
1463
1696
|
/* @__PURE__ */ jsx13(InputOTPSlot2, { className: "h-12", index: 2 }),
|
|
@@ -1466,22 +1699,18 @@ var VerificationForm = ({
|
|
|
1466
1699
|
/* @__PURE__ */ jsx13(InputOTPSlot2, { className: "h-12", index: 5 })
|
|
1467
1700
|
] })
|
|
1468
1701
|
}
|
|
1469
|
-
) })
|
|
1470
|
-
/* @__PURE__ */ jsx13(
|
|
1702
|
+
) }),
|
|
1703
|
+
fieldState.invalid && /* @__PURE__ */ jsx13(FieldError5, { errors: [fieldState.error] })
|
|
1471
1704
|
] })
|
|
1472
1705
|
}
|
|
1473
|
-
),
|
|
1474
|
-
/* @__PURE__ */
|
|
1706
|
+
) }),
|
|
1707
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex justify-between items-center mt-4", children: [
|
|
1475
1708
|
/* @__PURE__ */ jsx13(Countdown, { onResend, resending: isLoading }),
|
|
1476
|
-
/* @__PURE__ */
|
|
1709
|
+
/* @__PURE__ */ jsxs11(
|
|
1477
1710
|
Button6,
|
|
1478
1711
|
{
|
|
1479
|
-
type: "
|
|
1480
|
-
|
|
1481
|
-
form.handleSubmit(async (values) => {
|
|
1482
|
-
await onSubmit(values);
|
|
1483
|
-
})();
|
|
1484
|
-
},
|
|
1712
|
+
type: "submit",
|
|
1713
|
+
form: "verification-form",
|
|
1485
1714
|
disabled: isLoading || form.watch("code").length !== 6,
|
|
1486
1715
|
children: [
|
|
1487
1716
|
isLoading && /* @__PURE__ */ jsx13(Spinner5, {}),
|
|
@@ -1490,27 +1719,50 @@ var VerificationForm = ({
|
|
|
1490
1719
|
}
|
|
1491
1720
|
)
|
|
1492
1721
|
] })
|
|
1493
|
-
] })
|
|
1722
|
+
] });
|
|
1494
1723
|
};
|
|
1495
1724
|
|
|
1496
1725
|
// src/components/auth/pages/verify-email-page.tsx
|
|
1497
|
-
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1726
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1498
1727
|
var VerifyEmailPage = ({
|
|
1499
1728
|
verificationId,
|
|
1500
|
-
onNavigate,
|
|
1501
|
-
linkComponent: Link,
|
|
1502
|
-
links,
|
|
1503
1729
|
email,
|
|
1504
|
-
logoImage,
|
|
1505
1730
|
redirectUrl
|
|
1506
1731
|
}) => {
|
|
1507
|
-
const
|
|
1508
|
-
const
|
|
1509
|
-
const
|
|
1510
|
-
const
|
|
1732
|
+
const { hooks, setAuth } = useApi();
|
|
1733
|
+
const { config } = useConfig();
|
|
1734
|
+
const t = createTranslator(config.messages || {}, "Auth.verification");
|
|
1735
|
+
const common = createTranslator(config.messages || {}, "Common");
|
|
1736
|
+
const footer = createTranslator(
|
|
1737
|
+
config.messages || {},
|
|
1738
|
+
"Auth.forgotPassword.footer"
|
|
1739
|
+
);
|
|
1511
1740
|
const [isLoading, setIsLoading] = useState10(false);
|
|
1512
1741
|
const [error, setError] = useState10(null);
|
|
1513
|
-
const
|
|
1742
|
+
const verifyEmailMutation = hooks.useMutation(
|
|
1743
|
+
"post",
|
|
1744
|
+
"/email/verification/confirm"
|
|
1745
|
+
);
|
|
1746
|
+
const requestEmailMutation = hooks.useMutation(
|
|
1747
|
+
"post",
|
|
1748
|
+
"/email/verification/request"
|
|
1749
|
+
);
|
|
1750
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1751
|
+
const Link = config.navigation?.linkComponent;
|
|
1752
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1753
|
+
if (typeof window !== "undefined") {
|
|
1754
|
+
window.location.href = path;
|
|
1755
|
+
}
|
|
1756
|
+
});
|
|
1757
|
+
const logoImage = config.ui.logoImage;
|
|
1758
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1759
|
+
useEffect9(() => {
|
|
1760
|
+
if (error) {
|
|
1761
|
+
toast5.error(error.title || "Error", {
|
|
1762
|
+
description: error.description
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
}, [error]);
|
|
1514
1766
|
const handleSubmit = async (values) => {
|
|
1515
1767
|
if (!verificationId) {
|
|
1516
1768
|
setError({
|
|
@@ -1522,14 +1774,16 @@ var VerifyEmailPage = ({
|
|
|
1522
1774
|
setIsLoading(true);
|
|
1523
1775
|
setError(null);
|
|
1524
1776
|
try {
|
|
1525
|
-
const res = await
|
|
1526
|
-
|
|
1527
|
-
|
|
1777
|
+
const res = await verifyEmailMutation.mutateAsync({
|
|
1778
|
+
body: {
|
|
1779
|
+
verificationId,
|
|
1780
|
+
code: values.code
|
|
1781
|
+
}
|
|
1528
1782
|
});
|
|
1529
1783
|
if ("user" in res && "session" in res) {
|
|
1530
1784
|
setAuth(res);
|
|
1531
1785
|
}
|
|
1532
|
-
onNavigate(
|
|
1786
|
+
onNavigate(defaultRedirect);
|
|
1533
1787
|
} catch (err) {
|
|
1534
1788
|
handleError(err, setError, t);
|
|
1535
1789
|
} finally {
|
|
@@ -1539,7 +1793,11 @@ var VerifyEmailPage = ({
|
|
|
1539
1793
|
const handleResend = async () => {
|
|
1540
1794
|
setError(null);
|
|
1541
1795
|
try {
|
|
1542
|
-
const res = await
|
|
1796
|
+
const res = await requestEmailMutation.mutateAsync({
|
|
1797
|
+
body: {
|
|
1798
|
+
email
|
|
1799
|
+
}
|
|
1800
|
+
});
|
|
1543
1801
|
if (res.verificationId) {
|
|
1544
1802
|
onNavigate(
|
|
1545
1803
|
`/auth/verify-email?verificationId=${res.verificationId}&email=${encodeURIComponent(email)}`
|
|
@@ -1576,12 +1834,19 @@ var VerifyEmailPage = ({
|
|
|
1576
1834
|
}
|
|
1577
1835
|
);
|
|
1578
1836
|
}
|
|
1579
|
-
|
|
1837
|
+
let errorContent = null;
|
|
1838
|
+
if (error) {
|
|
1839
|
+
if (typeof error === "string") {
|
|
1840
|
+
errorContent = { title: "Error", description: error };
|
|
1841
|
+
} else {
|
|
1842
|
+
errorContent = error;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
return /* @__PURE__ */ jsxs12(
|
|
1580
1846
|
AuthPageLayout,
|
|
1581
1847
|
{
|
|
1582
1848
|
title: t("email.title"),
|
|
1583
1849
|
description: t("email.description"),
|
|
1584
|
-
error,
|
|
1585
1850
|
logoImage,
|
|
1586
1851
|
footer: Link ? /* @__PURE__ */ jsx14(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx14(
|
|
1587
1852
|
"a",
|
|
@@ -1595,41 +1860,77 @@ var VerifyEmailPage = ({
|
|
|
1595
1860
|
children: footer("backToSignIn")
|
|
1596
1861
|
}
|
|
1597
1862
|
),
|
|
1598
|
-
children:
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1863
|
+
children: [
|
|
1864
|
+
/* @__PURE__ */ jsx14(
|
|
1865
|
+
VerificationForm,
|
|
1866
|
+
{
|
|
1867
|
+
verificationId,
|
|
1868
|
+
onSubmit: handleSubmit,
|
|
1869
|
+
onResend: handleResend,
|
|
1870
|
+
isLoading: isLoading || verifyEmailMutation.isPending || requestEmailMutation.isPending,
|
|
1871
|
+
error
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1874
|
+
errorContent && /* @__PURE__ */ jsxs12(Alert5, { variant: "destructive", className: "mt-4", children: [
|
|
1875
|
+
/* @__PURE__ */ jsx14(IconAlertCircle5, { className: "h-4 w-4" }),
|
|
1876
|
+
/* @__PURE__ */ jsx14(AlertTitle5, { children: errorContent.title }),
|
|
1877
|
+
/* @__PURE__ */ jsx14(AlertDescription5, { children: errorContent.description })
|
|
1878
|
+
] })
|
|
1879
|
+
]
|
|
1608
1880
|
}
|
|
1609
1881
|
);
|
|
1610
1882
|
};
|
|
1611
1883
|
|
|
1612
1884
|
// src/components/auth/pages/verify-phone-page.tsx
|
|
1613
|
-
import {
|
|
1614
|
-
|
|
1615
|
-
|
|
1885
|
+
import {
|
|
1886
|
+
Alert as Alert6,
|
|
1887
|
+
AlertDescription as AlertDescription6,
|
|
1888
|
+
AlertTitle as AlertTitle6
|
|
1889
|
+
} from "@mesob/ui/components/alert";
|
|
1890
|
+
import { toast as toast6 } from "@mesob/ui/components/sonner";
|
|
1891
|
+
import { IconAlertCircle as IconAlertCircle6 } from "@tabler/icons-react";
|
|
1892
|
+
import { useEffect as useEffect10, useState as useState11 } from "react";
|
|
1893
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1616
1894
|
var VerifyPhonePage = ({
|
|
1617
1895
|
verificationId,
|
|
1618
1896
|
context,
|
|
1619
1897
|
phone = "",
|
|
1620
|
-
onNavigate,
|
|
1621
|
-
linkComponent: Link,
|
|
1622
|
-
links,
|
|
1623
|
-
logoImage,
|
|
1624
1898
|
redirectUrl
|
|
1625
1899
|
}) => {
|
|
1626
|
-
const
|
|
1627
|
-
const
|
|
1628
|
-
const
|
|
1629
|
-
const
|
|
1900
|
+
const { hooks, refresh, setAuth } = useApi();
|
|
1901
|
+
const { config } = useConfig();
|
|
1902
|
+
const t = createTranslator(config.messages || {}, "Auth.verification");
|
|
1903
|
+
const common = createTranslator(config.messages || {}, "Common");
|
|
1904
|
+
const footer = createTranslator(
|
|
1905
|
+
config.messages || {},
|
|
1906
|
+
"Auth.forgotPassword.footer"
|
|
1907
|
+
);
|
|
1630
1908
|
const [isLoading, setIsLoading] = useState11(false);
|
|
1631
1909
|
const [error, setError] = useState11(null);
|
|
1632
|
-
const
|
|
1910
|
+
const verifyPhoneMutation = hooks.useMutation(
|
|
1911
|
+
"post",
|
|
1912
|
+
"/phone/verification/confirm"
|
|
1913
|
+
);
|
|
1914
|
+
const requestPhoneMutation = hooks.useMutation(
|
|
1915
|
+
"post",
|
|
1916
|
+
"/phone/verification/request"
|
|
1917
|
+
);
|
|
1918
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1919
|
+
const Link = config.navigation?.linkComponent;
|
|
1920
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1921
|
+
if (typeof window !== "undefined") {
|
|
1922
|
+
window.location.href = path;
|
|
1923
|
+
}
|
|
1924
|
+
});
|
|
1925
|
+
const logoImage = config.ui.logoImage;
|
|
1926
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1927
|
+
useEffect10(() => {
|
|
1928
|
+
if (error) {
|
|
1929
|
+
toast6.error(error.title || "Error", {
|
|
1930
|
+
description: error.description
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
}, [error]);
|
|
1633
1934
|
const handleSubmit = async (values) => {
|
|
1634
1935
|
if (!verificationId) {
|
|
1635
1936
|
setError({
|
|
@@ -1641,18 +1942,20 @@ var VerifyPhonePage = ({
|
|
|
1641
1942
|
setIsLoading(true);
|
|
1642
1943
|
setError(null);
|
|
1643
1944
|
try {
|
|
1644
|
-
const res = await
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1945
|
+
const res = await verifyPhoneMutation.mutateAsync({
|
|
1946
|
+
body: {
|
|
1947
|
+
verificationId,
|
|
1948
|
+
code: values.code,
|
|
1949
|
+
context
|
|
1950
|
+
}
|
|
1648
1951
|
});
|
|
1649
1952
|
if (res && "user" in res && "session" in res && res.session) {
|
|
1650
1953
|
setAuth(res);
|
|
1651
|
-
onNavigate(
|
|
1954
|
+
onNavigate(defaultRedirect);
|
|
1652
1955
|
return;
|
|
1653
1956
|
}
|
|
1654
1957
|
await refresh();
|
|
1655
|
-
onNavigate(
|
|
1958
|
+
onNavigate(defaultRedirect);
|
|
1656
1959
|
} catch (err) {
|
|
1657
1960
|
handleError(err, setError, t);
|
|
1658
1961
|
} finally {
|
|
@@ -1670,7 +1973,12 @@ var VerifyPhonePage = ({
|
|
|
1670
1973
|
});
|
|
1671
1974
|
return;
|
|
1672
1975
|
}
|
|
1673
|
-
const res = await
|
|
1976
|
+
const res = await requestPhoneMutation.mutateAsync({
|
|
1977
|
+
body: {
|
|
1978
|
+
phone: targetPhone,
|
|
1979
|
+
context
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1674
1982
|
if (res && "verificationId" in res && res.verificationId) {
|
|
1675
1983
|
onNavigate(
|
|
1676
1984
|
`/auth/verify-phone?context=${context}&verificationId=${res.verificationId}&phone=${targetPhone}`
|
|
@@ -1707,14 +2015,21 @@ var VerifyPhonePage = ({
|
|
|
1707
2015
|
}
|
|
1708
2016
|
);
|
|
1709
2017
|
}
|
|
1710
|
-
|
|
2018
|
+
let errorContent = null;
|
|
2019
|
+
if (error) {
|
|
2020
|
+
if (typeof error === "string") {
|
|
2021
|
+
errorContent = { title: "Error", description: error };
|
|
2022
|
+
} else {
|
|
2023
|
+
errorContent = error;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
return /* @__PURE__ */ jsxs13(
|
|
1711
2027
|
AuthPageLayout,
|
|
1712
2028
|
{
|
|
1713
2029
|
title: t("phone.title"),
|
|
1714
2030
|
description: t("phone.description", {
|
|
1715
2031
|
target: phone || t("phone.missingPhone")
|
|
1716
2032
|
}),
|
|
1717
|
-
error,
|
|
1718
2033
|
logoImage,
|
|
1719
2034
|
footer: Link ? /* @__PURE__ */ jsx15(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx15(
|
|
1720
2035
|
"a",
|
|
@@ -1728,75 +2043,794 @@ var VerifyPhonePage = ({
|
|
|
1728
2043
|
children: footer("backToSignIn")
|
|
1729
2044
|
}
|
|
1730
2045
|
),
|
|
1731
|
-
children:
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
2046
|
+
children: [
|
|
2047
|
+
/* @__PURE__ */ jsx15(
|
|
2048
|
+
VerificationForm,
|
|
2049
|
+
{
|
|
2050
|
+
verificationId,
|
|
2051
|
+
onSubmit: handleSubmit,
|
|
2052
|
+
onResend: handleResend,
|
|
2053
|
+
isLoading: isLoading || verifyPhoneMutation.isPending || requestPhoneMutation.isPending,
|
|
2054
|
+
error
|
|
2055
|
+
}
|
|
2056
|
+
),
|
|
2057
|
+
errorContent && /* @__PURE__ */ jsxs13(Alert6, { variant: "destructive", className: "mt-4", children: [
|
|
2058
|
+
/* @__PURE__ */ jsx15(IconAlertCircle6, { className: "h-4 w-4" }),
|
|
2059
|
+
/* @__PURE__ */ jsx15(AlertTitle6, { children: errorContent.title }),
|
|
2060
|
+
/* @__PURE__ */ jsx15(AlertDescription6, { children: errorContent.description })
|
|
2061
|
+
] })
|
|
2062
|
+
]
|
|
1741
2063
|
}
|
|
1742
2064
|
);
|
|
1743
2065
|
};
|
|
1744
2066
|
|
|
1745
|
-
// src/
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
getSession: client.getSession.bind(client),
|
|
1762
|
-
useSession: () => {
|
|
1763
|
-
throw new Error("useSession must be used within AuthProvider");
|
|
1764
|
-
}
|
|
2067
|
+
// src/components/error-boundary.tsx
|
|
2068
|
+
import { Button as Button7 } from "@mesob/ui/components/button";
|
|
2069
|
+
import { Component } from "react";
|
|
2070
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2071
|
+
var ErrorBoundary = class extends Component {
|
|
2072
|
+
constructor(props) {
|
|
2073
|
+
super(props);
|
|
2074
|
+
this.state = { hasError: false, error: null };
|
|
2075
|
+
}
|
|
2076
|
+
static getDerivedStateFromError(error) {
|
|
2077
|
+
return { hasError: true, error };
|
|
2078
|
+
}
|
|
2079
|
+
componentDidCatch(_error, _errorInfo) {
|
|
2080
|
+
}
|
|
2081
|
+
reset = () => {
|
|
2082
|
+
this.setState({ hasError: false, error: null });
|
|
1765
2083
|
};
|
|
2084
|
+
render() {
|
|
2085
|
+
if (this.state.hasError && this.state.error) {
|
|
2086
|
+
if (this.props.fallback) {
|
|
2087
|
+
return this.props.fallback({
|
|
2088
|
+
error: this.state.error,
|
|
2089
|
+
reset: this.reset
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
return /* @__PURE__ */ jsx16(ErrorFallback, { error: this.state.error, reset: this.reset });
|
|
2093
|
+
}
|
|
2094
|
+
return this.props.children;
|
|
2095
|
+
}
|
|
1766
2096
|
};
|
|
2097
|
+
function ErrorFallback({ error, reset }) {
|
|
2098
|
+
return /* @__PURE__ */ jsx16("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: /* @__PURE__ */ jsxs14("div", { className: "max-w-md w-full space-y-4 text-center", children: [
|
|
2099
|
+
/* @__PURE__ */ jsxs14("div", { className: "space-y-2", children: [
|
|
2100
|
+
/* @__PURE__ */ jsx16("h2", { className: "text-2xl font-bold text-destructive", children: "Something went wrong" }),
|
|
2101
|
+
/* @__PURE__ */ jsx16("p", { className: "text-muted-foreground", children: error.message || "An unexpected error occurred" })
|
|
2102
|
+
] }),
|
|
2103
|
+
/* @__PURE__ */ jsx16(Button7, { onClick: reset, variant: "outline", children: "Try again" })
|
|
2104
|
+
] }) });
|
|
2105
|
+
}
|
|
2106
|
+
function AuthErrorBoundary({ children }) {
|
|
2107
|
+
return /* @__PURE__ */ jsx16(ErrorBoundary, { children });
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// src/components/iam/permissions/permissions-page.tsx
|
|
2111
|
+
import { Badge } from "@mesob/ui/components/badge";
|
|
2112
|
+
import { Button as Button8 } from "@mesob/ui/components/button";
|
|
2113
|
+
import { useState as useState12 } from "react";
|
|
2114
|
+
|
|
2115
|
+
// src/components/shared/data-table/data-table.tsx
|
|
2116
|
+
import {
|
|
2117
|
+
Table,
|
|
2118
|
+
TableBody,
|
|
2119
|
+
TableCell,
|
|
2120
|
+
TableHead,
|
|
2121
|
+
TableHeader,
|
|
2122
|
+
TableRow
|
|
2123
|
+
} from "@mesob/ui/components/table";
|
|
2124
|
+
|
|
2125
|
+
// src/components/skeletons/table-skeleton.tsx
|
|
2126
|
+
import { Skeleton } from "@mesob/ui/components/skeleton";
|
|
2127
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2128
|
+
function TableSkeleton({ columns = 5, rows = 10 }) {
|
|
2129
|
+
const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);
|
|
2130
|
+
const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);
|
|
2131
|
+
const cellKeys = Array.from(
|
|
2132
|
+
{ length: rows },
|
|
2133
|
+
(_, rowIdx) => Array.from({ length: columns }, (_2, colIdx) => `cell-${rowIdx}-${colIdx}`)
|
|
2134
|
+
);
|
|
2135
|
+
return /* @__PURE__ */ jsxs15("div", { className: "w-full space-y-4", children: [
|
|
2136
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between items-center", children: [
|
|
2137
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-8 w-48" }),
|
|
2138
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-32" })
|
|
2139
|
+
] }),
|
|
2140
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex gap-4", children: [
|
|
2141
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 flex-1 max-w-sm" }),
|
|
2142
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-24" }),
|
|
2143
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-24" })
|
|
2144
|
+
] }),
|
|
2145
|
+
/* @__PURE__ */ jsxs15("div", { className: "border rounded-lg overflow-hidden", children: [
|
|
2146
|
+
/* @__PURE__ */ jsx17("div", { className: "flex gap-4 p-4 bg-muted", children: headerKeys.map((key) => /* @__PURE__ */ jsx17(Skeleton, { className: "h-4 flex-1" }, key)) }),
|
|
2147
|
+
rowKeys.map((rowKey, rowIdx) => /* @__PURE__ */ jsx17("div", { className: "flex gap-4 p-4 border-t", children: cellKeys[rowIdx]?.map((cellKey) => /* @__PURE__ */ jsx17(Skeleton, { className: "h-4 flex-1" }, cellKey)) }, rowKey))
|
|
2148
|
+
] }),
|
|
2149
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between items-center", children: [
|
|
2150
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-4 w-32" }),
|
|
2151
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
|
|
2152
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-20" }),
|
|
2153
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-20" })
|
|
2154
|
+
] })
|
|
2155
|
+
] })
|
|
2156
|
+
] });
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
// src/components/shared/data-table/data-table.tsx
|
|
2160
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2161
|
+
function DataTable({
|
|
2162
|
+
data,
|
|
2163
|
+
columns,
|
|
2164
|
+
isLoading,
|
|
2165
|
+
onRowClick,
|
|
2166
|
+
emptyMessage = "No data available",
|
|
2167
|
+
actions
|
|
2168
|
+
}) {
|
|
2169
|
+
if (isLoading) {
|
|
2170
|
+
return /* @__PURE__ */ jsx18(TableSkeleton, { columns: columns.length, rows: 5 });
|
|
2171
|
+
}
|
|
2172
|
+
if (data.length === 0) {
|
|
2173
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: [
|
|
2174
|
+
/* @__PURE__ */ jsx18("p", { className: "text-muted-foreground", children: emptyMessage }),
|
|
2175
|
+
actions && /* @__PURE__ */ jsx18("div", { className: "mt-4", children: actions })
|
|
2176
|
+
] });
|
|
2177
|
+
}
|
|
2178
|
+
return /* @__PURE__ */ jsxs16("div", { className: "w-full space-y-4", children: [
|
|
2179
|
+
actions && /* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: actions }),
|
|
2180
|
+
/* @__PURE__ */ jsx18("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs16(Table, { children: [
|
|
2181
|
+
/* @__PURE__ */ jsx18(TableHeader, { children: /* @__PURE__ */ jsx18(TableRow, { children: columns.map((column) => /* @__PURE__ */ jsx18(TableHead, { children: column.header }, column.key)) }) }),
|
|
2182
|
+
/* @__PURE__ */ jsx18(TableBody, { children: data.map((row) => /* @__PURE__ */ jsx18(
|
|
2183
|
+
TableRow,
|
|
2184
|
+
{
|
|
2185
|
+
onClick: () => onRowClick?.(row),
|
|
2186
|
+
className: onRowClick ? "cursor-pointer hover:bg-muted/50" : "",
|
|
2187
|
+
children: columns.map((column) => /* @__PURE__ */ jsx18(TableCell, { children: column.cell(row) }, `${row.id}-${column.key}`))
|
|
2188
|
+
},
|
|
2189
|
+
row.id
|
|
2190
|
+
)) })
|
|
2191
|
+
] }) })
|
|
2192
|
+
] });
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
// src/components/iam/permissions/permissions-page.tsx
|
|
2196
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2197
|
+
function PermissionsPage() {
|
|
2198
|
+
const { hooks } = useApi();
|
|
2199
|
+
const [page, setPage] = useState12(1);
|
|
2200
|
+
const limit = 20;
|
|
2201
|
+
const { data, isLoading, error } = hooks.useQuery("get", "/permissions", {
|
|
2202
|
+
params: {
|
|
2203
|
+
query: {
|
|
2204
|
+
page: String(page),
|
|
2205
|
+
limit: String(limit)
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
});
|
|
2209
|
+
const columns = [
|
|
2210
|
+
{
|
|
2211
|
+
key: "name",
|
|
2212
|
+
header: "Permission",
|
|
2213
|
+
cell: (permission) => /* @__PURE__ */ jsxs17("div", { children: [
|
|
2214
|
+
/* @__PURE__ */ jsx19("p", { className: "font-medium", children: permission.name }),
|
|
2215
|
+
/* @__PURE__ */ jsx19(Badge, { variant: "outline", className: "mt-1 font-mono text-xs", children: permission.code })
|
|
2216
|
+
] })
|
|
2217
|
+
},
|
|
2218
|
+
{
|
|
2219
|
+
key: "resource",
|
|
2220
|
+
header: "Resource",
|
|
2221
|
+
cell: (permission) => /* @__PURE__ */ jsx19(Badge, { variant: "secondary", children: permission.resource })
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
key: "action",
|
|
2225
|
+
header: "Action",
|
|
2226
|
+
cell: (permission) => /* @__PURE__ */ jsx19(Badge, { variant: "outline", children: permission.action })
|
|
2227
|
+
},
|
|
2228
|
+
{
|
|
2229
|
+
key: "description",
|
|
2230
|
+
header: "Description",
|
|
2231
|
+
cell: (permission) => /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground max-w-xs truncate", children: permission.description })
|
|
2232
|
+
},
|
|
2233
|
+
{
|
|
2234
|
+
key: "actions",
|
|
2235
|
+
header: "Actions",
|
|
2236
|
+
cell: (_permission) => /* @__PURE__ */ jsx19(Button8, { variant: "outline", size: "sm", children: "Edit" })
|
|
2237
|
+
}
|
|
2238
|
+
];
|
|
2239
|
+
if (error) {
|
|
2240
|
+
return /* @__PURE__ */ jsx19("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx19("p", { className: "text-destructive", children: "Error loading permissions" }) });
|
|
2241
|
+
}
|
|
2242
|
+
return /* @__PURE__ */ jsxs17("div", { className: "w-full p-6 space-y-4", children: [
|
|
2243
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex justify-between items-center", children: [
|
|
2244
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
2245
|
+
/* @__PURE__ */ jsx19("h1", { className: "text-3xl font-bold", children: "Permissions" }),
|
|
2246
|
+
/* @__PURE__ */ jsx19("p", { className: "text-muted-foreground", children: "Manage system permissions" })
|
|
2247
|
+
] }),
|
|
2248
|
+
/* @__PURE__ */ jsx19(Button8, { children: "Create Permission" })
|
|
2249
|
+
] }),
|
|
2250
|
+
/* @__PURE__ */ jsx19(
|
|
2251
|
+
DataTable,
|
|
2252
|
+
{
|
|
2253
|
+
data: data?.permissions || [],
|
|
2254
|
+
columns,
|
|
2255
|
+
isLoading,
|
|
2256
|
+
emptyMessage: "No permissions found"
|
|
2257
|
+
}
|
|
2258
|
+
),
|
|
2259
|
+
data && "permissions" in data && data.permissions && data.permissions.length >= limit && /* @__PURE__ */ jsxs17("div", { className: "flex justify-between items-center", children: [
|
|
2260
|
+
/* @__PURE__ */ jsx19(
|
|
2261
|
+
Button8,
|
|
2262
|
+
{
|
|
2263
|
+
variant: "outline",
|
|
2264
|
+
disabled: page === 1,
|
|
2265
|
+
onClick: () => setPage(page - 1),
|
|
2266
|
+
children: "Previous"
|
|
2267
|
+
}
|
|
2268
|
+
),
|
|
2269
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-sm text-muted-foreground", children: [
|
|
2270
|
+
"Page ",
|
|
2271
|
+
page
|
|
2272
|
+
] }),
|
|
2273
|
+
/* @__PURE__ */ jsx19(Button8, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2274
|
+
] })
|
|
2275
|
+
] });
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// src/components/iam/roles/roles-page.tsx
|
|
2279
|
+
import { Badge as Badge2 } from "@mesob/ui/components/badge";
|
|
2280
|
+
import { Button as Button9 } from "@mesob/ui/components/button";
|
|
2281
|
+
import { useState as useState13 } from "react";
|
|
2282
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2283
|
+
function RolesPage() {
|
|
2284
|
+
const { hooks } = useApi();
|
|
2285
|
+
const [page, setPage] = useState13(1);
|
|
2286
|
+
const limit = 20;
|
|
2287
|
+
const { data, isLoading, error } = hooks.useQuery("get", "/roles", {
|
|
2288
|
+
params: {
|
|
2289
|
+
query: {
|
|
2290
|
+
page: String(page),
|
|
2291
|
+
limit: String(limit)
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
});
|
|
2295
|
+
const columns = [
|
|
2296
|
+
{
|
|
2297
|
+
key: "name",
|
|
2298
|
+
header: "Role",
|
|
2299
|
+
cell: (role) => /* @__PURE__ */ jsxs18("div", { children: [
|
|
2300
|
+
/* @__PURE__ */ jsx20("p", { className: "font-medium", children: role.name }),
|
|
2301
|
+
/* @__PURE__ */ jsx20(Badge2, { variant: "outline", className: "mt-1", children: role.code })
|
|
2302
|
+
] })
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
key: "description",
|
|
2306
|
+
header: "Description",
|
|
2307
|
+
cell: (role) => /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: role.description })
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
key: "createdAt",
|
|
2311
|
+
header: "Created",
|
|
2312
|
+
cell: (role) => /* @__PURE__ */ jsx20("p", { className: "text-sm", children: new Date(role.createdAt).toLocaleDateString() })
|
|
2313
|
+
},
|
|
2314
|
+
{
|
|
2315
|
+
key: "actions",
|
|
2316
|
+
header: "Actions",
|
|
2317
|
+
cell: (_role) => /* @__PURE__ */ jsxs18("div", { className: "flex gap-2", children: [
|
|
2318
|
+
/* @__PURE__ */ jsx20(Button9, { variant: "outline", size: "sm", children: "Permissions" }),
|
|
2319
|
+
/* @__PURE__ */ jsx20(Button9, { variant: "outline", size: "sm", children: "Edit" })
|
|
2320
|
+
] })
|
|
2321
|
+
}
|
|
2322
|
+
];
|
|
2323
|
+
if (error) {
|
|
2324
|
+
return /* @__PURE__ */ jsx20("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx20("p", { className: "text-destructive", children: "Error loading roles" }) });
|
|
2325
|
+
}
|
|
2326
|
+
return /* @__PURE__ */ jsxs18("div", { className: "w-full p-6 space-y-4", children: [
|
|
2327
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex justify-between items-center", children: [
|
|
2328
|
+
/* @__PURE__ */ jsxs18("div", { children: [
|
|
2329
|
+
/* @__PURE__ */ jsx20("h1", { className: "text-3xl font-bold", children: "Roles" }),
|
|
2330
|
+
/* @__PURE__ */ jsx20("p", { className: "text-muted-foreground", children: "Manage user roles" })
|
|
2331
|
+
] }),
|
|
2332
|
+
/* @__PURE__ */ jsx20(Button9, { children: "Create Role" })
|
|
2333
|
+
] }),
|
|
2334
|
+
/* @__PURE__ */ jsx20(
|
|
2335
|
+
DataTable,
|
|
2336
|
+
{
|
|
2337
|
+
data: data?.roles || [],
|
|
2338
|
+
columns,
|
|
2339
|
+
isLoading,
|
|
2340
|
+
emptyMessage: "No roles found"
|
|
2341
|
+
}
|
|
2342
|
+
),
|
|
2343
|
+
data && "roles" in data && data.roles && data.roles.length >= limit && /* @__PURE__ */ jsxs18("div", { className: "flex justify-between items-center", children: [
|
|
2344
|
+
/* @__PURE__ */ jsx20(
|
|
2345
|
+
Button9,
|
|
2346
|
+
{
|
|
2347
|
+
variant: "outline",
|
|
2348
|
+
disabled: page === 1,
|
|
2349
|
+
onClick: () => setPage(page - 1),
|
|
2350
|
+
children: "Previous"
|
|
2351
|
+
}
|
|
2352
|
+
),
|
|
2353
|
+
/* @__PURE__ */ jsxs18("span", { className: "text-sm text-muted-foreground", children: [
|
|
2354
|
+
"Page ",
|
|
2355
|
+
page
|
|
2356
|
+
] }),
|
|
2357
|
+
/* @__PURE__ */ jsx20(Button9, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2358
|
+
] })
|
|
2359
|
+
] });
|
|
2360
|
+
}
|
|
1767
2361
|
|
|
1768
|
-
// src/
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2362
|
+
// src/components/iam/sessions/sessions-page.tsx
|
|
2363
|
+
import { Button as Button10 } from "@mesob/ui/components/button";
|
|
2364
|
+
import { useState as useState14 } from "react";
|
|
2365
|
+
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2366
|
+
function SessionsPage() {
|
|
2367
|
+
const { hooks } = useApi();
|
|
2368
|
+
const [selectedSessionId] = useState14(null);
|
|
2369
|
+
const { data, isLoading, error, refetch } = hooks.useQuery(
|
|
2370
|
+
"get",
|
|
2371
|
+
"/sessions"
|
|
2372
|
+
);
|
|
2373
|
+
const deleteMutation = hooks.useMutation("delete", "/sessions/{id}", {
|
|
2374
|
+
onSuccess: () => {
|
|
2375
|
+
refetch();
|
|
2376
|
+
}
|
|
2377
|
+
});
|
|
2378
|
+
const handleDeleteSession = async (sessionId) => {
|
|
2379
|
+
if (confirm("Are you sure you want to revoke this session?")) {
|
|
2380
|
+
try {
|
|
2381
|
+
await deleteMutation.mutateAsync({
|
|
2382
|
+
params: {
|
|
2383
|
+
path: { id: sessionId }
|
|
2384
|
+
}
|
|
2385
|
+
});
|
|
2386
|
+
} catch (_err) {
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
1778
2389
|
};
|
|
2390
|
+
const columns = [
|
|
2391
|
+
{
|
|
2392
|
+
key: "createdAt",
|
|
2393
|
+
header: "Created",
|
|
2394
|
+
cell: (session) => /* @__PURE__ */ jsxs19("div", { children: [
|
|
2395
|
+
/* @__PURE__ */ jsx21("p", { className: "text-sm font-medium", children: new Date(session.createdAt).toLocaleDateString() }),
|
|
2396
|
+
/* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground", children: new Date(session.createdAt).toLocaleTimeString() })
|
|
2397
|
+
] })
|
|
2398
|
+
},
|
|
2399
|
+
{
|
|
2400
|
+
key: "expiresAt",
|
|
2401
|
+
header: "Expires",
|
|
2402
|
+
cell: (session) => /* @__PURE__ */ jsx21("p", { className: "text-sm", children: new Date(session.expiresAt).toLocaleDateString() })
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
key: "userAgent",
|
|
2406
|
+
header: "Device",
|
|
2407
|
+
cell: (session) => /* @__PURE__ */ jsx21("p", { className: "text-sm truncate max-w-xs", children: session.userAgent || "Unknown" })
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
key: "ip",
|
|
2411
|
+
header: "IP Address",
|
|
2412
|
+
cell: (session) => /* @__PURE__ */ jsx21("p", { className: "text-sm font-mono", children: session.ip || "Unknown" })
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
key: "actions",
|
|
2416
|
+
header: "Actions",
|
|
2417
|
+
cell: (session) => /* @__PURE__ */ jsx21(
|
|
2418
|
+
Button10,
|
|
2419
|
+
{
|
|
2420
|
+
variant: "destructive",
|
|
2421
|
+
size: "sm",
|
|
2422
|
+
onClick: () => handleDeleteSession(session.id),
|
|
2423
|
+
disabled: deleteMutation.isPending && selectedSessionId === session.id,
|
|
2424
|
+
children: deleteMutation.isPending && selectedSessionId === session.id ? "Revoking..." : "Revoke"
|
|
2425
|
+
}
|
|
2426
|
+
)
|
|
2427
|
+
}
|
|
2428
|
+
];
|
|
2429
|
+
if (error) {
|
|
2430
|
+
return /* @__PURE__ */ jsx21("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx21("p", { className: "text-destructive", children: "Error loading sessions" }) });
|
|
2431
|
+
}
|
|
2432
|
+
return /* @__PURE__ */ jsxs19("div", { className: "w-full p-6 space-y-4", children: [
|
|
2433
|
+
/* @__PURE__ */ jsxs19("div", { children: [
|
|
2434
|
+
/* @__PURE__ */ jsx21("h1", { className: "text-3xl font-bold", children: "Sessions" }),
|
|
2435
|
+
/* @__PURE__ */ jsx21("p", { className: "text-muted-foreground", children: "View and manage active sessions" })
|
|
2436
|
+
] }),
|
|
2437
|
+
/* @__PURE__ */ jsx21(
|
|
2438
|
+
DataTable,
|
|
2439
|
+
{
|
|
2440
|
+
data: data?.sessions || [],
|
|
2441
|
+
columns,
|
|
2442
|
+
isLoading,
|
|
2443
|
+
emptyMessage: "No active sessions"
|
|
2444
|
+
}
|
|
2445
|
+
)
|
|
2446
|
+
] });
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
// src/components/iam/tenants/tenants-page.tsx
|
|
2450
|
+
import { Badge as Badge3 } from "@mesob/ui/components/badge";
|
|
2451
|
+
import { Button as Button11 } from "@mesob/ui/components/button";
|
|
2452
|
+
import { useState as useState15 } from "react";
|
|
2453
|
+
import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2454
|
+
function TenantsPage() {
|
|
2455
|
+
const { hooks } = useApi();
|
|
2456
|
+
const [page, setPage] = useState15(1);
|
|
2457
|
+
const limit = 20;
|
|
2458
|
+
const { data, isLoading, error } = hooks.useQuery("get", "/tenants", {
|
|
2459
|
+
params: {
|
|
2460
|
+
query: {
|
|
2461
|
+
page: String(page),
|
|
2462
|
+
limit: String(limit)
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
});
|
|
2466
|
+
const columns = [
|
|
2467
|
+
{
|
|
2468
|
+
key: "name",
|
|
2469
|
+
header: "Tenant",
|
|
2470
|
+
cell: (tenant) => /* @__PURE__ */ jsxs20("div", { children: [
|
|
2471
|
+
/* @__PURE__ */ jsx22("p", { className: "font-medium", children: tenant.name }),
|
|
2472
|
+
/* @__PURE__ */ jsxs20("p", { className: "text-sm text-muted-foreground", children: [
|
|
2473
|
+
"/",
|
|
2474
|
+
tenant.slug
|
|
2475
|
+
] })
|
|
2476
|
+
] })
|
|
2477
|
+
},
|
|
2478
|
+
{
|
|
2479
|
+
key: "status",
|
|
2480
|
+
header: "Status",
|
|
2481
|
+
cell: (tenant) => /* @__PURE__ */ jsx22(Badge3, { variant: tenant.status === "active" ? "default" : "secondary", children: tenant.status })
|
|
2482
|
+
},
|
|
2483
|
+
{
|
|
2484
|
+
key: "createdAt",
|
|
2485
|
+
header: "Created",
|
|
2486
|
+
cell: (tenant) => /* @__PURE__ */ jsx22("p", { className: "text-sm", children: new Date(tenant.createdAt).toLocaleDateString() })
|
|
2487
|
+
},
|
|
2488
|
+
{
|
|
2489
|
+
key: "actions",
|
|
2490
|
+
header: "Actions",
|
|
2491
|
+
cell: (_tenant) => /* @__PURE__ */ jsxs20("div", { className: "flex gap-2", children: [
|
|
2492
|
+
/* @__PURE__ */ jsx22(Button11, { variant: "outline", size: "sm", children: "Domains" }),
|
|
2493
|
+
/* @__PURE__ */ jsx22(Button11, { variant: "outline", size: "sm", children: "Edit" })
|
|
2494
|
+
] })
|
|
2495
|
+
}
|
|
2496
|
+
];
|
|
2497
|
+
if (error) {
|
|
2498
|
+
return /* @__PURE__ */ jsx22("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx22("p", { className: "text-destructive", children: "Error loading tenants" }) });
|
|
2499
|
+
}
|
|
2500
|
+
return /* @__PURE__ */ jsxs20("div", { className: "w-full p-6 space-y-4", children: [
|
|
2501
|
+
/* @__PURE__ */ jsxs20("div", { className: "flex justify-between items-center", children: [
|
|
2502
|
+
/* @__PURE__ */ jsxs20("div", { children: [
|
|
2503
|
+
/* @__PURE__ */ jsx22("h1", { className: "text-3xl font-bold", children: "Tenants" }),
|
|
2504
|
+
/* @__PURE__ */ jsx22("p", { className: "text-muted-foreground", children: "Manage tenant organizations" })
|
|
2505
|
+
] }),
|
|
2506
|
+
/* @__PURE__ */ jsx22(Button11, { children: "Create Tenant" })
|
|
2507
|
+
] }),
|
|
2508
|
+
/* @__PURE__ */ jsx22(
|
|
2509
|
+
DataTable,
|
|
2510
|
+
{
|
|
2511
|
+
data: data?.tenants || [],
|
|
2512
|
+
columns,
|
|
2513
|
+
isLoading,
|
|
2514
|
+
emptyMessage: "No tenants found"
|
|
2515
|
+
}
|
|
2516
|
+
),
|
|
2517
|
+
data && "tenants" in data && data.tenants && data.tenants.length >= limit && /* @__PURE__ */ jsxs20("div", { className: "flex justify-between items-center", children: [
|
|
2518
|
+
/* @__PURE__ */ jsx22(
|
|
2519
|
+
Button11,
|
|
2520
|
+
{
|
|
2521
|
+
variant: "outline",
|
|
2522
|
+
disabled: page === 1,
|
|
2523
|
+
onClick: () => setPage(page - 1),
|
|
2524
|
+
children: "Previous"
|
|
2525
|
+
}
|
|
2526
|
+
),
|
|
2527
|
+
/* @__PURE__ */ jsxs20("span", { className: "text-sm text-muted-foreground", children: [
|
|
2528
|
+
"Page ",
|
|
2529
|
+
page
|
|
2530
|
+
] }),
|
|
2531
|
+
/* @__PURE__ */ jsx22(Button11, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2532
|
+
] })
|
|
2533
|
+
] });
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
// src/components/iam/users/users-page.tsx
|
|
2537
|
+
import { Badge as Badge4 } from "@mesob/ui/components/badge";
|
|
2538
|
+
import { Button as Button12 } from "@mesob/ui/components/button";
|
|
2539
|
+
import { useState as useState16 } from "react";
|
|
2540
|
+
import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2541
|
+
function UsersPage() {
|
|
2542
|
+
const { hooks } = useApi();
|
|
2543
|
+
const [page, setPage] = useState16(1);
|
|
2544
|
+
const limit = 20;
|
|
2545
|
+
const { data, isLoading, error } = hooks.useQuery("get", "/users", {
|
|
2546
|
+
params: {
|
|
2547
|
+
query: {
|
|
2548
|
+
page: String(page),
|
|
2549
|
+
limit: String(limit)
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
});
|
|
2553
|
+
const columns = [
|
|
2554
|
+
{
|
|
2555
|
+
key: "fullName",
|
|
2556
|
+
header: "Name",
|
|
2557
|
+
cell: (user) => /* @__PURE__ */ jsxs21("div", { children: [
|
|
2558
|
+
/* @__PURE__ */ jsx23("p", { className: "font-medium", children: user.fullName }),
|
|
2559
|
+
/* @__PURE__ */ jsxs21("p", { className: "text-sm text-muted-foreground", children: [
|
|
2560
|
+
"@",
|
|
2561
|
+
user.handle
|
|
2562
|
+
] })
|
|
2563
|
+
] })
|
|
2564
|
+
},
|
|
2565
|
+
{
|
|
2566
|
+
key: "contact",
|
|
2567
|
+
header: "Contact",
|
|
2568
|
+
cell: (user) => /* @__PURE__ */ jsxs21("div", { className: "space-y-1", children: [
|
|
2569
|
+
user.email && /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2", children: [
|
|
2570
|
+
/* @__PURE__ */ jsx23("p", { className: "text-sm", children: user.email }),
|
|
2571
|
+
user.emailVerified && /* @__PURE__ */ jsx23(Badge4, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2572
|
+
] }),
|
|
2573
|
+
user.phone && /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2", children: [
|
|
2574
|
+
/* @__PURE__ */ jsx23("p", { className: "text-sm", children: user.phone }),
|
|
2575
|
+
user.phoneVerified && /* @__PURE__ */ jsx23(Badge4, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2576
|
+
] })
|
|
2577
|
+
] })
|
|
2578
|
+
},
|
|
2579
|
+
{
|
|
2580
|
+
key: "lastSignIn",
|
|
2581
|
+
header: "Last Sign In",
|
|
2582
|
+
cell: (user) => /* @__PURE__ */ jsx23("p", { className: "text-sm", children: user.lastSignInAt ? new Date(user.lastSignInAt).toLocaleDateString() : "Never" })
|
|
2583
|
+
},
|
|
2584
|
+
{
|
|
2585
|
+
key: "actions",
|
|
2586
|
+
header: "Actions",
|
|
2587
|
+
cell: (_user) => /* @__PURE__ */ jsxs21("div", { className: "flex gap-2", children: [
|
|
2588
|
+
/* @__PURE__ */ jsx23(Button12, { variant: "outline", size: "sm", children: "View" }),
|
|
2589
|
+
/* @__PURE__ */ jsx23(Button12, { variant: "outline", size: "sm", children: "Edit" })
|
|
2590
|
+
] })
|
|
2591
|
+
}
|
|
2592
|
+
];
|
|
2593
|
+
if (error) {
|
|
2594
|
+
return /* @__PURE__ */ jsx23("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx23("p", { className: "text-destructive", children: "Error loading users" }) });
|
|
2595
|
+
}
|
|
2596
|
+
return /* @__PURE__ */ jsxs21("div", { className: "w-full p-6 space-y-4", children: [
|
|
2597
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex justify-between items-center", children: [
|
|
2598
|
+
/* @__PURE__ */ jsxs21("div", { children: [
|
|
2599
|
+
/* @__PURE__ */ jsx23("h1", { className: "text-3xl font-bold", children: "Users" }),
|
|
2600
|
+
/* @__PURE__ */ jsx23("p", { className: "text-muted-foreground", children: "Manage user accounts" })
|
|
2601
|
+
] }),
|
|
2602
|
+
/* @__PURE__ */ jsx23(Button12, { children: "Create User" })
|
|
2603
|
+
] }),
|
|
2604
|
+
/* @__PURE__ */ jsx23(
|
|
2605
|
+
DataTable,
|
|
2606
|
+
{
|
|
2607
|
+
data: data?.users || [],
|
|
2608
|
+
columns,
|
|
2609
|
+
isLoading,
|
|
2610
|
+
emptyMessage: "No users found"
|
|
2611
|
+
}
|
|
2612
|
+
),
|
|
2613
|
+
data && "users" in data && data.users && data.users.length >= limit && /* @__PURE__ */ jsxs21("div", { className: "flex justify-between items-center", children: [
|
|
2614
|
+
/* @__PURE__ */ jsx23(
|
|
2615
|
+
Button12,
|
|
2616
|
+
{
|
|
2617
|
+
variant: "outline",
|
|
2618
|
+
disabled: page === 1,
|
|
2619
|
+
onClick: () => setPage(page - 1),
|
|
2620
|
+
children: "Previous"
|
|
2621
|
+
}
|
|
2622
|
+
),
|
|
2623
|
+
/* @__PURE__ */ jsxs21("span", { className: "text-sm text-muted-foreground", children: [
|
|
2624
|
+
"Page ",
|
|
2625
|
+
page
|
|
2626
|
+
] }),
|
|
2627
|
+
/* @__PURE__ */ jsx23(Button12, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2628
|
+
] })
|
|
2629
|
+
] });
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
// src/components/profile/profile-page.tsx
|
|
2633
|
+
import { Button as Button13 } from "@mesob/ui/components/button";
|
|
2634
|
+
import {
|
|
2635
|
+
Card,
|
|
2636
|
+
CardContent,
|
|
2637
|
+
CardDescription,
|
|
2638
|
+
CardHeader,
|
|
2639
|
+
CardTitle
|
|
2640
|
+
} from "@mesob/ui/components/card";
|
|
2641
|
+
import { Separator } from "@mesob/ui/components/separator";
|
|
2642
|
+
|
|
2643
|
+
// src/components/skeletons/profile-skeleton.tsx
|
|
2644
|
+
import { Skeleton as Skeleton2 } from "@mesob/ui/components/skeleton";
|
|
2645
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2646
|
+
function ProfileSkeleton() {
|
|
2647
|
+
return /* @__PURE__ */ jsxs22("div", { className: "w-full max-w-4xl space-y-8 p-6", children: [
|
|
2648
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-6", children: [
|
|
2649
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-24 w-24 rounded-full" }),
|
|
2650
|
+
/* @__PURE__ */ jsxs22("div", { className: "space-y-2 flex-1", children: [
|
|
2651
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-8 w-48" }),
|
|
2652
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-64" })
|
|
2653
|
+
] })
|
|
2654
|
+
] }),
|
|
2655
|
+
/* @__PURE__ */ jsx24("div", { className: "space-y-6", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs22("div", { className: "space-y-4", children: [
|
|
2656
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-6 w-32" }),
|
|
2657
|
+
/* @__PURE__ */ jsxs22("div", { className: "space-y-3", children: [
|
|
2658
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex justify-between items-center", children: [
|
|
2659
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-24" }),
|
|
2660
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-32" })
|
|
2661
|
+
] }),
|
|
2662
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex justify-between items-center", children: [
|
|
2663
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-24" }),
|
|
2664
|
+
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-40" })
|
|
2665
|
+
] })
|
|
2666
|
+
] })
|
|
2667
|
+
] }, i)) })
|
|
2668
|
+
] });
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// src/components/profile/profile-page.tsx
|
|
2672
|
+
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2673
|
+
function ProfilePage({ onEditClick }) {
|
|
2674
|
+
const { user, isLoading } = useSession();
|
|
2675
|
+
if (isLoading) {
|
|
2676
|
+
return /* @__PURE__ */ jsx25(ProfileSkeleton, {});
|
|
2677
|
+
}
|
|
2678
|
+
if (!user) {
|
|
2679
|
+
return /* @__PURE__ */ jsx25("div", { className: "flex items-center justify-center min-h-[400px]", children: /* @__PURE__ */ jsx25("p", { className: "text-muted-foreground", children: "Not authenticated" }) });
|
|
2680
|
+
}
|
|
2681
|
+
return /* @__PURE__ */ jsxs23("div", { className: "w-full max-w-4xl mx-auto space-y-6 p-6", children: [
|
|
2682
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
|
|
2683
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2684
|
+
/* @__PURE__ */ jsx25("h1", { className: "text-3xl font-bold", children: user.fullName }),
|
|
2685
|
+
/* @__PURE__ */ jsxs23("p", { className: "text-muted-foreground", children: [
|
|
2686
|
+
"@",
|
|
2687
|
+
user.handle
|
|
2688
|
+
] })
|
|
2689
|
+
] }),
|
|
2690
|
+
onEditClick && /* @__PURE__ */ jsx25(Button13, { onClick: onEditClick, children: "Edit Profile" })
|
|
2691
|
+
] }),
|
|
2692
|
+
/* @__PURE__ */ jsx25(Separator, {}),
|
|
2693
|
+
/* @__PURE__ */ jsxs23("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
2694
|
+
/* @__PURE__ */ jsxs23(Card, { children: [
|
|
2695
|
+
/* @__PURE__ */ jsxs23(CardHeader, { children: [
|
|
2696
|
+
/* @__PURE__ */ jsx25(CardTitle, { children: "Contact Information" }),
|
|
2697
|
+
/* @__PURE__ */ jsx25(CardDescription, { children: "Your contact details" })
|
|
2698
|
+
] }),
|
|
2699
|
+
/* @__PURE__ */ jsxs23(CardContent, { className: "space-y-4", children: [
|
|
2700
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2701
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm font-medium text-muted-foreground", children: "Email" }),
|
|
2702
|
+
/* @__PURE__ */ jsxs23("p", { className: "text-sm", children: [
|
|
2703
|
+
user.email || "Not provided",
|
|
2704
|
+
user.email && /* @__PURE__ */ jsx25(
|
|
2705
|
+
"span",
|
|
2706
|
+
{
|
|
2707
|
+
className: user.emailVerified ? "text-green-600 ml-2" : "text-yellow-600 ml-2",
|
|
2708
|
+
children: user.emailVerified ? "(Verified)" : "(Not verified)"
|
|
2709
|
+
}
|
|
2710
|
+
)
|
|
2711
|
+
] })
|
|
2712
|
+
] }),
|
|
2713
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2714
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm font-medium text-muted-foreground", children: "Phone" }),
|
|
2715
|
+
/* @__PURE__ */ jsxs23("p", { className: "text-sm", children: [
|
|
2716
|
+
user.phone || "Not provided",
|
|
2717
|
+
user.phone && /* @__PURE__ */ jsx25(
|
|
2718
|
+
"span",
|
|
2719
|
+
{
|
|
2720
|
+
className: user.phoneVerified ? "text-green-600 ml-2" : "text-yellow-600 ml-2",
|
|
2721
|
+
children: user.phoneVerified ? "(Verified)" : "(Not verified)"
|
|
2722
|
+
}
|
|
2723
|
+
)
|
|
2724
|
+
] })
|
|
2725
|
+
] })
|
|
2726
|
+
] })
|
|
2727
|
+
] }),
|
|
2728
|
+
/* @__PURE__ */ jsxs23(Card, { children: [
|
|
2729
|
+
/* @__PURE__ */ jsxs23(CardHeader, { children: [
|
|
2730
|
+
/* @__PURE__ */ jsx25(CardTitle, { children: "Account Information" }),
|
|
2731
|
+
/* @__PURE__ */ jsx25(CardDescription, { children: "Your account details" })
|
|
2732
|
+
] }),
|
|
2733
|
+
/* @__PURE__ */ jsxs23(CardContent, { className: "space-y-4", children: [
|
|
2734
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2735
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm font-medium text-muted-foreground", children: "Tenant ID" }),
|
|
2736
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm font-mono", children: user.tenantId })
|
|
2737
|
+
] }),
|
|
2738
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2739
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm font-medium text-muted-foreground", children: "Last Sign In" }),
|
|
2740
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm", children: user.lastSignInAt ? new Date(user.lastSignInAt).toLocaleString() : "Never" })
|
|
2741
|
+
] })
|
|
2742
|
+
] })
|
|
2743
|
+
] }),
|
|
2744
|
+
user.userRoles && user.userRoles.length > 0 && /* @__PURE__ */ jsxs23(Card, { className: "md:col-span-2", children: [
|
|
2745
|
+
/* @__PURE__ */ jsxs23(CardHeader, { children: [
|
|
2746
|
+
/* @__PURE__ */ jsx25(CardTitle, { children: "Roles" }),
|
|
2747
|
+
/* @__PURE__ */ jsx25(CardDescription, { children: "Your assigned roles" })
|
|
2748
|
+
] }),
|
|
2749
|
+
/* @__PURE__ */ jsx25(CardContent, { children: /* @__PURE__ */ jsx25("div", { className: "flex flex-wrap gap-2", children: user.userRoles.map((role) => /* @__PURE__ */ jsx25(
|
|
2750
|
+
"div",
|
|
2751
|
+
{
|
|
2752
|
+
className: "px-3 py-1 bg-primary/10 text-primary rounded-full text-sm",
|
|
2753
|
+
children: role.name
|
|
2754
|
+
},
|
|
2755
|
+
role.id
|
|
2756
|
+
)) }) })
|
|
2757
|
+
] })
|
|
2758
|
+
] })
|
|
2759
|
+
] });
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
// src/components/skeletons/auth-form-skeleton.tsx
|
|
2763
|
+
import { Skeleton as Skeleton3 } from "@mesob/ui/components/skeleton";
|
|
2764
|
+
import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2765
|
+
function AuthFormSkeleton() {
|
|
2766
|
+
return /* @__PURE__ */ jsxs24("div", { className: "w-full max-w-md space-y-6 p-6", children: [
|
|
2767
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-2 text-center", children: [
|
|
2768
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-8 w-48 mx-auto" }),
|
|
2769
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-4 w-64 mx-auto" })
|
|
2770
|
+
] }),
|
|
2771
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-4", children: [
|
|
2772
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-2", children: [
|
|
2773
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-4 w-24" }),
|
|
2774
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-10 w-full" })
|
|
2775
|
+
] }),
|
|
2776
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-2", children: [
|
|
2777
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-4 w-24" }),
|
|
2778
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-10 w-full" })
|
|
2779
|
+
] }),
|
|
2780
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-10 w-full" })
|
|
2781
|
+
] }),
|
|
2782
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-2", children: [
|
|
2783
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-px w-full" }),
|
|
2784
|
+
/* @__PURE__ */ jsx26(Skeleton3, { className: "h-4 w-32 mx-auto" })
|
|
2785
|
+
] })
|
|
2786
|
+
] });
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
// src/utils/cookie.ts
|
|
2790
|
+
var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
|
|
2791
|
+
var getSessionCookieName = (config) => {
|
|
2792
|
+
const prefix = config.cookiePrefix || "";
|
|
2793
|
+
const baseName = "session_token";
|
|
2794
|
+
if (prefix) {
|
|
2795
|
+
return `${prefix}_${baseName}`;
|
|
2796
|
+
}
|
|
2797
|
+
return isProduction ? "__Host-session_token" : baseName;
|
|
1779
2798
|
};
|
|
2799
|
+
|
|
2800
|
+
// src/hooks/use-session-cookie-name.ts
|
|
2801
|
+
function useSessionCookieName() {
|
|
2802
|
+
const { config } = useConfig();
|
|
2803
|
+
return getSessionCookieName(config);
|
|
2804
|
+
}
|
|
1780
2805
|
export {
|
|
1781
2806
|
AuthCard,
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
ForgotPassword,
|
|
2807
|
+
AuthErrorBoundary,
|
|
2808
|
+
AuthFormSkeleton,
|
|
2809
|
+
DataTable,
|
|
2810
|
+
ErrorBoundary,
|
|
1787
2811
|
ForgotPasswordPage,
|
|
1788
|
-
|
|
2812
|
+
MesobAuthProvider,
|
|
2813
|
+
PermissionsPage,
|
|
2814
|
+
ProfilePage,
|
|
2815
|
+
ProfileSkeleton,
|
|
1789
2816
|
ResetPasswordPage,
|
|
1790
|
-
|
|
2817
|
+
RolesPage,
|
|
2818
|
+
SessionsPage,
|
|
1791
2819
|
SignInPage,
|
|
1792
|
-
SignUp,
|
|
1793
2820
|
SignUpPage,
|
|
2821
|
+
TableSkeleton,
|
|
2822
|
+
TenantsPage,
|
|
2823
|
+
UsersPage,
|
|
1794
2824
|
VerificationForm,
|
|
1795
2825
|
VerifyEmailPage,
|
|
1796
2826
|
VerifyPhonePage,
|
|
1797
|
-
|
|
2827
|
+
getSessionCookieName,
|
|
2828
|
+
handleError,
|
|
1798
2829
|
normalizePhone,
|
|
1799
|
-
|
|
1800
|
-
|
|
2830
|
+
useApi,
|
|
2831
|
+
useConfig,
|
|
2832
|
+
useSession,
|
|
2833
|
+
useSessionCookieName,
|
|
2834
|
+
useTranslator
|
|
1801
2835
|
};
|
|
1802
2836
|
//# sourceMappingURL=index.js.map
|