@mesob/auth-react 0.1.0 → 0.2.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 → auth-layout.d.ts} +3 -3
- package/dist/components/auth/{auth-page-layout.js → auth-layout.js} +4 -4
- package/dist/components/auth/auth-layout.js.map +1 -0
- package/dist/components/auth/countdown.js +15 -6
- package/dist/components/auth/countdown.js.map +1 -1
- package/dist/components/auth/forgot-password.d.ts +1 -9
- package/dist/components/auth/forgot-password.js +267 -43
- package/dist/components/auth/forgot-password.js.map +1 -1
- package/dist/components/auth/reset-password-form.d.ts +2 -10
- package/dist/components/auth/reset-password-form.js +366 -118
- package/dist/components/auth/reset-password-form.js.map +1 -1
- package/dist/components/auth/sign-in.d.ts +2 -10
- package/dist/components/auth/sign-in.js +358 -130
- package/dist/components/auth/sign-in.js.map +1 -1
- package/dist/components/auth/sign-up.d.ts +2 -10
- package/dist/components/auth/sign-up.js +379 -131
- package/dist/components/auth/sign-up.js.map +1 -1
- package/dist/components/auth/verification-form.d.ts +2 -16
- package/dist/components/auth/verification-form.js +15 -6
- package/dist/components/auth/verification-form.js.map +1 -1
- package/dist/components/auth/verify-email.d.ts +10 -0
- package/dist/components/auth/{pages/verify-email-page.js → verify-email.js} +54 -34
- package/dist/components/auth/verify-email.js.map +1 -0
- package/dist/components/auth/verify-phone.d.ts +11 -0
- package/dist/components/auth/{pages/verify-phone-page.js → verify-phone.js} +53 -46
- package/dist/components/auth/verify-phone.js.map +1 -0
- package/dist/components/error-boundary.d.ts +2 -2
- package/dist/components/iam/permissions.d.ts +5 -0
- package/dist/components/iam/{permissions/permissions-page.js → permissions.js} +29 -13
- package/dist/components/iam/permissions.js.map +1 -0
- package/dist/components/iam/roles.d.ts +5 -0
- package/dist/components/iam/{roles/roles-page.js → roles.js} +29 -13
- package/dist/components/iam/roles.js.map +1 -0
- package/dist/components/iam/sessions.d.ts +5 -0
- package/dist/components/iam/{sessions/sessions-page.js → sessions.js} +13 -11
- package/dist/components/iam/sessions.js.map +1 -0
- package/dist/components/iam/tenants.d.ts +5 -0
- package/dist/components/iam/{tenants/tenants-page.js → tenants.js} +13 -11
- package/dist/components/iam/tenants.js.map +1 -0
- package/dist/components/iam/users.d.ts +5 -0
- package/dist/components/iam/{users/users-page.js → users.js} +13 -11
- package/dist/components/iam/users.js.map +1 -0
- package/dist/components/profile/account.d.ts +5 -0
- package/dist/components/profile/account.js +66 -0
- package/dist/components/profile/account.js.map +1 -0
- package/dist/components/profile/change-email-form.d.ts +5 -0
- package/dist/components/profile/change-email-form.js +721 -0
- package/dist/components/profile/change-email-form.js.map +1 -0
- package/dist/components/profile/change-password-form.d.ts +5 -0
- package/dist/components/profile/change-password-form.js +256 -0
- package/dist/components/profile/change-password-form.js.map +1 -0
- package/dist/components/profile/change-phone-form.d.ts +5 -0
- package/dist/components/profile/change-phone-form.js +758 -0
- package/dist/components/profile/change-phone-form.js.map +1 -0
- package/dist/components/profile/change-profile.d.ts +9 -0
- package/dist/components/profile/change-profile.js +37 -0
- package/dist/components/profile/change-profile.js.map +1 -0
- package/dist/components/profile/otp-verification-modal.d.ts +15 -0
- package/dist/components/profile/otp-verification-modal.js +261 -0
- package/dist/components/profile/otp-verification-modal.js.map +1 -0
- package/dist/components/profile/request-change-email-form.d.ts +10 -0
- package/dist/components/profile/request-change-email-form.js +293 -0
- package/dist/components/profile/request-change-email-form.js.map +1 -0
- package/dist/components/profile/request-change-phone-form.d.ts +10 -0
- package/dist/components/profile/request-change-phone-form.js +331 -0
- package/dist/components/profile/request-change-phone-form.js.map +1 -0
- package/dist/components/profile/security.d.ts +5 -0
- package/dist/components/profile/security.js +1439 -0
- package/dist/components/profile/security.js.map +1 -0
- package/dist/components/profile/verify-change-email-form.d.ts +11 -0
- package/dist/components/profile/verify-change-email-form.js +402 -0
- package/dist/components/profile/verify-change-email-form.js.map +1 -0
- package/dist/components/profile/verify-change-phone-form.d.ts +11 -0
- package/dist/components/profile/verify-change-phone-form.js +406 -0
- package/dist/components/profile/verify-change-phone-form.js.map +1 -0
- package/dist/components/shared/{data-table/data-table.js → data-table.js} +2 -2
- package/dist/components/shared/data-table.js.map +1 -0
- package/dist/index.d.ts +42 -88
- package/dist/index.js +2297 -1299
- package/dist/index.js.map +1 -1
- package/dist/types-D3s9oE-5.d.ts +75 -0
- package/dist/verification-form-ipSRTtQB.d.ts +22 -0
- package/package.json +3 -2
- package/dist/components/auth/auth-page-layout.js.map +0 -1
- package/dist/components/auth/pages/forgot-password-page.d.ts +0 -6
- package/dist/components/auth/pages/forgot-password-page.js +0 -362
- package/dist/components/auth/pages/forgot-password-page.js.map +0 -1
- package/dist/components/auth/pages/reset-password-page.d.ts +0 -9
- package/dist/components/auth/pages/reset-password-page.js +0 -514
- package/dist/components/auth/pages/reset-password-page.js.map +0 -1
- package/dist/components/auth/pages/sign-in-page.d.ts +0 -8
- package/dist/components/auth/pages/sign-in-page.js +0 -565
- package/dist/components/auth/pages/sign-in-page.js.map +0 -1
- package/dist/components/auth/pages/sign-up-page.d.ts +0 -9
- package/dist/components/auth/pages/sign-up-page.js +0 -518
- package/dist/components/auth/pages/sign-up-page.js.map +0 -1
- package/dist/components/auth/pages/verify-email-page.d.ts +0 -10
- package/dist/components/auth/pages/verify-email-page.js.map +0 -1
- package/dist/components/auth/pages/verify-phone-page.d.ts +0 -11
- package/dist/components/auth/pages/verify-phone-page.js.map +0 -1
- package/dist/components/iam/permissions/permissions-page.d.ts +0 -5
- package/dist/components/iam/permissions/permissions-page.js.map +0 -1
- package/dist/components/iam/roles/roles-page.d.ts +0 -5
- package/dist/components/iam/roles/roles-page.js.map +0 -1
- package/dist/components/iam/sessions/sessions-page.d.ts +0 -5
- package/dist/components/iam/sessions/sessions-page.js.map +0 -1
- package/dist/components/iam/tenants/tenants-page.d.ts +0 -5
- package/dist/components/iam/tenants/tenants-page.js.map +0 -1
- package/dist/components/iam/users/users-page.d.ts +0 -5
- package/dist/components/iam/users/users-page.js.map +0 -1
- package/dist/components/profile/profile-page.d.ts +0 -8
- package/dist/components/profile/profile-page.js +0 -163
- package/dist/components/profile/profile-page.js.map +0 -1
- package/dist/components/shared/data-table/data-table.js.map +0 -1
- package/dist/handle-error-BqDMxnQZ.d.ts +0 -8
- /package/dist/components/shared/{data-table/data-table.d.ts → data-table.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -6,15 +6,31 @@ var AuthCard = ({ children }) => {
|
|
|
6
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 }) }) });
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
// src/components/auth/
|
|
9
|
+
// src/components/auth/forgot-password.tsx
|
|
10
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
10
11
|
import {
|
|
11
12
|
Alert,
|
|
12
13
|
AlertDescription,
|
|
13
14
|
AlertTitle
|
|
14
15
|
} from "@mesob/ui/components/alert";
|
|
15
|
-
import {
|
|
16
|
+
import { Button } from "@mesob/ui/components/button";
|
|
17
|
+
import {
|
|
18
|
+
Field,
|
|
19
|
+
FieldError,
|
|
20
|
+
FieldGroup,
|
|
21
|
+
FieldLabel
|
|
22
|
+
} from "@mesob/ui/components/field";
|
|
23
|
+
import { Input } from "@mesob/ui/components/input";
|
|
24
|
+
import { useMesob as useMesob2 } from "@mesob/ui/components/mesob-context";
|
|
25
|
+
import { Spinner } from "@mesob/ui/components/spinner";
|
|
16
26
|
import { IconAlertCircle } from "@tabler/icons-react";
|
|
17
|
-
import { useEffect
|
|
27
|
+
import { useEffect, useState as useState2 } from "react";
|
|
28
|
+
import { Controller, useForm } from "react-hook-form";
|
|
29
|
+
import { toast } from "sonner";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
|
|
32
|
+
// src/hooks/use-translator.ts
|
|
33
|
+
import { useMesob } from "@mesob/ui/components/mesob-context";
|
|
18
34
|
|
|
19
35
|
// src/lib/translations.ts
|
|
20
36
|
function createTranslator(messages, namespace) {
|
|
@@ -47,7 +63,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
47
63
|
import { deepmerge } from "deepmerge-ts";
|
|
48
64
|
import createFetchClient from "openapi-fetch";
|
|
49
65
|
import createClient from "openapi-react-query";
|
|
50
|
-
import { createContext, useContext,
|
|
66
|
+
import { createContext, useContext, useMemo, useState } from "react";
|
|
51
67
|
|
|
52
68
|
// src/types.ts
|
|
53
69
|
var defaultAuthClientConfig = {
|
|
@@ -62,57 +78,45 @@ var defaultAuthClientConfig = {
|
|
|
62
78
|
navigation: {
|
|
63
79
|
locale: "en"
|
|
64
80
|
},
|
|
65
|
-
cookiePrefix: "msb"
|
|
81
|
+
cookiePrefix: "msb",
|
|
82
|
+
phoneRegex: /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/utils/cookie.ts
|
|
86
|
+
var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
|
|
87
|
+
var getSessionCookieName = (config) => {
|
|
88
|
+
const prefix = config.cookiePrefix || "";
|
|
89
|
+
const baseName = "session_token";
|
|
90
|
+
if (prefix) {
|
|
91
|
+
return `${prefix}_${baseName}`;
|
|
92
|
+
}
|
|
93
|
+
return isProduction ? "__Host-session_token" : baseName;
|
|
66
94
|
};
|
|
67
95
|
|
|
68
96
|
// src/utils/custom-fetch.ts
|
|
69
|
-
var createCustomFetch = (
|
|
97
|
+
var createCustomFetch = (_config) => {
|
|
70
98
|
return (input, init) => {
|
|
71
|
-
const baseUrl = config.baseURL;
|
|
72
99
|
if (input instanceof Request) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return fetch(input, {
|
|
77
|
-
credentials: "include"
|
|
78
|
-
});
|
|
79
|
-
}
|
|
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
|
-
});
|
|
100
|
+
return fetch(input, { ...init, credentials: "include" });
|
|
101
|
+
}
|
|
102
|
+
return fetch(input, { ...init, credentials: "include" });
|
|
102
103
|
};
|
|
103
104
|
};
|
|
104
105
|
|
|
105
106
|
// src/provider.tsx
|
|
106
107
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
108
|
+
function isServer() {
|
|
109
|
+
return typeof document === "undefined";
|
|
110
|
+
}
|
|
111
|
+
function hasAuthCookie(_cookieName) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
107
114
|
var SessionContext = createContext(null);
|
|
108
115
|
var ApiContext = createContext(null);
|
|
109
116
|
var ConfigContext = createContext(null);
|
|
110
117
|
var queryClient = new QueryClient({
|
|
111
118
|
defaultOptions: {
|
|
112
119
|
queries: {
|
|
113
|
-
staleTime: 1e3 * 60 * 5,
|
|
114
|
-
gcTime: 1e3 * 60 * 10,
|
|
115
|
-
retry: 1,
|
|
116
120
|
refetchOnWindowFocus: false
|
|
117
121
|
}
|
|
118
122
|
}
|
|
@@ -138,35 +142,54 @@ function useConfig() {
|
|
|
138
142
|
}
|
|
139
143
|
return context;
|
|
140
144
|
}
|
|
145
|
+
function useHasAuthCookie() {
|
|
146
|
+
const { status } = useSession();
|
|
147
|
+
return status === "authenticated" || status === "loading";
|
|
148
|
+
}
|
|
141
149
|
function MesobAuthProvider({
|
|
142
150
|
config,
|
|
143
151
|
children
|
|
144
152
|
}) {
|
|
145
|
-
const mergedConfig =
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
const mergedConfig = useMemo(
|
|
154
|
+
() => deepmerge(
|
|
155
|
+
{ ...defaultAuthClientConfig },
|
|
156
|
+
config
|
|
157
|
+
),
|
|
158
|
+
[config]
|
|
148
159
|
);
|
|
149
|
-
const api =
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
const api = useMemo(
|
|
161
|
+
() => createFetchClient({
|
|
162
|
+
baseUrl: mergedConfig.baseURL,
|
|
163
|
+
fetch: createCustomFetch(mergedConfig)
|
|
164
|
+
}),
|
|
165
|
+
[mergedConfig]
|
|
166
|
+
);
|
|
167
|
+
const hooks = useMemo(() => createClient(api), [api]);
|
|
168
|
+
const cookieName = useMemo(
|
|
169
|
+
() => getSessionCookieName(mergedConfig),
|
|
170
|
+
[mergedConfig]
|
|
171
|
+
);
|
|
172
|
+
return /* @__PURE__ */ jsx2(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx2(
|
|
173
|
+
AuthStateProvider,
|
|
174
|
+
{
|
|
175
|
+
config: mergedConfig,
|
|
176
|
+
hooks,
|
|
177
|
+
cookieName,
|
|
178
|
+
children
|
|
179
|
+
}
|
|
180
|
+
) });
|
|
155
181
|
}
|
|
156
182
|
function AuthStateProvider({
|
|
157
183
|
config,
|
|
158
184
|
hooks,
|
|
185
|
+
cookieName,
|
|
159
186
|
children
|
|
160
187
|
}) {
|
|
161
|
-
const [
|
|
162
|
-
user: null,
|
|
163
|
-
session: null,
|
|
164
|
-
isLoading: false,
|
|
165
|
-
error: null
|
|
166
|
-
});
|
|
188
|
+
const [override, setOverride] = useState(null);
|
|
167
189
|
const {
|
|
168
190
|
data: sessionData,
|
|
169
|
-
isLoading
|
|
191
|
+
isLoading,
|
|
192
|
+
isFetched,
|
|
170
193
|
error: sessionError,
|
|
171
194
|
refetch
|
|
172
195
|
} = hooks.useQuery(
|
|
@@ -174,63 +197,93 @@ function AuthStateProvider({
|
|
|
174
197
|
"/session",
|
|
175
198
|
{},
|
|
176
199
|
{
|
|
177
|
-
enabled:
|
|
178
|
-
refetchOnMount:
|
|
200
|
+
enabled: !(override || isServer()),
|
|
201
|
+
refetchOnMount: false,
|
|
179
202
|
refetchOnWindowFocus: false,
|
|
180
203
|
refetchOnReconnect: false,
|
|
181
|
-
retry: false
|
|
204
|
+
retry: false,
|
|
205
|
+
gcTime: 0,
|
|
206
|
+
staleTime: 0
|
|
182
207
|
}
|
|
183
208
|
);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
const user = override?.user ?? sessionData?.user ?? null;
|
|
210
|
+
const session = override?.session ?? sessionData?.session ?? null;
|
|
211
|
+
const error = override?.error ?? sessionError;
|
|
212
|
+
const errorStatus = (() => {
|
|
213
|
+
if (!sessionError) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const err = sessionError;
|
|
217
|
+
return err.status ?? null;
|
|
218
|
+
})();
|
|
219
|
+
const isNetworkError = (() => {
|
|
220
|
+
if (!sessionError) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
const error2 = sessionError;
|
|
224
|
+
const errorMessage = error2.message || String(error2) || JSON.stringify(error2);
|
|
225
|
+
if (error2 instanceof TypeError || error2 instanceof DOMException || error2.name === "TypeError" || errorMessage.includes("Failed to fetch") || errorMessage.includes("ERR_CONNECTION_REFUSED") || errorMessage.includes("NetworkError") || errorMessage.includes("Network request failed") || errorMessage.includes("fetch failed")) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
if (error2.cause) {
|
|
229
|
+
const causeStr = String(error2.cause);
|
|
230
|
+
if (causeStr.includes("Failed to fetch") || causeStr.includes("ERR_CONNECTION_REFUSED") || causeStr.includes("NetworkError")) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
188
233
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
error: sessionError
|
|
195
|
-
});
|
|
196
|
-
return;
|
|
234
|
+
return false;
|
|
235
|
+
})();
|
|
236
|
+
const status = (() => {
|
|
237
|
+
if (override) {
|
|
238
|
+
return override.status;
|
|
197
239
|
}
|
|
198
|
-
if (
|
|
199
|
-
|
|
200
|
-
user: sessionData.user,
|
|
201
|
-
session: sessionData.session,
|
|
202
|
-
isLoading: false,
|
|
203
|
-
error: null
|
|
204
|
-
});
|
|
205
|
-
return;
|
|
240
|
+
if (isServer()) {
|
|
241
|
+
return "loading";
|
|
206
242
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
243
|
+
if (user && session) {
|
|
244
|
+
return "authenticated";
|
|
245
|
+
}
|
|
246
|
+
if (isNetworkError || errorStatus === 401) {
|
|
247
|
+
return "unauthenticated";
|
|
248
|
+
}
|
|
249
|
+
if (sessionError && !isNetworkError && errorStatus !== 401) {
|
|
250
|
+
if (errorStatus && errorStatus >= 500) {
|
|
251
|
+
return "authenticated";
|
|
252
|
+
}
|
|
253
|
+
if (isFetched) {
|
|
254
|
+
return "unauthenticated";
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (isLoading || !isFetched) {
|
|
258
|
+
return "loading";
|
|
259
|
+
}
|
|
260
|
+
if (isFetched && !user && !session) {
|
|
261
|
+
return "unauthenticated";
|
|
262
|
+
}
|
|
263
|
+
return "unauthenticated";
|
|
264
|
+
})();
|
|
265
|
+
const signOutMutation = hooks.useMutation("post", "/sign-out");
|
|
266
|
+
const t = createTranslator(config.messages || {});
|
|
217
267
|
const setAuth = (auth) => {
|
|
218
|
-
|
|
268
|
+
setOverride({
|
|
219
269
|
user: auth.user,
|
|
220
270
|
session: auth.session,
|
|
221
|
-
|
|
271
|
+
status: "authenticated",
|
|
222
272
|
error: null
|
|
223
273
|
});
|
|
224
274
|
};
|
|
225
275
|
const clearAuth = () => {
|
|
226
|
-
|
|
276
|
+
setOverride({
|
|
227
277
|
user: null,
|
|
228
278
|
session: null,
|
|
229
|
-
|
|
279
|
+
status: "unauthenticated",
|
|
230
280
|
error: null
|
|
231
281
|
});
|
|
232
282
|
};
|
|
233
|
-
const
|
|
283
|
+
const refresh = async () => {
|
|
284
|
+
setOverride(null);
|
|
285
|
+
await refetch();
|
|
286
|
+
};
|
|
234
287
|
const signOut = async () => {
|
|
235
288
|
try {
|
|
236
289
|
await signOutMutation.mutateAsync({});
|
|
@@ -238,16 +291,16 @@ function AuthStateProvider({
|
|
|
238
291
|
clearAuth();
|
|
239
292
|
}
|
|
240
293
|
};
|
|
241
|
-
|
|
242
|
-
return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value: { config, t }, children: /* @__PURE__ */ jsx2(ApiContext.Provider, { value: { hooks, setAuth, clearAuth, refresh }, children: /* @__PURE__ */ jsx2(
|
|
294
|
+
return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value: { config, cookieName, t }, children: /* @__PURE__ */ jsx2(ApiContext.Provider, { value: { hooks, setAuth, clearAuth, refresh }, children: /* @__PURE__ */ jsx2(
|
|
243
295
|
SessionContext.Provider,
|
|
244
296
|
{
|
|
245
297
|
value: {
|
|
246
|
-
user
|
|
247
|
-
session
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
298
|
+
user,
|
|
299
|
+
session,
|
|
300
|
+
status,
|
|
301
|
+
error,
|
|
302
|
+
isLoading: status === "loading",
|
|
303
|
+
isAuthenticated: status === "authenticated",
|
|
251
304
|
refresh,
|
|
252
305
|
signOut
|
|
253
306
|
},
|
|
@@ -256,6 +309,16 @@ function AuthStateProvider({
|
|
|
256
309
|
) }) });
|
|
257
310
|
}
|
|
258
311
|
|
|
312
|
+
// src/hooks/use-translator.ts
|
|
313
|
+
function useTranslator(namespace) {
|
|
314
|
+
const mesob = useMesob();
|
|
315
|
+
const { config } = useConfig();
|
|
316
|
+
if (mesob?.t) {
|
|
317
|
+
return (key, params) => mesob.t(namespace ? `${namespace}.${key}` : key, params);
|
|
318
|
+
}
|
|
319
|
+
return createTranslator(config.messages || {}, namespace);
|
|
320
|
+
}
|
|
321
|
+
|
|
259
322
|
// src/constants/auth.error.codes.ts
|
|
260
323
|
var AUTH_ERROR_MAPPING = {
|
|
261
324
|
USER_NOT_FOUND: {
|
|
@@ -321,6 +384,14 @@ function extractErrorCode(err) {
|
|
|
321
384
|
}
|
|
322
385
|
return "";
|
|
323
386
|
}
|
|
387
|
+
function sanitizeErrorMessage(message) {
|
|
388
|
+
const lowerMessage = message.toLowerCase();
|
|
389
|
+
const isDatabaseError = lowerMessage.includes("failed query") || lowerMessage.includes("select") || lowerMessage.includes("insert") || lowerMessage.includes("update") || lowerMessage.includes("delete") || lowerMessage.includes("from") || lowerMessage.includes("where") || lowerMessage.includes("limit") || lowerMessage.includes("params:") || lowerMessage.includes("query") || message.includes('"iam".') || message.includes('"tenants"') || message.includes('"users"') || message.includes('"sessions"') || message.includes('"accounts"') || lowerMessage.includes("relation") || lowerMessage.includes("column") || lowerMessage.includes("syntax error") || lowerMessage.includes("database") || lowerMessage.includes("postgres") || lowerMessage.includes("sql");
|
|
390
|
+
if (isDatabaseError) {
|
|
391
|
+
return "An error occurred while processing your request";
|
|
392
|
+
}
|
|
393
|
+
return message;
|
|
394
|
+
}
|
|
324
395
|
function handleAuthError(err, setError, t) {
|
|
325
396
|
const errorCode = extractErrorCode(err);
|
|
326
397
|
if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
|
|
@@ -331,16 +402,20 @@ function handleAuthError(err, setError, t) {
|
|
|
331
402
|
});
|
|
332
403
|
return;
|
|
333
404
|
}
|
|
405
|
+
const sanitizedMessage = sanitizeErrorMessage(
|
|
406
|
+
err.message || t("errors.fallback")
|
|
407
|
+
);
|
|
334
408
|
setError({
|
|
335
409
|
title: t("errors.fallback"),
|
|
336
|
-
description:
|
|
410
|
+
description: sanitizedMessage
|
|
337
411
|
});
|
|
338
412
|
}
|
|
339
413
|
function handleGenericError(err, setError, t) {
|
|
340
|
-
const
|
|
414
|
+
const rawMessage = err instanceof Error ? err.message : t("errors.fallback");
|
|
415
|
+
const sanitizedMessage = sanitizeErrorMessage(rawMessage);
|
|
341
416
|
setError({
|
|
342
417
|
title: "Error",
|
|
343
|
-
description:
|
|
418
|
+
description: sanitizedMessage
|
|
344
419
|
});
|
|
345
420
|
}
|
|
346
421
|
var handleError = (err, setError, t) => {
|
|
@@ -351,9 +426,9 @@ var handleError = (err, setError, t) => {
|
|
|
351
426
|
}
|
|
352
427
|
};
|
|
353
428
|
|
|
354
|
-
// src/components/auth/auth-
|
|
429
|
+
// src/components/auth/auth-layout.tsx
|
|
355
430
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
356
|
-
var
|
|
431
|
+
var AuthLayout = ({
|
|
357
432
|
title,
|
|
358
433
|
description,
|
|
359
434
|
children,
|
|
@@ -371,108 +446,41 @@ var AuthPageLayout = ({
|
|
|
371
446
|
] });
|
|
372
447
|
};
|
|
373
448
|
|
|
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
449
|
// src/components/auth/forgot-password.tsx
|
|
395
450
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
396
451
|
var forgotPasswordSchema = (t) => z.object({
|
|
397
452
|
account: z.string().min(1, t("errors.accountRequired"))
|
|
398
453
|
});
|
|
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
|
+
var ForgotPassword = () => {
|
|
454
455
|
const { hooks } = useApi();
|
|
455
456
|
const { config } = useConfig();
|
|
456
|
-
const
|
|
457
|
+
const mesob = useMesob2();
|
|
458
|
+
const t = useTranslator("Auth.forgotPassword");
|
|
459
|
+
const Link3 = mesob?.linkComponent ?? config.navigation?.linkComponent;
|
|
457
460
|
const [isLoading, setIsLoading] = useState2(false);
|
|
458
461
|
const [error, setError] = useState2(null);
|
|
459
462
|
const forgotPasswordMutation = hooks.useMutation("post", "/password/forgot");
|
|
460
463
|
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
461
|
-
const Link = config.navigation?.linkComponent;
|
|
462
464
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
463
465
|
if (typeof window !== "undefined") {
|
|
464
466
|
window.location.href = path;
|
|
465
467
|
}
|
|
466
468
|
});
|
|
467
469
|
const logoImage = config.ui.logoImage;
|
|
468
|
-
|
|
470
|
+
const form = useForm({
|
|
471
|
+
resolver: zodResolver(forgotPasswordSchema(t)),
|
|
472
|
+
defaultValues: {
|
|
473
|
+
account: ""
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
useEffect(() => {
|
|
469
477
|
if (error) {
|
|
470
478
|
toast.error(error.title || "Error", {
|
|
471
479
|
description: error.description
|
|
472
480
|
});
|
|
473
481
|
}
|
|
474
482
|
}, [error]);
|
|
475
|
-
const handleSubmit = async (values) => {
|
|
483
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
476
484
|
setIsLoading(true);
|
|
477
485
|
setError(null);
|
|
478
486
|
try {
|
|
@@ -493,10 +501,7 @@ var ForgotPasswordPage = (_props = {}) => {
|
|
|
493
501
|
} finally {
|
|
494
502
|
setIsLoading(false);
|
|
495
503
|
}
|
|
496
|
-
};
|
|
497
|
-
const handleBack = () => {
|
|
498
|
-
onNavigate(signInLink);
|
|
499
|
-
};
|
|
504
|
+
});
|
|
500
505
|
let errorContent = null;
|
|
501
506
|
if (error) {
|
|
502
507
|
if (typeof error === "string") {
|
|
@@ -505,13 +510,13 @@ var ForgotPasswordPage = (_props = {}) => {
|
|
|
505
510
|
errorContent = error;
|
|
506
511
|
}
|
|
507
512
|
}
|
|
508
|
-
return /* @__PURE__ */
|
|
509
|
-
|
|
513
|
+
return /* @__PURE__ */ jsxs2(
|
|
514
|
+
AuthLayout,
|
|
510
515
|
{
|
|
511
516
|
title: t("title"),
|
|
512
517
|
description: t("description"),
|
|
513
518
|
logoImage,
|
|
514
|
-
footer:
|
|
519
|
+
footer: Link3 ? /* @__PURE__ */ jsx4(Link3, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }) : /* @__PURE__ */ jsx4(
|
|
515
520
|
"a",
|
|
516
521
|
{
|
|
517
522
|
href: signInLink,
|
|
@@ -524,36 +529,59 @@ var ForgotPasswordPage = (_props = {}) => {
|
|
|
524
529
|
}
|
|
525
530
|
),
|
|
526
531
|
children: [
|
|
527
|
-
/* @__PURE__ */
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
532
|
+
/* @__PURE__ */ jsxs2("form", { id: "forgot-password-form", onSubmit: handleSubmit, children: [
|
|
533
|
+
/* @__PURE__ */ jsx4(FieldGroup, { children: /* @__PURE__ */ jsx4(
|
|
534
|
+
Controller,
|
|
535
|
+
{
|
|
536
|
+
name: "account",
|
|
537
|
+
control: form.control,
|
|
538
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
|
|
539
|
+
/* @__PURE__ */ jsx4(FieldLabel, { htmlFor: "forgot-password-account", children: t("form.accountLabel") }),
|
|
540
|
+
/* @__PURE__ */ jsx4(
|
|
541
|
+
Input,
|
|
542
|
+
{
|
|
543
|
+
...field,
|
|
544
|
+
id: "forgot-password-account",
|
|
545
|
+
type: "text",
|
|
546
|
+
placeholder: t("form.accountPlaceholder"),
|
|
547
|
+
"aria-invalid": fieldState.invalid
|
|
548
|
+
}
|
|
549
|
+
),
|
|
550
|
+
fieldState.invalid && /* @__PURE__ */ jsx4(FieldError, { errors: [fieldState.error] })
|
|
551
|
+
] })
|
|
552
|
+
}
|
|
553
|
+
) }),
|
|
554
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-4", children: /* @__PURE__ */ jsxs2(
|
|
555
|
+
Button,
|
|
556
|
+
{
|
|
557
|
+
type: "submit",
|
|
558
|
+
form: "forgot-password-form",
|
|
559
|
+
className: "w-full",
|
|
560
|
+
disabled: isLoading || forgotPasswordMutation.isPending,
|
|
561
|
+
children: [
|
|
562
|
+
isLoading || forgotPasswordMutation.isPending && /* @__PURE__ */ jsx4(Spinner, {}),
|
|
563
|
+
isLoading || forgotPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
) })
|
|
567
|
+
] }),
|
|
568
|
+
errorContent && /* @__PURE__ */ jsxs2(Alert, { variant: "destructive", className: "mt-4", children: [
|
|
569
|
+
/* @__PURE__ */ jsx4(IconAlertCircle, { className: "h-4 w-4" }),
|
|
570
|
+
/* @__PURE__ */ jsx4(AlertTitle, { children: errorContent.title }),
|
|
571
|
+
/* @__PURE__ */ jsx4(AlertDescription, { children: errorContent.description })
|
|
539
572
|
] })
|
|
540
573
|
]
|
|
541
574
|
}
|
|
542
575
|
);
|
|
543
576
|
};
|
|
544
577
|
|
|
545
|
-
// src/components/auth/
|
|
578
|
+
// src/components/auth/reset-password-form.tsx
|
|
579
|
+
import { zodResolver as zodResolver2 } from "@hookform/resolvers/zod";
|
|
546
580
|
import {
|
|
547
581
|
Alert as Alert2,
|
|
548
582
|
AlertDescription as AlertDescription2,
|
|
549
583
|
AlertTitle as AlertTitle2
|
|
550
584
|
} 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";
|
|
554
|
-
|
|
555
|
-
// src/components/auth/reset-password-form.tsx
|
|
556
|
-
import { zodResolver as zodResolver2 } from "@hookform/resolvers/zod";
|
|
557
585
|
import { Button as Button2 } from "@mesob/ui/components/button";
|
|
558
586
|
import {
|
|
559
587
|
Field as Field2,
|
|
@@ -567,12 +595,14 @@ import {
|
|
|
567
595
|
InputOTPGroup,
|
|
568
596
|
InputOTPSlot
|
|
569
597
|
} from "@mesob/ui/components/input-otp";
|
|
598
|
+
import { Link } from "@mesob/ui/components/link";
|
|
570
599
|
import { Spinner as Spinner2 } from "@mesob/ui/components/spinner";
|
|
571
|
-
import { IconEye, IconEyeOff } from "@tabler/icons-react";
|
|
572
|
-
import { useState as useState3 } from "react";
|
|
600
|
+
import { IconAlertCircle as IconAlertCircle2, IconEye, IconEyeOff } from "@tabler/icons-react";
|
|
601
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
573
602
|
import { Controller as Controller2, useForm as useForm2 } from "react-hook-form";
|
|
603
|
+
import { toast as toast2 } from "sonner";
|
|
574
604
|
import { z as z2 } from "zod";
|
|
575
|
-
import { jsx as
|
|
605
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
576
606
|
var resetPasswordSchema = (t) => z2.object({
|
|
577
607
|
code: z2.string().length(6, t("errors.codeLength")),
|
|
578
608
|
password: z2.string().min(8, t("errors.passwordLength")),
|
|
@@ -582,151 +612,19 @@ var resetPasswordSchema = (t) => z2.object({
|
|
|
582
612
|
path: ["confirmPassword"]
|
|
583
613
|
});
|
|
584
614
|
var ResetPasswordForm = ({
|
|
585
|
-
onSubmit,
|
|
586
|
-
isLoading = false
|
|
587
|
-
}) => {
|
|
588
|
-
const t = useTranslator("Auth.resetPassword");
|
|
589
|
-
const [showPassword, setShowPassword] = useState3(false);
|
|
590
|
-
const form = useForm2({
|
|
591
|
-
resolver: zodResolver2(resetPasswordSchema(t)),
|
|
592
|
-
defaultValues: {
|
|
593
|
-
code: "",
|
|
594
|
-
password: "",
|
|
595
|
-
confirmPassword: ""
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
const handleSubmit = form.handleSubmit(async (values) => {
|
|
599
|
-
await onSubmit(values);
|
|
600
|
-
});
|
|
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,
|
|
612
|
-
{
|
|
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
|
-
] })
|
|
627
|
-
}
|
|
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,
|
|
700
|
-
{
|
|
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
|
-
}
|
|
710
|
-
) })
|
|
711
|
-
] });
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
// src/components/auth/pages/reset-password-page.tsx
|
|
715
|
-
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
716
|
-
var ResetPasswordPage = ({
|
|
717
615
|
verificationId,
|
|
718
616
|
redirectUrl
|
|
719
617
|
}) => {
|
|
720
618
|
const { hooks, refresh } = useApi();
|
|
721
619
|
const { config } = useConfig();
|
|
722
|
-
const t =
|
|
723
|
-
const common =
|
|
724
|
-
const [isLoading, setIsLoading] =
|
|
725
|
-
const [error, setError] =
|
|
620
|
+
const t = useTranslator("Auth.resetPassword");
|
|
621
|
+
const common = useTranslator("Common");
|
|
622
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
623
|
+
const [error, setError] = useState3(null);
|
|
624
|
+
const [showPassword, setShowPassword] = useState3(false);
|
|
726
625
|
const resetPasswordMutation = hooks.useMutation("post", "/password/reset");
|
|
727
626
|
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
728
627
|
const forgotPasswordLink = config.navigation?.links?.forgotPassword || "/auth/forgot-password";
|
|
729
|
-
const Link = config.navigation?.linkComponent;
|
|
730
628
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
731
629
|
if (typeof window !== "undefined") {
|
|
732
630
|
window.location.href = path;
|
|
@@ -734,14 +632,22 @@ var ResetPasswordPage = ({
|
|
|
734
632
|
});
|
|
735
633
|
const logoImage = config.ui.logoImage;
|
|
736
634
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
737
|
-
|
|
635
|
+
const form = useForm2({
|
|
636
|
+
resolver: zodResolver2(resetPasswordSchema(t)),
|
|
637
|
+
defaultValues: {
|
|
638
|
+
code: "",
|
|
639
|
+
password: "",
|
|
640
|
+
confirmPassword: ""
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
useEffect2(() => {
|
|
738
644
|
if (error) {
|
|
739
645
|
toast2.error(error.title || "Error", {
|
|
740
646
|
description: error.description
|
|
741
647
|
});
|
|
742
648
|
}
|
|
743
649
|
}, [error]);
|
|
744
|
-
const handleSubmit = async (values) => {
|
|
650
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
745
651
|
if (!verificationId) {
|
|
746
652
|
setError({
|
|
747
653
|
title: t("errors.fallback"),
|
|
@@ -766,34 +672,23 @@ var ResetPasswordPage = ({
|
|
|
766
672
|
} finally {
|
|
767
673
|
setIsLoading(false);
|
|
768
674
|
}
|
|
769
|
-
};
|
|
675
|
+
});
|
|
770
676
|
if (!verificationId) {
|
|
771
|
-
return /* @__PURE__ */
|
|
772
|
-
|
|
677
|
+
return /* @__PURE__ */ jsx5(
|
|
678
|
+
AuthLayout,
|
|
773
679
|
{
|
|
774
680
|
title: common("invalidLinkTitle"),
|
|
775
681
|
description: common("invalidLinkDescription"),
|
|
776
682
|
logoImage,
|
|
777
|
-
footer:
|
|
683
|
+
footer: /* @__PURE__ */ jsx5(
|
|
778
684
|
Link,
|
|
779
685
|
{
|
|
780
686
|
href: forgotPasswordLink,
|
|
781
687
|
className: "text-primary hover:underline",
|
|
782
688
|
children: t("footer.requestNew")
|
|
783
689
|
}
|
|
784
|
-
) : /* @__PURE__ */ jsx7(
|
|
785
|
-
"a",
|
|
786
|
-
{
|
|
787
|
-
href: forgotPasswordLink,
|
|
788
|
-
onClick: (e) => {
|
|
789
|
-
e.preventDefault();
|
|
790
|
-
onNavigate(forgotPasswordLink);
|
|
791
|
-
},
|
|
792
|
-
className: "text-primary hover:underline",
|
|
793
|
-
children: t("footer.requestNew")
|
|
794
|
-
}
|
|
795
690
|
),
|
|
796
|
-
children: /* @__PURE__ */
|
|
691
|
+
children: /* @__PURE__ */ jsx5("div", {})
|
|
797
692
|
}
|
|
798
693
|
);
|
|
799
694
|
}
|
|
@@ -805,15 +700,15 @@ var ResetPasswordPage = ({
|
|
|
805
700
|
errorContent = error;
|
|
806
701
|
}
|
|
807
702
|
}
|
|
808
|
-
return /* @__PURE__ */
|
|
809
|
-
|
|
703
|
+
return /* @__PURE__ */ jsxs3(
|
|
704
|
+
AuthLayout,
|
|
810
705
|
{
|
|
811
706
|
title: t("title"),
|
|
812
707
|
description: t("description"),
|
|
813
708
|
logoImage,
|
|
814
|
-
footer:
|
|
815
|
-
/* @__PURE__ */
|
|
816
|
-
/* @__PURE__ */
|
|
709
|
+
footer: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between w-full gap-2", children: [
|
|
710
|
+
/* @__PURE__ */ jsx5(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }),
|
|
711
|
+
/* @__PURE__ */ jsx5(
|
|
817
712
|
Link,
|
|
818
713
|
{
|
|
819
714
|
href: forgotPasswordLink,
|
|
@@ -821,64 +716,136 @@ var ResetPasswordPage = ({
|
|
|
821
716
|
children: t("footer.changeAccount")
|
|
822
717
|
}
|
|
823
718
|
)
|
|
824
|
-
] }) : /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between w-full gap-2", children: [
|
|
825
|
-
/* @__PURE__ */ jsx7(
|
|
826
|
-
"a",
|
|
827
|
-
{
|
|
828
|
-
href: forgotPasswordLink,
|
|
829
|
-
onClick: (e) => {
|
|
830
|
-
e.preventDefault();
|
|
831
|
-
onNavigate(forgotPasswordLink);
|
|
832
|
-
},
|
|
833
|
-
className: "text-primary hover:underline",
|
|
834
|
-
children: t("footer.backToSignIn")
|
|
835
|
-
}
|
|
836
|
-
),
|
|
837
|
-
/* @__PURE__ */ jsx7(
|
|
838
|
-
"a",
|
|
839
|
-
{
|
|
840
|
-
href: forgotPasswordLink,
|
|
841
|
-
onClick: (e) => {
|
|
842
|
-
e.preventDefault();
|
|
843
|
-
onNavigate(forgotPasswordLink);
|
|
844
|
-
},
|
|
845
|
-
className: "text-primary hover:underline",
|
|
846
|
-
children: t("footer.changeAccount")
|
|
847
|
-
}
|
|
848
|
-
)
|
|
849
719
|
] }),
|
|
850
720
|
children: [
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
721
|
+
/* @__PURE__ */ jsxs3("form", { id: "reset-password-form", onSubmit: handleSubmit, children: [
|
|
722
|
+
/* @__PURE__ */ jsxs3(FieldGroup2, { children: [
|
|
723
|
+
/* @__PURE__ */ jsx5(
|
|
724
|
+
Controller2,
|
|
725
|
+
{
|
|
726
|
+
name: "code",
|
|
727
|
+
control: form.control,
|
|
728
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs3(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
729
|
+
/* @__PURE__ */ jsx5("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx5(FieldLabel2, { children: t("form.codeLabel") }) }),
|
|
730
|
+
/* @__PURE__ */ jsx5("div", { className: "flex mt-2 justify-center", children: /* @__PURE__ */ jsx5(
|
|
731
|
+
InputOTP,
|
|
732
|
+
{
|
|
733
|
+
maxLength: 6,
|
|
734
|
+
value: field.value,
|
|
735
|
+
onChange: field.onChange,
|
|
736
|
+
onBlur: field.onBlur,
|
|
737
|
+
containerClassName: "gap-4",
|
|
738
|
+
"aria-invalid": fieldState.invalid,
|
|
739
|
+
children: /* @__PURE__ */ jsxs3(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: [
|
|
740
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 0 }),
|
|
741
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 1 }),
|
|
742
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 2 }),
|
|
743
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 3 }),
|
|
744
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 4 }),
|
|
745
|
+
/* @__PURE__ */ jsx5(InputOTPSlot, { className: "h-12", index: 5 })
|
|
746
|
+
] })
|
|
747
|
+
}
|
|
748
|
+
) }),
|
|
749
|
+
fieldState.invalid && /* @__PURE__ */ jsx5(FieldError2, { errors: [fieldState.error] })
|
|
750
|
+
] })
|
|
751
|
+
}
|
|
752
|
+
),
|
|
753
|
+
/* @__PURE__ */ jsx5(
|
|
754
|
+
Controller2,
|
|
755
|
+
{
|
|
756
|
+
name: "password",
|
|
757
|
+
control: form.control,
|
|
758
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs3(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
759
|
+
/* @__PURE__ */ jsx5(FieldLabel2, { htmlFor: "reset-password-password", children: t("form.passwordLabel") }),
|
|
760
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
761
|
+
/* @__PURE__ */ jsx5(
|
|
762
|
+
Input2,
|
|
763
|
+
{
|
|
764
|
+
...field,
|
|
765
|
+
id: "reset-password-password",
|
|
766
|
+
type: showPassword ? "text" : "password",
|
|
767
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
768
|
+
"aria-invalid": fieldState.invalid
|
|
769
|
+
}
|
|
770
|
+
),
|
|
771
|
+
/* @__PURE__ */ jsx5(
|
|
772
|
+
"button",
|
|
773
|
+
{
|
|
774
|
+
type: "button",
|
|
775
|
+
onClick: () => setShowPassword(!showPassword),
|
|
776
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
777
|
+
children: showPassword ? /* @__PURE__ */ jsx5(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx5(IconEye, { className: "h-4 w-4" })
|
|
778
|
+
}
|
|
779
|
+
)
|
|
780
|
+
] }),
|
|
781
|
+
fieldState.invalid && /* @__PURE__ */ jsx5(FieldError2, { errors: [fieldState.error] })
|
|
782
|
+
] })
|
|
783
|
+
}
|
|
784
|
+
),
|
|
785
|
+
/* @__PURE__ */ jsx5(
|
|
786
|
+
Controller2,
|
|
787
|
+
{
|
|
788
|
+
name: "confirmPassword",
|
|
789
|
+
control: form.control,
|
|
790
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs3(Field2, { "data-invalid": fieldState.invalid, children: [
|
|
791
|
+
/* @__PURE__ */ jsx5(FieldLabel2, { htmlFor: "reset-password-confirmPassword", children: t("form.confirmPasswordLabel") }),
|
|
792
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
793
|
+
/* @__PURE__ */ jsx5(
|
|
794
|
+
Input2,
|
|
795
|
+
{
|
|
796
|
+
...field,
|
|
797
|
+
id: "reset-password-confirmPassword",
|
|
798
|
+
type: showPassword ? "text" : "password",
|
|
799
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
800
|
+
"aria-invalid": fieldState.invalid
|
|
801
|
+
}
|
|
802
|
+
),
|
|
803
|
+
/* @__PURE__ */ jsx5(
|
|
804
|
+
"button",
|
|
805
|
+
{
|
|
806
|
+
type: "button",
|
|
807
|
+
onClick: () => setShowPassword(!showPassword),
|
|
808
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
809
|
+
children: showPassword ? /* @__PURE__ */ jsx5(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx5(IconEye, { className: "h-4 w-4" })
|
|
810
|
+
}
|
|
811
|
+
)
|
|
812
|
+
] }),
|
|
813
|
+
fieldState.invalid && /* @__PURE__ */ jsx5(FieldError2, { errors: [fieldState.error] })
|
|
814
|
+
] })
|
|
815
|
+
}
|
|
816
|
+
)
|
|
817
|
+
] }),
|
|
818
|
+
/* @__PURE__ */ jsx5("div", { className: "mt-4", children: /* @__PURE__ */ jsxs3(
|
|
819
|
+
Button2,
|
|
820
|
+
{
|
|
821
|
+
type: "submit",
|
|
822
|
+
form: "reset-password-form",
|
|
823
|
+
className: "w-full",
|
|
824
|
+
disabled: isLoading || resetPasswordMutation.isPending,
|
|
825
|
+
children: [
|
|
826
|
+
isLoading || resetPasswordMutation.isPending && /* @__PURE__ */ jsx5(Spinner2, {}),
|
|
827
|
+
isLoading || resetPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
828
|
+
]
|
|
829
|
+
}
|
|
830
|
+
) })
|
|
831
|
+
] }),
|
|
832
|
+
errorContent && /* @__PURE__ */ jsxs3(Alert2, { variant: "destructive", className: "mt-4", children: [
|
|
833
|
+
/* @__PURE__ */ jsx5(IconAlertCircle2, { className: "h-4 w-4" }),
|
|
834
|
+
/* @__PURE__ */ jsx5(AlertTitle2, { children: errorContent.title }),
|
|
835
|
+
/* @__PURE__ */ jsx5(AlertDescription2, { children: errorContent.description })
|
|
864
836
|
] })
|
|
865
837
|
]
|
|
866
838
|
}
|
|
867
839
|
);
|
|
868
840
|
};
|
|
869
841
|
|
|
870
|
-
// src/components/auth/
|
|
842
|
+
// src/components/auth/sign-in.tsx
|
|
843
|
+
import { zodResolver as zodResolver3 } from "@hookform/resolvers/zod";
|
|
871
844
|
import {
|
|
872
845
|
Alert as Alert3,
|
|
873
846
|
AlertDescription as AlertDescription3,
|
|
874
847
|
AlertTitle as AlertTitle3
|
|
875
848
|
} 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";
|
|
879
|
-
|
|
880
|
-
// src/components/auth/sign-in.tsx
|
|
881
|
-
import { zodResolver as zodResolver3 } from "@hookform/resolvers/zod";
|
|
882
849
|
import { Button as Button3 } from "@mesob/ui/components/button";
|
|
883
850
|
import {
|
|
884
851
|
Field as Field3,
|
|
@@ -887,39 +854,41 @@ import {
|
|
|
887
854
|
FieldLabel as FieldLabel3
|
|
888
855
|
} from "@mesob/ui/components/field";
|
|
889
856
|
import { Input as Input3 } from "@mesob/ui/components/input";
|
|
857
|
+
import { useMesob as useMesob3 } from "@mesob/ui/components/mesob-context";
|
|
890
858
|
import { Spinner as Spinner3 } from "@mesob/ui/components/spinner";
|
|
891
|
-
import { IconEye as IconEye2, IconEyeOff as IconEyeOff2 } from "@tabler/icons-react";
|
|
892
|
-
import { useEffect as
|
|
859
|
+
import { IconAlertCircle as IconAlertCircle3, IconEye as IconEye2, IconEyeOff as IconEyeOff2 } from "@tabler/icons-react";
|
|
860
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
893
861
|
import { Controller as Controller3, useForm as useForm3 } from "react-hook-form";
|
|
862
|
+
import { toast as toast3 } from "sonner";
|
|
894
863
|
import { z as z3 } from "zod";
|
|
895
864
|
|
|
896
865
|
// src/utils/normalize-phone.ts
|
|
897
866
|
function normalizePhone(phone) {
|
|
898
867
|
const cleaned = phone.trim().replace(/\s/g, "");
|
|
899
|
-
if (cleaned.startsWith("+2519")) {
|
|
868
|
+
if (cleaned.startsWith("+2519") || cleaned.startsWith("+2517")) {
|
|
900
869
|
return cleaned;
|
|
901
870
|
}
|
|
902
|
-
if (cleaned.startsWith("2519")) {
|
|
871
|
+
if (cleaned.startsWith("2519") || cleaned.startsWith("2517")) {
|
|
903
872
|
return `+${cleaned}`;
|
|
904
873
|
}
|
|
905
|
-
if (cleaned.startsWith("09")) {
|
|
874
|
+
if (cleaned.startsWith("09") || cleaned.startsWith("07")) {
|
|
906
875
|
return `+251${cleaned.slice(1)}`;
|
|
907
876
|
}
|
|
908
|
-
if (cleaned.startsWith("9") && cleaned.length === 9) {
|
|
877
|
+
if ((cleaned.startsWith("9") || cleaned.startsWith("7")) && cleaned.length === 9) {
|
|
909
878
|
return `+251${cleaned}`;
|
|
910
879
|
}
|
|
911
880
|
return cleaned;
|
|
912
881
|
}
|
|
913
882
|
|
|
914
883
|
// src/components/auth/sign-in.tsx
|
|
915
|
-
import { jsx as
|
|
916
|
-
var
|
|
917
|
-
|
|
884
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
885
|
+
var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
886
|
+
var usernameSchema = (t, phoneRegex) => z3.object({
|
|
887
|
+
username: z3.string().trim().min(1, { message: t("errors.requiredField") }).refine(
|
|
918
888
|
(val) => {
|
|
919
889
|
const isEmail = z3.email().safeParse(val).success;
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
return isEmail || isPhone4;
|
|
890
|
+
const isPhone3 = phoneRegex.test(val);
|
|
891
|
+
return isEmail || isPhone3;
|
|
923
892
|
},
|
|
924
893
|
{
|
|
925
894
|
message: t("errors.invalidEmailOrPhone")
|
|
@@ -929,253 +898,111 @@ var identifierSchema = (t) => z3.object({
|
|
|
929
898
|
var passwordSchema = (t) => z3.object({
|
|
930
899
|
password: z3.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError"))
|
|
931
900
|
});
|
|
932
|
-
var SignIn = ({
|
|
933
|
-
onSubmit,
|
|
934
|
-
isLoading = false,
|
|
935
|
-
identifier: initialIdentifier = "",
|
|
936
|
-
step = "identifier",
|
|
937
|
-
onBack: _onBack
|
|
938
|
-
}) => {
|
|
939
|
-
const { hooks } = useApi();
|
|
940
|
-
const t = useTranslator("Auth.signIn");
|
|
941
|
-
const [showPassword, setShowPassword] = useState5(false);
|
|
942
|
-
const [currentIdentifier, setCurrentIdentifier] = useState5(initialIdentifier);
|
|
943
|
-
const identifierForm = useForm3({
|
|
944
|
-
resolver: zodResolver3(identifierSchema(t)),
|
|
945
|
-
defaultValues: {
|
|
946
|
-
identifier: initialIdentifier
|
|
947
|
-
},
|
|
948
|
-
mode: "onChange"
|
|
949
|
-
});
|
|
950
|
-
const passwordForm = useForm3({
|
|
951
|
-
resolver: zodResolver3(passwordSchema(t)),
|
|
952
|
-
defaultValues: {
|
|
953
|
-
password: ""
|
|
954
|
-
},
|
|
955
|
-
mode: "onChange"
|
|
956
|
-
});
|
|
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) => {
|
|
965
|
-
const phoneRegex = /^(\+2519|2519|09)\d{8}$/;
|
|
966
|
-
const normalizedIdentifier = phoneRegex.test(values.identifier) ? normalizePhone(values.identifier) : values.identifier;
|
|
967
|
-
setCurrentIdentifier(normalizedIdentifier);
|
|
968
|
-
identifierForm.setValue("identifier", normalizedIdentifier);
|
|
969
|
-
await onSubmit(
|
|
970
|
-
{ identifier: normalizedIdentifier, password: "" },
|
|
971
|
-
"identifier"
|
|
972
|
-
);
|
|
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(
|
|
983
|
-
{
|
|
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(
|
|
1069
|
-
Input3,
|
|
1070
|
-
{
|
|
1071
|
-
...field,
|
|
1072
|
-
id: "sign-in-identifier",
|
|
1073
|
-
type: "text",
|
|
1074
|
-
placeholder: t("form.accountPlaceholder"),
|
|
1075
|
-
autoComplete: "username",
|
|
1076
|
-
"aria-invalid": fieldState.invalid
|
|
1077
|
-
}
|
|
1078
|
-
),
|
|
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
|
-
);
|
|
1090
|
-
};
|
|
1091
|
-
|
|
1092
|
-
// src/components/auth/pages/sign-in-page.tsx
|
|
1093
|
-
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1094
|
-
var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1095
|
-
var SignInPage = ({ redirectUrl } = {}) => {
|
|
901
|
+
var SignIn = ({ redirectUrl } = {}) => {
|
|
1096
902
|
const { hooks, setAuth } = useApi();
|
|
1097
903
|
const { config } = useConfig();
|
|
1098
|
-
const
|
|
1099
|
-
const
|
|
1100
|
-
const
|
|
1101
|
-
const [
|
|
1102
|
-
const [
|
|
1103
|
-
const
|
|
904
|
+
const mesob = useMesob3();
|
|
905
|
+
const t = useTranslator("Auth.signIn");
|
|
906
|
+
const Link3 = mesob?.linkComponent ?? config.navigation?.linkComponent;
|
|
907
|
+
const [isLoading, setIsLoading] = useState4(false);
|
|
908
|
+
const [error, setError] = useState4(null);
|
|
909
|
+
const [showPasswordField, setShowPasswordField] = useState4(false);
|
|
910
|
+
const [showPassword, setShowPassword] = useState4(false);
|
|
911
|
+
const [username, setUsername] = useState4("");
|
|
912
|
+
const [isChecking, setIsChecking] = useState4(false);
|
|
913
|
+
const checkUserMutation = hooks.useMutation("post", "/check-account");
|
|
1104
914
|
const signInMutation = hooks.useMutation("post", "/sign-in");
|
|
915
|
+
const phoneRegex = typeof config.phoneRegex === "string" ? new RegExp(config.phoneRegex) : config.phoneRegex || /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/;
|
|
1105
916
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/dashboard";
|
|
1106
917
|
const forgotPasswordLink = config.navigation?.links?.forgotPassword || "/auth/forgot-password";
|
|
1107
918
|
const signUpLink = config.navigation?.links?.signUp || "/auth/sign-up";
|
|
1108
|
-
const Link = config.navigation?.linkComponent;
|
|
1109
919
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1110
920
|
if (typeof window !== "undefined") {
|
|
1111
921
|
window.location.href = path;
|
|
1112
922
|
}
|
|
1113
923
|
});
|
|
1114
924
|
const logoImage = config.ui.logoImage;
|
|
1115
|
-
|
|
925
|
+
const usernameForm = useForm3({
|
|
926
|
+
resolver: zodResolver3(usernameSchema(t, phoneRegex)),
|
|
927
|
+
defaultValues: { username: "" },
|
|
928
|
+
mode: "onChange"
|
|
929
|
+
});
|
|
930
|
+
const passwordForm = useForm3({
|
|
931
|
+
resolver: zodResolver3(passwordSchema(t)),
|
|
932
|
+
defaultValues: { password: "" },
|
|
933
|
+
mode: "onChange"
|
|
934
|
+
});
|
|
935
|
+
useEffect3(() => {
|
|
1116
936
|
if (error) {
|
|
1117
937
|
toast3.error(error.title || "Error", {
|
|
1118
938
|
description: error.description
|
|
1119
939
|
});
|
|
1120
940
|
}
|
|
1121
941
|
}, [error]);
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
942
|
+
const handleCheckAccount = async (usernameValue) => {
|
|
943
|
+
setIsChecking(true);
|
|
944
|
+
try {
|
|
945
|
+
const normalizedUsername = phoneRegex.test(usernameValue) ? normalizePhone(usernameValue) : usernameValue;
|
|
946
|
+
const result = await checkUserMutation.mutateAsync({
|
|
947
|
+
body: {
|
|
948
|
+
username: normalizedUsername
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
if (result.exists) {
|
|
952
|
+
setUsername(normalizedUsername);
|
|
953
|
+
setShowPasswordField(true);
|
|
954
|
+
} else {
|
|
955
|
+
const email = isPhone(normalizedUsername) ? "" : normalizedUsername;
|
|
956
|
+
if (email) {
|
|
957
|
+
onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);
|
|
958
|
+
} else {
|
|
959
|
+
onNavigate(
|
|
960
|
+
`${signUpLink}?phone=${encodeURIComponent(normalizedUsername)}`
|
|
961
|
+
);
|
|
962
|
+
}
|
|
1126
963
|
}
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
const email = isPhone(identifierValue) ? "" : identifierValue;
|
|
1134
|
-
if (email) {
|
|
1135
|
-
onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);
|
|
1136
|
-
} else {
|
|
1137
|
-
onNavigate(`${signUpLink}?phone=${encodeURIComponent(identifierValue)}`);
|
|
964
|
+
} catch {
|
|
965
|
+
usernameForm.setError("username", {
|
|
966
|
+
message: t("errors.checkAccountFailed")
|
|
967
|
+
});
|
|
968
|
+
} finally {
|
|
969
|
+
setIsChecking(false);
|
|
1138
970
|
}
|
|
1139
971
|
};
|
|
1140
|
-
const
|
|
1141
|
-
|
|
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);
|
|
972
|
+
const handleUsernameSubmit = async (values) => {
|
|
973
|
+
await handleCheckAccount(values.username);
|
|
1156
974
|
};
|
|
1157
|
-
const
|
|
975
|
+
const handlePasswordSubmit = async (values) => {
|
|
1158
976
|
setIsLoading(true);
|
|
1159
977
|
setError(null);
|
|
1160
978
|
try {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
979
|
+
const res = await signInMutation.mutateAsync({
|
|
980
|
+
body: {
|
|
981
|
+
identifier: username,
|
|
982
|
+
password: values.password
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
if ("verificationId" in res && res.verificationId) {
|
|
986
|
+
const verifyPath = isPhone(username) ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(username)}` : `/auth/verify-email?verificationId=${res.verificationId}`;
|
|
987
|
+
onNavigate(verifyPath);
|
|
988
|
+
return;
|
|
1165
989
|
}
|
|
990
|
+
if ("user" in res && "session" in res) {
|
|
991
|
+
setAuth(res);
|
|
992
|
+
}
|
|
993
|
+
onNavigate(defaultRedirect);
|
|
1166
994
|
} catch (err) {
|
|
1167
995
|
handleError(err, setError, t);
|
|
1168
996
|
} finally {
|
|
1169
997
|
setIsLoading(false);
|
|
1170
998
|
}
|
|
1171
999
|
};
|
|
1172
|
-
const isSubmitting = isLoading || checkUserMutation.isPending || signInMutation.isPending;
|
|
1173
1000
|
const handleBack = () => {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1001
|
+
setShowPasswordField(false);
|
|
1002
|
+
setUsername("");
|
|
1003
|
+
passwordForm.reset();
|
|
1177
1004
|
};
|
|
1178
|
-
const
|
|
1005
|
+
const isSubmitting = isLoading || checkUserMutation.isPending || signInMutation.isPending || isChecking;
|
|
1179
1006
|
let errorContent = null;
|
|
1180
1007
|
if (error) {
|
|
1181
1008
|
if (typeof error === "string") {
|
|
@@ -1184,79 +1011,145 @@ var SignInPage = ({ redirectUrl } = {}) => {
|
|
|
1184
1011
|
errorContent = error;
|
|
1185
1012
|
}
|
|
1186
1013
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1014
|
+
const formContent = showPasswordField ? /* @__PURE__ */ jsxs4(
|
|
1015
|
+
"form",
|
|
1189
1016
|
{
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
},
|
|
1200
|
-
children: [
|
|
1201
|
-
isStepPassword && // biome-ignore lint/a11y/useKeyWithClickEvents: change account
|
|
1202
|
-
/* @__PURE__ */ jsx9(
|
|
1203
|
-
"p",
|
|
1017
|
+
id: "sign-in-form",
|
|
1018
|
+
onSubmit: passwordForm.handleSubmit(handlePasswordSubmit),
|
|
1019
|
+
children: [
|
|
1020
|
+
/* @__PURE__ */ jsxs4(FieldGroup3, { children: [
|
|
1021
|
+
/* @__PURE__ */ jsxs4("div", { className: "text-center mb-4", children: [
|
|
1022
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground mb-1", children: t("form.enterPasswordFor") }),
|
|
1023
|
+
/* @__PURE__ */ jsx6("p", { className: "font-medium text-foreground", children: username }),
|
|
1024
|
+
/* @__PURE__ */ jsx6(
|
|
1025
|
+
"button",
|
|
1204
1026
|
{
|
|
1205
|
-
|
|
1027
|
+
type: "button",
|
|
1206
1028
|
onClick: handleBack,
|
|
1029
|
+
className: "text-sm text-primary hover:underline mt-2",
|
|
1207
1030
|
children: t("changeAccount")
|
|
1208
1031
|
}
|
|
1209
|
-
),
|
|
1210
|
-
Link ? /* @__PURE__ */ jsx9(
|
|
1211
|
-
Link,
|
|
1212
|
-
{
|
|
1213
|
-
href: forgotPasswordLink,
|
|
1214
|
-
className: "text-primary inline-block hover:underline",
|
|
1215
|
-
children: t("footer.forgotPassword")
|
|
1216
|
-
}
|
|
1217
|
-
) : /* @__PURE__ */ jsx9(
|
|
1218
|
-
"a",
|
|
1219
|
-
{
|
|
1220
|
-
href: forgotPasswordLink,
|
|
1221
|
-
className: "text-primary inline-block hover:underline",
|
|
1222
|
-
children: t("footer.forgotPassword")
|
|
1223
|
-
}
|
|
1224
1032
|
)
|
|
1225
|
-
]
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1033
|
+
] }),
|
|
1034
|
+
/* @__PURE__ */ jsx6(
|
|
1035
|
+
Controller3,
|
|
1036
|
+
{
|
|
1037
|
+
name: "password",
|
|
1038
|
+
control: passwordForm.control,
|
|
1039
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs4(Field3, { "data-invalid": fieldState.invalid, children: [
|
|
1040
|
+
/* @__PURE__ */ jsx6(FieldLabel3, { htmlFor: "sign-in-password", children: t("form.passwordLabel") }),
|
|
1041
|
+
/* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx6(
|
|
1043
|
+
Input3,
|
|
1044
|
+
{
|
|
1045
|
+
...field,
|
|
1046
|
+
id: "sign-in-password",
|
|
1047
|
+
type: showPassword ? "text" : "password",
|
|
1048
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1049
|
+
autoComplete: "current-password",
|
|
1050
|
+
"aria-invalid": fieldState.invalid
|
|
1051
|
+
}
|
|
1052
|
+
),
|
|
1053
|
+
/* @__PURE__ */ jsx6(
|
|
1054
|
+
"button",
|
|
1055
|
+
{
|
|
1056
|
+
type: "button",
|
|
1057
|
+
onClick: () => setShowPassword(!showPassword),
|
|
1058
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1059
|
+
children: showPassword ? /* @__PURE__ */ jsx6(IconEyeOff2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx6(IconEye2, { className: "h-4 w-4" })
|
|
1060
|
+
}
|
|
1061
|
+
)
|
|
1062
|
+
] }),
|
|
1063
|
+
fieldState.invalid && /* @__PURE__ */ jsx6(FieldError3, { errors: [fieldState.error] })
|
|
1064
|
+
] })
|
|
1065
|
+
}
|
|
1066
|
+
)
|
|
1067
|
+
] }),
|
|
1068
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsxs4(Button3, { type: "submit", className: "w-full", disabled: isSubmitting, children: [
|
|
1069
|
+
isSubmitting && /* @__PURE__ */ jsx6(Spinner3, {}),
|
|
1070
|
+
isSubmitting ? t("form.submitting") : t("form.submit")
|
|
1071
|
+
] }) })
|
|
1072
|
+
]
|
|
1073
|
+
}
|
|
1074
|
+
) : /* @__PURE__ */ jsxs4(
|
|
1075
|
+
"form",
|
|
1076
|
+
{
|
|
1077
|
+
id: "sign-in-form",
|
|
1078
|
+
onSubmit: usernameForm.handleSubmit(handleUsernameSubmit),
|
|
1079
|
+
children: [
|
|
1080
|
+
/* @__PURE__ */ jsx6(FieldGroup3, { children: /* @__PURE__ */ jsx6(
|
|
1081
|
+
Controller3,
|
|
1082
|
+
{
|
|
1083
|
+
name: "username",
|
|
1084
|
+
control: usernameForm.control,
|
|
1085
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs4(Field3, { "data-invalid": fieldState.invalid, children: [
|
|
1086
|
+
/* @__PURE__ */ jsx6(FieldLabel3, { htmlFor: "sign-in-username", children: t("form.accountLabel") }),
|
|
1087
|
+
/* @__PURE__ */ jsx6(
|
|
1088
|
+
Input3,
|
|
1089
|
+
{
|
|
1090
|
+
...field,
|
|
1091
|
+
id: "sign-in-username",
|
|
1092
|
+
type: "text",
|
|
1093
|
+
placeholder: t("form.accountPlaceholder"),
|
|
1094
|
+
autoComplete: "username",
|
|
1095
|
+
"aria-invalid": fieldState.invalid
|
|
1096
|
+
}
|
|
1097
|
+
),
|
|
1098
|
+
fieldState.invalid && /* @__PURE__ */ jsx6(FieldError3, { errors: [fieldState.error] })
|
|
1099
|
+
] })
|
|
1100
|
+
}
|
|
1101
|
+
) }),
|
|
1102
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsxs4(Button3, { type: "submit", className: "w-full", disabled: isSubmitting, children: [
|
|
1103
|
+
isSubmitting && /* @__PURE__ */ jsx6(Spinner3, {}),
|
|
1104
|
+
isSubmitting ? t("form.submitting") : t("form.continue")
|
|
1105
|
+
] }) })
|
|
1106
|
+
]
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
return /* @__PURE__ */ jsx6("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs4(
|
|
1110
|
+
AuthLayout,
|
|
1111
|
+
{
|
|
1112
|
+
title: t("title"),
|
|
1113
|
+
description: t("description"),
|
|
1114
|
+
logoImage,
|
|
1115
|
+
footer: showPasswordField ? /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center w-full", children: Link3 ? /* @__PURE__ */ jsx6(
|
|
1116
|
+
Link3,
|
|
1117
|
+
{
|
|
1118
|
+
href: forgotPasswordLink,
|
|
1119
|
+
className: "text-primary inline-block hover:underline",
|
|
1120
|
+
children: t("footer.forgotPassword")
|
|
1121
|
+
}
|
|
1122
|
+
) : /* @__PURE__ */ jsx6(
|
|
1123
|
+
"a",
|
|
1124
|
+
{
|
|
1125
|
+
href: forgotPasswordLink,
|
|
1126
|
+
onClick: (e) => {
|
|
1127
|
+
e.preventDefault();
|
|
1128
|
+
onNavigate(forgotPasswordLink);
|
|
1129
|
+
},
|
|
1130
|
+
className: "text-primary inline-block hover:underline",
|
|
1131
|
+
children: t("footer.forgotPassword")
|
|
1132
|
+
}
|
|
1133
|
+
) }) : void 0,
|
|
1134
|
+
children: [
|
|
1135
|
+
formContent,
|
|
1136
|
+
errorContent && /* @__PURE__ */ jsxs4(Alert3, { variant: "destructive", className: "mt-4", children: [
|
|
1137
|
+
/* @__PURE__ */ jsx6(IconAlertCircle3, { className: "h-4 w-4" }),
|
|
1138
|
+
/* @__PURE__ */ jsx6(AlertTitle3, { children: errorContent.title }),
|
|
1139
|
+
/* @__PURE__ */ jsx6(AlertDescription3, { children: errorContent.description })
|
|
1242
1140
|
] })
|
|
1243
1141
|
]
|
|
1244
1142
|
}
|
|
1245
1143
|
) });
|
|
1246
1144
|
};
|
|
1247
1145
|
|
|
1248
|
-
// src/components/auth/
|
|
1146
|
+
// src/components/auth/sign-up.tsx
|
|
1147
|
+
import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
|
|
1249
1148
|
import {
|
|
1250
1149
|
Alert as Alert4,
|
|
1251
1150
|
AlertDescription as AlertDescription4,
|
|
1252
1151
|
AlertTitle as AlertTitle4
|
|
1253
1152
|
} 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";
|
|
1257
|
-
|
|
1258
|
-
// src/components/auth/sign-up.tsx
|
|
1259
|
-
import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
|
|
1260
1153
|
import { Button as Button4 } from "@mesob/ui/components/button";
|
|
1261
1154
|
import {
|
|
1262
1155
|
Field as Field4,
|
|
@@ -1265,11 +1158,13 @@ import {
|
|
|
1265
1158
|
FieldLabel as FieldLabel4
|
|
1266
1159
|
} from "@mesob/ui/components/field";
|
|
1267
1160
|
import { Input as Input4 } from "@mesob/ui/components/input";
|
|
1268
|
-
import {
|
|
1269
|
-
import {
|
|
1161
|
+
import { useMesob as useMesob4 } from "@mesob/ui/components/mesob-context";
|
|
1162
|
+
import { IconAlertCircle as IconAlertCircle4, IconEye as IconEye3, IconEyeOff as IconEyeOff3 } from "@tabler/icons-react";
|
|
1163
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
1270
1164
|
import { Controller as Controller4, useForm as useForm4 } from "react-hook-form";
|
|
1165
|
+
import { toast as toast4 } from "sonner";
|
|
1271
1166
|
import { z as z4 } from "zod";
|
|
1272
|
-
import { jsx as
|
|
1167
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1273
1168
|
var isPhone2 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1274
1169
|
var signUpSchema = (t) => z4.object({
|
|
1275
1170
|
fullName: z4.string().min(1, t("errors.fullNameRequired")),
|
|
@@ -1291,14 +1186,28 @@ var signUpSchema = (t) => z4.object({
|
|
|
1291
1186
|
path: ["confirmPassword"]
|
|
1292
1187
|
});
|
|
1293
1188
|
var SignUp = ({
|
|
1294
|
-
|
|
1295
|
-
isLoading = false,
|
|
1189
|
+
redirectUrl,
|
|
1296
1190
|
initialIdentifier
|
|
1297
|
-
}) => {
|
|
1191
|
+
} = {}) => {
|
|
1192
|
+
const { hooks, setAuth } = useApi();
|
|
1193
|
+
const { config } = useConfig();
|
|
1194
|
+
const mesob = useMesob4();
|
|
1298
1195
|
const t = useTranslator("Auth.signUp");
|
|
1196
|
+
const Link3 = mesob?.linkComponent ?? config.navigation?.linkComponent;
|
|
1197
|
+
const [isLoading, setIsLoading] = useState5(false);
|
|
1198
|
+
const [error, setError] = useState5(null);
|
|
1199
|
+
const [showPassword, setShowPassword] = useState5(false);
|
|
1200
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState5(false);
|
|
1201
|
+
const signUpMutation = hooks.useMutation("post", "/sign-up");
|
|
1202
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1203
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1204
|
+
if (typeof window !== "undefined") {
|
|
1205
|
+
window.location.href = path;
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
const logoImage = config.ui.logoImage;
|
|
1209
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1299
1210
|
const hasInitialIdentifier = !!initialIdentifier;
|
|
1300
|
-
const [showPassword, setShowPassword] = useState7(false);
|
|
1301
|
-
const [showConfirmPassword, setShowConfirmPassword] = useState7(false);
|
|
1302
1211
|
const form = useForm4({
|
|
1303
1212
|
resolver: zodResolver4(signUpSchema(t)),
|
|
1304
1213
|
defaultValues: {
|
|
@@ -1308,188 +1217,24 @@ var SignUp = ({
|
|
|
1308
1217
|
confirmPassword: ""
|
|
1309
1218
|
}
|
|
1310
1219
|
});
|
|
1311
|
-
|
|
1220
|
+
useEffect4(() => {
|
|
1312
1221
|
if (initialIdentifier) {
|
|
1313
1222
|
form.setValue("identifier", initialIdentifier);
|
|
1314
1223
|
}
|
|
1315
1224
|
}, [initialIdentifier, form]);
|
|
1316
|
-
|
|
1317
|
-
await onSubmit(values);
|
|
1318
|
-
});
|
|
1319
|
-
const getIdentifierLabel = () => {
|
|
1320
|
-
if (!hasInitialIdentifier) {
|
|
1321
|
-
return t("form.accountLabel") || "Email/Phone";
|
|
1322
|
-
}
|
|
1323
|
-
if (initialIdentifier?.includes("@")) {
|
|
1324
|
-
return t("form.emailLabel");
|
|
1325
|
-
}
|
|
1326
|
-
return t("form.phoneLabel");
|
|
1327
|
-
};
|
|
1328
|
-
const identifierLabel = getIdentifierLabel();
|
|
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(
|
|
1339
|
-
Input4,
|
|
1340
|
-
{
|
|
1341
|
-
...field,
|
|
1342
|
-
id: "sign-up-fullName",
|
|
1343
|
-
placeholder: t("form.fullNamePlaceholder"),
|
|
1344
|
-
"aria-invalid": fieldState.invalid
|
|
1345
|
-
}
|
|
1346
|
-
),
|
|
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,
|
|
1359
|
-
{
|
|
1360
|
-
htmlFor: "sign-up-identifier",
|
|
1361
|
-
className: hasInitialIdentifier ? "block" : void 0,
|
|
1362
|
-
children: identifierLabel
|
|
1363
|
-
}
|
|
1364
|
-
),
|
|
1365
|
-
/* @__PURE__ */ jsx10(
|
|
1366
|
-
Input4,
|
|
1367
|
-
{
|
|
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
|
|
1374
|
-
}
|
|
1375
|
-
),
|
|
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")
|
|
1453
|
-
}
|
|
1454
|
-
) })
|
|
1455
|
-
] });
|
|
1456
|
-
};
|
|
1457
|
-
|
|
1458
|
-
// src/components/auth/pages/sign-up-page.tsx
|
|
1459
|
-
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1460
|
-
var isPhone3 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1461
|
-
var SignUpPage = ({
|
|
1462
|
-
redirectUrl,
|
|
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(() => {
|
|
1225
|
+
useEffect4(() => {
|
|
1481
1226
|
if (error) {
|
|
1482
1227
|
toast4.error(error.title || "Error", {
|
|
1483
1228
|
description: error.description
|
|
1484
1229
|
});
|
|
1485
1230
|
}
|
|
1486
1231
|
}, [error]);
|
|
1487
|
-
const handleSubmit = async (values) => {
|
|
1232
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1488
1233
|
setIsLoading(true);
|
|
1489
1234
|
setError(null);
|
|
1490
1235
|
try {
|
|
1491
1236
|
const identifier = values.identifier;
|
|
1492
|
-
const usingPhone =
|
|
1237
|
+
const usingPhone = isPhone2(identifier);
|
|
1493
1238
|
const res = await signUpMutation.mutateAsync({
|
|
1494
1239
|
body: usingPhone ? {
|
|
1495
1240
|
phone: identifier,
|
|
@@ -1524,7 +1269,17 @@ var SignUpPage = ({
|
|
|
1524
1269
|
} finally {
|
|
1525
1270
|
setIsLoading(false);
|
|
1526
1271
|
}
|
|
1272
|
+
});
|
|
1273
|
+
const getIdentifierLabel = () => {
|
|
1274
|
+
if (!hasInitialIdentifier) {
|
|
1275
|
+
return t("form.accountLabel") || "Email/Phone";
|
|
1276
|
+
}
|
|
1277
|
+
if (initialIdentifier?.includes("@")) {
|
|
1278
|
+
return t("form.emailLabel");
|
|
1279
|
+
}
|
|
1280
|
+
return t("form.phoneLabel");
|
|
1527
1281
|
};
|
|
1282
|
+
const identifierLabel = getIdentifierLabel();
|
|
1528
1283
|
let errorContent = null;
|
|
1529
1284
|
if (error) {
|
|
1530
1285
|
if (typeof error === "string") {
|
|
@@ -1533,16 +1288,16 @@ var SignUpPage = ({
|
|
|
1533
1288
|
errorContent = error;
|
|
1534
1289
|
}
|
|
1535
1290
|
}
|
|
1536
|
-
return /* @__PURE__ */
|
|
1537
|
-
|
|
1291
|
+
return /* @__PURE__ */ jsxs5(
|
|
1292
|
+
AuthLayout,
|
|
1538
1293
|
{
|
|
1539
1294
|
title: t("title"),
|
|
1540
1295
|
description: t("description"),
|
|
1541
1296
|
logoImage,
|
|
1542
|
-
footer: /* @__PURE__ */
|
|
1297
|
+
footer: /* @__PURE__ */ jsxs5("p", { children: [
|
|
1543
1298
|
t("footer.hasAccount"),
|
|
1544
1299
|
" ",
|
|
1545
|
-
|
|
1300
|
+
Link3 ? /* @__PURE__ */ jsx7(Link3, { href: signInLink, className: "text-primary hover:underline", children: t("footer.signInCta") }) : /* @__PURE__ */ jsx7(
|
|
1546
1301
|
"a",
|
|
1547
1302
|
{
|
|
1548
1303
|
href: signInLink,
|
|
@@ -1556,34 +1311,143 @@ var SignUpPage = ({
|
|
|
1556
1311
|
)
|
|
1557
1312
|
] }),
|
|
1558
1313
|
children: [
|
|
1559
|
-
/* @__PURE__ */
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1314
|
+
/* @__PURE__ */ jsxs5("form", { id: "sign-up-form", onSubmit: handleSubmit, children: [
|
|
1315
|
+
/* @__PURE__ */ jsxs5(FieldGroup4, { children: [
|
|
1316
|
+
/* @__PURE__ */ jsx7(
|
|
1317
|
+
Controller4,
|
|
1318
|
+
{
|
|
1319
|
+
name: "fullName",
|
|
1320
|
+
control: form.control,
|
|
1321
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs5(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1322
|
+
/* @__PURE__ */ jsx7(FieldLabel4, { htmlFor: "sign-up-fullName", children: t("form.fullNameLabel") }),
|
|
1323
|
+
/* @__PURE__ */ jsx7(
|
|
1324
|
+
Input4,
|
|
1325
|
+
{
|
|
1326
|
+
...field,
|
|
1327
|
+
id: "sign-up-fullName",
|
|
1328
|
+
placeholder: t("form.fullNamePlaceholder"),
|
|
1329
|
+
"aria-invalid": fieldState.invalid
|
|
1330
|
+
}
|
|
1331
|
+
),
|
|
1332
|
+
fieldState.invalid && /* @__PURE__ */ jsx7(FieldError4, { errors: [fieldState.error] })
|
|
1333
|
+
] })
|
|
1334
|
+
}
|
|
1335
|
+
),
|
|
1336
|
+
/* @__PURE__ */ jsx7(
|
|
1337
|
+
Controller4,
|
|
1338
|
+
{
|
|
1339
|
+
name: "identifier",
|
|
1340
|
+
control: form.control,
|
|
1341
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs5(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1342
|
+
/* @__PURE__ */ jsx7(
|
|
1343
|
+
FieldLabel4,
|
|
1344
|
+
{
|
|
1345
|
+
htmlFor: "sign-up-identifier",
|
|
1346
|
+
className: hasInitialIdentifier ? "block" : void 0,
|
|
1347
|
+
children: identifierLabel
|
|
1348
|
+
}
|
|
1349
|
+
),
|
|
1350
|
+
/* @__PURE__ */ jsx7(
|
|
1351
|
+
Input4,
|
|
1352
|
+
{
|
|
1353
|
+
...field,
|
|
1354
|
+
id: "sign-up-identifier",
|
|
1355
|
+
type: field.value.includes("@") ? "email" : "tel",
|
|
1356
|
+
placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
|
|
1357
|
+
disabled: hasInitialIdentifier,
|
|
1358
|
+
"aria-invalid": fieldState.invalid
|
|
1359
|
+
}
|
|
1360
|
+
),
|
|
1361
|
+
fieldState.invalid && /* @__PURE__ */ jsx7(FieldError4, { errors: [fieldState.error] })
|
|
1362
|
+
] })
|
|
1363
|
+
}
|
|
1364
|
+
),
|
|
1365
|
+
/* @__PURE__ */ jsx7(
|
|
1366
|
+
Controller4,
|
|
1367
|
+
{
|
|
1368
|
+
name: "password",
|
|
1369
|
+
control: form.control,
|
|
1370
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs5(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1371
|
+
/* @__PURE__ */ jsx7(FieldLabel4, { htmlFor: "sign-up-password", children: t("form.passwordLabel") }),
|
|
1372
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
1373
|
+
/* @__PURE__ */ jsx7(
|
|
1374
|
+
Input4,
|
|
1375
|
+
{
|
|
1376
|
+
...field,
|
|
1377
|
+
id: "sign-up-password",
|
|
1378
|
+
type: showPassword ? "text" : "password",
|
|
1379
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1380
|
+
"aria-invalid": fieldState.invalid
|
|
1381
|
+
}
|
|
1382
|
+
),
|
|
1383
|
+
/* @__PURE__ */ jsx7(
|
|
1384
|
+
"button",
|
|
1385
|
+
{
|
|
1386
|
+
type: "button",
|
|
1387
|
+
onClick: () => setShowPassword(!showPassword),
|
|
1388
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1389
|
+
children: showPassword ? /* @__PURE__ */ jsx7(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(IconEye3, { className: "h-4 w-4" })
|
|
1390
|
+
}
|
|
1391
|
+
)
|
|
1392
|
+
] }),
|
|
1393
|
+
fieldState.invalid && /* @__PURE__ */ jsx7(FieldError4, { errors: [fieldState.error] })
|
|
1394
|
+
] })
|
|
1395
|
+
}
|
|
1396
|
+
),
|
|
1397
|
+
/* @__PURE__ */ jsx7(
|
|
1398
|
+
Controller4,
|
|
1399
|
+
{
|
|
1400
|
+
name: "confirmPassword",
|
|
1401
|
+
control: form.control,
|
|
1402
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs5(Field4, { "data-invalid": fieldState.invalid, children: [
|
|
1403
|
+
/* @__PURE__ */ jsx7(FieldLabel4, { htmlFor: "sign-up-confirmPassword", children: t("form.confirmPasswordLabel") }),
|
|
1404
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
1405
|
+
/* @__PURE__ */ jsx7(
|
|
1406
|
+
Input4,
|
|
1407
|
+
{
|
|
1408
|
+
...field,
|
|
1409
|
+
id: "sign-up-confirmPassword",
|
|
1410
|
+
type: showConfirmPassword ? "text" : "password",
|
|
1411
|
+
placeholder: t("form.passwordPlaceholder"),
|
|
1412
|
+
"aria-invalid": fieldState.invalid
|
|
1413
|
+
}
|
|
1414
|
+
),
|
|
1415
|
+
/* @__PURE__ */ jsx7(
|
|
1416
|
+
"button",
|
|
1417
|
+
{
|
|
1418
|
+
type: "button",
|
|
1419
|
+
onClick: () => setShowConfirmPassword(!showConfirmPassword),
|
|
1420
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
1421
|
+
children: showConfirmPassword ? /* @__PURE__ */ jsx7(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(IconEye3, { className: "h-4 w-4" })
|
|
1422
|
+
}
|
|
1423
|
+
)
|
|
1424
|
+
] }),
|
|
1425
|
+
fieldState.invalid && /* @__PURE__ */ jsx7(FieldError4, { errors: [fieldState.error] })
|
|
1426
|
+
] })
|
|
1427
|
+
}
|
|
1428
|
+
)
|
|
1429
|
+
] }),
|
|
1430
|
+
/* @__PURE__ */ jsx7("div", { className: "mt-4", children: /* @__PURE__ */ jsx7(
|
|
1431
|
+
Button4,
|
|
1432
|
+
{
|
|
1433
|
+
type: "submit",
|
|
1434
|
+
form: "sign-up-form",
|
|
1435
|
+
className: "w-full",
|
|
1436
|
+
disabled: isLoading || signUpMutation.isPending,
|
|
1437
|
+
children: isLoading || signUpMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
1438
|
+
}
|
|
1439
|
+
) })
|
|
1440
|
+
] }),
|
|
1441
|
+
errorContent && /* @__PURE__ */ jsxs5(Alert4, { variant: "destructive", className: "mt-4", children: [
|
|
1442
|
+
/* @__PURE__ */ jsx7(IconAlertCircle4, { className: "h-4 w-4" }),
|
|
1443
|
+
/* @__PURE__ */ jsx7(AlertTitle4, { children: errorContent.title }),
|
|
1444
|
+
/* @__PURE__ */ jsx7(AlertDescription4, { children: errorContent.description })
|
|
1571
1445
|
] })
|
|
1572
1446
|
]
|
|
1573
1447
|
}
|
|
1574
1448
|
);
|
|
1575
1449
|
};
|
|
1576
1450
|
|
|
1577
|
-
// src/components/auth/pages/verify-email-page.tsx
|
|
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";
|
|
1586
|
-
|
|
1587
1451
|
// src/components/auth/verification-form.tsx
|
|
1588
1452
|
import { zodResolver as zodResolver5 } from "@hookform/resolvers/zod";
|
|
1589
1453
|
import { Button as Button6 } from "@mesob/ui/components/button";
|
|
@@ -1600,17 +1464,17 @@ import { z as z5 } from "zod";
|
|
|
1600
1464
|
// src/components/auth/countdown.tsx
|
|
1601
1465
|
import { Button as Button5 } from "@mesob/ui/components/button";
|
|
1602
1466
|
import { Spinner as Spinner4 } from "@mesob/ui/components/spinner";
|
|
1603
|
-
import { useEffect as
|
|
1604
|
-
import { jsx as
|
|
1467
|
+
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
1468
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1605
1469
|
var Countdown = ({
|
|
1606
1470
|
initialSeconds = 60,
|
|
1607
1471
|
onResend,
|
|
1608
1472
|
resending = false
|
|
1609
1473
|
}) => {
|
|
1610
1474
|
const t = useTranslator("Common");
|
|
1611
|
-
const [seconds, setSeconds] =
|
|
1612
|
-
const [isResending, setIsResending] =
|
|
1613
|
-
|
|
1475
|
+
const [seconds, setSeconds] = useState6(initialSeconds);
|
|
1476
|
+
const [isResending, setIsResending] = useState6(false);
|
|
1477
|
+
useEffect5(() => {
|
|
1614
1478
|
if (seconds <= 0) {
|
|
1615
1479
|
return;
|
|
1616
1480
|
}
|
|
@@ -1636,16 +1500,16 @@ var Countdown = ({
|
|
|
1636
1500
|
}
|
|
1637
1501
|
};
|
|
1638
1502
|
if (seconds > 0) {
|
|
1639
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsx8(Button5, { variant: "ghost", disabled: true, children: t("resendIn", { seconds }) });
|
|
1640
1504
|
}
|
|
1641
|
-
return /* @__PURE__ */
|
|
1505
|
+
return /* @__PURE__ */ jsxs6(
|
|
1642
1506
|
Button5,
|
|
1643
1507
|
{
|
|
1644
1508
|
variant: "ghost",
|
|
1645
1509
|
onClick: handleResend,
|
|
1646
1510
|
disabled: isResending || resending,
|
|
1647
1511
|
children: [
|
|
1648
|
-
isResending || resending && /* @__PURE__ */
|
|
1512
|
+
isResending || resending && /* @__PURE__ */ jsx8(Spinner4, {}),
|
|
1649
1513
|
t("resend")
|
|
1650
1514
|
]
|
|
1651
1515
|
}
|
|
@@ -1653,7 +1517,7 @@ var Countdown = ({
|
|
|
1653
1517
|
};
|
|
1654
1518
|
|
|
1655
1519
|
// src/components/auth/verification-form.tsx
|
|
1656
|
-
import { jsx as
|
|
1520
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1657
1521
|
var verificationSchema = (t) => z5.object({
|
|
1658
1522
|
code: z5.string().length(6, t("form.codeLength"))
|
|
1659
1523
|
});
|
|
@@ -1672,14 +1536,14 @@ var VerificationForm = ({
|
|
|
1672
1536
|
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1673
1537
|
await onSubmit(values);
|
|
1674
1538
|
});
|
|
1675
|
-
return /* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1539
|
+
return /* @__PURE__ */ jsxs7("form", { id: "verification-form", onSubmit: handleSubmit, children: [
|
|
1540
|
+
/* @__PURE__ */ jsx9(FieldGroup5, { children: /* @__PURE__ */ jsx9(
|
|
1677
1541
|
Controller5,
|
|
1678
1542
|
{
|
|
1679
1543
|
name: "code",
|
|
1680
1544
|
control: form.control,
|
|
1681
|
-
render: ({ field, fieldState }) => /* @__PURE__ */
|
|
1682
|
-
/* @__PURE__ */
|
|
1545
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ jsxs7(Field5, { "data-invalid": fieldState.invalid, children: [
|
|
1546
|
+
/* @__PURE__ */ jsx9("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx9(
|
|
1683
1547
|
InputOTP2,
|
|
1684
1548
|
{
|
|
1685
1549
|
maxLength: 6,
|
|
@@ -1690,30 +1554,30 @@ var VerificationForm = ({
|
|
|
1690
1554
|
onBlur: field.onBlur,
|
|
1691
1555
|
containerClassName: "gap-4 justify-center mb-2 flex items-center",
|
|
1692
1556
|
"aria-invalid": fieldState.invalid,
|
|
1693
|
-
children: /* @__PURE__ */
|
|
1694
|
-
/* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1696
|
-
/* @__PURE__ */
|
|
1697
|
-
/* @__PURE__ */
|
|
1698
|
-
/* @__PURE__ */
|
|
1699
|
-
/* @__PURE__ */
|
|
1557
|
+
children: /* @__PURE__ */ jsxs7(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: [
|
|
1558
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 0 }),
|
|
1559
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 1 }),
|
|
1560
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 2 }),
|
|
1561
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 3 }),
|
|
1562
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 4 }),
|
|
1563
|
+
/* @__PURE__ */ jsx9(InputOTPSlot2, { className: "h-12", index: 5 })
|
|
1700
1564
|
] })
|
|
1701
1565
|
}
|
|
1702
1566
|
) }),
|
|
1703
|
-
fieldState.invalid && /* @__PURE__ */
|
|
1567
|
+
fieldState.invalid && /* @__PURE__ */ jsx9(FieldError5, { errors: [fieldState.error] })
|
|
1704
1568
|
] })
|
|
1705
1569
|
}
|
|
1706
1570
|
) }),
|
|
1707
|
-
/* @__PURE__ */
|
|
1708
|
-
/* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
1571
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex justify-between items-center mt-4", children: [
|
|
1572
|
+
/* @__PURE__ */ jsx9(Countdown, { onResend, resending: isLoading }),
|
|
1573
|
+
/* @__PURE__ */ jsxs7(
|
|
1710
1574
|
Button6,
|
|
1711
1575
|
{
|
|
1712
1576
|
type: "submit",
|
|
1713
1577
|
form: "verification-form",
|
|
1714
1578
|
disabled: isLoading || form.watch("code").length !== 6,
|
|
1715
1579
|
children: [
|
|
1716
|
-
isLoading && /* @__PURE__ */
|
|
1580
|
+
isLoading && /* @__PURE__ */ jsx9(Spinner5, {}),
|
|
1717
1581
|
t("form.confirm")
|
|
1718
1582
|
]
|
|
1719
1583
|
}
|
|
@@ -1722,23 +1586,31 @@ var VerificationForm = ({
|
|
|
1722
1586
|
] });
|
|
1723
1587
|
};
|
|
1724
1588
|
|
|
1725
|
-
// src/components/auth/
|
|
1726
|
-
import {
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
const
|
|
1589
|
+
// src/components/auth/verify-email.tsx
|
|
1590
|
+
import {
|
|
1591
|
+
Alert as Alert5,
|
|
1592
|
+
AlertDescription as AlertDescription5,
|
|
1593
|
+
AlertTitle as AlertTitle5
|
|
1594
|
+
} from "@mesob/ui/components/alert";
|
|
1595
|
+
import { useMesob as useMesob5 } from "@mesob/ui/components/mesob-context";
|
|
1596
|
+
import { IconAlertCircle as IconAlertCircle5 } from "@tabler/icons-react";
|
|
1597
|
+
import { useEffect as useEffect6, useState as useState7 } from "react";
|
|
1598
|
+
import { toast as toast5 } from "sonner";
|
|
1599
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1600
|
+
var VerifyEmail = ({
|
|
1601
|
+
verificationId,
|
|
1602
|
+
email,
|
|
1603
|
+
redirectUrl
|
|
1604
|
+
}) => {
|
|
1605
|
+
const { hooks, setAuth } = useApi();
|
|
1606
|
+
const { config } = useConfig();
|
|
1607
|
+
const mesob = useMesob5();
|
|
1608
|
+
const t = useTranslator("Auth.verification");
|
|
1609
|
+
const common = useTranslator("Common");
|
|
1610
|
+
const footer = useTranslator("Auth.forgotPassword.footer");
|
|
1611
|
+
const Link3 = mesob?.linkComponent ?? config.navigation?.linkComponent;
|
|
1612
|
+
const [isLoading, setIsLoading] = useState7(false);
|
|
1613
|
+
const [error, setError] = useState7(null);
|
|
1742
1614
|
const verifyEmailMutation = hooks.useMutation(
|
|
1743
1615
|
"post",
|
|
1744
1616
|
"/email/verification/confirm"
|
|
@@ -1748,7 +1620,6 @@ var VerifyEmailPage = ({
|
|
|
1748
1620
|
"/email/verification/request"
|
|
1749
1621
|
);
|
|
1750
1622
|
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1751
|
-
const Link = config.navigation?.linkComponent;
|
|
1752
1623
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1753
1624
|
if (typeof window !== "undefined") {
|
|
1754
1625
|
window.location.href = path;
|
|
@@ -1756,7 +1627,7 @@ var VerifyEmailPage = ({
|
|
|
1756
1627
|
});
|
|
1757
1628
|
const logoImage = config.ui.logoImage;
|
|
1758
1629
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1759
|
-
|
|
1630
|
+
useEffect6(() => {
|
|
1760
1631
|
if (error) {
|
|
1761
1632
|
toast5.error(error.title || "Error", {
|
|
1762
1633
|
description: error.description
|
|
@@ -1813,12 +1684,12 @@ var VerifyEmailPage = ({
|
|
|
1813
1684
|
}
|
|
1814
1685
|
};
|
|
1815
1686
|
if (!verificationId) {
|
|
1816
|
-
return /* @__PURE__ */
|
|
1817
|
-
|
|
1687
|
+
return /* @__PURE__ */ jsx10(
|
|
1688
|
+
AuthLayout,
|
|
1818
1689
|
{
|
|
1819
1690
|
title: common("invalidLinkTitle"),
|
|
1820
1691
|
description: common("invalidLinkDescription"),
|
|
1821
|
-
footer:
|
|
1692
|
+
footer: Link3 ? /* @__PURE__ */ jsx10(Link3, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx10(
|
|
1822
1693
|
"a",
|
|
1823
1694
|
{
|
|
1824
1695
|
href: signInLink,
|
|
@@ -1830,7 +1701,7 @@ var VerifyEmailPage = ({
|
|
|
1830
1701
|
children: footer("backToSignIn")
|
|
1831
1702
|
}
|
|
1832
1703
|
),
|
|
1833
|
-
children: /* @__PURE__ */
|
|
1704
|
+
children: /* @__PURE__ */ jsx10("div", {})
|
|
1834
1705
|
}
|
|
1835
1706
|
);
|
|
1836
1707
|
}
|
|
@@ -1842,13 +1713,13 @@ var VerifyEmailPage = ({
|
|
|
1842
1713
|
errorContent = error;
|
|
1843
1714
|
}
|
|
1844
1715
|
}
|
|
1845
|
-
return /* @__PURE__ */
|
|
1846
|
-
|
|
1716
|
+
return /* @__PURE__ */ jsxs8(
|
|
1717
|
+
AuthLayout,
|
|
1847
1718
|
{
|
|
1848
1719
|
title: t("email.title"),
|
|
1849
1720
|
description: t("email.description"),
|
|
1850
1721
|
logoImage,
|
|
1851
|
-
footer:
|
|
1722
|
+
footer: Link3 ? /* @__PURE__ */ jsx10(Link3, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx10(
|
|
1852
1723
|
"a",
|
|
1853
1724
|
{
|
|
1854
1725
|
href: signInLink,
|
|
@@ -1861,7 +1732,7 @@ var VerifyEmailPage = ({
|
|
|
1861
1732
|
}
|
|
1862
1733
|
),
|
|
1863
1734
|
children: [
|
|
1864
|
-
/* @__PURE__ */
|
|
1735
|
+
/* @__PURE__ */ jsx10(
|
|
1865
1736
|
VerificationForm,
|
|
1866
1737
|
{
|
|
1867
1738
|
verificationId,
|
|
@@ -1871,27 +1742,28 @@ var VerifyEmailPage = ({
|
|
|
1871
1742
|
error
|
|
1872
1743
|
}
|
|
1873
1744
|
),
|
|
1874
|
-
errorContent && /* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1876
|
-
/* @__PURE__ */
|
|
1877
|
-
/* @__PURE__ */
|
|
1745
|
+
errorContent && /* @__PURE__ */ jsxs8(Alert5, { variant: "destructive", className: "mt-4", children: [
|
|
1746
|
+
/* @__PURE__ */ jsx10(IconAlertCircle5, { className: "h-4 w-4" }),
|
|
1747
|
+
/* @__PURE__ */ jsx10(AlertTitle5, { children: errorContent.title }),
|
|
1748
|
+
/* @__PURE__ */ jsx10(AlertDescription5, { children: errorContent.description })
|
|
1878
1749
|
] })
|
|
1879
1750
|
]
|
|
1880
1751
|
}
|
|
1881
1752
|
);
|
|
1882
1753
|
};
|
|
1883
1754
|
|
|
1884
|
-
// src/components/auth/
|
|
1755
|
+
// src/components/auth/verify-phone.tsx
|
|
1885
1756
|
import {
|
|
1886
1757
|
Alert as Alert6,
|
|
1887
1758
|
AlertDescription as AlertDescription6,
|
|
1888
1759
|
AlertTitle as AlertTitle6
|
|
1889
1760
|
} from "@mesob/ui/components/alert";
|
|
1890
|
-
import {
|
|
1761
|
+
import { Link as Link2 } from "@mesob/ui/components/link";
|
|
1891
1762
|
import { IconAlertCircle as IconAlertCircle6 } from "@tabler/icons-react";
|
|
1892
|
-
import { useEffect as
|
|
1893
|
-
import {
|
|
1894
|
-
|
|
1763
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
1764
|
+
import { toast as toast6 } from "sonner";
|
|
1765
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1766
|
+
var VerifyPhone = ({
|
|
1895
1767
|
verificationId,
|
|
1896
1768
|
context,
|
|
1897
1769
|
phone = "",
|
|
@@ -1899,14 +1771,11 @@ var VerifyPhonePage = ({
|
|
|
1899
1771
|
}) => {
|
|
1900
1772
|
const { hooks, refresh, setAuth } = useApi();
|
|
1901
1773
|
const { config } = useConfig();
|
|
1902
|
-
const t =
|
|
1903
|
-
const common =
|
|
1904
|
-
const footer =
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
);
|
|
1908
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
1909
|
-
const [error, setError] = useState11(null);
|
|
1774
|
+
const t = useTranslator("Auth.verification");
|
|
1775
|
+
const common = useTranslator("Common");
|
|
1776
|
+
const footer = useTranslator("Auth.forgotPassword.footer");
|
|
1777
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1778
|
+
const [error, setError] = useState8(null);
|
|
1910
1779
|
const verifyPhoneMutation = hooks.useMutation(
|
|
1911
1780
|
"post",
|
|
1912
1781
|
"/phone/verification/confirm"
|
|
@@ -1916,7 +1785,6 @@ var VerifyPhonePage = ({
|
|
|
1916
1785
|
"/phone/verification/request"
|
|
1917
1786
|
);
|
|
1918
1787
|
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1919
|
-
const Link = config.navigation?.linkComponent;
|
|
1920
1788
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
1921
1789
|
if (typeof window !== "undefined") {
|
|
1922
1790
|
window.location.href = path;
|
|
@@ -1924,7 +1792,7 @@ var VerifyPhonePage = ({
|
|
|
1924
1792
|
});
|
|
1925
1793
|
const logoImage = config.ui.logoImage;
|
|
1926
1794
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1927
|
-
|
|
1795
|
+
useEffect7(() => {
|
|
1928
1796
|
if (error) {
|
|
1929
1797
|
toast6.error(error.title || "Error", {
|
|
1930
1798
|
description: error.description
|
|
@@ -1994,24 +1862,13 @@ var VerifyPhonePage = ({
|
|
|
1994
1862
|
}
|
|
1995
1863
|
};
|
|
1996
1864
|
if (!verificationId) {
|
|
1997
|
-
return /* @__PURE__ */
|
|
1998
|
-
|
|
1865
|
+
return /* @__PURE__ */ jsx11(
|
|
1866
|
+
AuthLayout,
|
|
1999
1867
|
{
|
|
2000
1868
|
title: common("invalidLinkTitle"),
|
|
2001
1869
|
description: common("invalidLinkDescription"),
|
|
2002
|
-
footer:
|
|
2003
|
-
|
|
2004
|
-
{
|
|
2005
|
-
href: signInLink,
|
|
2006
|
-
onClick: (e) => {
|
|
2007
|
-
e.preventDefault();
|
|
2008
|
-
onNavigate(signInLink);
|
|
2009
|
-
},
|
|
2010
|
-
className: "text-primary hover:underline",
|
|
2011
|
-
children: footer("backToSignIn")
|
|
2012
|
-
}
|
|
2013
|
-
),
|
|
2014
|
-
children: /* @__PURE__ */ jsx15("div", {})
|
|
1870
|
+
footer: /* @__PURE__ */ jsx11(Link2, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }),
|
|
1871
|
+
children: /* @__PURE__ */ jsx11("div", {})
|
|
2015
1872
|
}
|
|
2016
1873
|
);
|
|
2017
1874
|
}
|
|
@@ -2023,15 +1880,15 @@ var VerifyPhonePage = ({
|
|
|
2023
1880
|
errorContent = error;
|
|
2024
1881
|
}
|
|
2025
1882
|
}
|
|
2026
|
-
return /* @__PURE__ */
|
|
2027
|
-
|
|
1883
|
+
return /* @__PURE__ */ jsxs9(
|
|
1884
|
+
AuthLayout,
|
|
2028
1885
|
{
|
|
2029
1886
|
title: t("phone.title"),
|
|
2030
1887
|
description: t("phone.description", {
|
|
2031
1888
|
target: phone || t("phone.missingPhone")
|
|
2032
1889
|
}),
|
|
2033
1890
|
logoImage,
|
|
2034
|
-
footer:
|
|
1891
|
+
footer: Link2 ? /* @__PURE__ */ jsx11(Link2, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx11(
|
|
2035
1892
|
"a",
|
|
2036
1893
|
{
|
|
2037
1894
|
href: signInLink,
|
|
@@ -2044,7 +1901,7 @@ var VerifyPhonePage = ({
|
|
|
2044
1901
|
}
|
|
2045
1902
|
),
|
|
2046
1903
|
children: [
|
|
2047
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ jsx11(
|
|
2048
1905
|
VerificationForm,
|
|
2049
1906
|
{
|
|
2050
1907
|
verificationId,
|
|
@@ -2054,10 +1911,10 @@ var VerifyPhonePage = ({
|
|
|
2054
1911
|
error
|
|
2055
1912
|
}
|
|
2056
1913
|
),
|
|
2057
|
-
errorContent && /* @__PURE__ */
|
|
2058
|
-
/* @__PURE__ */
|
|
2059
|
-
/* @__PURE__ */
|
|
2060
|
-
/* @__PURE__ */
|
|
1914
|
+
errorContent && /* @__PURE__ */ jsxs9(Alert6, { variant: "destructive", className: "mt-4", children: [
|
|
1915
|
+
/* @__PURE__ */ jsx11(IconAlertCircle6, { className: "h-4 w-4" }),
|
|
1916
|
+
/* @__PURE__ */ jsx11(AlertTitle6, { children: errorContent.title }),
|
|
1917
|
+
/* @__PURE__ */ jsx11(AlertDescription6, { children: errorContent.description })
|
|
2061
1918
|
] })
|
|
2062
1919
|
]
|
|
2063
1920
|
}
|
|
@@ -2067,7 +1924,7 @@ var VerifyPhonePage = ({
|
|
|
2067
1924
|
// src/components/error-boundary.tsx
|
|
2068
1925
|
import { Button as Button7 } from "@mesob/ui/components/button";
|
|
2069
1926
|
import { Component } from "react";
|
|
2070
|
-
import { jsx as
|
|
1927
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2071
1928
|
var ErrorBoundary = class extends Component {
|
|
2072
1929
|
constructor(props) {
|
|
2073
1930
|
super(props);
|
|
@@ -2089,30 +1946,31 @@ var ErrorBoundary = class extends Component {
|
|
|
2089
1946
|
reset: this.reset
|
|
2090
1947
|
});
|
|
2091
1948
|
}
|
|
2092
|
-
return /* @__PURE__ */
|
|
1949
|
+
return /* @__PURE__ */ jsx12(ErrorFallback, { error: this.state.error, reset: this.reset });
|
|
2093
1950
|
}
|
|
2094
1951
|
return this.props.children;
|
|
2095
1952
|
}
|
|
2096
1953
|
};
|
|
2097
1954
|
function ErrorFallback({ error, reset }) {
|
|
2098
|
-
return /* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
1955
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: /* @__PURE__ */ jsxs10("div", { className: "max-w-md w-full space-y-4 text-center", children: [
|
|
1956
|
+
/* @__PURE__ */ jsxs10("div", { className: "space-y-2", children: [
|
|
1957
|
+
/* @__PURE__ */ jsx12("h2", { className: "text-2xl font-bold text-destructive", children: "Something went wrong" }),
|
|
1958
|
+
/* @__PURE__ */ jsx12("p", { className: "text-muted-foreground", children: error.message || "An unexpected error occurred" })
|
|
2102
1959
|
] }),
|
|
2103
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsx12(Button7, { onClick: reset, variant: "outline", children: "Try again" })
|
|
2104
1961
|
] }) });
|
|
2105
1962
|
}
|
|
2106
1963
|
function AuthErrorBoundary({ children }) {
|
|
2107
|
-
return /* @__PURE__ */
|
|
1964
|
+
return /* @__PURE__ */ jsx12(ErrorBoundary, { children });
|
|
2108
1965
|
}
|
|
2109
1966
|
|
|
2110
|
-
// src/components/iam/permissions
|
|
1967
|
+
// src/components/iam/permissions.tsx
|
|
2111
1968
|
import { Badge } from "@mesob/ui/components/badge";
|
|
2112
1969
|
import { Button as Button8 } from "@mesob/ui/components/button";
|
|
2113
|
-
import {
|
|
1970
|
+
import { useLocale } from "next-intl";
|
|
1971
|
+
import { useState as useState9 } from "react";
|
|
2114
1972
|
|
|
2115
|
-
// src/components/shared/data-table
|
|
1973
|
+
// src/components/shared/data-table.tsx
|
|
2116
1974
|
import {
|
|
2117
1975
|
Table,
|
|
2118
1976
|
TableBody,
|
|
@@ -2124,7 +1982,7 @@ import {
|
|
|
2124
1982
|
|
|
2125
1983
|
// src/components/skeletons/table-skeleton.tsx
|
|
2126
1984
|
import { Skeleton } from "@mesob/ui/components/skeleton";
|
|
2127
|
-
import { jsx as
|
|
1985
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2128
1986
|
function TableSkeleton({ columns = 5, rows = 10 }) {
|
|
2129
1987
|
const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);
|
|
2130
1988
|
const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);
|
|
@@ -2132,32 +1990,32 @@ function TableSkeleton({ columns = 5, rows = 10 }) {
|
|
|
2132
1990
|
{ length: rows },
|
|
2133
1991
|
(_, rowIdx) => Array.from({ length: columns }, (_2, colIdx) => `cell-${rowIdx}-${colIdx}`)
|
|
2134
1992
|
);
|
|
2135
|
-
return /* @__PURE__ */
|
|
2136
|
-
/* @__PURE__ */
|
|
2137
|
-
/* @__PURE__ */
|
|
2138
|
-
/* @__PURE__ */
|
|
1993
|
+
return /* @__PURE__ */ jsxs11("div", { className: "w-full space-y-4", children: [
|
|
1994
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex justify-between items-center", children: [
|
|
1995
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-8 w-48" }),
|
|
1996
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 w-32" })
|
|
2139
1997
|
] }),
|
|
2140
|
-
/* @__PURE__ */
|
|
2141
|
-
/* @__PURE__ */
|
|
2142
|
-
/* @__PURE__ */
|
|
2143
|
-
/* @__PURE__ */
|
|
1998
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex gap-4", children: [
|
|
1999
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 flex-1 max-w-sm" }),
|
|
2000
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 w-24" }),
|
|
2001
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 w-24" })
|
|
2144
2002
|
] }),
|
|
2145
|
-
/* @__PURE__ */
|
|
2146
|
-
/* @__PURE__ */
|
|
2147
|
-
rowKeys.map((rowKey, rowIdx) => /* @__PURE__ */
|
|
2003
|
+
/* @__PURE__ */ jsxs11("div", { className: "border rounded-lg overflow-hidden", children: [
|
|
2004
|
+
/* @__PURE__ */ jsx13("div", { className: "flex gap-4 p-4 bg-muted", children: headerKeys.map((key) => /* @__PURE__ */ jsx13(Skeleton, { className: "h-4 flex-1" }, key)) }),
|
|
2005
|
+
rowKeys.map((rowKey, rowIdx) => /* @__PURE__ */ jsx13("div", { className: "flex gap-4 p-4 border-t", children: cellKeys[rowIdx]?.map((cellKey) => /* @__PURE__ */ jsx13(Skeleton, { className: "h-4 flex-1" }, cellKey)) }, rowKey))
|
|
2148
2006
|
] }),
|
|
2149
|
-
/* @__PURE__ */
|
|
2150
|
-
/* @__PURE__ */
|
|
2151
|
-
/* @__PURE__ */
|
|
2152
|
-
/* @__PURE__ */
|
|
2153
|
-
/* @__PURE__ */
|
|
2007
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex justify-between items-center", children: [
|
|
2008
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-4 w-32" }),
|
|
2009
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex gap-2", children: [
|
|
2010
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 w-20" }),
|
|
2011
|
+
/* @__PURE__ */ jsx13(Skeleton, { className: "h-10 w-20" })
|
|
2154
2012
|
] })
|
|
2155
2013
|
] })
|
|
2156
2014
|
] });
|
|
2157
2015
|
}
|
|
2158
2016
|
|
|
2159
|
-
// src/components/shared/data-table
|
|
2160
|
-
import { jsx as
|
|
2017
|
+
// src/components/shared/data-table.tsx
|
|
2018
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2161
2019
|
function DataTable({
|
|
2162
2020
|
data,
|
|
2163
2021
|
columns,
|
|
@@ -2167,24 +2025,24 @@ function DataTable({
|
|
|
2167
2025
|
actions
|
|
2168
2026
|
}) {
|
|
2169
2027
|
if (isLoading) {
|
|
2170
|
-
return /* @__PURE__ */
|
|
2028
|
+
return /* @__PURE__ */ jsx14(TableSkeleton, { columns: columns.length, rows: 5 });
|
|
2171
2029
|
}
|
|
2172
2030
|
if (data.length === 0) {
|
|
2173
|
-
return /* @__PURE__ */
|
|
2174
|
-
/* @__PURE__ */
|
|
2175
|
-
actions && /* @__PURE__ */
|
|
2031
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: [
|
|
2032
|
+
/* @__PURE__ */ jsx14("p", { className: "text-muted-foreground", children: emptyMessage }),
|
|
2033
|
+
actions && /* @__PURE__ */ jsx14("div", { className: "mt-4", children: actions })
|
|
2176
2034
|
] });
|
|
2177
2035
|
}
|
|
2178
|
-
return /* @__PURE__ */
|
|
2179
|
-
actions && /* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
2036
|
+
return /* @__PURE__ */ jsxs12("div", { className: "w-full space-y-4", children: [
|
|
2037
|
+
actions && /* @__PURE__ */ jsx14("div", { className: "flex justify-end", children: actions }),
|
|
2038
|
+
/* @__PURE__ */ jsx14("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs12(Table, { children: [
|
|
2039
|
+
/* @__PURE__ */ jsx14(TableHeader, { children: /* @__PURE__ */ jsx14(TableRow, { children: columns.map((column) => /* @__PURE__ */ jsx14(TableHead, { children: column.header }, column.key)) }) }),
|
|
2040
|
+
/* @__PURE__ */ jsx14(TableBody, { children: data.map((row) => /* @__PURE__ */ jsx14(
|
|
2183
2041
|
TableRow,
|
|
2184
2042
|
{
|
|
2185
2043
|
onClick: () => onRowClick?.(row),
|
|
2186
2044
|
className: onRowClick ? "cursor-pointer hover:bg-muted/50" : "",
|
|
2187
|
-
children: columns.map((column) => /* @__PURE__ */
|
|
2045
|
+
children: columns.map((column) => /* @__PURE__ */ jsx14(TableCell, { children: column.cell(row) }, `${row.id}-${column.key}`))
|
|
2188
2046
|
},
|
|
2189
2047
|
row.id
|
|
2190
2048
|
)) })
|
|
@@ -2192,11 +2050,24 @@ function DataTable({
|
|
|
2192
2050
|
] });
|
|
2193
2051
|
}
|
|
2194
2052
|
|
|
2195
|
-
// src/components/iam/permissions
|
|
2196
|
-
import { jsx as
|
|
2197
|
-
function
|
|
2053
|
+
// src/components/iam/permissions.tsx
|
|
2054
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2055
|
+
function getTranslation(value, locale) {
|
|
2056
|
+
if (!value) {
|
|
2057
|
+
return "";
|
|
2058
|
+
}
|
|
2059
|
+
if (typeof value === "string") {
|
|
2060
|
+
return value;
|
|
2061
|
+
}
|
|
2062
|
+
if (typeof value === "object") {
|
|
2063
|
+
return value[locale] ?? value.en ?? value.am ?? "";
|
|
2064
|
+
}
|
|
2065
|
+
return "";
|
|
2066
|
+
}
|
|
2067
|
+
function Permissions() {
|
|
2198
2068
|
const { hooks } = useApi();
|
|
2199
|
-
const
|
|
2069
|
+
const locale = useLocale();
|
|
2070
|
+
const [page, setPage] = useState9(1);
|
|
2200
2071
|
const limit = 20;
|
|
2201
2072
|
const { data, isLoading, error } = hooks.useQuery("get", "/permissions", {
|
|
2202
2073
|
params: {
|
|
@@ -2210,44 +2081,44 @@ function PermissionsPage() {
|
|
|
2210
2081
|
{
|
|
2211
2082
|
key: "name",
|
|
2212
2083
|
header: "Permission",
|
|
2213
|
-
cell: (permission) => /* @__PURE__ */
|
|
2214
|
-
/* @__PURE__ */
|
|
2215
|
-
/* @__PURE__ */
|
|
2084
|
+
cell: (permission) => /* @__PURE__ */ jsxs13("div", { children: [
|
|
2085
|
+
/* @__PURE__ */ jsx15("p", { className: "font-medium", children: getTranslation(permission.name, locale) }),
|
|
2086
|
+
/* @__PURE__ */ jsx15(Badge, { variant: "outline", className: "mt-1 font-mono text-xs", children: permission.code })
|
|
2216
2087
|
] })
|
|
2217
2088
|
},
|
|
2218
2089
|
{
|
|
2219
2090
|
key: "resource",
|
|
2220
2091
|
header: "Resource",
|
|
2221
|
-
cell: (permission) => /* @__PURE__ */
|
|
2092
|
+
cell: (permission) => /* @__PURE__ */ jsx15(Badge, { variant: "secondary", children: permission.resource })
|
|
2222
2093
|
},
|
|
2223
2094
|
{
|
|
2224
2095
|
key: "action",
|
|
2225
2096
|
header: "Action",
|
|
2226
|
-
cell: (permission) => /* @__PURE__ */
|
|
2097
|
+
cell: (permission) => /* @__PURE__ */ jsx15(Badge, { variant: "outline", children: permission.action })
|
|
2227
2098
|
},
|
|
2228
2099
|
{
|
|
2229
2100
|
key: "description",
|
|
2230
2101
|
header: "Description",
|
|
2231
|
-
cell: (permission) => /* @__PURE__ */
|
|
2102
|
+
cell: (permission) => /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground max-w-xs truncate", children: getTranslation(permission.description, locale) })
|
|
2232
2103
|
},
|
|
2233
2104
|
{
|
|
2234
2105
|
key: "actions",
|
|
2235
2106
|
header: "Actions",
|
|
2236
|
-
cell: (_permission) => /* @__PURE__ */
|
|
2107
|
+
cell: (_permission) => /* @__PURE__ */ jsx15(Button8, { variant: "outline", size: "sm", children: "Edit" })
|
|
2237
2108
|
}
|
|
2238
2109
|
];
|
|
2239
2110
|
if (error) {
|
|
2240
|
-
return /* @__PURE__ */
|
|
2111
|
+
return /* @__PURE__ */ jsx15("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx15("p", { className: "text-destructive", children: "Error loading permissions" }) });
|
|
2241
2112
|
}
|
|
2242
|
-
return /* @__PURE__ */
|
|
2243
|
-
/* @__PURE__ */
|
|
2244
|
-
/* @__PURE__ */
|
|
2245
|
-
/* @__PURE__ */
|
|
2246
|
-
/* @__PURE__ */
|
|
2113
|
+
return /* @__PURE__ */ jsxs13("div", { className: "w-full p-6 space-y-4", children: [
|
|
2114
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex justify-between items-center", children: [
|
|
2115
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
2116
|
+
/* @__PURE__ */ jsx15("h1", { className: "text-3xl font-bold", children: "Permissions" }),
|
|
2117
|
+
/* @__PURE__ */ jsx15("p", { className: "text-muted-foreground", children: "Manage system permissions" })
|
|
2247
2118
|
] }),
|
|
2248
|
-
/* @__PURE__ */
|
|
2119
|
+
/* @__PURE__ */ jsx15(Button8, { children: "Create Permission" })
|
|
2249
2120
|
] }),
|
|
2250
|
-
/* @__PURE__ */
|
|
2121
|
+
/* @__PURE__ */ jsx15(
|
|
2251
2122
|
DataTable,
|
|
2252
2123
|
{
|
|
2253
2124
|
data: data?.permissions || [],
|
|
@@ -2256,8 +2127,8 @@ function PermissionsPage() {
|
|
|
2256
2127
|
emptyMessage: "No permissions found"
|
|
2257
2128
|
}
|
|
2258
2129
|
),
|
|
2259
|
-
data && "permissions" in data && data.permissions && data.permissions.length >= limit && /* @__PURE__ */
|
|
2260
|
-
/* @__PURE__ */
|
|
2130
|
+
data && "permissions" in data && data.permissions && data.permissions.length >= limit && /* @__PURE__ */ jsxs13("div", { className: "flex justify-between items-center", children: [
|
|
2131
|
+
/* @__PURE__ */ jsx15(
|
|
2261
2132
|
Button8,
|
|
2262
2133
|
{
|
|
2263
2134
|
variant: "outline",
|
|
@@ -2266,23 +2137,37 @@ function PermissionsPage() {
|
|
|
2266
2137
|
children: "Previous"
|
|
2267
2138
|
}
|
|
2268
2139
|
),
|
|
2269
|
-
/* @__PURE__ */
|
|
2140
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-sm text-muted-foreground", children: [
|
|
2270
2141
|
"Page ",
|
|
2271
2142
|
page
|
|
2272
2143
|
] }),
|
|
2273
|
-
/* @__PURE__ */
|
|
2144
|
+
/* @__PURE__ */ jsx15(Button8, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2274
2145
|
] })
|
|
2275
2146
|
] });
|
|
2276
2147
|
}
|
|
2277
2148
|
|
|
2278
|
-
// src/components/iam/roles
|
|
2149
|
+
// src/components/iam/roles.tsx
|
|
2279
2150
|
import { Badge as Badge2 } from "@mesob/ui/components/badge";
|
|
2280
2151
|
import { Button as Button9 } from "@mesob/ui/components/button";
|
|
2281
|
-
import {
|
|
2282
|
-
import {
|
|
2283
|
-
|
|
2152
|
+
import { useLocale as useLocale2 } from "next-intl";
|
|
2153
|
+
import { useState as useState10 } from "react";
|
|
2154
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2155
|
+
function getTranslation2(value, locale) {
|
|
2156
|
+
if (!value) {
|
|
2157
|
+
return "";
|
|
2158
|
+
}
|
|
2159
|
+
if (typeof value === "string") {
|
|
2160
|
+
return value;
|
|
2161
|
+
}
|
|
2162
|
+
if (typeof value === "object") {
|
|
2163
|
+
return value[locale] ?? value.en ?? value.am ?? "";
|
|
2164
|
+
}
|
|
2165
|
+
return "";
|
|
2166
|
+
}
|
|
2167
|
+
function Roles() {
|
|
2284
2168
|
const { hooks } = useApi();
|
|
2285
|
-
const
|
|
2169
|
+
const locale = useLocale2();
|
|
2170
|
+
const [page, setPage] = useState10(1);
|
|
2286
2171
|
const limit = 20;
|
|
2287
2172
|
const { data, isLoading, error } = hooks.useQuery("get", "/roles", {
|
|
2288
2173
|
params: {
|
|
@@ -2296,42 +2181,42 @@ function RolesPage() {
|
|
|
2296
2181
|
{
|
|
2297
2182
|
key: "name",
|
|
2298
2183
|
header: "Role",
|
|
2299
|
-
cell: (role) => /* @__PURE__ */
|
|
2300
|
-
/* @__PURE__ */
|
|
2301
|
-
/* @__PURE__ */
|
|
2184
|
+
cell: (role) => /* @__PURE__ */ jsxs14("div", { children: [
|
|
2185
|
+
/* @__PURE__ */ jsx16("p", { className: "font-medium", children: getTranslation2(role.name, locale) }),
|
|
2186
|
+
/* @__PURE__ */ jsx16(Badge2, { variant: "outline", className: "mt-1", children: role.code })
|
|
2302
2187
|
] })
|
|
2303
2188
|
},
|
|
2304
2189
|
{
|
|
2305
2190
|
key: "description",
|
|
2306
2191
|
header: "Description",
|
|
2307
|
-
cell: (role) => /* @__PURE__ */
|
|
2192
|
+
cell: (role) => /* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground", children: getTranslation2(role.description, locale) })
|
|
2308
2193
|
},
|
|
2309
2194
|
{
|
|
2310
2195
|
key: "createdAt",
|
|
2311
2196
|
header: "Created",
|
|
2312
|
-
cell: (role) => /* @__PURE__ */
|
|
2197
|
+
cell: (role) => /* @__PURE__ */ jsx16("p", { className: "text-sm", children: new Date(role.createdAt).toLocaleDateString() })
|
|
2313
2198
|
},
|
|
2314
2199
|
{
|
|
2315
2200
|
key: "actions",
|
|
2316
2201
|
header: "Actions",
|
|
2317
|
-
cell: (_role) => /* @__PURE__ */
|
|
2318
|
-
/* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2202
|
+
cell: (_role) => /* @__PURE__ */ jsxs14("div", { className: "flex gap-2", children: [
|
|
2203
|
+
/* @__PURE__ */ jsx16(Button9, { variant: "outline", size: "sm", children: "Permissions" }),
|
|
2204
|
+
/* @__PURE__ */ jsx16(Button9, { variant: "outline", size: "sm", children: "Edit" })
|
|
2320
2205
|
] })
|
|
2321
2206
|
}
|
|
2322
2207
|
];
|
|
2323
2208
|
if (error) {
|
|
2324
|
-
return /* @__PURE__ */
|
|
2209
|
+
return /* @__PURE__ */ jsx16("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx16("p", { className: "text-destructive", children: "Error loading roles" }) });
|
|
2325
2210
|
}
|
|
2326
|
-
return /* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
/* @__PURE__ */
|
|
2330
|
-
/* @__PURE__ */
|
|
2211
|
+
return /* @__PURE__ */ jsxs14("div", { className: "w-full p-6 space-y-4", children: [
|
|
2212
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex justify-between items-center", children: [
|
|
2213
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
2214
|
+
/* @__PURE__ */ jsx16("h1", { className: "text-3xl font-bold", children: "Roles" }),
|
|
2215
|
+
/* @__PURE__ */ jsx16("p", { className: "text-muted-foreground", children: "Manage user roles" })
|
|
2331
2216
|
] }),
|
|
2332
|
-
/* @__PURE__ */
|
|
2217
|
+
/* @__PURE__ */ jsx16(Button9, { children: "Create Role" })
|
|
2333
2218
|
] }),
|
|
2334
|
-
/* @__PURE__ */
|
|
2219
|
+
/* @__PURE__ */ jsx16(
|
|
2335
2220
|
DataTable,
|
|
2336
2221
|
{
|
|
2337
2222
|
data: data?.roles || [],
|
|
@@ -2340,8 +2225,8 @@ function RolesPage() {
|
|
|
2340
2225
|
emptyMessage: "No roles found"
|
|
2341
2226
|
}
|
|
2342
2227
|
),
|
|
2343
|
-
data && "roles" in data && data.roles && data.roles.length >= limit && /* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2228
|
+
data && "roles" in data && data.roles && data.roles.length >= limit && /* @__PURE__ */ jsxs14("div", { className: "flex justify-between items-center", children: [
|
|
2229
|
+
/* @__PURE__ */ jsx16(
|
|
2345
2230
|
Button9,
|
|
2346
2231
|
{
|
|
2347
2232
|
variant: "outline",
|
|
@@ -2350,22 +2235,22 @@ function RolesPage() {
|
|
|
2350
2235
|
children: "Previous"
|
|
2351
2236
|
}
|
|
2352
2237
|
),
|
|
2353
|
-
/* @__PURE__ */
|
|
2238
|
+
/* @__PURE__ */ jsxs14("span", { className: "text-sm text-muted-foreground", children: [
|
|
2354
2239
|
"Page ",
|
|
2355
2240
|
page
|
|
2356
2241
|
] }),
|
|
2357
|
-
/* @__PURE__ */
|
|
2242
|
+
/* @__PURE__ */ jsx16(Button9, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2358
2243
|
] })
|
|
2359
2244
|
] });
|
|
2360
2245
|
}
|
|
2361
2246
|
|
|
2362
|
-
// src/components/iam/sessions
|
|
2247
|
+
// src/components/iam/sessions.tsx
|
|
2363
2248
|
import { Button as Button10 } from "@mesob/ui/components/button";
|
|
2364
|
-
import { useState as
|
|
2365
|
-
import { jsx as
|
|
2366
|
-
function
|
|
2249
|
+
import { useState as useState11 } from "react";
|
|
2250
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2251
|
+
function Sessions() {
|
|
2367
2252
|
const { hooks } = useApi();
|
|
2368
|
-
const [selectedSessionId] =
|
|
2253
|
+
const [selectedSessionId] = useState11(null);
|
|
2369
2254
|
const { data, isLoading, error, refetch } = hooks.useQuery(
|
|
2370
2255
|
"get",
|
|
2371
2256
|
"/sessions"
|
|
@@ -2391,30 +2276,30 @@ function SessionsPage() {
|
|
|
2391
2276
|
{
|
|
2392
2277
|
key: "createdAt",
|
|
2393
2278
|
header: "Created",
|
|
2394
|
-
cell: (session) => /* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2279
|
+
cell: (session) => /* @__PURE__ */ jsxs15("div", { children: [
|
|
2280
|
+
/* @__PURE__ */ jsx17("p", { className: "text-sm font-medium", children: new Date(session.createdAt).toLocaleDateString() }),
|
|
2281
|
+
/* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground", children: new Date(session.createdAt).toLocaleTimeString() })
|
|
2397
2282
|
] })
|
|
2398
2283
|
},
|
|
2399
2284
|
{
|
|
2400
2285
|
key: "expiresAt",
|
|
2401
2286
|
header: "Expires",
|
|
2402
|
-
cell: (session) => /* @__PURE__ */
|
|
2287
|
+
cell: (session) => /* @__PURE__ */ jsx17("p", { className: "text-sm", children: new Date(session.expiresAt).toLocaleDateString() })
|
|
2403
2288
|
},
|
|
2404
2289
|
{
|
|
2405
2290
|
key: "userAgent",
|
|
2406
2291
|
header: "Device",
|
|
2407
|
-
cell: (session) => /* @__PURE__ */
|
|
2292
|
+
cell: (session) => /* @__PURE__ */ jsx17("p", { className: "text-sm truncate max-w-xs", children: session.userAgent || "Unknown" })
|
|
2408
2293
|
},
|
|
2409
2294
|
{
|
|
2410
2295
|
key: "ip",
|
|
2411
2296
|
header: "IP Address",
|
|
2412
|
-
cell: (session) => /* @__PURE__ */
|
|
2297
|
+
cell: (session) => /* @__PURE__ */ jsx17("p", { className: "text-sm font-mono", children: session.ip || "Unknown" })
|
|
2413
2298
|
},
|
|
2414
2299
|
{
|
|
2415
2300
|
key: "actions",
|
|
2416
2301
|
header: "Actions",
|
|
2417
|
-
cell: (session) => /* @__PURE__ */
|
|
2302
|
+
cell: (session) => /* @__PURE__ */ jsx17(
|
|
2418
2303
|
Button10,
|
|
2419
2304
|
{
|
|
2420
2305
|
variant: "destructive",
|
|
@@ -2427,14 +2312,14 @@ function SessionsPage() {
|
|
|
2427
2312
|
}
|
|
2428
2313
|
];
|
|
2429
2314
|
if (error) {
|
|
2430
|
-
return /* @__PURE__ */
|
|
2315
|
+
return /* @__PURE__ */ jsx17("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx17("p", { className: "text-destructive", children: "Error loading sessions" }) });
|
|
2431
2316
|
}
|
|
2432
|
-
return /* @__PURE__ */
|
|
2433
|
-
/* @__PURE__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2317
|
+
return /* @__PURE__ */ jsxs15("div", { className: "w-full p-6 space-y-4", children: [
|
|
2318
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
2319
|
+
/* @__PURE__ */ jsx17("h1", { className: "text-3xl font-bold", children: "Sessions" }),
|
|
2320
|
+
/* @__PURE__ */ jsx17("p", { className: "text-muted-foreground", children: "View and manage active sessions" })
|
|
2436
2321
|
] }),
|
|
2437
|
-
/* @__PURE__ */
|
|
2322
|
+
/* @__PURE__ */ jsx17(
|
|
2438
2323
|
DataTable,
|
|
2439
2324
|
{
|
|
2440
2325
|
data: data?.sessions || [],
|
|
@@ -2446,14 +2331,14 @@ function SessionsPage() {
|
|
|
2446
2331
|
] });
|
|
2447
2332
|
}
|
|
2448
2333
|
|
|
2449
|
-
// src/components/iam/tenants
|
|
2334
|
+
// src/components/iam/tenants.tsx
|
|
2450
2335
|
import { Badge as Badge3 } from "@mesob/ui/components/badge";
|
|
2451
2336
|
import { Button as Button11 } from "@mesob/ui/components/button";
|
|
2452
|
-
import { useState as
|
|
2453
|
-
import { jsx as
|
|
2454
|
-
function
|
|
2337
|
+
import { useState as useState12 } from "react";
|
|
2338
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2339
|
+
function Tenants() {
|
|
2455
2340
|
const { hooks } = useApi();
|
|
2456
|
-
const [page, setPage] =
|
|
2341
|
+
const [page, setPage] = useState12(1);
|
|
2457
2342
|
const limit = 20;
|
|
2458
2343
|
const { data, isLoading, error } = hooks.useQuery("get", "/tenants", {
|
|
2459
2344
|
params: {
|
|
@@ -2467,9 +2352,9 @@ function TenantsPage() {
|
|
|
2467
2352
|
{
|
|
2468
2353
|
key: "name",
|
|
2469
2354
|
header: "Tenant",
|
|
2470
|
-
cell: (tenant) => /* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
2472
|
-
/* @__PURE__ */
|
|
2355
|
+
cell: (tenant) => /* @__PURE__ */ jsxs16("div", { children: [
|
|
2356
|
+
/* @__PURE__ */ jsx18("p", { className: "font-medium", children: tenant.name }),
|
|
2357
|
+
/* @__PURE__ */ jsxs16("p", { className: "text-sm text-muted-foreground", children: [
|
|
2473
2358
|
"/",
|
|
2474
2359
|
tenant.slug
|
|
2475
2360
|
] })
|
|
@@ -2478,34 +2363,34 @@ function TenantsPage() {
|
|
|
2478
2363
|
{
|
|
2479
2364
|
key: "status",
|
|
2480
2365
|
header: "Status",
|
|
2481
|
-
cell: (tenant) => /* @__PURE__ */
|
|
2366
|
+
cell: (tenant) => /* @__PURE__ */ jsx18(Badge3, { variant: tenant.status === "active" ? "default" : "secondary", children: tenant.status })
|
|
2482
2367
|
},
|
|
2483
2368
|
{
|
|
2484
2369
|
key: "createdAt",
|
|
2485
2370
|
header: "Created",
|
|
2486
|
-
cell: (tenant) => /* @__PURE__ */
|
|
2371
|
+
cell: (tenant) => /* @__PURE__ */ jsx18("p", { className: "text-sm", children: new Date(tenant.createdAt).toLocaleDateString() })
|
|
2487
2372
|
},
|
|
2488
2373
|
{
|
|
2489
2374
|
key: "actions",
|
|
2490
2375
|
header: "Actions",
|
|
2491
|
-
cell: (_tenant) => /* @__PURE__ */
|
|
2492
|
-
/* @__PURE__ */
|
|
2493
|
-
/* @__PURE__ */
|
|
2376
|
+
cell: (_tenant) => /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
|
|
2377
|
+
/* @__PURE__ */ jsx18(Button11, { variant: "outline", size: "sm", children: "Domains" }),
|
|
2378
|
+
/* @__PURE__ */ jsx18(Button11, { variant: "outline", size: "sm", children: "Edit" })
|
|
2494
2379
|
] })
|
|
2495
2380
|
}
|
|
2496
2381
|
];
|
|
2497
2382
|
if (error) {
|
|
2498
|
-
return /* @__PURE__ */
|
|
2383
|
+
return /* @__PURE__ */ jsx18("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx18("p", { className: "text-destructive", children: "Error loading tenants" }) });
|
|
2499
2384
|
}
|
|
2500
|
-
return /* @__PURE__ */
|
|
2501
|
-
/* @__PURE__ */
|
|
2502
|
-
/* @__PURE__ */
|
|
2503
|
-
/* @__PURE__ */
|
|
2504
|
-
/* @__PURE__ */
|
|
2385
|
+
return /* @__PURE__ */ jsxs16("div", { className: "w-full p-6 space-y-4", children: [
|
|
2386
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex justify-between items-center", children: [
|
|
2387
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
2388
|
+
/* @__PURE__ */ jsx18("h1", { className: "text-3xl font-bold", children: "Tenants" }),
|
|
2389
|
+
/* @__PURE__ */ jsx18("p", { className: "text-muted-foreground", children: "Manage tenant organizations" })
|
|
2505
2390
|
] }),
|
|
2506
|
-
/* @__PURE__ */
|
|
2391
|
+
/* @__PURE__ */ jsx18(Button11, { children: "Create Tenant" })
|
|
2507
2392
|
] }),
|
|
2508
|
-
/* @__PURE__ */
|
|
2393
|
+
/* @__PURE__ */ jsx18(
|
|
2509
2394
|
DataTable,
|
|
2510
2395
|
{
|
|
2511
2396
|
data: data?.tenants || [],
|
|
@@ -2514,8 +2399,8 @@ function TenantsPage() {
|
|
|
2514
2399
|
emptyMessage: "No tenants found"
|
|
2515
2400
|
}
|
|
2516
2401
|
),
|
|
2517
|
-
data && "tenants" in data && data.tenants && data.tenants.length >= limit && /* @__PURE__ */
|
|
2518
|
-
/* @__PURE__ */
|
|
2402
|
+
data && "tenants" in data && data.tenants && data.tenants.length >= limit && /* @__PURE__ */ jsxs16("div", { className: "flex justify-between items-center", children: [
|
|
2403
|
+
/* @__PURE__ */ jsx18(
|
|
2519
2404
|
Button11,
|
|
2520
2405
|
{
|
|
2521
2406
|
variant: "outline",
|
|
@@ -2524,23 +2409,23 @@ function TenantsPage() {
|
|
|
2524
2409
|
children: "Previous"
|
|
2525
2410
|
}
|
|
2526
2411
|
),
|
|
2527
|
-
/* @__PURE__ */
|
|
2412
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-sm text-muted-foreground", children: [
|
|
2528
2413
|
"Page ",
|
|
2529
2414
|
page
|
|
2530
2415
|
] }),
|
|
2531
|
-
/* @__PURE__ */
|
|
2416
|
+
/* @__PURE__ */ jsx18(Button11, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2532
2417
|
] })
|
|
2533
2418
|
] });
|
|
2534
2419
|
}
|
|
2535
2420
|
|
|
2536
|
-
// src/components/iam/users
|
|
2421
|
+
// src/components/iam/users.tsx
|
|
2537
2422
|
import { Badge as Badge4 } from "@mesob/ui/components/badge";
|
|
2538
2423
|
import { Button as Button12 } from "@mesob/ui/components/button";
|
|
2539
|
-
import { useState as
|
|
2540
|
-
import { jsx as
|
|
2541
|
-
function
|
|
2424
|
+
import { useState as useState13 } from "react";
|
|
2425
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2426
|
+
function Users() {
|
|
2542
2427
|
const { hooks } = useApi();
|
|
2543
|
-
const [page, setPage] =
|
|
2428
|
+
const [page, setPage] = useState13(1);
|
|
2544
2429
|
const limit = 20;
|
|
2545
2430
|
const { data, isLoading, error } = hooks.useQuery("get", "/users", {
|
|
2546
2431
|
params: {
|
|
@@ -2554,9 +2439,9 @@ function UsersPage() {
|
|
|
2554
2439
|
{
|
|
2555
2440
|
key: "fullName",
|
|
2556
2441
|
header: "Name",
|
|
2557
|
-
cell: (user) => /* @__PURE__ */
|
|
2558
|
-
/* @__PURE__ */
|
|
2559
|
-
/* @__PURE__ */
|
|
2442
|
+
cell: (user) => /* @__PURE__ */ jsxs17("div", { children: [
|
|
2443
|
+
/* @__PURE__ */ jsx19("p", { className: "font-medium", children: user.fullName }),
|
|
2444
|
+
/* @__PURE__ */ jsxs17("p", { className: "text-sm text-muted-foreground", children: [
|
|
2560
2445
|
"@",
|
|
2561
2446
|
user.handle
|
|
2562
2447
|
] })
|
|
@@ -2565,43 +2450,43 @@ function UsersPage() {
|
|
|
2565
2450
|
{
|
|
2566
2451
|
key: "contact",
|
|
2567
2452
|
header: "Contact",
|
|
2568
|
-
cell: (user) => /* @__PURE__ */
|
|
2569
|
-
user.email && /* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
user.emailVerified && /* @__PURE__ */
|
|
2453
|
+
cell: (user) => /* @__PURE__ */ jsxs17("div", { className: "space-y-1", children: [
|
|
2454
|
+
user.email && /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
2455
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sm", children: user.email }),
|
|
2456
|
+
user.emailVerified && /* @__PURE__ */ jsx19(Badge4, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2572
2457
|
] }),
|
|
2573
|
-
user.phone && /* @__PURE__ */
|
|
2574
|
-
/* @__PURE__ */
|
|
2575
|
-
user.phoneVerified && /* @__PURE__ */
|
|
2458
|
+
user.phone && /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
2459
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sm", children: user.phone }),
|
|
2460
|
+
user.phoneVerified && /* @__PURE__ */ jsx19(Badge4, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2576
2461
|
] })
|
|
2577
2462
|
] })
|
|
2578
2463
|
},
|
|
2579
2464
|
{
|
|
2580
2465
|
key: "lastSignIn",
|
|
2581
2466
|
header: "Last Sign In",
|
|
2582
|
-
cell: (user) => /* @__PURE__ */
|
|
2467
|
+
cell: (user) => /* @__PURE__ */ jsx19("p", { className: "text-sm", children: user.lastSignInAt ? new Date(user.lastSignInAt).toLocaleDateString() : "Never" })
|
|
2583
2468
|
},
|
|
2584
2469
|
{
|
|
2585
2470
|
key: "actions",
|
|
2586
2471
|
header: "Actions",
|
|
2587
|
-
cell: (_user) => /* @__PURE__ */
|
|
2588
|
-
/* @__PURE__ */
|
|
2589
|
-
/* @__PURE__ */
|
|
2472
|
+
cell: (_user) => /* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
|
|
2473
|
+
/* @__PURE__ */ jsx19(Button12, { variant: "outline", size: "sm", children: "View" }),
|
|
2474
|
+
/* @__PURE__ */ jsx19(Button12, { variant: "outline", size: "sm", children: "Edit" })
|
|
2590
2475
|
] })
|
|
2591
2476
|
}
|
|
2592
2477
|
];
|
|
2593
2478
|
if (error) {
|
|
2594
|
-
return /* @__PURE__ */
|
|
2479
|
+
return /* @__PURE__ */ jsx19("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx19("p", { className: "text-destructive", children: "Error loading users" }) });
|
|
2595
2480
|
}
|
|
2596
|
-
return /* @__PURE__ */
|
|
2597
|
-
/* @__PURE__ */
|
|
2598
|
-
/* @__PURE__ */
|
|
2599
|
-
/* @__PURE__ */
|
|
2600
|
-
/* @__PURE__ */
|
|
2481
|
+
return /* @__PURE__ */ jsxs17("div", { className: "w-full p-6 space-y-4", children: [
|
|
2482
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex justify-between items-center", children: [
|
|
2483
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
2484
|
+
/* @__PURE__ */ jsx19("h1", { className: "text-3xl font-bold", children: "Users" }),
|
|
2485
|
+
/* @__PURE__ */ jsx19("p", { className: "text-muted-foreground", children: "Manage user accounts" })
|
|
2601
2486
|
] }),
|
|
2602
|
-
/* @__PURE__ */
|
|
2487
|
+
/* @__PURE__ */ jsx19(Button12, { children: "Create User" })
|
|
2603
2488
|
] }),
|
|
2604
|
-
/* @__PURE__ */
|
|
2489
|
+
/* @__PURE__ */ jsx19(
|
|
2605
2490
|
DataTable,
|
|
2606
2491
|
{
|
|
2607
2492
|
data: data?.users || [],
|
|
@@ -2610,8 +2495,8 @@ function UsersPage() {
|
|
|
2610
2495
|
emptyMessage: "No users found"
|
|
2611
2496
|
}
|
|
2612
2497
|
),
|
|
2613
|
-
data && "users" in data && data.users && data.users.length >= limit && /* @__PURE__ */
|
|
2614
|
-
/* @__PURE__ */
|
|
2498
|
+
data && "users" in data && data.users && data.users.length >= limit && /* @__PURE__ */ jsxs17("div", { className: "flex justify-between items-center", children: [
|
|
2499
|
+
/* @__PURE__ */ jsx19(
|
|
2615
2500
|
Button12,
|
|
2616
2501
|
{
|
|
2617
2502
|
variant: "outline",
|
|
@@ -2620,182 +2505,1291 @@ function UsersPage() {
|
|
|
2620
2505
|
children: "Previous"
|
|
2621
2506
|
}
|
|
2622
2507
|
),
|
|
2623
|
-
/* @__PURE__ */
|
|
2508
|
+
/* @__PURE__ */ jsxs17("span", { className: "text-sm text-muted-foreground", children: [
|
|
2624
2509
|
"Page ",
|
|
2625
2510
|
page
|
|
2626
2511
|
] }),
|
|
2627
|
-
/* @__PURE__ */
|
|
2512
|
+
/* @__PURE__ */ jsx19(Button12, { variant: "outline", onClick: () => setPage(page + 1), children: "Next" })
|
|
2628
2513
|
] })
|
|
2629
2514
|
] });
|
|
2630
2515
|
}
|
|
2631
2516
|
|
|
2632
|
-
// src/components/profile/
|
|
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";
|
|
2517
|
+
// src/components/profile/account.tsx
|
|
2641
2518
|
import { Separator } from "@mesob/ui/components/separator";
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
/* @__PURE__ */
|
|
2651
|
-
|
|
2652
|
-
/* @__PURE__ */ jsx24(Skeleton2, { className: "h-4 w-64" })
|
|
2653
|
-
] })
|
|
2519
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2520
|
+
function Account() {
|
|
2521
|
+
const { user, isAuthenticated } = useSession();
|
|
2522
|
+
if (!(isAuthenticated && user)) {
|
|
2523
|
+
return /* @__PURE__ */ jsx20("div", { children: "Sign in required" });
|
|
2524
|
+
}
|
|
2525
|
+
return /* @__PURE__ */ jsxs18("div", { className: "p-6 max-w-4xl", children: [
|
|
2526
|
+
/* @__PURE__ */ jsxs18("div", { className: "mb-6", children: [
|
|
2527
|
+
/* @__PURE__ */ jsx20("h2", { className: "text-lg font-semibold mb-4", children: "Profile details" }),
|
|
2528
|
+
/* @__PURE__ */ jsx20(Separator, {})
|
|
2654
2529
|
] }),
|
|
2655
|
-
/* @__PURE__ */
|
|
2656
|
-
/* @__PURE__ */
|
|
2657
|
-
/* @__PURE__ */
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2530
|
+
/* @__PURE__ */ jsxs18("div", { className: "space-y-6 transition-all duration-300 ease-in-out", children: [
|
|
2531
|
+
/* @__PURE__ */ jsx20("div", { className: "flex flex-col md:flex-row items-start gap-4 md:gap-12 min-h-[3rem]", children: /* @__PURE__ */ jsx20("div", { className: "w-full md:w-48 mt-4 shrink-0 h-fit", children: /* @__PURE__ */ jsx20("span", { className: "font-medium text-sm", children: "Profile" }) }) }),
|
|
2532
|
+
/* @__PURE__ */ jsx20(Separator, {}),
|
|
2533
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col md:flex-row gap-4 md:gap-12 py-2", children: [
|
|
2534
|
+
/* @__PURE__ */ jsx20("div", { className: "w-full md:w-48 shrink-0", children: /* @__PURE__ */ jsx20("span", { className: "font-medium text-sm", children: "Email addresses" }) }),
|
|
2535
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-1 space-y-4", children: /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-between group", children: user.email ? /* @__PURE__ */ jsx20("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx20("span", { className: "text-sm", children: user.email }) }) : /* @__PURE__ */ jsx20("span", { className: "text-sm text-muted-foreground", children: "No email address" }) }) })
|
|
2536
|
+
] }),
|
|
2537
|
+
/* @__PURE__ */ jsx20(Separator, {}),
|
|
2538
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col md:flex-row gap-4 md:gap-12 py-2", children: [
|
|
2539
|
+
/* @__PURE__ */ jsx20("div", { className: "w-full md:w-48 shrink-0", children: /* @__PURE__ */ jsx20("span", { className: "font-medium text-sm", children: "Phone numbers" }) }),
|
|
2540
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-1 space-y-4", children: user.phone ? /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx20("span", { className: "text-sm", children: user.phone }) }) : /* @__PURE__ */ jsx20("span", { className: "text-sm text-muted-foreground", children: "No phone number" }) })
|
|
2666
2541
|
] })
|
|
2667
|
-
] }
|
|
2542
|
+
] })
|
|
2668
2543
|
] });
|
|
2669
2544
|
}
|
|
2670
2545
|
|
|
2671
|
-
// src/components/profile/
|
|
2672
|
-
import {
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2546
|
+
// src/components/profile/change-email-form.tsx
|
|
2547
|
+
import { Button as Button14 } from "@mesob/ui/components/button";
|
|
2548
|
+
import {
|
|
2549
|
+
Collapsible,
|
|
2550
|
+
CollapsibleContent,
|
|
2551
|
+
CollapsibleTrigger
|
|
2552
|
+
} from "@mesob/ui/components/collapsible";
|
|
2553
|
+
import { IconChevronDown } from "@tabler/icons-react";
|
|
2554
|
+
import { useState as useState16 } from "react";
|
|
2555
|
+
|
|
2556
|
+
// src/components/profile/request-change-email-form.tsx
|
|
2557
|
+
import { zodResolver as zodResolver6 } from "@hookform/resolvers/zod";
|
|
2558
|
+
import { Button as Button13 } from "@mesob/ui/components/button";
|
|
2559
|
+
import { Input as Input5 } from "@mesob/ui/components/input";
|
|
2560
|
+
import { Label } from "@mesob/ui/components/label";
|
|
2561
|
+
import { Spinner as Spinner6 } from "@mesob/ui/components/spinner";
|
|
2562
|
+
import { IconEye as IconEye4, IconEyeOff as IconEyeOff4 } from "@tabler/icons-react";
|
|
2563
|
+
import { useEffect as useEffect8, useState as useState14 } from "react";
|
|
2564
|
+
import { useForm as useForm6 } from "react-hook-form";
|
|
2565
|
+
import { toast as toast7 } from "sonner";
|
|
2566
|
+
import { z as z6 } from "zod";
|
|
2567
|
+
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2568
|
+
var emailPasswordSchema = z6.object({
|
|
2569
|
+
email: z6.string().email("Invalid email address"),
|
|
2570
|
+
password: z6.string().min(8, "Password must be at least 8 characters").max(128, "Password too long")
|
|
2571
|
+
});
|
|
2572
|
+
function isAuthError2(error) {
|
|
2573
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
2574
|
+
}
|
|
2575
|
+
function getErrorCode(error) {
|
|
2576
|
+
if (error.code) {
|
|
2577
|
+
return error.code;
|
|
2677
2578
|
}
|
|
2678
|
-
if (
|
|
2679
|
-
|
|
2579
|
+
if (error.message) {
|
|
2580
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
2581
|
+
const validCodes2 = [
|
|
2582
|
+
"USER_NOT_FOUND",
|
|
2583
|
+
"USER_EXISTS",
|
|
2584
|
+
"INVALID_PASSWORD",
|
|
2585
|
+
"VERIFICATION_EXPIRED",
|
|
2586
|
+
"VERIFICATION_MISMATCH",
|
|
2587
|
+
"VERIFICATION_NOT_FOUND",
|
|
2588
|
+
"TOO_MANY_ATTEMPTS",
|
|
2589
|
+
"UNAUTHORIZED"
|
|
2590
|
+
];
|
|
2591
|
+
if (validCodes2.includes(upperMessage)) {
|
|
2592
|
+
return upperMessage;
|
|
2593
|
+
}
|
|
2680
2594
|
}
|
|
2681
|
-
return
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2595
|
+
return void 0;
|
|
2596
|
+
}
|
|
2597
|
+
function getErrorMessage(error) {
|
|
2598
|
+
if (isAuthError2(error)) {
|
|
2599
|
+
const errorCode = getErrorCode(error);
|
|
2600
|
+
switch (errorCode) {
|
|
2601
|
+
case "USER_EXISTS":
|
|
2602
|
+
return "This email is already taken. Please use a different email.";
|
|
2603
|
+
case "VERIFICATION_EXPIRED":
|
|
2604
|
+
return "Verification code has expired. Please request a new one.";
|
|
2605
|
+
case "VERIFICATION_MISMATCH":
|
|
2606
|
+
return "Invalid verification code. Please try again.";
|
|
2607
|
+
case "VERIFICATION_NOT_FOUND":
|
|
2608
|
+
return "Verification not found. Please request a new code.";
|
|
2609
|
+
default:
|
|
2610
|
+
return error.message || "An error occurred. Please try again.";
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
if (error instanceof Error) {
|
|
2614
|
+
return error.message;
|
|
2615
|
+
}
|
|
2616
|
+
return "An error occurred. Please try again.";
|
|
2617
|
+
}
|
|
2618
|
+
function RequestChangeEmailForm({
|
|
2619
|
+
onSuccess,
|
|
2620
|
+
onCancel,
|
|
2621
|
+
buttonText
|
|
2622
|
+
}) {
|
|
2623
|
+
const { user } = useSession();
|
|
2624
|
+
const { hooks } = useApi();
|
|
2625
|
+
const [isSubmitting, setIsSubmitting] = useState14(false);
|
|
2626
|
+
const [isChecking, setIsChecking] = useState14(true);
|
|
2627
|
+
const [showPassword, setShowPassword] = useState14(false);
|
|
2628
|
+
const getPendingAccountChangeQuery = hooks.useQuery(
|
|
2629
|
+
"get",
|
|
2630
|
+
"/account-change/pending",
|
|
2631
|
+
{},
|
|
2632
|
+
{ enabled: false }
|
|
2633
|
+
);
|
|
2634
|
+
const verifyPasswordMutation = hooks.useMutation("post", "/password/verify");
|
|
2635
|
+
const checkUserMutation = hooks.useMutation("post", "/check-account");
|
|
2636
|
+
const requestEmailVerificationMutation = hooks.useMutation(
|
|
2637
|
+
"post",
|
|
2638
|
+
"/email/verification/request"
|
|
2639
|
+
);
|
|
2640
|
+
const emailPasswordForm = useForm6({
|
|
2641
|
+
resolver: zodResolver6(emailPasswordSchema),
|
|
2642
|
+
defaultValues: {
|
|
2643
|
+
email: "",
|
|
2644
|
+
password: ""
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
const {
|
|
2648
|
+
register,
|
|
2649
|
+
handleSubmit,
|
|
2650
|
+
getValues,
|
|
2651
|
+
setValue,
|
|
2652
|
+
formState: { errors }
|
|
2653
|
+
} = emailPasswordForm;
|
|
2654
|
+
useEffect8(() => {
|
|
2655
|
+
let active = true;
|
|
2656
|
+
const run = async () => {
|
|
2657
|
+
try {
|
|
2658
|
+
const data = await getPendingAccountChangeQuery.refetch();
|
|
2659
|
+
if (!active) {
|
|
2660
|
+
return;
|
|
2661
|
+
}
|
|
2662
|
+
const accountChange = data.data?.accountChange;
|
|
2663
|
+
const verificationId = data.data?.verificationId;
|
|
2664
|
+
if (accountChange?.changeType !== "email") {
|
|
2665
|
+
setIsChecking(false);
|
|
2666
|
+
return;
|
|
2667
|
+
}
|
|
2668
|
+
if (!accountChange.newEmail) {
|
|
2669
|
+
setIsChecking(false);
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
if (getValues("email")) {
|
|
2673
|
+
setIsChecking(false);
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
setValue("email", accountChange.newEmail, { shouldValidate: true });
|
|
2677
|
+
if (verificationId) {
|
|
2678
|
+
toast7.message("Resuming verification\u2026");
|
|
2679
|
+
onSuccess(verificationId, accountChange.newEmail);
|
|
2680
|
+
return;
|
|
2681
|
+
}
|
|
2682
|
+
setIsChecking(false);
|
|
2683
|
+
} catch {
|
|
2684
|
+
setIsChecking(false);
|
|
2685
|
+
}
|
|
2686
|
+
};
|
|
2687
|
+
run().catch(() => void 0);
|
|
2688
|
+
return () => {
|
|
2689
|
+
active = false;
|
|
2690
|
+
};
|
|
2691
|
+
}, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);
|
|
2692
|
+
const onEmailPasswordSubmit = async (data) => {
|
|
2693
|
+
if (!user) {
|
|
2694
|
+
toast7.error("User not found");
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
try {
|
|
2698
|
+
setIsSubmitting(true);
|
|
2699
|
+
await verifyPasswordMutation.mutateAsync({
|
|
2700
|
+
body: { password: data.password }
|
|
2701
|
+
});
|
|
2702
|
+
const checkResult = await checkUserMutation.mutateAsync({
|
|
2703
|
+
body: { identifier: data.email }
|
|
2704
|
+
});
|
|
2705
|
+
if (checkResult.data?.exists) {
|
|
2706
|
+
if (user?.email?.toLowerCase() === data.email.toLowerCase()) {
|
|
2707
|
+
toast7.error("This is already your current email address.");
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
toast7.error(
|
|
2711
|
+
"This email is already taken. Please use a different email."
|
|
2712
|
+
);
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
const verification = await requestEmailVerificationMutation.mutateAsync({
|
|
2716
|
+
body: { email: data.email }
|
|
2717
|
+
});
|
|
2718
|
+
toast7.success("Verification code sent to your email");
|
|
2719
|
+
onSuccess(verification.data?.verificationId ?? "", data.email);
|
|
2720
|
+
} catch (error) {
|
|
2721
|
+
const errorMessage = getErrorMessage(error);
|
|
2722
|
+
if (isAuthError2(error)) {
|
|
2723
|
+
const errorCode = getErrorCode(error);
|
|
2724
|
+
if (errorCode === "INVALID_PASSWORD" || errorCode === "USER_NOT_FOUND") {
|
|
2725
|
+
toast7.error("Incorrect password. Please try again.");
|
|
2726
|
+
return;
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
toast7.error(errorMessage);
|
|
2730
|
+
} finally {
|
|
2731
|
+
setIsSubmitting(false);
|
|
2732
|
+
}
|
|
2733
|
+
};
|
|
2734
|
+
const isLoading = isSubmitting || isChecking;
|
|
2735
|
+
return /* @__PURE__ */ jsxs19(
|
|
2736
|
+
"form",
|
|
2737
|
+
{
|
|
2738
|
+
onSubmit: handleSubmit(onEmailPasswordSubmit),
|
|
2739
|
+
className: "p-4 space-y-4 border-t",
|
|
2740
|
+
children: [
|
|
2741
|
+
/* @__PURE__ */ jsxs19("div", { className: "space-y-4 w-full md:w-1/2", children: [
|
|
2742
|
+
/* @__PURE__ */ jsxs19("div", { className: "space-y-2", children: [
|
|
2743
|
+
/* @__PURE__ */ jsx21(Label, { htmlFor: "email", children: "New Email Address" }),
|
|
2744
|
+
/* @__PURE__ */ jsx21(
|
|
2745
|
+
Input5,
|
|
2746
|
+
{
|
|
2747
|
+
id: "email",
|
|
2748
|
+
type: "email",
|
|
2749
|
+
placeholder: "Enter your new email",
|
|
2750
|
+
...register("email"),
|
|
2751
|
+
disabled: isLoading
|
|
2752
|
+
}
|
|
2753
|
+
),
|
|
2754
|
+
errors.email && /* @__PURE__ */ jsx21("p", { className: "text-sm text-destructive", children: errors.email.message })
|
|
2755
|
+
] }),
|
|
2756
|
+
/* @__PURE__ */ jsxs19("div", { className: "space-y-2", children: [
|
|
2757
|
+
/* @__PURE__ */ jsx21(Label, { htmlFor: "password", children: "Password" }),
|
|
2758
|
+
/* @__PURE__ */ jsxs19("div", { className: "relative", children: [
|
|
2759
|
+
/* @__PURE__ */ jsx21(
|
|
2760
|
+
Input5,
|
|
2761
|
+
{
|
|
2762
|
+
id: "password",
|
|
2763
|
+
type: showPassword ? "text" : "password",
|
|
2764
|
+
autoComplete: "current-password",
|
|
2765
|
+
placeholder: "Enter your password",
|
|
2766
|
+
...register("password"),
|
|
2767
|
+
disabled: isLoading
|
|
2768
|
+
}
|
|
2769
|
+
),
|
|
2770
|
+
/* @__PURE__ */ jsx21(
|
|
2771
|
+
"button",
|
|
2772
|
+
{
|
|
2773
|
+
type: "button",
|
|
2774
|
+
onClick: () => setShowPassword(!showPassword),
|
|
2775
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
2776
|
+
disabled: isLoading,
|
|
2777
|
+
children: showPassword ? /* @__PURE__ */ jsx21(IconEyeOff4, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx21(IconEye4, { className: "h-4 w-4" })
|
|
2778
|
+
}
|
|
2779
|
+
)
|
|
2780
|
+
] }),
|
|
2781
|
+
errors.password && /* @__PURE__ */ jsx21("p", { className: "text-sm text-destructive", children: errors.password.message })
|
|
2782
|
+
] })
|
|
2783
|
+
] }),
|
|
2784
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex justify-end gap-2", children: [
|
|
2785
|
+
/* @__PURE__ */ jsx21(
|
|
2786
|
+
Button13,
|
|
2787
|
+
{
|
|
2788
|
+
type: "button",
|
|
2789
|
+
variant: "outline",
|
|
2790
|
+
onClick: onCancel,
|
|
2791
|
+
disabled: isLoading,
|
|
2792
|
+
children: "Cancel"
|
|
2793
|
+
}
|
|
2794
|
+
),
|
|
2795
|
+
/* @__PURE__ */ jsxs19(Button13, { type: "submit", disabled: isLoading, children: [
|
|
2796
|
+
isLoading && /* @__PURE__ */ jsx21(Spinner6, { className: "mr-2 h-4 w-4" }),
|
|
2797
|
+
isChecking ? "Checking\u2026" : buttonText
|
|
2798
|
+
] })
|
|
2688
2799
|
] })
|
|
2689
|
-
]
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2800
|
+
]
|
|
2801
|
+
}
|
|
2802
|
+
);
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
// src/components/profile/verify-change-email-form.tsx
|
|
2806
|
+
import { useState as useState15 } from "react";
|
|
2807
|
+
import { toast as toast8 } from "sonner";
|
|
2808
|
+
|
|
2809
|
+
// src/components/profile/otp-verification-modal.tsx
|
|
2810
|
+
import {
|
|
2811
|
+
Dialog,
|
|
2812
|
+
DialogContent,
|
|
2813
|
+
DialogDescription,
|
|
2814
|
+
DialogHeader,
|
|
2815
|
+
DialogTitle
|
|
2816
|
+
} from "@mesob/ui/components/dialog";
|
|
2817
|
+
import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2818
|
+
function OtpVerificationModal({
|
|
2819
|
+
open,
|
|
2820
|
+
title,
|
|
2821
|
+
description,
|
|
2822
|
+
verificationId,
|
|
2823
|
+
isLoading,
|
|
2824
|
+
onSubmit,
|
|
2825
|
+
onResend,
|
|
2826
|
+
onCancel
|
|
2827
|
+
}) {
|
|
2828
|
+
return /* @__PURE__ */ jsx22(
|
|
2829
|
+
Dialog,
|
|
2830
|
+
{
|
|
2831
|
+
open,
|
|
2832
|
+
onOpenChange: (nextOpen) => {
|
|
2833
|
+
if (!nextOpen) {
|
|
2834
|
+
onCancel?.();
|
|
2835
|
+
}
|
|
2836
|
+
},
|
|
2837
|
+
children: /* @__PURE__ */ jsxs20(DialogContent, { children: [
|
|
2838
|
+
/* @__PURE__ */ jsxs20(DialogHeader, { children: [
|
|
2839
|
+
/* @__PURE__ */ jsx22(DialogTitle, { children: title }),
|
|
2840
|
+
description && /* @__PURE__ */ jsx22(DialogDescription, { children: description })
|
|
2698
2841
|
] }),
|
|
2699
|
-
/* @__PURE__ */
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2842
|
+
/* @__PURE__ */ jsx22(
|
|
2843
|
+
VerificationForm,
|
|
2844
|
+
{
|
|
2845
|
+
verificationId,
|
|
2846
|
+
isLoading,
|
|
2847
|
+
onSubmit: async ({ code }) => onSubmit(code),
|
|
2848
|
+
onResend: onResend ?? (() => void 0)
|
|
2849
|
+
}
|
|
2850
|
+
)
|
|
2851
|
+
] })
|
|
2852
|
+
}
|
|
2853
|
+
);
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// src/components/profile/verify-change-email-form.tsx
|
|
2857
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
2858
|
+
function isAuthError3(error) {
|
|
2859
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
2860
|
+
}
|
|
2861
|
+
function getErrorCode2(error) {
|
|
2862
|
+
if (error.code) {
|
|
2863
|
+
return error.code;
|
|
2864
|
+
}
|
|
2865
|
+
if (error.message) {
|
|
2866
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
2867
|
+
const validCodes2 = [
|
|
2868
|
+
"USER_NOT_FOUND",
|
|
2869
|
+
"USER_EXISTS",
|
|
2870
|
+
"INVALID_PASSWORD",
|
|
2871
|
+
"VERIFICATION_EXPIRED",
|
|
2872
|
+
"VERIFICATION_MISMATCH",
|
|
2873
|
+
"VERIFICATION_NOT_FOUND",
|
|
2874
|
+
"TOO_MANY_ATTEMPTS",
|
|
2875
|
+
"UNAUTHORIZED"
|
|
2876
|
+
];
|
|
2877
|
+
if (validCodes2.includes(upperMessage)) {
|
|
2878
|
+
return upperMessage;
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
return void 0;
|
|
2882
|
+
}
|
|
2883
|
+
function getErrorMessage2(error) {
|
|
2884
|
+
if (isAuthError3(error)) {
|
|
2885
|
+
const errorCode = getErrorCode2(error);
|
|
2886
|
+
switch (errorCode) {
|
|
2887
|
+
case "USER_EXISTS":
|
|
2888
|
+
return "This email is already taken. Please use a different email.";
|
|
2889
|
+
case "VERIFICATION_EXPIRED":
|
|
2890
|
+
return "Verification code has expired. Please request a new one.";
|
|
2891
|
+
case "VERIFICATION_MISMATCH":
|
|
2892
|
+
return "Invalid verification code. Please try again.";
|
|
2893
|
+
case "VERIFICATION_NOT_FOUND":
|
|
2894
|
+
return "Verification not found. Please request a new code.";
|
|
2895
|
+
default:
|
|
2896
|
+
return error.message || "An error occurred. Please try again.";
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
if (error instanceof Error) {
|
|
2900
|
+
return error.message;
|
|
2901
|
+
}
|
|
2902
|
+
return "An error occurred. Please try again.";
|
|
2903
|
+
}
|
|
2904
|
+
function VerifyChangeEmailForm({
|
|
2905
|
+
email,
|
|
2906
|
+
verificationId,
|
|
2907
|
+
onSuccess,
|
|
2908
|
+
onCancel
|
|
2909
|
+
}) {
|
|
2910
|
+
const { refresh } = useSession();
|
|
2911
|
+
const { hooks } = useApi();
|
|
2912
|
+
const [isSubmitting, setIsSubmitting] = useState15(false);
|
|
2913
|
+
const [currentVerificationId, setCurrentVerificationId] = useState15(verificationId);
|
|
2914
|
+
const verifyEmailMutation = hooks.useMutation(
|
|
2915
|
+
"post",
|
|
2916
|
+
"/email/verification/confirm"
|
|
2917
|
+
);
|
|
2918
|
+
const updateEmailMutation = hooks.useMutation("put", "/profile/email");
|
|
2919
|
+
const requestEmailVerificationMutation = hooks.useMutation(
|
|
2920
|
+
"post",
|
|
2921
|
+
"/email/verification/request"
|
|
2922
|
+
);
|
|
2923
|
+
const onOtpSubmit = async (code) => {
|
|
2924
|
+
if (!currentVerificationId) {
|
|
2925
|
+
toast8.error("Verification not found. Please request a new code.");
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2928
|
+
try {
|
|
2929
|
+
setIsSubmitting(true);
|
|
2930
|
+
await verifyEmailMutation.mutateAsync({
|
|
2931
|
+
body: {
|
|
2932
|
+
verificationId: currentVerificationId,
|
|
2933
|
+
code
|
|
2934
|
+
}
|
|
2935
|
+
});
|
|
2936
|
+
await updateEmailMutation.mutateAsync({
|
|
2937
|
+
body: { email }
|
|
2938
|
+
});
|
|
2939
|
+
toast8.success("Email updated successfully");
|
|
2940
|
+
await refresh();
|
|
2941
|
+
onSuccess();
|
|
2942
|
+
} catch (error) {
|
|
2943
|
+
const errorMessage = getErrorMessage2(error);
|
|
2944
|
+
toast8.error(errorMessage);
|
|
2945
|
+
} finally {
|
|
2946
|
+
setIsSubmitting(false);
|
|
2947
|
+
}
|
|
2948
|
+
};
|
|
2949
|
+
if (!currentVerificationId) {
|
|
2950
|
+
toast8.error("Verification not found. Please request a new code.");
|
|
2951
|
+
return null;
|
|
2952
|
+
}
|
|
2953
|
+
return /* @__PURE__ */ jsx23(
|
|
2954
|
+
OtpVerificationModal,
|
|
2955
|
+
{
|
|
2956
|
+
open: true,
|
|
2957
|
+
title: "Verify email",
|
|
2958
|
+
description: `Enter the verification code sent to ${email}`,
|
|
2959
|
+
verificationId: currentVerificationId,
|
|
2960
|
+
isLoading: isSubmitting,
|
|
2961
|
+
onSubmit: onOtpSubmit,
|
|
2962
|
+
onResend: async () => {
|
|
2963
|
+
try {
|
|
2964
|
+
setIsSubmitting(true);
|
|
2965
|
+
const next = await requestEmailVerificationMutation.mutateAsync({
|
|
2966
|
+
body: { email }
|
|
2967
|
+
});
|
|
2968
|
+
setCurrentVerificationId(next.data?.verificationId ?? null);
|
|
2969
|
+
toast8.success("Verification code resent");
|
|
2970
|
+
} catch (error) {
|
|
2971
|
+
toast8.error(getErrorMessage2(error));
|
|
2972
|
+
} finally {
|
|
2973
|
+
setIsSubmitting(false);
|
|
2974
|
+
}
|
|
2975
|
+
},
|
|
2976
|
+
onCancel
|
|
2977
|
+
}
|
|
2978
|
+
);
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
// src/components/profile/change-email-form.tsx
|
|
2982
|
+
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2983
|
+
function ChangeEmailForm() {
|
|
2984
|
+
const { user } = useSession();
|
|
2985
|
+
const [isOpen, setIsOpen] = useState16(false);
|
|
2986
|
+
const [showOtp, setShowOtp] = useState16(false);
|
|
2987
|
+
const [verificationId, setVerificationId] = useState16(null);
|
|
2988
|
+
const [newEmail, setNewEmail] = useState16("");
|
|
2989
|
+
const resetForms = () => {
|
|
2990
|
+
setShowOtp(false);
|
|
2991
|
+
setVerificationId(null);
|
|
2992
|
+
setNewEmail("");
|
|
2993
|
+
};
|
|
2994
|
+
const handleRequestSuccess = (id, email) => {
|
|
2995
|
+
setVerificationId(id);
|
|
2996
|
+
setNewEmail(email);
|
|
2997
|
+
setShowOtp(true);
|
|
2998
|
+
};
|
|
2999
|
+
const handleVerifySuccess = () => {
|
|
3000
|
+
resetForms();
|
|
3001
|
+
setIsOpen(false);
|
|
3002
|
+
};
|
|
3003
|
+
const handleCancel = () => {
|
|
3004
|
+
resetForms();
|
|
3005
|
+
setIsOpen(false);
|
|
3006
|
+
};
|
|
3007
|
+
const title = user?.email ? "Change Email" : "Add Email";
|
|
3008
|
+
const description = user?.email ? "Update your email address" : "Add an email address to your account";
|
|
3009
|
+
return /* @__PURE__ */ jsx24(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs21("div", { className: "border rounded-lg", children: [
|
|
3010
|
+
/* @__PURE__ */ jsx24(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxs21(Button14, { variant: "ghost", className: "w-full justify-between p-4 h-auto", children: [
|
|
3011
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-start", children: [
|
|
3012
|
+
/* @__PURE__ */ jsx24("span", { className: "font-medium", children: title }),
|
|
3013
|
+
/* @__PURE__ */ jsx24("span", { className: "text-sm text-muted-foreground", children: description })
|
|
3014
|
+
] }),
|
|
3015
|
+
/* @__PURE__ */ jsx24(
|
|
3016
|
+
IconChevronDown,
|
|
3017
|
+
{
|
|
3018
|
+
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
3019
|
+
}
|
|
3020
|
+
)
|
|
3021
|
+
] }) }),
|
|
3022
|
+
/* @__PURE__ */ jsx24(CollapsibleContent, { children: showOtp ? /* @__PURE__ */ jsx24(
|
|
3023
|
+
VerifyChangeEmailForm,
|
|
3024
|
+
{
|
|
3025
|
+
email: newEmail,
|
|
3026
|
+
verificationId,
|
|
3027
|
+
onSuccess: handleVerifySuccess,
|
|
3028
|
+
onCancel: handleCancel
|
|
3029
|
+
}
|
|
3030
|
+
) : /* @__PURE__ */ jsx24(
|
|
3031
|
+
RequestChangeEmailForm,
|
|
3032
|
+
{
|
|
3033
|
+
onSuccess: handleRequestSuccess,
|
|
3034
|
+
onCancel: handleCancel,
|
|
3035
|
+
buttonText: title
|
|
3036
|
+
}
|
|
3037
|
+
) })
|
|
3038
|
+
] }) });
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
// src/components/profile/change-password-form.tsx
|
|
3042
|
+
import { zodResolver as zodResolver7 } from "@hookform/resolvers/zod";
|
|
3043
|
+
import { Button as Button15 } from "@mesob/ui/components/button";
|
|
3044
|
+
import {
|
|
3045
|
+
Collapsible as Collapsible2,
|
|
3046
|
+
CollapsibleContent as CollapsibleContent2,
|
|
3047
|
+
CollapsibleTrigger as CollapsibleTrigger2
|
|
3048
|
+
} from "@mesob/ui/components/collapsible";
|
|
3049
|
+
import { Input as Input6 } from "@mesob/ui/components/input";
|
|
3050
|
+
import { Label as Label2 } from "@mesob/ui/components/label";
|
|
3051
|
+
import { Spinner as Spinner7 } from "@mesob/ui/components/spinner";
|
|
3052
|
+
import { IconChevronDown as IconChevronDown2, IconEye as IconEye5, IconEyeOff as IconEyeOff5 } from "@tabler/icons-react";
|
|
3053
|
+
import { useState as useState17 } from "react";
|
|
3054
|
+
import { useForm as useForm7 } from "react-hook-form";
|
|
3055
|
+
import { toast as toast9 } from "sonner";
|
|
3056
|
+
import { z as z7 } from "zod";
|
|
3057
|
+
import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3058
|
+
var changePasswordSchema = z7.object({
|
|
3059
|
+
currentPassword: z7.string().min(8, "Password must be at least 8 characters"),
|
|
3060
|
+
newPassword: z7.string().min(8, "Password must be at least 8 characters"),
|
|
3061
|
+
confirmPassword: z7.string().min(8, "Password must be at least 8 characters")
|
|
3062
|
+
}).refine((data) => data.newPassword === data.confirmPassword, {
|
|
3063
|
+
message: "Passwords don't match",
|
|
3064
|
+
path: ["confirmPassword"]
|
|
3065
|
+
});
|
|
3066
|
+
function isAuthError4(error) {
|
|
3067
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
3068
|
+
}
|
|
3069
|
+
function getErrorCode3(error) {
|
|
3070
|
+
if (error.code) {
|
|
3071
|
+
return error.code;
|
|
3072
|
+
}
|
|
3073
|
+
if (error.message) {
|
|
3074
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
3075
|
+
const validCodes2 = [
|
|
3076
|
+
"INVALID_PASSWORD",
|
|
3077
|
+
"UNAUTHORIZED",
|
|
3078
|
+
"HAS_NO_PASSWORD",
|
|
3079
|
+
"USER_NOT_FOUND",
|
|
3080
|
+
"USER_EXISTS",
|
|
3081
|
+
"VERIFICATION_EXPIRED",
|
|
3082
|
+
"VERIFICATION_MISMATCH",
|
|
3083
|
+
"VERIFICATION_NOT_FOUND",
|
|
3084
|
+
"TOO_MANY_ATTEMPTS",
|
|
3085
|
+
"REQUIRES_VERIFICATION",
|
|
3086
|
+
"ACCESS_DENIED"
|
|
3087
|
+
];
|
|
3088
|
+
if (validCodes2.includes(upperMessage)) {
|
|
3089
|
+
return upperMessage;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
return void 0;
|
|
3093
|
+
}
|
|
3094
|
+
function getPasswordChangeErrorMessage(error) {
|
|
3095
|
+
if (isAuthError4(error)) {
|
|
3096
|
+
const errorCode = getErrorCode3(error);
|
|
3097
|
+
switch (errorCode) {
|
|
3098
|
+
case "INVALID_PASSWORD":
|
|
3099
|
+
return "The current password you entered is incorrect. Please try again.";
|
|
3100
|
+
case "UNAUTHORIZED":
|
|
3101
|
+
return "You are not authorized to perform this action. Please sign in again.";
|
|
3102
|
+
case "HAS_NO_PASSWORD":
|
|
3103
|
+
return "Your account does not have a password set. Please use password reset instead.";
|
|
3104
|
+
default:
|
|
3105
|
+
return error.message || "Failed to change password. Please try again.";
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
if (error instanceof Error) {
|
|
3109
|
+
return error.message;
|
|
3110
|
+
}
|
|
3111
|
+
return "Failed to change password. Please try again.";
|
|
3112
|
+
}
|
|
3113
|
+
function ChangePasswordForm() {
|
|
3114
|
+
const { user: _user } = useSession();
|
|
3115
|
+
const [isOpen, setIsOpen] = useState17(false);
|
|
3116
|
+
const [isSubmitting, setIsSubmitting] = useState17(false);
|
|
3117
|
+
const [showPassword, setShowPassword] = useState17(false);
|
|
3118
|
+
const [showNewPassword, setShowNewPassword] = useState17(false);
|
|
3119
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState17(false);
|
|
3120
|
+
const form = useForm7({
|
|
3121
|
+
resolver: zodResolver7(changePasswordSchema),
|
|
3122
|
+
defaultValues: {
|
|
3123
|
+
currentPassword: "",
|
|
3124
|
+
newPassword: "",
|
|
3125
|
+
confirmPassword: ""
|
|
3126
|
+
}
|
|
3127
|
+
});
|
|
3128
|
+
const { register, handleSubmit, formState, reset } = form;
|
|
3129
|
+
const onSubmit = (_data) => {
|
|
3130
|
+
try {
|
|
3131
|
+
setIsSubmitting(true);
|
|
3132
|
+
toast9.error("Password change unavailable");
|
|
3133
|
+
setIsOpen(false);
|
|
3134
|
+
} catch (error) {
|
|
3135
|
+
const errorMessage = getPasswordChangeErrorMessage(error);
|
|
3136
|
+
toast9.error(errorMessage);
|
|
3137
|
+
} finally {
|
|
3138
|
+
setIsSubmitting(false);
|
|
3139
|
+
}
|
|
3140
|
+
};
|
|
3141
|
+
return /* @__PURE__ */ jsx25(Collapsible2, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs22("div", { className: "border rounded-lg", children: [
|
|
3142
|
+
/* @__PURE__ */ jsx25(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs22(Button15, { variant: "ghost", className: "w-full justify-between p-4 h-auto", children: [
|
|
3143
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-start", children: [
|
|
3144
|
+
/* @__PURE__ */ jsx25("span", { className: "font-medium", children: "Change Password" }),
|
|
3145
|
+
/* @__PURE__ */ jsx25("span", { className: "text-sm text-muted-foreground", children: "Update your account password" })
|
|
3146
|
+
] }),
|
|
3147
|
+
/* @__PURE__ */ jsx25(
|
|
3148
|
+
IconChevronDown2,
|
|
3149
|
+
{
|
|
3150
|
+
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
3151
|
+
}
|
|
3152
|
+
)
|
|
3153
|
+
] }) }),
|
|
3154
|
+
/* @__PURE__ */ jsx25(CollapsibleContent2, { children: /* @__PURE__ */ jsxs22(
|
|
3155
|
+
"form",
|
|
3156
|
+
{
|
|
3157
|
+
onSubmit: handleSubmit(onSubmit),
|
|
3158
|
+
className: "p-4 space-y-4 border-t",
|
|
3159
|
+
children: [
|
|
3160
|
+
/* @__PURE__ */ jsxs22("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
3161
|
+
/* @__PURE__ */ jsx25(Label2, { htmlFor: "currentPassword", children: "Old Password" }),
|
|
3162
|
+
/* @__PURE__ */ jsxs22("div", { className: "relative", children: [
|
|
3163
|
+
/* @__PURE__ */ jsx25(
|
|
3164
|
+
Input6,
|
|
2706
3165
|
{
|
|
2707
|
-
|
|
2708
|
-
|
|
3166
|
+
id: "currentPassword",
|
|
3167
|
+
type: showPassword ? "text" : "password",
|
|
3168
|
+
autoComplete: "current-password",
|
|
3169
|
+
placeholder: "Enter your current password",
|
|
3170
|
+
...register("currentPassword")
|
|
3171
|
+
}
|
|
3172
|
+
),
|
|
3173
|
+
/* @__PURE__ */ jsx25(
|
|
3174
|
+
"button",
|
|
3175
|
+
{
|
|
3176
|
+
type: "button",
|
|
3177
|
+
onClick: () => setShowPassword(!showPassword),
|
|
3178
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3179
|
+
children: showPassword ? /* @__PURE__ */ jsx25(IconEyeOff5, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx25(IconEye5, { className: "h-4 w-4" })
|
|
2709
3180
|
}
|
|
2710
3181
|
)
|
|
2711
|
-
] })
|
|
3182
|
+
] }),
|
|
3183
|
+
formState.errors.currentPassword && /* @__PURE__ */ jsx25("p", { className: "text-sm text-destructive", children: formState.errors.currentPassword.message })
|
|
2712
3184
|
] }),
|
|
2713
|
-
/* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */ jsx25(
|
|
2715
|
-
/* @__PURE__ */
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
"span",
|
|
3185
|
+
/* @__PURE__ */ jsxs22("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
3186
|
+
/* @__PURE__ */ jsx25(Label2, { htmlFor: "newPassword", children: "New Password" }),
|
|
3187
|
+
/* @__PURE__ */ jsxs22("div", { className: "relative", children: [
|
|
3188
|
+
/* @__PURE__ */ jsx25(
|
|
3189
|
+
Input6,
|
|
2719
3190
|
{
|
|
2720
|
-
|
|
2721
|
-
|
|
3191
|
+
id: "newPassword",
|
|
3192
|
+
type: showNewPassword ? "text" : "password",
|
|
3193
|
+
placeholder: "Enter your new password",
|
|
3194
|
+
autoComplete: "new-password",
|
|
3195
|
+
...register("newPassword")
|
|
3196
|
+
}
|
|
3197
|
+
),
|
|
3198
|
+
/* @__PURE__ */ jsx25(
|
|
3199
|
+
"button",
|
|
3200
|
+
{
|
|
3201
|
+
type: "button",
|
|
3202
|
+
onClick: () => setShowNewPassword(!showNewPassword),
|
|
3203
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3204
|
+
children: showNewPassword ? /* @__PURE__ */ jsx25(IconEyeOff5, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx25(IconEye5, { className: "h-4 w-4" })
|
|
2722
3205
|
}
|
|
2723
3206
|
)
|
|
3207
|
+
] }),
|
|
3208
|
+
formState.errors.newPassword && /* @__PURE__ */ jsx25("p", { className: "text-sm text-destructive", children: formState.errors.newPassword.message })
|
|
3209
|
+
] }),
|
|
3210
|
+
/* @__PURE__ */ jsxs22("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
3211
|
+
/* @__PURE__ */ jsx25(Label2, { htmlFor: "confirmPassword", children: "Confirm New Password" }),
|
|
3212
|
+
/* @__PURE__ */ jsxs22("div", { className: "relative", children: [
|
|
3213
|
+
/* @__PURE__ */ jsx25(
|
|
3214
|
+
Input6,
|
|
3215
|
+
{
|
|
3216
|
+
id: "confirmPassword",
|
|
3217
|
+
type: showConfirmPassword ? "text" : "password",
|
|
3218
|
+
placeholder: "Confirm your new password",
|
|
3219
|
+
autoComplete: "new-password",
|
|
3220
|
+
...register("confirmPassword")
|
|
3221
|
+
}
|
|
3222
|
+
),
|
|
3223
|
+
/* @__PURE__ */ jsx25(
|
|
3224
|
+
"button",
|
|
3225
|
+
{
|
|
3226
|
+
type: "button",
|
|
3227
|
+
onClick: () => setShowConfirmPassword(!showConfirmPassword),
|
|
3228
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3229
|
+
children: showConfirmPassword ? /* @__PURE__ */ jsx25(IconEyeOff5, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx25(IconEye5, { className: "h-4 w-4" })
|
|
3230
|
+
}
|
|
3231
|
+
)
|
|
3232
|
+
] }),
|
|
3233
|
+
formState.errors.confirmPassword && /* @__PURE__ */ jsx25("p", { className: "text-sm text-destructive", children: formState.errors.confirmPassword.message })
|
|
3234
|
+
] }),
|
|
3235
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex justify-end gap-2", children: [
|
|
3236
|
+
/* @__PURE__ */ jsx25(
|
|
3237
|
+
Button15,
|
|
3238
|
+
{
|
|
3239
|
+
type: "button",
|
|
3240
|
+
variant: "outline",
|
|
3241
|
+
onClick: () => {
|
|
3242
|
+
reset();
|
|
3243
|
+
setIsOpen(false);
|
|
3244
|
+
},
|
|
3245
|
+
disabled: isSubmitting,
|
|
3246
|
+
children: "Cancel"
|
|
3247
|
+
}
|
|
3248
|
+
),
|
|
3249
|
+
/* @__PURE__ */ jsxs22(Button15, { type: "submit", disabled: isSubmitting, children: [
|
|
3250
|
+
isSubmitting && /* @__PURE__ */ jsx25(Spinner7, { className: "mr-2 h-4 w-4" }),
|
|
3251
|
+
"Change Password"
|
|
2724
3252
|
] })
|
|
2725
3253
|
] })
|
|
2726
|
-
]
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
3254
|
+
]
|
|
3255
|
+
}
|
|
3256
|
+
) })
|
|
3257
|
+
] }) });
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
// src/components/profile/change-phone-form.tsx
|
|
3261
|
+
import { Button as Button17 } from "@mesob/ui/components/button";
|
|
3262
|
+
import {
|
|
3263
|
+
Collapsible as Collapsible3,
|
|
3264
|
+
CollapsibleContent as CollapsibleContent3,
|
|
3265
|
+
CollapsibleTrigger as CollapsibleTrigger3
|
|
3266
|
+
} from "@mesob/ui/components/collapsible";
|
|
3267
|
+
import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
3268
|
+
import { useState as useState20 } from "react";
|
|
3269
|
+
|
|
3270
|
+
// src/components/profile/request-change-phone-form.tsx
|
|
3271
|
+
import { zodResolver as zodResolver8 } from "@hookform/resolvers/zod";
|
|
3272
|
+
import { Button as Button16 } from "@mesob/ui/components/button";
|
|
3273
|
+
import { Input as Input7 } from "@mesob/ui/components/input";
|
|
3274
|
+
import { Label as Label3 } from "@mesob/ui/components/label";
|
|
3275
|
+
import { Spinner as Spinner8 } from "@mesob/ui/components/spinner";
|
|
3276
|
+
import { IconEye as IconEye6, IconEyeOff as IconEyeOff6 } from "@tabler/icons-react";
|
|
3277
|
+
import { useEffect as useEffect9, useState as useState18 } from "react";
|
|
3278
|
+
import { useForm as useForm8 } from "react-hook-form";
|
|
3279
|
+
import { toast as toast10 } from "sonner";
|
|
3280
|
+
import { z as z8 } from "zod";
|
|
3281
|
+
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3282
|
+
var phonePasswordSchema = (phoneRegex) => z8.object({
|
|
3283
|
+
phone: z8.string().trim().min(1, { message: "Phone number is required" }).refine(
|
|
3284
|
+
(val) => {
|
|
3285
|
+
const isPhone3 = phoneRegex.test(val);
|
|
3286
|
+
return isPhone3;
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
message: "Invalid phone number"
|
|
3290
|
+
}
|
|
3291
|
+
),
|
|
3292
|
+
password: z8.string().min(8, "Password must be at least 8 characters").max(128, "Password too long")
|
|
3293
|
+
});
|
|
3294
|
+
function isAuthError5(error) {
|
|
3295
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
3296
|
+
}
|
|
3297
|
+
function getErrorCode4(error) {
|
|
3298
|
+
if (error.code) {
|
|
3299
|
+
return error.code;
|
|
3300
|
+
}
|
|
3301
|
+
if (error.message) {
|
|
3302
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
3303
|
+
const validCodes2 = [
|
|
3304
|
+
"USER_NOT_FOUND",
|
|
3305
|
+
"USER_EXISTS",
|
|
3306
|
+
"INVALID_PASSWORD",
|
|
3307
|
+
"VERIFICATION_EXPIRED",
|
|
3308
|
+
"VERIFICATION_MISMATCH",
|
|
3309
|
+
"VERIFICATION_NOT_FOUND",
|
|
3310
|
+
"TOO_MANY_ATTEMPTS",
|
|
3311
|
+
"UNAUTHORIZED"
|
|
3312
|
+
];
|
|
3313
|
+
if (validCodes2.includes(upperMessage)) {
|
|
3314
|
+
return upperMessage;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
return void 0;
|
|
3318
|
+
}
|
|
3319
|
+
function getErrorMessage3(error) {
|
|
3320
|
+
if (isAuthError5(error)) {
|
|
3321
|
+
const errorCode = getErrorCode4(error);
|
|
3322
|
+
switch (errorCode) {
|
|
3323
|
+
case "USER_EXISTS":
|
|
3324
|
+
return "This phone number is already taken. Please use a different number.";
|
|
3325
|
+
case "VERIFICATION_EXPIRED":
|
|
3326
|
+
return "Verification code has expired. Please request a new one.";
|
|
3327
|
+
case "VERIFICATION_MISMATCH":
|
|
3328
|
+
return "Invalid verification code. Please try again.";
|
|
3329
|
+
case "VERIFICATION_NOT_FOUND":
|
|
3330
|
+
return "Verification not found. Please request a new code.";
|
|
3331
|
+
default:
|
|
3332
|
+
return error.message || "An error occurred. Please try again.";
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
if (error instanceof Error) {
|
|
3336
|
+
return error.message;
|
|
3337
|
+
}
|
|
3338
|
+
return "An error occurred. Please try again.";
|
|
3339
|
+
}
|
|
3340
|
+
function RequestChangePhoneForm({
|
|
3341
|
+
onSuccess,
|
|
3342
|
+
onCancel,
|
|
3343
|
+
buttonText
|
|
3344
|
+
}) {
|
|
3345
|
+
const { user } = useSession();
|
|
3346
|
+
const { hooks } = useApi();
|
|
3347
|
+
const { config } = useConfig();
|
|
3348
|
+
const [isSubmitting, setIsSubmitting] = useState18(false);
|
|
3349
|
+
const [isChecking, setIsChecking] = useState18(true);
|
|
3350
|
+
const [showPassword, setShowPassword] = useState18(false);
|
|
3351
|
+
const phoneRegex = typeof config.phoneRegex === "string" ? new RegExp(config.phoneRegex) : config.phoneRegex || /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/;
|
|
3352
|
+
const getPendingAccountChangeQuery = hooks.useQuery(
|
|
3353
|
+
"get",
|
|
3354
|
+
"/account-change/pending",
|
|
3355
|
+
{},
|
|
3356
|
+
{ enabled: false }
|
|
3357
|
+
);
|
|
3358
|
+
const verifyPasswordMutation = hooks.useMutation("post", "/password/verify");
|
|
3359
|
+
const checkUserMutation = hooks.useMutation("post", "/check-account");
|
|
3360
|
+
const requestPhoneOtpMutation = hooks.useMutation(
|
|
3361
|
+
"post",
|
|
3362
|
+
"/phone/verification/request"
|
|
3363
|
+
);
|
|
3364
|
+
const phonePasswordForm = useForm8({
|
|
3365
|
+
resolver: zodResolver8(phonePasswordSchema(phoneRegex)),
|
|
3366
|
+
defaultValues: {
|
|
3367
|
+
phone: "",
|
|
3368
|
+
password: ""
|
|
3369
|
+
}
|
|
3370
|
+
});
|
|
3371
|
+
const {
|
|
3372
|
+
register,
|
|
3373
|
+
handleSubmit,
|
|
3374
|
+
getValues,
|
|
3375
|
+
setValue,
|
|
3376
|
+
formState: { errors }
|
|
3377
|
+
} = phonePasswordForm;
|
|
3378
|
+
useEffect9(() => {
|
|
3379
|
+
let active = true;
|
|
3380
|
+
const run = async () => {
|
|
3381
|
+
try {
|
|
3382
|
+
const data = await getPendingAccountChangeQuery.refetch();
|
|
3383
|
+
if (!active) {
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
const accountChange = data.data?.accountChange;
|
|
3387
|
+
const verificationId = data.data?.verificationId;
|
|
3388
|
+
if (accountChange?.changeType !== "phone") {
|
|
3389
|
+
setIsChecking(false);
|
|
3390
|
+
return;
|
|
3391
|
+
}
|
|
3392
|
+
if (!accountChange.newPhone) {
|
|
3393
|
+
setIsChecking(false);
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
if (getValues("phone")) {
|
|
3397
|
+
setIsChecking(false);
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
setValue("phone", accountChange.newPhone, { shouldValidate: true });
|
|
3401
|
+
if (verificationId) {
|
|
3402
|
+
toast10.message("Resuming verification\u2026");
|
|
3403
|
+
onSuccess(verificationId, accountChange.newPhone);
|
|
3404
|
+
return;
|
|
3405
|
+
}
|
|
3406
|
+
setIsChecking(false);
|
|
3407
|
+
} catch {
|
|
3408
|
+
setIsChecking(false);
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3411
|
+
run().catch(() => void 0);
|
|
3412
|
+
return () => {
|
|
3413
|
+
active = false;
|
|
3414
|
+
};
|
|
3415
|
+
}, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);
|
|
3416
|
+
const onPhonePasswordSubmit = async (data) => {
|
|
3417
|
+
if (!user) {
|
|
3418
|
+
toast10.error("User not found");
|
|
3419
|
+
return;
|
|
3420
|
+
}
|
|
3421
|
+
try {
|
|
3422
|
+
setIsSubmitting(true);
|
|
3423
|
+
const normalizedPhone = normalizePhone(data.phone);
|
|
3424
|
+
await verifyPasswordMutation.mutateAsync({
|
|
3425
|
+
body: { password: data.password }
|
|
3426
|
+
});
|
|
3427
|
+
const checkResult = await checkUserMutation.mutateAsync({
|
|
3428
|
+
body: { identifier: normalizedPhone }
|
|
3429
|
+
});
|
|
3430
|
+
if (checkResult.data?.exists) {
|
|
3431
|
+
if (user?.phone?.replace(/\s/g, "") === normalizedPhone.replace(/\s/g, "")) {
|
|
3432
|
+
toast10.error("This is already your current phone number.");
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3435
|
+
toast10.error(
|
|
3436
|
+
"This phone number is already taken. Please use a different number."
|
|
3437
|
+
);
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
const verification = await requestPhoneOtpMutation.mutateAsync({
|
|
3441
|
+
body: {
|
|
3442
|
+
phone: normalizedPhone,
|
|
3443
|
+
context: "change-phone"
|
|
3444
|
+
}
|
|
3445
|
+
});
|
|
3446
|
+
toast10.success("Verification code sent to your phone");
|
|
3447
|
+
onSuccess(verification.data?.verificationId ?? "", normalizedPhone);
|
|
3448
|
+
} catch (error) {
|
|
3449
|
+
const errorMessage = getErrorMessage3(error);
|
|
3450
|
+
if (isAuthError5(error)) {
|
|
3451
|
+
const errorCode = getErrorCode4(error);
|
|
3452
|
+
if (errorCode === "INVALID_PASSWORD" || errorCode === "USER_NOT_FOUND") {
|
|
3453
|
+
toast10.error("Incorrect password. Please try again.");
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
toast10.error(errorMessage);
|
|
3458
|
+
} finally {
|
|
3459
|
+
setIsSubmitting(false);
|
|
3460
|
+
}
|
|
3461
|
+
};
|
|
3462
|
+
const isLoading = isSubmitting || isChecking;
|
|
3463
|
+
return /* @__PURE__ */ jsxs23(
|
|
3464
|
+
"form",
|
|
3465
|
+
{
|
|
3466
|
+
onSubmit: handleSubmit(onPhonePasswordSubmit),
|
|
3467
|
+
className: "p-4 space-y-4 border-t",
|
|
3468
|
+
children: [
|
|
3469
|
+
/* @__PURE__ */ jsxs23("div", { className: "space-y-4 w-full md:w-1/2", children: [
|
|
3470
|
+
/* @__PURE__ */ jsxs23("div", { className: "space-y-2", children: [
|
|
3471
|
+
/* @__PURE__ */ jsx26(Label3, { htmlFor: "phone", children: "Phone Number" }),
|
|
3472
|
+
/* @__PURE__ */ jsx26(
|
|
3473
|
+
Input7,
|
|
3474
|
+
{
|
|
3475
|
+
id: "phone",
|
|
3476
|
+
type: "tel",
|
|
3477
|
+
placeholder: "Enter your new phone number",
|
|
3478
|
+
...register("phone"),
|
|
3479
|
+
disabled: isLoading
|
|
3480
|
+
}
|
|
3481
|
+
),
|
|
3482
|
+
errors.phone && /* @__PURE__ */ jsx26("p", { className: "text-sm text-destructive", children: errors.phone.message })
|
|
2737
3483
|
] }),
|
|
2738
|
-
/* @__PURE__ */ jsxs23("div", { children: [
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
/* @__PURE__ */
|
|
3484
|
+
/* @__PURE__ */ jsxs23("div", { className: "space-y-2", children: [
|
|
3485
|
+
/* @__PURE__ */ jsx26(Label3, { htmlFor: "password", children: "Password" }),
|
|
3486
|
+
/* @__PURE__ */ jsxs23("div", { className: "relative", children: [
|
|
3487
|
+
/* @__PURE__ */ jsx26(
|
|
3488
|
+
Input7,
|
|
3489
|
+
{
|
|
3490
|
+
id: "password",
|
|
3491
|
+
type: showPassword ? "text" : "password",
|
|
3492
|
+
autoComplete: "current-password",
|
|
3493
|
+
placeholder: "Enter your password",
|
|
3494
|
+
...register("password"),
|
|
3495
|
+
disabled: isLoading
|
|
3496
|
+
}
|
|
3497
|
+
),
|
|
3498
|
+
/* @__PURE__ */ jsx26(
|
|
3499
|
+
"button",
|
|
3500
|
+
{
|
|
3501
|
+
type: "button",
|
|
3502
|
+
onClick: () => setShowPassword(!showPassword),
|
|
3503
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3504
|
+
children: showPassword ? /* @__PURE__ */ jsx26(IconEyeOff6, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx26(IconEye6, { className: "h-4 w-4" })
|
|
3505
|
+
}
|
|
3506
|
+
)
|
|
3507
|
+
] }),
|
|
3508
|
+
errors.password && /* @__PURE__ */ jsx26("p", { className: "text-sm text-destructive", children: errors.password.message })
|
|
3509
|
+
] })
|
|
3510
|
+
] }),
|
|
3511
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex justify-end gap-2", children: [
|
|
3512
|
+
/* @__PURE__ */ jsx26(
|
|
3513
|
+
Button16,
|
|
3514
|
+
{
|
|
3515
|
+
type: "button",
|
|
3516
|
+
variant: "outline",
|
|
3517
|
+
onClick: onCancel,
|
|
3518
|
+
disabled: isLoading,
|
|
3519
|
+
children: "Cancel"
|
|
3520
|
+
}
|
|
3521
|
+
),
|
|
3522
|
+
/* @__PURE__ */ jsxs23(Button16, { type: "submit", disabled: isLoading, children: [
|
|
3523
|
+
isLoading && /* @__PURE__ */ jsx26(Spinner8, { className: "mr-2 h-4 w-4" }),
|
|
3524
|
+
isChecking ? "Checking\u2026" : buttonText
|
|
2741
3525
|
] })
|
|
2742
3526
|
] })
|
|
3527
|
+
]
|
|
3528
|
+
}
|
|
3529
|
+
);
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3532
|
+
// src/components/profile/verify-change-phone-form.tsx
|
|
3533
|
+
import { useState as useState19 } from "react";
|
|
3534
|
+
import { toast as toast11 } from "sonner";
|
|
3535
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
3536
|
+
function isAuthError6(error) {
|
|
3537
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
3538
|
+
}
|
|
3539
|
+
function getErrorCode5(error) {
|
|
3540
|
+
if (error.code) {
|
|
3541
|
+
return error.code;
|
|
3542
|
+
}
|
|
3543
|
+
if (error.message) {
|
|
3544
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
3545
|
+
const validCodes2 = [
|
|
3546
|
+
"USER_NOT_FOUND",
|
|
3547
|
+
"USER_EXISTS",
|
|
3548
|
+
"INVALID_PASSWORD",
|
|
3549
|
+
"VERIFICATION_EXPIRED",
|
|
3550
|
+
"VERIFICATION_MISMATCH",
|
|
3551
|
+
"VERIFICATION_NOT_FOUND",
|
|
3552
|
+
"TOO_MANY_ATTEMPTS",
|
|
3553
|
+
"UNAUTHORIZED"
|
|
3554
|
+
];
|
|
3555
|
+
if (validCodes2.includes(upperMessage)) {
|
|
3556
|
+
return upperMessage;
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
return void 0;
|
|
3560
|
+
}
|
|
3561
|
+
function getErrorMessage4(error) {
|
|
3562
|
+
if (isAuthError6(error)) {
|
|
3563
|
+
const errorCode = getErrorCode5(error);
|
|
3564
|
+
switch (errorCode) {
|
|
3565
|
+
case "USER_EXISTS":
|
|
3566
|
+
return "This phone number is already taken. Please use a different number.";
|
|
3567
|
+
case "VERIFICATION_EXPIRED":
|
|
3568
|
+
return "Verification code has expired. Please request a new one.";
|
|
3569
|
+
case "VERIFICATION_MISMATCH":
|
|
3570
|
+
return "Invalid verification code. Please try again.";
|
|
3571
|
+
case "VERIFICATION_NOT_FOUND":
|
|
3572
|
+
return "Verification not found. Please request a new code.";
|
|
3573
|
+
default:
|
|
3574
|
+
return error.message || "An error occurred. Please try again.";
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
if (error instanceof Error) {
|
|
3578
|
+
return error.message;
|
|
3579
|
+
}
|
|
3580
|
+
return "An error occurred. Please try again.";
|
|
3581
|
+
}
|
|
3582
|
+
function VerifyChangePhoneForm({
|
|
3583
|
+
phone,
|
|
3584
|
+
verificationId,
|
|
3585
|
+
onSuccess,
|
|
3586
|
+
onCancel
|
|
3587
|
+
}) {
|
|
3588
|
+
const { refresh } = useSession();
|
|
3589
|
+
const { hooks } = useApi();
|
|
3590
|
+
const [isSubmitting, setIsSubmitting] = useState19(false);
|
|
3591
|
+
const [currentVerificationId, setCurrentVerificationId] = useState19(verificationId);
|
|
3592
|
+
const verifyPhoneOtpMutation = hooks.useMutation(
|
|
3593
|
+
"post",
|
|
3594
|
+
"/phone/verification/confirm"
|
|
3595
|
+
);
|
|
3596
|
+
const updatePhoneMutation = hooks.useMutation("put", "/profile/phone");
|
|
3597
|
+
const requestPhoneOtpMutation = hooks.useMutation(
|
|
3598
|
+
"post",
|
|
3599
|
+
"/phone/verification/request"
|
|
3600
|
+
);
|
|
3601
|
+
const onOtpSubmit = async (code) => {
|
|
3602
|
+
if (!currentVerificationId) {
|
|
3603
|
+
toast11.error("Verification not found. Please request a new code.");
|
|
3604
|
+
return;
|
|
3605
|
+
}
|
|
3606
|
+
try {
|
|
3607
|
+
setIsSubmitting(true);
|
|
3608
|
+
await verifyPhoneOtpMutation.mutateAsync({
|
|
3609
|
+
body: {
|
|
3610
|
+
verificationId: currentVerificationId,
|
|
3611
|
+
code,
|
|
3612
|
+
context: "change-phone"
|
|
3613
|
+
}
|
|
3614
|
+
});
|
|
3615
|
+
await updatePhoneMutation.mutateAsync({
|
|
3616
|
+
body: { phone }
|
|
3617
|
+
});
|
|
3618
|
+
toast11.success("Phone number updated successfully");
|
|
3619
|
+
await refresh();
|
|
3620
|
+
onSuccess();
|
|
3621
|
+
} catch (error) {
|
|
3622
|
+
const errorMessage = getErrorMessage4(error);
|
|
3623
|
+
toast11.error(errorMessage);
|
|
3624
|
+
} finally {
|
|
3625
|
+
setIsSubmitting(false);
|
|
3626
|
+
}
|
|
3627
|
+
};
|
|
3628
|
+
if (!currentVerificationId) {
|
|
3629
|
+
toast11.error("Verification not found. Please request a new code.");
|
|
3630
|
+
return null;
|
|
3631
|
+
}
|
|
3632
|
+
return /* @__PURE__ */ jsx27(
|
|
3633
|
+
OtpVerificationModal,
|
|
3634
|
+
{
|
|
3635
|
+
open: true,
|
|
3636
|
+
title: "Verify phone",
|
|
3637
|
+
description: `Enter the verification code sent to ${phone}`,
|
|
3638
|
+
verificationId: currentVerificationId,
|
|
3639
|
+
isLoading: isSubmitting,
|
|
3640
|
+
onSubmit: onOtpSubmit,
|
|
3641
|
+
onResend: async () => {
|
|
3642
|
+
try {
|
|
3643
|
+
setIsSubmitting(true);
|
|
3644
|
+
const next = await requestPhoneOtpMutation.mutateAsync({
|
|
3645
|
+
body: {
|
|
3646
|
+
phone,
|
|
3647
|
+
context: "change-phone"
|
|
3648
|
+
}
|
|
3649
|
+
});
|
|
3650
|
+
setCurrentVerificationId(next.data?.verificationId ?? null);
|
|
3651
|
+
toast11.success("Verification code resent");
|
|
3652
|
+
} catch (error) {
|
|
3653
|
+
toast11.error(getErrorMessage4(error));
|
|
3654
|
+
} finally {
|
|
3655
|
+
setIsSubmitting(false);
|
|
3656
|
+
}
|
|
3657
|
+
},
|
|
3658
|
+
onCancel
|
|
3659
|
+
}
|
|
3660
|
+
);
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
// src/components/profile/change-phone-form.tsx
|
|
3664
|
+
import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
3665
|
+
function ChangePhoneForm() {
|
|
3666
|
+
const { user } = useSession();
|
|
3667
|
+
const [isOpen, setIsOpen] = useState20(false);
|
|
3668
|
+
const [showOtp, setShowOtp] = useState20(false);
|
|
3669
|
+
const [verificationId, setVerificationId] = useState20(null);
|
|
3670
|
+
const [newPhone, setNewPhone] = useState20("");
|
|
3671
|
+
const resetForms = () => {
|
|
3672
|
+
setShowOtp(false);
|
|
3673
|
+
setVerificationId(null);
|
|
3674
|
+
setNewPhone("");
|
|
3675
|
+
};
|
|
3676
|
+
const handleRequestSuccess = (id, phone) => {
|
|
3677
|
+
setVerificationId(id);
|
|
3678
|
+
setNewPhone(phone);
|
|
3679
|
+
setShowOtp(true);
|
|
3680
|
+
};
|
|
3681
|
+
const handleVerifySuccess = () => {
|
|
3682
|
+
resetForms();
|
|
3683
|
+
setIsOpen(false);
|
|
3684
|
+
};
|
|
3685
|
+
const handleCancel = () => {
|
|
3686
|
+
resetForms();
|
|
3687
|
+
setIsOpen(false);
|
|
3688
|
+
};
|
|
3689
|
+
const title = user?.phone ? "Change Phone" : "Add Phone";
|
|
3690
|
+
const description = user?.phone ? "Update your phone number" : "Add a phone number to your account";
|
|
3691
|
+
return /* @__PURE__ */ jsx28(Collapsible3, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs24("div", { className: "border rounded-lg", children: [
|
|
3692
|
+
/* @__PURE__ */ jsx28(CollapsibleTrigger3, { asChild: true, children: /* @__PURE__ */ jsxs24(Button17, { variant: "ghost", className: "w-full justify-between p-4 h-auto", children: [
|
|
3693
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex flex-col items-start", children: [
|
|
3694
|
+
/* @__PURE__ */ jsx28("span", { className: "font-medium", children: title }),
|
|
3695
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-muted-foreground", children: description })
|
|
2743
3696
|
] }),
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
3697
|
+
/* @__PURE__ */ jsx28(
|
|
3698
|
+
IconChevronDown3,
|
|
3699
|
+
{
|
|
3700
|
+
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
3701
|
+
}
|
|
3702
|
+
)
|
|
3703
|
+
] }) }),
|
|
3704
|
+
/* @__PURE__ */ jsx28(CollapsibleContent3, { children: showOtp ? /* @__PURE__ */ jsx28(
|
|
3705
|
+
VerifyChangePhoneForm,
|
|
3706
|
+
{
|
|
3707
|
+
phone: newPhone,
|
|
3708
|
+
verificationId,
|
|
3709
|
+
onSuccess: handleVerifySuccess,
|
|
3710
|
+
onCancel: handleCancel
|
|
3711
|
+
}
|
|
3712
|
+
) : /* @__PURE__ */ jsx28(
|
|
3713
|
+
RequestChangePhoneForm,
|
|
3714
|
+
{
|
|
3715
|
+
onSuccess: handleRequestSuccess,
|
|
3716
|
+
onCancel: handleCancel,
|
|
3717
|
+
buttonText: title
|
|
3718
|
+
}
|
|
3719
|
+
) })
|
|
3720
|
+
] }) });
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
// src/components/profile/security.tsx
|
|
3724
|
+
import { jsx as jsx29, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3725
|
+
function Security() {
|
|
3726
|
+
return /* @__PURE__ */ jsxs25("div", { className: "p-6 space-y-6", children: [
|
|
3727
|
+
/* @__PURE__ */ jsxs25("div", { children: [
|
|
3728
|
+
/* @__PURE__ */ jsx29("h1", { className: "text-2xl font-semibold", children: "Security" }),
|
|
3729
|
+
/* @__PURE__ */ jsx29("p", { className: "text-muted-foreground", children: "Manage your security settings" })
|
|
3730
|
+
] }),
|
|
3731
|
+
/* @__PURE__ */ jsxs25("div", { className: "space-y-4", children: [
|
|
3732
|
+
/* @__PURE__ */ jsx29(ChangePasswordForm, {}),
|
|
3733
|
+
/* @__PURE__ */ jsx29(ChangeEmailForm, {}),
|
|
3734
|
+
/* @__PURE__ */ jsx29(ChangePhoneForm, {})
|
|
2758
3735
|
] })
|
|
2759
3736
|
] });
|
|
2760
3737
|
}
|
|
2761
3738
|
|
|
2762
3739
|
// src/components/skeletons/auth-form-skeleton.tsx
|
|
2763
|
-
import { Skeleton as
|
|
2764
|
-
import { jsx as
|
|
3740
|
+
import { Skeleton as Skeleton2 } from "@mesob/ui/components/skeleton";
|
|
3741
|
+
import { jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2765
3742
|
function AuthFormSkeleton() {
|
|
2766
|
-
return /* @__PURE__ */
|
|
2767
|
-
/* @__PURE__ */
|
|
2768
|
-
/* @__PURE__ */
|
|
2769
|
-
/* @__PURE__ */
|
|
3743
|
+
return /* @__PURE__ */ jsxs26("div", { className: "w-full max-w-md space-y-6 p-6", children: [
|
|
3744
|
+
/* @__PURE__ */ jsxs26("div", { className: "space-y-2 text-center", children: [
|
|
3745
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-8 w-48 mx-auto" }),
|
|
3746
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-4 w-64 mx-auto" })
|
|
2770
3747
|
] }),
|
|
2771
|
-
/* @__PURE__ */
|
|
2772
|
-
/* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
2774
|
-
/* @__PURE__ */
|
|
3748
|
+
/* @__PURE__ */ jsxs26("div", { className: "space-y-4", children: [
|
|
3749
|
+
/* @__PURE__ */ jsxs26("div", { className: "space-y-2", children: [
|
|
3750
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-4 w-24" }),
|
|
3751
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-10 w-full" })
|
|
2775
3752
|
] }),
|
|
2776
|
-
/* @__PURE__ */
|
|
2777
|
-
/* @__PURE__ */
|
|
2778
|
-
/* @__PURE__ */
|
|
3753
|
+
/* @__PURE__ */ jsxs26("div", { className: "space-y-2", children: [
|
|
3754
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-4 w-24" }),
|
|
3755
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-10 w-full" })
|
|
2779
3756
|
] }),
|
|
2780
|
-
/* @__PURE__ */
|
|
3757
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-10 w-full" })
|
|
2781
3758
|
] }),
|
|
2782
|
-
/* @__PURE__ */
|
|
2783
|
-
/* @__PURE__ */
|
|
2784
|
-
/* @__PURE__ */
|
|
3759
|
+
/* @__PURE__ */ jsxs26("div", { className: "space-y-2", children: [
|
|
3760
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-px w-full" }),
|
|
3761
|
+
/* @__PURE__ */ jsx30(Skeleton2, { className: "h-4 w-32 mx-auto" })
|
|
2785
3762
|
] })
|
|
2786
3763
|
] });
|
|
2787
3764
|
}
|
|
2788
3765
|
|
|
2789
|
-
// src/
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
}
|
|
3766
|
+
// src/components/skeletons/profile-skeleton.tsx
|
|
3767
|
+
import { Skeleton as Skeleton3 } from "@mesob/ui/components/skeleton";
|
|
3768
|
+
import { jsx as jsx31, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3769
|
+
function ProfileSkeleton() {
|
|
3770
|
+
return /* @__PURE__ */ jsxs27("div", { className: "w-full max-w-4xl space-y-8 p-6", children: [
|
|
3771
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-6", children: [
|
|
3772
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-24 w-24 rounded-full" }),
|
|
3773
|
+
/* @__PURE__ */ jsxs27("div", { className: "space-y-2 flex-1", children: [
|
|
3774
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-8 w-48" }),
|
|
3775
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-4 w-64" })
|
|
3776
|
+
] })
|
|
3777
|
+
] }),
|
|
3778
|
+
/* @__PURE__ */ jsx31("div", { className: "space-y-6", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs27("div", { className: "space-y-4", children: [
|
|
3779
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-6 w-32" }),
|
|
3780
|
+
/* @__PURE__ */ jsxs27("div", { className: "space-y-3", children: [
|
|
3781
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex justify-between items-center", children: [
|
|
3782
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-4 w-24" }),
|
|
3783
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-4 w-32" })
|
|
3784
|
+
] }),
|
|
3785
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex justify-between items-center", children: [
|
|
3786
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-4 w-24" }),
|
|
3787
|
+
/* @__PURE__ */ jsx31(Skeleton3, { className: "h-4 w-40" })
|
|
3788
|
+
] })
|
|
3789
|
+
] })
|
|
3790
|
+
] }, i)) })
|
|
3791
|
+
] });
|
|
3792
|
+
}
|
|
2799
3793
|
|
|
2800
3794
|
// src/hooks/use-session-cookie-name.ts
|
|
2801
3795
|
function useSessionCookieName() {
|
|
@@ -2803,32 +3797,36 @@ function useSessionCookieName() {
|
|
|
2803
3797
|
return getSessionCookieName(config);
|
|
2804
3798
|
}
|
|
2805
3799
|
export {
|
|
3800
|
+
Account,
|
|
2806
3801
|
AuthCard,
|
|
2807
3802
|
AuthErrorBoundary,
|
|
2808
3803
|
AuthFormSkeleton,
|
|
2809
3804
|
DataTable,
|
|
2810
3805
|
ErrorBoundary,
|
|
2811
|
-
|
|
3806
|
+
ForgotPassword,
|
|
2812
3807
|
MesobAuthProvider,
|
|
2813
|
-
|
|
2814
|
-
ProfilePage,
|
|
3808
|
+
Permissions,
|
|
2815
3809
|
ProfileSkeleton,
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3810
|
+
ResetPasswordForm,
|
|
3811
|
+
Roles,
|
|
3812
|
+
Security,
|
|
3813
|
+
Sessions,
|
|
3814
|
+
SignIn,
|
|
3815
|
+
SignUp,
|
|
2821
3816
|
TableSkeleton,
|
|
2822
|
-
|
|
2823
|
-
|
|
3817
|
+
Tenants,
|
|
3818
|
+
Users,
|
|
2824
3819
|
VerificationForm,
|
|
2825
|
-
|
|
2826
|
-
|
|
3820
|
+
VerifyEmail,
|
|
3821
|
+
VerifyPhone,
|
|
2827
3822
|
getSessionCookieName,
|
|
2828
3823
|
handleError,
|
|
3824
|
+
hasAuthCookie,
|
|
2829
3825
|
normalizePhone,
|
|
2830
3826
|
useApi,
|
|
2831
3827
|
useConfig,
|
|
3828
|
+
useHasAuthCookie,
|
|
3829
|
+
useHasAuthCookie as useIsAuthenticated,
|
|
2832
3830
|
useSession,
|
|
2833
3831
|
useSessionCookieName,
|
|
2834
3832
|
useTranslator
|