@mesob/auth-react 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/components/auth/auth-page-layout.d.ts +1 -3
  2. package/dist/components/auth/auth-page-layout.js +1 -17
  3. package/dist/components/auth/auth-page-layout.js.map +1 -1
  4. package/dist/components/auth/countdown.js +70 -9
  5. package/dist/components/auth/countdown.js.map +1 -1
  6. package/dist/components/auth/forgot-password.js +101 -35
  7. package/dist/components/auth/forgot-password.js.map +1 -1
  8. package/dist/components/auth/pages/forgot-password-page.d.ts +2 -13
  9. package/dist/components/auth/pages/forgot-password-page.js +198 -126
  10. package/dist/components/auth/pages/forgot-password-page.js.map +1 -1
  11. package/dist/components/auth/pages/reset-password-page.d.ts +1 -12
  12. package/dist/components/auth/pages/reset-password-page.js +288 -200
  13. package/dist/components/auth/pages/reset-password-page.js.map +1 -1
  14. package/dist/components/auth/pages/sign-in-page.d.ts +1 -12
  15. package/dist/components/auth/pages/sign-in-page.js +352 -230
  16. package/dist/components/auth/pages/sign-in-page.js.map +1 -1
  17. package/dist/components/auth/pages/sign-up-page.d.ts +1 -11
  18. package/dist/components/auth/pages/sign-up-page.js +310 -216
  19. package/dist/components/auth/pages/sign-up-page.js.map +1 -1
  20. package/dist/components/auth/pages/verify-email-page.d.ts +2 -12
  21. package/dist/components/auth/pages/verify-email-page.js +203 -135
  22. package/dist/components/auth/pages/verify-email-page.js.map +1 -1
  23. package/dist/components/auth/pages/verify-phone-page.d.ts +1 -11
  24. package/dist/components/auth/pages/verify-phone-page.js +206 -137
  25. package/dist/components/auth/pages/verify-phone-page.js.map +1 -1
  26. package/dist/components/auth/reset-password-form.d.ts +1 -1
  27. package/dist/components/auth/reset-password-form.js +188 -106
  28. package/dist/components/auth/reset-password-form.js.map +1 -1
  29. package/dist/components/auth/sign-in.d.ts +3 -3
  30. package/dist/components/auth/sign-in.js +228 -109
  31. package/dist/components/auth/sign-in.js.map +1 -1
  32. package/dist/components/auth/sign-up.js +210 -122
  33. package/dist/components/auth/sign-up.js.map +1 -1
  34. package/dist/components/auth/verification-form.d.ts +1 -1
  35. package/dist/components/auth/verification-form.js +101 -53
  36. package/dist/components/auth/verification-form.js.map +1 -1
  37. package/dist/components/error-boundary.d.ts +27 -0
  38. package/dist/components/error-boundary.js +49 -0
  39. package/dist/components/error-boundary.js.map +1 -0
  40. package/dist/components/iam/permissions/permissions-page.d.ts +5 -0
  41. package/dist/components/iam/permissions/permissions-page.js +201 -0
  42. package/dist/components/iam/permissions/permissions-page.js.map +1 -0
  43. package/dist/components/iam/roles/roles-page.d.ts +5 -0
  44. package/dist/components/iam/roles/roles-page.js +199 -0
  45. package/dist/components/iam/roles/roles-page.js.map +1 -0
  46. package/dist/components/iam/sessions/sessions-page.d.ts +5 -0
  47. package/dist/components/iam/sessions/sessions-page.js +202 -0
  48. package/dist/components/iam/sessions/sessions-page.js.map +1 -0
  49. package/dist/components/iam/tenants/tenants-page.d.ts +5 -0
  50. package/dist/components/iam/tenants/tenants-page.js +202 -0
  51. package/dist/components/iam/tenants/tenants-page.js.map +1 -0
  52. package/dist/components/iam/users/users-page.d.ts +5 -0
  53. package/dist/components/iam/users/users-page.js +211 -0
  54. package/dist/components/iam/users/users-page.js.map +1 -0
  55. package/dist/components/profile/profile-page.d.ts +8 -0
  56. package/dist/components/profile/profile-page.js +163 -0
  57. package/dist/components/profile/profile-page.js.map +1 -0
  58. package/dist/components/shared/data-table/data-table.d.ts +22 -0
  59. package/dist/components/shared/data-table/data-table.js +85 -0
  60. package/dist/components/shared/data-table/data-table.js.map +1 -0
  61. package/dist/components/skeletons/auth-form-skeleton.d.ts +5 -0
  62. package/dist/components/skeletons/auth-form-skeleton.js +32 -0
  63. package/dist/components/skeletons/auth-form-skeleton.js.map +1 -0
  64. package/dist/components/skeletons/profile-skeleton.d.ts +5 -0
  65. package/dist/components/skeletons/profile-skeleton.js +33 -0
  66. package/dist/components/skeletons/profile-skeleton.js.map +1 -0
  67. package/dist/components/skeletons/table-skeleton.d.ts +9 -0
  68. package/dist/components/skeletons/table-skeleton.js +39 -0
  69. package/dist/components/skeletons/table-skeleton.js.map +1 -0
  70. package/dist/handle-error-BqDMxnQZ.d.ts +8 -0
  71. package/dist/index.d.ts +75 -208
  72. package/dist/index.js +2091 -1057
  73. package/dist/index.js.map +1 -1
  74. package/package.json +9 -3
  75. package/dist/handle-error-H0iqQxJ5.d.ts +0 -6
@@ -1,40 +1,75 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/auth/pages/sign-up-page.tsx
4
- import { useTranslations as useTranslations2 } from "next-intl";
5
- import { useState as useState3 } from "react";
6
-
7
- // src/context/auth-provider.tsx
8
4
  import {
9
- createContext,
10
- useCallback,
11
- useContext,
12
- useEffect,
13
- useState
14
- } from "react";
5
+ Alert,
6
+ AlertDescription,
7
+ AlertTitle
8
+ } from "@mesob/ui/components/alert";
9
+ import { toast } from "@mesob/ui/components/sonner";
10
+ import { IconAlertCircle } from "@tabler/icons-react";
11
+ import { useEffect as useEffect3, useState as useState3 } from "react";
12
+
13
+ // src/lib/translations.ts
14
+ function createTranslator(messages, namespace) {
15
+ return (key, params) => {
16
+ const fullKey = namespace ? `${namespace}.${key}` : key;
17
+ const keys = fullKey.split(".");
18
+ let value = messages;
19
+ for (const k of keys) {
20
+ if (value && typeof value === "object" && value !== null) {
21
+ value = value[k];
22
+ } else {
23
+ return fullKey;
24
+ }
25
+ }
26
+ if (typeof value !== "string") {
27
+ return fullKey;
28
+ }
29
+ if (params) {
30
+ return value.replace(
31
+ /\{(\w+)\}/g,
32
+ (_, param) => String(params[param] ?? `{${param}}`)
33
+ );
34
+ }
35
+ return value;
36
+ };
37
+ }
38
+
39
+ // src/provider.tsx
40
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
41
+ import { deepmerge } from "deepmerge-ts";
42
+ import createFetchClient from "openapi-fetch";
43
+ import createClient from "openapi-react-query";
44
+ import { createContext, useContext, useEffect, useState } from "react";
15
45
  import { jsx } from "react/jsx-runtime";
16
- var AuthContext = createContext(null);
17
- var useAuth = () => {
18
- const context = useContext(AuthContext);
46
+ var SessionContext = createContext(null);
47
+ var ApiContext = createContext(null);
48
+ var ConfigContext = createContext(null);
49
+ var queryClient = new QueryClient({
50
+ defaultOptions: {
51
+ queries: {
52
+ staleTime: 1e3 * 60 * 5,
53
+ gcTime: 1e3 * 60 * 10,
54
+ retry: 1,
55
+ refetchOnWindowFocus: false
56
+ }
57
+ }
58
+ });
59
+ function useApi() {
60
+ const context = useContext(ApiContext);
19
61
  if (!context) {
20
- throw new Error("useAuth must be used within AuthProvider");
62
+ throw new Error("useApi must be used within MesobAuthProvider");
21
63
  }
22
64
  return context;
23
- };
24
-
25
- // src/client.ts
26
- var AuthError = class extends Error {
27
- code;
28
- status;
29
- details;
30
- constructor(message, code, status, details) {
31
- super(message);
32
- this.name = "AuthError";
33
- this.code = code;
34
- this.status = status;
35
- this.details = details;
65
+ }
66
+ function useConfig() {
67
+ const context = useContext(ConfigContext);
68
+ if (!context) {
69
+ throw new Error("useConfig must be used within MesobAuthProvider");
36
70
  }
37
- };
71
+ return context;
72
+ }
38
73
 
39
74
  // src/constants/auth.error.codes.ts
40
75
  var AUTH_ERROR_MAPPING = {
@@ -86,71 +121,67 @@ var AUTH_ERROR_MAPPING = {
86
121
  var validCodes = Object.keys(AUTH_ERROR_MAPPING);
87
122
 
88
123
  // src/utils/handle-error.ts
89
- var handleError = (err, setError, t) => {
90
- if (err instanceof AuthError) {
91
- let errorCode = "";
92
- if (err.code && validCodes.includes(err.code)) {
93
- errorCode = err.code;
94
- } else if (err.message) {
95
- const messageUpper = err.message.toUpperCase().trim();
96
- if (validCodes.includes(messageUpper)) {
97
- errorCode = messageUpper;
98
- }
99
- }
100
- if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
101
- const mapping = AUTH_ERROR_MAPPING[errorCode];
102
- setError({
103
- title: mapping.title,
104
- description: mapping.description
105
- });
106
- return;
124
+ function isAuthError(err) {
125
+ return typeof err === "object" && err !== null && "message" in err && typeof err.message === "string";
126
+ }
127
+ function extractErrorCode(err) {
128
+ if (err.code && validCodes.includes(err.code)) {
129
+ return err.code;
130
+ }
131
+ if (err.message) {
132
+ const messageUpper = err.message.toUpperCase().trim();
133
+ if (validCodes.includes(messageUpper)) {
134
+ return messageUpper;
107
135
  }
136
+ }
137
+ return "";
138
+ }
139
+ function handleAuthError(err, setError, t) {
140
+ const errorCode = extractErrorCode(err);
141
+ if (errorCode && AUTH_ERROR_MAPPING[errorCode]) {
142
+ const mapping = AUTH_ERROR_MAPPING[errorCode];
108
143
  setError({
109
- title: t("errors.fallback"),
110
- // or 'Error'
111
- description: err.message || t("errors.fallback")
144
+ title: mapping.title,
145
+ description: mapping.description
112
146
  });
147
+ return;
148
+ }
149
+ setError({
150
+ title: t("errors.fallback"),
151
+ description: err.message || t("errors.fallback")
152
+ });
153
+ }
154
+ function handleGenericError(err, setError, t) {
155
+ const message = err instanceof Error ? err.message : t("errors.fallback");
156
+ setError({
157
+ title: "Error",
158
+ description: message
159
+ });
160
+ }
161
+ var handleError = (err, setError, t) => {
162
+ if (isAuthError(err)) {
163
+ handleAuthError(err, setError, t);
113
164
  } else {
114
- const message = err instanceof Error ? err.message : t("errors.fallback");
115
- setError({
116
- title: "Error",
117
- description: message
118
- });
165
+ handleGenericError(err, setError, t);
119
166
  }
120
167
  };
121
168
 
122
169
  // src/components/auth/auth-page-layout.tsx
123
- import {
124
- Alert,
125
- AlertDescription,
126
- AlertTitle
127
- } from "@mesob/ui/components/alert";
128
- import { IconAlertCircle } from "@tabler/icons-react";
129
170
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
130
171
  var AuthPageLayout = ({
131
172
  title,
132
173
  description,
133
174
  children,
134
- error,
135
175
  footer,
136
176
  logoImage
137
177
  }) => {
138
- const errorContent = error ? (
139
- // biome-ignore lint/style/noNestedTernary: <explanation>
140
- typeof error === "string" ? { title: "Error", description: error } : error
141
- ) : null;
142
178
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
143
- /* @__PURE__ */ jsx2("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx2("img", { src: logoImage || "", alt: "Jiret", width: 42, height: 42 }) }),
179
+ /* @__PURE__ */ jsx2("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx2("img", { src: logoImage || "", alt: "Mesob", width: 42, height: 42 }) }),
144
180
  /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
145
181
  /* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
146
182
  description && /* @__PURE__ */ jsx2("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
147
183
  ] }),
148
184
  children,
149
- errorContent && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
150
- /* @__PURE__ */ jsx2(IconAlertCircle, { className: "h-4 w-4" }),
151
- /* @__PURE__ */ jsx2(AlertTitle, { children: errorContent.title }),
152
- /* @__PURE__ */ jsx2(AlertDescription, { children: errorContent.description })
153
- ] }),
154
185
  /* @__PURE__ */ jsx2("div", { className: "mt-2 w-full", children: footer && /* @__PURE__ */ jsx2("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
155
186
  ] });
156
187
  };
@@ -159,54 +190,56 @@ var AuthPageLayout = ({
159
190
  import { zodResolver } from "@hookform/resolvers/zod";
160
191
  import { Button } from "@mesob/ui/components/button";
161
192
  import {
162
- Form,
163
- FormControl,
164
- FormField,
165
- FormItem,
166
- FormLabel,
167
- FormMessage
168
- } from "@mesob/ui/components/form";
193
+ Field,
194
+ FieldError,
195
+ FieldGroup,
196
+ FieldLabel
197
+ } from "@mesob/ui/components/field";
169
198
  import { Input } from "@mesob/ui/components/input";
170
199
  import { IconEye, IconEyeOff } from "@tabler/icons-react";
171
- import { useTranslations } from "next-intl";
172
- import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
173
- import { useForm } from "react-hook-form";
200
+ import { useEffect as useEffect2, useState as useState2 } from "react";
201
+ import { Controller, useForm } from "react-hook-form";
174
202
  import { z } from "zod";
203
+
204
+ // src/hooks/use-translator.ts
205
+ function useTranslator(namespace) {
206
+ const { config } = useConfig();
207
+ return createTranslator(config.messages || {}, namespace);
208
+ }
209
+
210
+ // src/components/auth/sign-up.tsx
175
211
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
176
212
  var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
213
+ var signUpSchema = (t) => z.object({
214
+ fullName: z.string().min(1, t("errors.fullNameRequired")),
215
+ identifier: z.string().min(1, t("errors.contactRequired")).refine(
216
+ (val) => {
217
+ if (!val) {
218
+ return false;
219
+ }
220
+ return val.includes("@") || isPhone(val);
221
+ },
222
+ {
223
+ message: t("errors.invalidEmailOrPhone")
224
+ }
225
+ ),
226
+ password: z.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
227
+ confirmPassword: z.string()
228
+ }).refine((data) => data.password === data.confirmPassword, {
229
+ message: t("errors.passwordsMismatch"),
230
+ path: ["confirmPassword"]
231
+ });
177
232
  var SignUp = ({
178
233
  onSubmit,
179
234
  isLoading = false,
180
235
  initialIdentifier
181
236
  }) => {
182
- const t = useTranslations("Auth.signUp");
237
+ const t = useTranslator("Auth.signUp");
183
238
  const hasInitialIdentifier = !!initialIdentifier;
184
239
  const [showPassword, setShowPassword] = useState2(false);
185
240
  const [showConfirmPassword, setShowConfirmPassword] = useState2(false);
186
- const signUpSchema = useMemo(
187
- () => z.object({
188
- fullName: z.string().min(1, t("errors.fullNameRequired")),
189
- identifier: z.string().min(1, t("errors.contactRequired")).refine(
190
- (val) => {
191
- if (!val) {
192
- return false;
193
- }
194
- return val.includes("@") || isPhone(val);
195
- },
196
- {
197
- message: t("errors.invalidEmailOrPhone")
198
- }
199
- ),
200
- password: z.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
201
- confirmPassword: z.string()
202
- }).refine((data) => data.password === data.confirmPassword, {
203
- message: t("errors.passwordsMismatch"),
204
- path: ["confirmPassword"]
205
- }),
206
- [t]
207
- );
208
241
  const form = useForm({
209
- resolver: zodResolver(signUpSchema),
242
+ resolver: zodResolver(signUpSchema(t)),
210
243
  defaultValues: {
211
244
  fullName: "",
212
245
  identifier: initialIdentifier || "",
@@ -232,101 +265,133 @@ var SignUp = ({
232
265
  return t("form.phoneLabel");
233
266
  };
234
267
  const identifierLabel = getIdentifierLabel();
235
- return /* @__PURE__ */ jsx3(Form, { ...form, children: /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
236
- /* @__PURE__ */ jsx3(
237
- FormField,
238
- {
239
- control: form.control,
240
- name: "fullName",
241
- render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
242
- /* @__PURE__ */ jsx3(FormLabel, { children: t("form.fullNameLabel") }),
243
- /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsx3(Input, { placeholder: t("form.fullNamePlaceholder"), ...field }) }),
244
- /* @__PURE__ */ jsx3(FormMessage, {})
245
- ] })
246
- }
247
- ),
248
- /* @__PURE__ */ jsx3(
249
- FormField,
250
- {
251
- control: form.control,
252
- name: "identifier",
253
- render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
254
- /* @__PURE__ */ jsx3(FormLabel, { className: hasInitialIdentifier ? "block" : void 0, children: identifierLabel }),
255
- /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsx3(
256
- Input,
257
- {
258
- type: field.value.includes("@") ? "email" : "tel",
259
- placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
260
- ...field,
261
- disabled: hasInitialIdentifier
262
- }
263
- ) }),
264
- /* @__PURE__ */ jsx3(FormMessage, {})
265
- ] })
266
- }
267
- ),
268
- /* @__PURE__ */ jsx3(
269
- FormField,
270
- {
271
- control: form.control,
272
- name: "password",
273
- render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
274
- /* @__PURE__ */ jsx3(FormLabel, { children: t("form.passwordLabel") }),
275
- /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
268
+ return /* @__PURE__ */ jsxs2("form", { id: "sign-up-form", onSubmit: handleSubmit, children: [
269
+ /* @__PURE__ */ jsxs2(FieldGroup, { children: [
270
+ /* @__PURE__ */ jsx3(
271
+ Controller,
272
+ {
273
+ name: "fullName",
274
+ control: form.control,
275
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
276
+ /* @__PURE__ */ jsx3(FieldLabel, { htmlFor: "sign-up-fullName", children: t("form.fullNameLabel") }),
276
277
  /* @__PURE__ */ jsx3(
277
278
  Input,
278
279
  {
279
- type: showPassword ? "text" : "password",
280
- placeholder: t("form.passwordPlaceholder"),
281
- ...field
280
+ ...field,
281
+ id: "sign-up-fullName",
282
+ placeholder: t("form.fullNamePlaceholder"),
283
+ "aria-invalid": fieldState.invalid
282
284
  }
283
285
  ),
286
+ fieldState.invalid && /* @__PURE__ */ jsx3(FieldError, { errors: [fieldState.error] })
287
+ ] })
288
+ }
289
+ ),
290
+ /* @__PURE__ */ jsx3(
291
+ Controller,
292
+ {
293
+ name: "identifier",
294
+ control: form.control,
295
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
284
296
  /* @__PURE__ */ jsx3(
285
- "button",
297
+ FieldLabel,
286
298
  {
287
- type: "button",
288
- onClick: () => setShowPassword(!showPassword),
289
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
290
- children: showPassword ? /* @__PURE__ */ jsx3(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(IconEye, { className: "h-4 w-4" })
299
+ htmlFor: "sign-up-identifier",
300
+ className: hasInitialIdentifier ? "block" : void 0,
301
+ children: identifierLabel
291
302
  }
292
- )
293
- ] }) }),
294
- /* @__PURE__ */ jsx3(FormMessage, {})
295
- ] })
296
- }
297
- ),
298
- /* @__PURE__ */ jsx3(
299
- FormField,
300
- {
301
- control: form.control,
302
- name: "confirmPassword",
303
- render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
304
- /* @__PURE__ */ jsx3(FormLabel, { children: t("form.confirmPasswordLabel") }),
305
- /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
303
+ ),
306
304
  /* @__PURE__ */ jsx3(
307
305
  Input,
308
306
  {
309
- type: showConfirmPassword ? "text" : "password",
310
- placeholder: t("form.passwordPlaceholder"),
311
- ...field
307
+ ...field,
308
+ id: "sign-up-identifier",
309
+ type: field.value.includes("@") ? "email" : "tel",
310
+ placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
311
+ disabled: hasInitialIdentifier,
312
+ "aria-invalid": fieldState.invalid
312
313
  }
313
314
  ),
314
- /* @__PURE__ */ jsx3(
315
- "button",
316
- {
317
- type: "button",
318
- onClick: () => setShowConfirmPassword(!showConfirmPassword),
319
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
320
- children: showConfirmPassword ? /* @__PURE__ */ jsx3(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(IconEye, { className: "h-4 w-4" })
321
- }
322
- )
323
- ] }) }),
324
- /* @__PURE__ */ jsx3(FormMessage, {})
325
- ] })
315
+ fieldState.invalid && /* @__PURE__ */ jsx3(FieldError, { errors: [fieldState.error] })
316
+ ] })
317
+ }
318
+ ),
319
+ /* @__PURE__ */ jsx3(
320
+ Controller,
321
+ {
322
+ name: "password",
323
+ control: form.control,
324
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
325
+ /* @__PURE__ */ jsx3(FieldLabel, { htmlFor: "sign-up-password", children: t("form.passwordLabel") }),
326
+ /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
327
+ /* @__PURE__ */ jsx3(
328
+ Input,
329
+ {
330
+ ...field,
331
+ id: "sign-up-password",
332
+ type: showPassword ? "text" : "password",
333
+ placeholder: t("form.passwordPlaceholder"),
334
+ "aria-invalid": fieldState.invalid
335
+ }
336
+ ),
337
+ /* @__PURE__ */ jsx3(
338
+ "button",
339
+ {
340
+ type: "button",
341
+ onClick: () => setShowPassword(!showPassword),
342
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
343
+ children: showPassword ? /* @__PURE__ */ jsx3(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(IconEye, { className: "h-4 w-4" })
344
+ }
345
+ )
346
+ ] }),
347
+ fieldState.invalid && /* @__PURE__ */ jsx3(FieldError, { errors: [fieldState.error] })
348
+ ] })
349
+ }
350
+ ),
351
+ /* @__PURE__ */ jsx3(
352
+ Controller,
353
+ {
354
+ name: "confirmPassword",
355
+ control: form.control,
356
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsxs2(Field, { "data-invalid": fieldState.invalid, children: [
357
+ /* @__PURE__ */ jsx3(FieldLabel, { htmlFor: "sign-up-confirmPassword", children: t("form.confirmPasswordLabel") }),
358
+ /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
359
+ /* @__PURE__ */ jsx3(
360
+ Input,
361
+ {
362
+ ...field,
363
+ id: "sign-up-confirmPassword",
364
+ type: showConfirmPassword ? "text" : "password",
365
+ placeholder: t("form.passwordPlaceholder"),
366
+ "aria-invalid": fieldState.invalid
367
+ }
368
+ ),
369
+ /* @__PURE__ */ jsx3(
370
+ "button",
371
+ {
372
+ type: "button",
373
+ onClick: () => setShowConfirmPassword(!showConfirmPassword),
374
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
375
+ children: showConfirmPassword ? /* @__PURE__ */ jsx3(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(IconEye, { className: "h-4 w-4" })
376
+ }
377
+ )
378
+ ] }),
379
+ fieldState.invalid && /* @__PURE__ */ jsx3(FieldError, { errors: [fieldState.error] })
380
+ ] })
381
+ }
382
+ )
383
+ ] }),
384
+ /* @__PURE__ */ jsx3("div", { className: "mt-4", children: /* @__PURE__ */ jsx3(
385
+ Button,
386
+ {
387
+ type: "submit",
388
+ form: "sign-up-form",
389
+ className: "w-full",
390
+ disabled: isLoading,
391
+ children: isLoading ? t("form.submitting") : t("form.submit")
326
392
  }
327
- ),
328
- /* @__PURE__ */ jsx3(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.submit") })
329
- ] }) });
393
+ ) })
394
+ ] });
330
395
  };
331
396
 
332
397
  // src/components/auth/pages/sign-up-page.tsx
@@ -334,33 +399,48 @@ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
334
399
  var isPhone2 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
335
400
  var SignUpPage = ({
336
401
  redirectUrl,
337
- onNavigate,
338
- linkComponent: Link,
339
- links,
340
- initialIdentifier,
341
- logoImage
342
- }) => {
343
- const t = useTranslations2("Auth.signUp");
344
- const { client, setAuth } = useAuth();
402
+ initialIdentifier
403
+ } = {}) => {
404
+ const { hooks, setAuth } = useApi();
405
+ const { config } = useConfig();
406
+ const t = createTranslator(config.messages || {}, "Auth.signUp");
345
407
  const [isLoading, setIsLoading] = useState3(false);
346
408
  const [error, setError] = useState3(null);
347
- const signInLink = links?.signIn || "/auth/sign-in";
409
+ const signUpMutation = hooks.useMutation("post", "/sign-up");
410
+ const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
411
+ const Link = config.navigation?.linkComponent;
412
+ const onNavigate = config.navigation?.onNavigate || ((path) => {
413
+ if (typeof window !== "undefined") {
414
+ window.location.href = path;
415
+ }
416
+ });
417
+ const logoImage = config.ui.logoImage;
418
+ const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
419
+ useEffect3(() => {
420
+ if (error) {
421
+ toast.error(error.title || "Error", {
422
+ description: error.description
423
+ });
424
+ }
425
+ }, [error]);
348
426
  const handleSubmit = async (values) => {
349
427
  setIsLoading(true);
350
428
  setError(null);
351
429
  try {
352
430
  const identifier = values.identifier;
353
431
  const usingPhone = isPhone2(identifier);
354
- const res = usingPhone ? await client.signUpWithPhone({
355
- phone: identifier,
356
- password: values.password,
357
- fullName: values.fullName,
358
- handle: values.handle
359
- }) : await client.signUpWithEmail({
360
- email: identifier,
361
- password: values.password,
362
- fullName: values.fullName,
363
- handle: values.handle
432
+ const res = await signUpMutation.mutateAsync({
433
+ body: usingPhone ? {
434
+ phone: identifier,
435
+ password: values.password,
436
+ fullName: values.fullName,
437
+ handle: values.handle
438
+ } : {
439
+ email: identifier,
440
+ password: values.password,
441
+ fullName: values.fullName,
442
+ handle: values.handle
443
+ }
364
444
  });
365
445
  if ("verificationId" in res && res.verificationId) {
366
446
  if (usingPhone) {
@@ -377,19 +457,26 @@ var SignUpPage = ({
377
457
  if ("user" in res && "session" in res) {
378
458
  setAuth(res);
379
459
  }
380
- onNavigate(redirectUrl || "/");
460
+ onNavigate(defaultRedirect);
381
461
  } catch (err) {
382
462
  handleError(err, setError, t);
383
463
  } finally {
384
464
  setIsLoading(false);
385
465
  }
386
466
  };
387
- return /* @__PURE__ */ jsx4(
467
+ let errorContent = null;
468
+ if (error) {
469
+ if (typeof error === "string") {
470
+ errorContent = { title: "Error", description: error };
471
+ } else {
472
+ errorContent = error;
473
+ }
474
+ }
475
+ return /* @__PURE__ */ jsxs3(
388
476
  AuthPageLayout,
389
477
  {
390
478
  title: t("title"),
391
479
  description: t("description"),
392
- error,
393
480
  logoImage,
394
481
  footer: /* @__PURE__ */ jsxs3("p", { children: [
395
482
  t("footer.hasAccount"),
@@ -407,14 +494,21 @@ var SignUpPage = ({
407
494
  }
408
495
  )
409
496
  ] }),
410
- children: /* @__PURE__ */ jsx4(
411
- SignUp,
412
- {
413
- onSubmit: handleSubmit,
414
- isLoading,
415
- initialIdentifier
416
- }
417
- )
497
+ children: [
498
+ /* @__PURE__ */ jsx4(
499
+ SignUp,
500
+ {
501
+ onSubmit: handleSubmit,
502
+ isLoading: isLoading || signUpMutation.isPending,
503
+ initialIdentifier
504
+ }
505
+ ),
506
+ errorContent && /* @__PURE__ */ jsxs3(Alert, { variant: "destructive", className: "mt-4", children: [
507
+ /* @__PURE__ */ jsx4(IconAlertCircle, { className: "h-4 w-4" }),
508
+ /* @__PURE__ */ jsx4(AlertTitle, { children: errorContent.title }),
509
+ /* @__PURE__ */ jsx4(AlertDescription, { children: errorContent.description })
510
+ ] })
511
+ ]
418
512
  }
419
513
  );
420
514
  };