@mesob/auth-react 0.3.4 → 0.4.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-layout.d.ts +1 -1
- package/dist/components/auth/auth-layout.js +10 -2
- package/dist/components/auth/auth-layout.js.map +1 -1
- package/dist/components/auth/countdown.js +8 -6
- package/dist/components/auth/countdown.js.map +1 -1
- package/dist/components/auth/forgot-password.js +21 -19
- package/dist/components/auth/forgot-password.js.map +1 -1
- package/dist/components/auth/reset-password-form.js +22 -21
- package/dist/components/auth/reset-password-form.js.map +1 -1
- package/dist/components/auth/set-password.d.ts +9 -0
- package/dist/components/auth/set-password.js +527 -0
- package/dist/components/auth/set-password.js.map +1 -0
- package/dist/components/auth/sign-in.js +45 -26
- package/dist/components/auth/sign-in.js.map +1 -1
- package/dist/components/auth/sign-up.js +25 -29
- package/dist/components/auth/sign-up.js.map +1 -1
- package/dist/components/auth/verification-form.js +24 -27
- package/dist/components/auth/verification-form.js.map +1 -1
- package/dist/components/auth/verify-email.js +40 -31
- package/dist/components/auth/verify-email.js.map +1 -1
- package/dist/components/auth/verify-phone.js +40 -31
- package/dist/components/auth/verify-phone.js.map +1 -1
- package/dist/components/authorization/deny.d.ts +11 -0
- package/dist/components/authorization/deny.js +52 -0
- package/dist/components/authorization/deny.js.map +1 -0
- package/dist/components/authorization/grant.d.ts +12 -0
- package/dist/components/authorization/grant.js +57 -0
- package/dist/components/authorization/grant.js.map +1 -0
- package/dist/components/iam/permission-selector.d.ts +19 -0
- package/dist/components/iam/permission-selector.js +122 -0
- package/dist/components/iam/permission-selector.js.map +1 -0
- package/dist/components/iam/permissions.js +21 -33
- package/dist/components/iam/permissions.js.map +1 -1
- package/dist/components/iam/role-detail-layout.d.ts +11 -0
- package/dist/components/iam/role-detail-layout.js +137 -0
- package/dist/components/iam/role-detail-layout.js.map +1 -0
- package/dist/components/iam/role-detail-page.d.ts +9 -0
- package/dist/components/iam/role-detail-page.js +229 -0
- package/dist/components/iam/role-detail-page.js.map +1 -0
- package/dist/components/iam/role-permissions-page.d.ts +8 -0
- package/dist/components/iam/role-permissions-page.js +397 -0
- package/dist/components/iam/role-permissions-page.js.map +1 -0
- package/dist/components/iam/roles.js +20 -10
- package/dist/components/iam/roles.js.map +1 -1
- package/dist/components/iam/tenants.js +9 -2
- package/dist/components/iam/tenants.js.map +1 -1
- package/dist/components/iam/users.js +10 -9
- package/dist/components/iam/users.js.map +1 -1
- package/dist/components/profile/account.js +110 -19
- package/dist/components/profile/account.js.map +1 -1
- package/dist/components/profile/change-email-form.js +26 -29
- package/dist/components/profile/change-email-form.js.map +1 -1
- package/dist/components/profile/change-phone-form.js +26 -29
- package/dist/components/profile/change-phone-form.js.map +1 -1
- package/dist/components/profile/change-profile.d.ts +2 -1
- package/dist/components/profile/change-profile.js +16 -8
- package/dist/components/profile/change-profile.js.map +1 -1
- package/dist/components/profile/otp-verification-modal.js +24 -27
- package/dist/components/profile/otp-verification-modal.js.map +1 -1
- package/dist/components/profile/security.js +88 -57
- package/dist/components/profile/security.js.map +1 -1
- package/dist/components/profile/verify-change-email-form.js +24 -27
- package/dist/components/profile/verify-change-email-form.js.map +1 -1
- package/dist/components/profile/verify-change-phone-form.js +24 -27
- package/dist/components/profile/verify-change-phone-form.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +1897 -821
- package/dist/index.js.map +1 -1
- package/dist/pages/auth/forgot-password.d.ts +7 -0
- package/dist/pages/auth/forgot-password.js +784 -0
- package/dist/pages/auth/forgot-password.js.map +1 -0
- package/dist/pages/auth/layout.d.ts +8 -0
- package/dist/pages/auth/layout.js +562 -0
- package/dist/pages/auth/layout.js.map +1 -0
- package/dist/pages/auth/reset-password.d.ts +10 -0
- package/dist/pages/auth/reset-password.js +913 -0
- package/dist/pages/auth/reset-password.js.map +1 -0
- package/dist/pages/auth/set-password.d.ts +10 -0
- package/dist/pages/auth/set-password.js +946 -0
- package/dist/pages/auth/set-password.js.map +1 -0
- package/dist/pages/auth/sign-in.d.ts +10 -0
- package/dist/pages/auth/sign-in.js +984 -0
- package/dist/pages/auth/sign-in.js.map +1 -0
- package/dist/pages/auth/sign-up.d.ts +10 -0
- package/dist/pages/auth/sign-up.js +940 -0
- package/dist/pages/auth/sign-up.js.map +1 -0
- package/dist/pages/auth/verify-email.d.ts +10 -0
- package/dist/pages/auth/verify-email.js +950 -0
- package/dist/pages/auth/verify-email.js.map +1 -0
- package/dist/pages/auth/verify-phone.d.ts +10 -0
- package/dist/pages/auth/verify-phone.js +964 -0
- package/dist/pages/auth/verify-phone.js.map +1 -0
- package/dist/pages/iam/permissions.d.ts +5 -0
- package/dist/pages/iam/permissions.js +308 -0
- package/dist/pages/iam/permissions.js.map +1 -0
- package/dist/pages/iam/role-detail-layout.d.ts +12 -0
- package/dist/pages/iam/role-detail-layout.js +145 -0
- package/dist/pages/iam/role-detail-layout.js.map +1 -0
- package/dist/pages/iam/role-detail.d.ts +12 -0
- package/dist/pages/iam/role-detail.js +241 -0
- package/dist/pages/iam/role-detail.js.map +1 -0
- package/dist/pages/iam/role-permissions.d.ts +12 -0
- package/dist/pages/iam/role-permissions.js +409 -0
- package/dist/pages/iam/role-permissions.js.map +1 -0
- package/dist/pages/iam/role-users.d.ts +12 -0
- package/dist/pages/iam/role-users.js +825 -0
- package/dist/pages/iam/role-users.js.map +1 -0
- package/dist/pages/iam/roles.d.ts +5 -0
- package/dist/pages/iam/roles.js +684 -0
- package/dist/pages/iam/roles.js.map +1 -0
- package/dist/pages/iam/sessions.d.ts +5 -0
- package/dist/pages/iam/sessions.js +315 -0
- package/dist/pages/iam/sessions.js.map +1 -0
- package/dist/pages/iam/tenant-detail.d.ts +10 -0
- package/dist/pages/iam/tenant-detail.js +186 -0
- package/dist/pages/iam/tenant-detail.js.map +1 -0
- package/dist/pages/iam/tenants.d.ts +5 -0
- package/dist/pages/iam/tenants.js +610 -0
- package/dist/pages/iam/tenants.js.map +1 -0
- package/dist/pages/iam/user-activity.d.ts +10 -0
- package/dist/pages/iam/user-activity.js +850 -0
- package/dist/pages/iam/user-activity.js.map +1 -0
- package/dist/pages/iam/user-detail-layout.d.ts +12 -0
- package/dist/pages/iam/user-detail-layout.js +106 -0
- package/dist/pages/iam/user-detail-layout.js.map +1 -0
- package/dist/pages/iam/user-detail.d.ts +10 -0
- package/dist/pages/iam/user-detail.js +102 -0
- package/dist/pages/iam/user-detail.js.map +1 -0
- package/dist/pages/iam/users.d.ts +5 -0
- package/dist/pages/iam/users.js +1275 -0
- package/dist/pages/iam/users.js.map +1 -0
- package/dist/pages/profile/account.d.ts +5 -0
- package/dist/pages/profile/account.js +182 -0
- package/dist/pages/profile/account.js.map +1 -0
- package/dist/pages/profile/layout.d.ts +8 -0
- package/dist/pages/profile/layout.js +133 -0
- package/dist/pages/profile/layout.js.map +1 -0
- package/dist/pages/profile/security.d.ts +5 -0
- package/dist/pages/profile/security.js +1539 -0
- package/dist/pages/profile/security.js.map +1 -0
- package/dist/{types-vcfvnAzQ.d.ts → types-g9QcNRxT.d.ts} +13 -7
- package/package.json +102 -3
package/dist/index.js
CHANGED
|
@@ -20,8 +20,7 @@ import {
|
|
|
20
20
|
FormItem,
|
|
21
21
|
FormLabel,
|
|
22
22
|
FormMessage,
|
|
23
|
-
Input
|
|
24
|
-
Spinner
|
|
23
|
+
Input
|
|
25
24
|
} from "@mesob/ui/components";
|
|
26
25
|
import { useMesob as useMesob2 } from "@mesob/ui/providers";
|
|
27
26
|
import { IconAlertCircle } from "@tabler/icons-react";
|
|
@@ -367,7 +366,11 @@ var AUTH_ERROR_MAPPING = {
|
|
|
367
366
|
},
|
|
368
367
|
HAS_NO_PASSWORD: {
|
|
369
368
|
title: "No Password Set",
|
|
370
|
-
description: "Your account does not have a password
|
|
369
|
+
description: "Your account does not have a password yet. Continue to set a password before signing in."
|
|
370
|
+
},
|
|
371
|
+
PASSWORD_ALREADY_SET: {
|
|
372
|
+
title: "Password Already Set",
|
|
373
|
+
description: "This account already has a password. Use the normal sign-in form instead."
|
|
371
374
|
}
|
|
372
375
|
};
|
|
373
376
|
var validCodes = Object.keys(AUTH_ERROR_MAPPING);
|
|
@@ -440,13 +443,21 @@ var AuthLayout = ({
|
|
|
440
443
|
logoImage
|
|
441
444
|
}) => {
|
|
442
445
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
443
|
-
/* @__PURE__ */ jsx3("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx3(
|
|
446
|
+
/* @__PURE__ */ jsx3("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx3(
|
|
447
|
+
"img",
|
|
448
|
+
{
|
|
449
|
+
src: logoImage || "",
|
|
450
|
+
alt: title,
|
|
451
|
+
width: 42,
|
|
452
|
+
height: 42
|
|
453
|
+
}
|
|
454
|
+
) }),
|
|
444
455
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
445
456
|
/* @__PURE__ */ jsx3("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
446
457
|
description && /* @__PURE__ */ jsx3("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
447
458
|
] }),
|
|
448
459
|
children,
|
|
449
|
-
/* @__PURE__ */ jsx3("div", { className: "mt-2 w-full", children:
|
|
460
|
+
footer && /* @__PURE__ */ jsx3("div", { className: "mt-2 w-full", children: /* @__PURE__ */ jsx3("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
|
|
450
461
|
] });
|
|
451
462
|
};
|
|
452
463
|
|
|
@@ -517,7 +528,7 @@ var ForgotPassword = () => {
|
|
|
517
528
|
return /* @__PURE__ */ jsxs2(
|
|
518
529
|
AuthLayout,
|
|
519
530
|
{
|
|
520
|
-
title:
|
|
531
|
+
title: config.ui.name,
|
|
521
532
|
description: t("description"),
|
|
522
533
|
logoImage,
|
|
523
534
|
footer: Link ? /* @__PURE__ */ jsx4(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.backToSignIn") }) : /* @__PURE__ */ jsx4(
|
|
@@ -547,29 +558,20 @@ var ForgotPassword = () => {
|
|
|
547
558
|
name: "account",
|
|
548
559
|
render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
|
|
549
560
|
/* @__PURE__ */ jsx4(FormLabel, { children: t("form.accountLabel") }),
|
|
550
|
-
/* @__PURE__ */ jsx4(FormControl, { children: /* @__PURE__ */ jsx4(
|
|
551
|
-
Input,
|
|
552
|
-
{
|
|
553
|
-
...field,
|
|
554
|
-
type: "text",
|
|
555
|
-
placeholder: t("form.accountPlaceholder")
|
|
556
|
-
}
|
|
557
|
-
) }),
|
|
561
|
+
/* @__PURE__ */ jsx4(FormControl, { children: /* @__PURE__ */ jsx4(Input, { ...field, type: "text" }) }),
|
|
558
562
|
/* @__PURE__ */ jsx4(FormMessage, {})
|
|
559
563
|
] })
|
|
560
564
|
}
|
|
561
565
|
),
|
|
562
|
-
/* @__PURE__ */
|
|
566
|
+
/* @__PURE__ */ jsx4(
|
|
563
567
|
Button,
|
|
564
568
|
{
|
|
565
569
|
type: "submit",
|
|
566
570
|
form: "forgot-password-form",
|
|
567
571
|
className: "w-full",
|
|
568
572
|
disabled: isLoading || forgotPasswordMutation.isPending,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
isLoading || forgotPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
572
|
-
]
|
|
573
|
+
loading: isLoading || forgotPasswordMutation.isPending,
|
|
574
|
+
children: isLoading || forgotPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
573
575
|
}
|
|
574
576
|
)
|
|
575
577
|
]
|
|
@@ -602,7 +604,6 @@ import {
|
|
|
602
604
|
InputOTP,
|
|
603
605
|
InputOTPGroup,
|
|
604
606
|
InputOTPSlot,
|
|
605
|
-
Spinner as Spinner2,
|
|
606
607
|
useFormField
|
|
607
608
|
} from "@mesob/ui/components";
|
|
608
609
|
import { useMesob as useMesob3 } from "@mesob/ui/providers";
|
|
@@ -612,12 +613,7 @@ import { useForm as useForm2 } from "react-hook-form";
|
|
|
612
613
|
import { toast as toast2 } from "sonner";
|
|
613
614
|
import { z as z2 } from "zod";
|
|
614
615
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
615
|
-
function PasswordInput({
|
|
616
|
-
field,
|
|
617
|
-
show,
|
|
618
|
-
onToggle,
|
|
619
|
-
placeholder
|
|
620
|
-
}) {
|
|
616
|
+
function PasswordInput({ field, show, onToggle }) {
|
|
621
617
|
const { formItemId, error } = useFormField();
|
|
622
618
|
return /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
623
619
|
/* @__PURE__ */ jsx5(
|
|
@@ -626,7 +622,6 @@ function PasswordInput({
|
|
|
626
622
|
...field,
|
|
627
623
|
id: formItemId,
|
|
628
624
|
type: show ? "text" : "password",
|
|
629
|
-
placeholder,
|
|
630
625
|
"aria-invalid": !!error,
|
|
631
626
|
className: "pr-10"
|
|
632
627
|
}
|
|
@@ -747,7 +742,7 @@ var ResetPasswordForm = ({
|
|
|
747
742
|
return /* @__PURE__ */ jsxs3(
|
|
748
743
|
AuthLayout,
|
|
749
744
|
{
|
|
750
|
-
title:
|
|
745
|
+
title: config.ui.name,
|
|
751
746
|
description: t("description"),
|
|
752
747
|
logoImage,
|
|
753
748
|
footer: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between w-full gap-2", children: [
|
|
@@ -810,8 +805,7 @@ var ResetPasswordForm = ({
|
|
|
810
805
|
{
|
|
811
806
|
field,
|
|
812
807
|
show: showPassword,
|
|
813
|
-
onToggle: () => setShowPassword(!showPassword)
|
|
814
|
-
placeholder: t("form.passwordPlaceholder")
|
|
808
|
+
onToggle: () => setShowPassword(!showPassword)
|
|
815
809
|
}
|
|
816
810
|
),
|
|
817
811
|
/* @__PURE__ */ jsx5(FormMessage2, {})
|
|
@@ -830,25 +824,22 @@ var ResetPasswordForm = ({
|
|
|
830
824
|
{
|
|
831
825
|
field,
|
|
832
826
|
show: showPassword,
|
|
833
|
-
onToggle: () => setShowPassword(!showPassword)
|
|
834
|
-
placeholder: t("form.passwordPlaceholder")
|
|
827
|
+
onToggle: () => setShowPassword(!showPassword)
|
|
835
828
|
}
|
|
836
829
|
),
|
|
837
830
|
/* @__PURE__ */ jsx5(FormMessage2, {})
|
|
838
831
|
] })
|
|
839
832
|
}
|
|
840
833
|
),
|
|
841
|
-
/* @__PURE__ */
|
|
834
|
+
/* @__PURE__ */ jsx5(
|
|
842
835
|
Button2,
|
|
843
836
|
{
|
|
844
837
|
type: "submit",
|
|
845
838
|
form: "reset-password-form",
|
|
846
839
|
className: "w-full",
|
|
847
840
|
disabled: isLoading || resetPasswordMutation.isPending,
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
isLoading || resetPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
851
|
-
]
|
|
841
|
+
loading: isLoading || resetPasswordMutation.isPending,
|
|
842
|
+
children: isLoading || resetPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
852
843
|
}
|
|
853
844
|
)
|
|
854
845
|
]
|
|
@@ -864,7 +855,7 @@ var ResetPasswordForm = ({
|
|
|
864
855
|
);
|
|
865
856
|
};
|
|
866
857
|
|
|
867
|
-
// src/components/auth/
|
|
858
|
+
// src/components/auth/set-password.tsx
|
|
868
859
|
import { zodResolver as zodResolver3 } from "@hookform/resolvers/zod";
|
|
869
860
|
import {
|
|
870
861
|
Alert as Alert3,
|
|
@@ -882,7 +873,7 @@ import {
|
|
|
882
873
|
} from "@mesob/ui/components";
|
|
883
874
|
import { useMesob as useMesob4 } from "@mesob/ui/providers";
|
|
884
875
|
import { IconAlertCircle as IconAlertCircle3, IconEye as IconEye2, IconEyeOff as IconEyeOff2 } from "@tabler/icons-react";
|
|
885
|
-
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
876
|
+
import { useEffect as useEffect3, useEffectEvent, useState as useState4 } from "react";
|
|
886
877
|
import { useForm as useForm3 } from "react-hook-form";
|
|
887
878
|
import { toast as toast3 } from "sonner";
|
|
888
879
|
import { z as z3 } from "zod";
|
|
@@ -905,15 +896,9 @@ function normalizePhone(phone) {
|
|
|
905
896
|
return cleaned;
|
|
906
897
|
}
|
|
907
898
|
|
|
908
|
-
// src/components/auth/
|
|
909
|
-
import {
|
|
910
|
-
|
|
911
|
-
function PasswordInput2({
|
|
912
|
-
field,
|
|
913
|
-
show,
|
|
914
|
-
onToggle,
|
|
915
|
-
placeholder
|
|
916
|
-
}) {
|
|
899
|
+
// src/components/auth/set-password.tsx
|
|
900
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
901
|
+
function PasswordInput2({ field, show, onToggle }) {
|
|
917
902
|
const { formItemId, error } = useFormField2();
|
|
918
903
|
return /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
919
904
|
/* @__PURE__ */ jsx6(
|
|
@@ -922,8 +907,6 @@ function PasswordInput2({
|
|
|
922
907
|
...field,
|
|
923
908
|
id: formItemId,
|
|
924
909
|
type: show ? "text" : "password",
|
|
925
|
-
placeholder,
|
|
926
|
-
autoComplete: "current-password",
|
|
927
910
|
"aria-invalid": !!error,
|
|
928
911
|
className: "pr-10"
|
|
929
912
|
}
|
|
@@ -942,52 +925,339 @@ function PasswordInput2({
|
|
|
942
925
|
)
|
|
943
926
|
] });
|
|
944
927
|
}
|
|
945
|
-
var
|
|
946
|
-
|
|
928
|
+
var setPasswordSchema = (t) => z3.object({
|
|
929
|
+
password: z3.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
|
|
930
|
+
confirmPassword: z3.string()
|
|
931
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
932
|
+
message: t("errors.passwordsMismatch"),
|
|
933
|
+
path: ["confirmPassword"]
|
|
934
|
+
});
|
|
935
|
+
var getPhoneRegex = (phoneRegex) => {
|
|
936
|
+
if (typeof phoneRegex === "string") {
|
|
937
|
+
return new RegExp(phoneRegex);
|
|
938
|
+
}
|
|
939
|
+
return phoneRegex || /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/;
|
|
940
|
+
};
|
|
941
|
+
var normalizeIdentifier = (identifier, phoneRegex) => {
|
|
942
|
+
const resolvedPhoneRegex = getPhoneRegex(phoneRegex);
|
|
943
|
+
return resolvedPhoneRegex.test(identifier) ? normalizePhone(identifier) : identifier;
|
|
944
|
+
};
|
|
945
|
+
var SetPassword = function SetPassword2({
|
|
946
|
+
identifier,
|
|
947
|
+
redirectUrl
|
|
948
|
+
} = {}) {
|
|
949
|
+
const { hooks, setAuth } = useApi();
|
|
950
|
+
const { config } = useConfig();
|
|
951
|
+
const mesob = useMesob4();
|
|
952
|
+
const t = useTranslator("Auth.setPassword");
|
|
953
|
+
const Link = mesob?.navigation?.Link;
|
|
954
|
+
const [error, setError] = useState4(null);
|
|
955
|
+
const [isLoading, setIsLoading] = useState4(false);
|
|
956
|
+
const [isChecking, setIsChecking] = useState4(true);
|
|
957
|
+
const [showPassword, setShowPassword] = useState4(false);
|
|
958
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState4(false);
|
|
959
|
+
const [account, setAccount] = useState4(null);
|
|
960
|
+
const checkAccountMutation = hooks.useMutation("post", "/check-account");
|
|
961
|
+
const setPasswordMutation = hooks.useMutation("post", "/password/set");
|
|
962
|
+
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
963
|
+
if (typeof window !== "undefined") {
|
|
964
|
+
window.location.href = path;
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
968
|
+
const logoImage = config.ui.logoImage;
|
|
969
|
+
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
970
|
+
const form = useForm3({
|
|
971
|
+
resolver: zodResolver3(setPasswordSchema(t)),
|
|
972
|
+
defaultValues: {
|
|
973
|
+
password: "",
|
|
974
|
+
confirmPassword: ""
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
useEffect3(() => {
|
|
978
|
+
if (error) {
|
|
979
|
+
toast3.error(error.title || "Error", {
|
|
980
|
+
description: error.description
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}, [error]);
|
|
984
|
+
const loadAccount = useEffectEvent(async () => {
|
|
985
|
+
if (!identifier) {
|
|
986
|
+
setError({
|
|
987
|
+
title: t("errors.fallback"),
|
|
988
|
+
description: t("errors.missingIdentifier")
|
|
989
|
+
});
|
|
990
|
+
setIsChecking(false);
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
try {
|
|
994
|
+
const normalizedIdentifier = normalizeIdentifier(
|
|
995
|
+
identifier,
|
|
996
|
+
config.phoneRegex
|
|
997
|
+
);
|
|
998
|
+
const res = await checkAccountMutation.mutateAsync({
|
|
999
|
+
body: { username: normalizedIdentifier }
|
|
1000
|
+
});
|
|
1001
|
+
if (!(res.exists && res.account && res.requiresPasswordSetup)) {
|
|
1002
|
+
setError({
|
|
1003
|
+
title: t("errors.fallback"),
|
|
1004
|
+
description: t("errors.accountNotEligible")
|
|
1005
|
+
});
|
|
1006
|
+
setIsChecking(false);
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
setAccount({
|
|
1010
|
+
fullName: res.account.fullName,
|
|
1011
|
+
email: res.account.email,
|
|
1012
|
+
phone: res.account.phone
|
|
1013
|
+
});
|
|
1014
|
+
} catch {
|
|
1015
|
+
setError({
|
|
1016
|
+
title: t("errors.fallback"),
|
|
1017
|
+
description: t("errors.accountLookupFailed")
|
|
1018
|
+
});
|
|
1019
|
+
} finally {
|
|
1020
|
+
setIsChecking(false);
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
useEffect3(() => {
|
|
1024
|
+
loadAccount().catch(() => {
|
|
1025
|
+
setIsChecking(false);
|
|
1026
|
+
});
|
|
1027
|
+
}, [identifier]);
|
|
1028
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1029
|
+
if (!identifier) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
setIsLoading(true);
|
|
1033
|
+
setError(null);
|
|
1034
|
+
try {
|
|
1035
|
+
const normalizedIdentifier = normalizeIdentifier(
|
|
1036
|
+
identifier,
|
|
1037
|
+
config.phoneRegex
|
|
1038
|
+
);
|
|
1039
|
+
const res = await setPasswordMutation.mutateAsync({
|
|
1040
|
+
body: {
|
|
1041
|
+
identifier: normalizedIdentifier,
|
|
1042
|
+
password: values.password
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
if ("user" in res && "session" in res) {
|
|
1046
|
+
setAuth(res);
|
|
1047
|
+
}
|
|
1048
|
+
onNavigate(defaultRedirect);
|
|
1049
|
+
} catch (err) {
|
|
1050
|
+
handleError(err, setError, t);
|
|
1051
|
+
} finally {
|
|
1052
|
+
setIsLoading(false);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
const accountLabel = account?.email ? t("form.emailLabel") : t("form.phoneLabel");
|
|
1056
|
+
const accountValue = account?.email || account?.phone || identifier || "";
|
|
1057
|
+
let errorContent = null;
|
|
1058
|
+
if (error) {
|
|
1059
|
+
errorContent = typeof error === "string" ? { title: "Error", description: error } : error;
|
|
1060
|
+
}
|
|
1061
|
+
const showError = !isChecking && !!errorContent;
|
|
1062
|
+
const errorAlert = showError && errorContent && /* @__PURE__ */ jsxs4(Alert3, { variant: "destructive", className: "mt-4", children: [
|
|
1063
|
+
/* @__PURE__ */ jsx6(IconAlertCircle3, { className: "h-4 w-4" }),
|
|
1064
|
+
/* @__PURE__ */ jsx6(AlertTitle3, { children: errorContent.title }),
|
|
1065
|
+
/* @__PURE__ */ jsx6(AlertDescription3, { children: errorContent.description })
|
|
1066
|
+
] });
|
|
1067
|
+
return /* @__PURE__ */ jsxs4(
|
|
1068
|
+
AuthLayout,
|
|
1069
|
+
{
|
|
1070
|
+
title: config.ui.name,
|
|
1071
|
+
description: t("description"),
|
|
1072
|
+
logoImage,
|
|
1073
|
+
footer: /* @__PURE__ */ jsxs4("p", { children: [
|
|
1074
|
+
t("footer.hasPassword"),
|
|
1075
|
+
" ",
|
|
1076
|
+
Link ? /* @__PURE__ */ jsx6(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.signInCta") }) : /* @__PURE__ */ jsx6(
|
|
1077
|
+
"a",
|
|
1078
|
+
{
|
|
1079
|
+
href: signInLink,
|
|
1080
|
+
onClick: (e) => {
|
|
1081
|
+
e.preventDefault();
|
|
1082
|
+
onNavigate(signInLink);
|
|
1083
|
+
},
|
|
1084
|
+
className: "text-primary hover:underline",
|
|
1085
|
+
children: t("footer.signInCta")
|
|
1086
|
+
}
|
|
1087
|
+
)
|
|
1088
|
+
] }),
|
|
1089
|
+
children: [
|
|
1090
|
+
/* @__PURE__ */ jsx6(Form3, { ...form, children: /* @__PURE__ */ jsxs4(
|
|
1091
|
+
"form",
|
|
1092
|
+
{
|
|
1093
|
+
id: "set-password-form",
|
|
1094
|
+
onSubmit: handleSubmit,
|
|
1095
|
+
className: "space-y-4",
|
|
1096
|
+
children: [
|
|
1097
|
+
/* @__PURE__ */ jsxs4(FormItem3, { children: [
|
|
1098
|
+
/* @__PURE__ */ jsx6(FormLabel3, { children: t("form.fullNameLabel") }),
|
|
1099
|
+
/* @__PURE__ */ jsx6(FormControl3, { children: /* @__PURE__ */ jsx6(Input3, { value: account?.fullName || "", disabled: true }) })
|
|
1100
|
+
] }),
|
|
1101
|
+
/* @__PURE__ */ jsxs4(FormItem3, { children: [
|
|
1102
|
+
/* @__PURE__ */ jsx6(FormLabel3, { children: accountLabel }),
|
|
1103
|
+
/* @__PURE__ */ jsx6(FormControl3, { children: /* @__PURE__ */ jsx6(Input3, { value: accountValue, disabled: true }) })
|
|
1104
|
+
] }),
|
|
1105
|
+
/* @__PURE__ */ jsx6(
|
|
1106
|
+
FormField3,
|
|
1107
|
+
{
|
|
1108
|
+
control: form.control,
|
|
1109
|
+
name: "password",
|
|
1110
|
+
render: ({ field }) => /* @__PURE__ */ jsxs4(FormItem3, { children: [
|
|
1111
|
+
/* @__PURE__ */ jsx6(FormLabel3, { children: t("form.passwordLabel") }),
|
|
1112
|
+
/* @__PURE__ */ jsx6(
|
|
1113
|
+
PasswordInput2,
|
|
1114
|
+
{
|
|
1115
|
+
field,
|
|
1116
|
+
show: showPassword,
|
|
1117
|
+
onToggle: () => setShowPassword(!showPassword)
|
|
1118
|
+
}
|
|
1119
|
+
),
|
|
1120
|
+
/* @__PURE__ */ jsx6(FormMessage3, {})
|
|
1121
|
+
] })
|
|
1122
|
+
}
|
|
1123
|
+
),
|
|
1124
|
+
/* @__PURE__ */ jsx6(
|
|
1125
|
+
FormField3,
|
|
1126
|
+
{
|
|
1127
|
+
control: form.control,
|
|
1128
|
+
name: "confirmPassword",
|
|
1129
|
+
render: ({ field }) => /* @__PURE__ */ jsxs4(FormItem3, { children: [
|
|
1130
|
+
/* @__PURE__ */ jsx6(FormLabel3, { children: t("form.confirmPasswordLabel") }),
|
|
1131
|
+
/* @__PURE__ */ jsx6(
|
|
1132
|
+
PasswordInput2,
|
|
1133
|
+
{
|
|
1134
|
+
field,
|
|
1135
|
+
show: showConfirmPassword,
|
|
1136
|
+
onToggle: () => setShowConfirmPassword(!showConfirmPassword)
|
|
1137
|
+
}
|
|
1138
|
+
),
|
|
1139
|
+
/* @__PURE__ */ jsx6(FormMessage3, {})
|
|
1140
|
+
] })
|
|
1141
|
+
}
|
|
1142
|
+
),
|
|
1143
|
+
/* @__PURE__ */ jsx6(
|
|
1144
|
+
Button3,
|
|
1145
|
+
{
|
|
1146
|
+
type: "submit",
|
|
1147
|
+
form: "set-password-form",
|
|
1148
|
+
className: "w-full",
|
|
1149
|
+
disabled: isChecking || !account || isLoading || setPasswordMutation.isPending,
|
|
1150
|
+
children: isLoading || setPasswordMutation.isPending ? t("form.submitting") : t("form.submit")
|
|
1151
|
+
}
|
|
1152
|
+
)
|
|
1153
|
+
]
|
|
1154
|
+
}
|
|
1155
|
+
) }),
|
|
1156
|
+
errorAlert
|
|
1157
|
+
]
|
|
1158
|
+
}
|
|
1159
|
+
);
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
// src/components/auth/sign-in.tsx
|
|
1163
|
+
import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
|
|
1164
|
+
import {
|
|
1165
|
+
Alert as Alert4,
|
|
1166
|
+
AlertDescription as AlertDescription4,
|
|
1167
|
+
AlertTitle as AlertTitle4,
|
|
1168
|
+
Button as Button4,
|
|
1169
|
+
Form as Form4,
|
|
1170
|
+
FormControl as FormControl4,
|
|
1171
|
+
FormField as FormField4,
|
|
1172
|
+
FormItem as FormItem4,
|
|
1173
|
+
FormLabel as FormLabel4,
|
|
1174
|
+
FormMessage as FormMessage4,
|
|
1175
|
+
Input as Input4,
|
|
1176
|
+
useFormField as useFormField3
|
|
1177
|
+
} from "@mesob/ui/components";
|
|
1178
|
+
import { useMesob as useMesob5 } from "@mesob/ui/providers";
|
|
1179
|
+
import { IconAlertCircle as IconAlertCircle4, IconEye as IconEye3, IconEyeOff as IconEyeOff3 } from "@tabler/icons-react";
|
|
1180
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
1181
|
+
import { useForm as useForm4 } from "react-hook-form";
|
|
1182
|
+
import { toast as toast4 } from "sonner";
|
|
1183
|
+
import { z as z4 } from "zod";
|
|
1184
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1185
|
+
var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1186
|
+
function PasswordInput3({ field, show, onToggle }) {
|
|
1187
|
+
const { formItemId, error } = useFormField3();
|
|
1188
|
+
return /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
1189
|
+
/* @__PURE__ */ jsx7(
|
|
1190
|
+
Input4,
|
|
1191
|
+
{
|
|
1192
|
+
...field,
|
|
1193
|
+
id: formItemId,
|
|
1194
|
+
type: show ? "text" : "password",
|
|
1195
|
+
autoComplete: "current-password",
|
|
1196
|
+
"aria-invalid": !!error,
|
|
1197
|
+
className: "pr-10"
|
|
1198
|
+
}
|
|
1199
|
+
),
|
|
1200
|
+
/* @__PURE__ */ jsx7(
|
|
1201
|
+
Button4,
|
|
1202
|
+
{
|
|
1203
|
+
type: "button",
|
|
1204
|
+
variant: "ghost",
|
|
1205
|
+
size: "icon",
|
|
1206
|
+
className: "absolute right-0 top-0 h-full px-3 text-muted-foreground hover:text-foreground",
|
|
1207
|
+
onClick: onToggle,
|
|
1208
|
+
"aria-label": show ? "Hide password" : "Show password",
|
|
1209
|
+
children: show ? /* @__PURE__ */ jsx7(IconEyeOff3, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx7(IconEye3, { className: "h-4 w-4" })
|
|
1210
|
+
}
|
|
1211
|
+
)
|
|
1212
|
+
] });
|
|
1213
|
+
}
|
|
1214
|
+
var signInSchema = (t, phoneRegex) => z4.object({
|
|
1215
|
+
username: z4.string().trim().min(1, { message: t("errors.requiredField") }).refine(
|
|
947
1216
|
(val) => {
|
|
948
|
-
const isEmail =
|
|
1217
|
+
const isEmail = z4.email().safeParse(val).success;
|
|
949
1218
|
const isPhone3 = phoneRegex.test(val);
|
|
950
1219
|
return isEmail || isPhone3;
|
|
951
1220
|
},
|
|
952
1221
|
{ message: t("errors.invalidEmailOrPhone") }
|
|
953
1222
|
),
|
|
954
|
-
password:
|
|
955
|
-
|
|
956
|
-
|
|
1223
|
+
password: z4.union([
|
|
1224
|
+
z4.literal(""),
|
|
1225
|
+
z4.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError"))
|
|
957
1226
|
]).optional()
|
|
958
1227
|
});
|
|
959
1228
|
var SignIn = ({ redirectUrl } = {}) => {
|
|
960
1229
|
const { hooks, setAuth } = useApi();
|
|
961
1230
|
const { config } = useConfig();
|
|
962
|
-
const mesob =
|
|
1231
|
+
const mesob = useMesob5();
|
|
963
1232
|
const t = useTranslator("Auth.signIn");
|
|
964
1233
|
const Link = mesob?.navigation?.Link;
|
|
965
|
-
const [isLoading, setIsLoading] =
|
|
966
|
-
const [error, setError] =
|
|
967
|
-
const [showPasswordField, setShowPasswordField] =
|
|
968
|
-
const [showPassword, setShowPassword] =
|
|
969
|
-
const [username, setUsername] =
|
|
970
|
-
const [isChecking, setIsChecking] =
|
|
1234
|
+
const [isLoading, setIsLoading] = useState5(false);
|
|
1235
|
+
const [error, setError] = useState5(null);
|
|
1236
|
+
const [showPasswordField, setShowPasswordField] = useState5(false);
|
|
1237
|
+
const [showPassword, setShowPassword] = useState5(false);
|
|
1238
|
+
const [username, setUsername] = useState5("");
|
|
1239
|
+
const [isChecking, setIsChecking] = useState5(false);
|
|
971
1240
|
const checkUserMutation = hooks.useMutation("post", "/check-account");
|
|
972
1241
|
const signInMutation = hooks.useMutation("post", "/sign-in");
|
|
973
1242
|
const phoneRegex = typeof config.phoneRegex === "string" ? new RegExp(config.phoneRegex) : config.phoneRegex || /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/;
|
|
974
1243
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/dashboard";
|
|
975
1244
|
const forgotPasswordLink = config.navigation?.links?.forgotPassword || "/auth/forgot-password";
|
|
976
1245
|
const signUpLink = config.navigation?.links?.signUp || "/auth/sign-up";
|
|
1246
|
+
const setPasswordLink = config.navigation?.links?.setPassword || "/auth/set-password";
|
|
977
1247
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
978
1248
|
if (typeof window !== "undefined") {
|
|
979
1249
|
window.location.href = path;
|
|
980
1250
|
}
|
|
981
1251
|
});
|
|
982
1252
|
const logoImage = config.ui.logoImage;
|
|
983
|
-
const form =
|
|
984
|
-
resolver:
|
|
1253
|
+
const form = useForm4({
|
|
1254
|
+
resolver: zodResolver4(signInSchema(t, phoneRegex)),
|
|
985
1255
|
defaultValues: { username: "", password: "" },
|
|
986
|
-
mode: "
|
|
1256
|
+
mode: "onBlur"
|
|
987
1257
|
});
|
|
988
|
-
|
|
1258
|
+
useEffect4(() => {
|
|
989
1259
|
if (error) {
|
|
990
|
-
|
|
1260
|
+
toast4.error(error.title || "Error", {
|
|
991
1261
|
description: error.description
|
|
992
1262
|
});
|
|
993
1263
|
}
|
|
@@ -1002,16 +1272,26 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1002
1272
|
}
|
|
1003
1273
|
});
|
|
1004
1274
|
if (result.exists) {
|
|
1275
|
+
if (result.requiresPasswordSetup) {
|
|
1276
|
+
const redirectParam = defaultRedirect ? `&redirect=${encodeURIComponent(defaultRedirect)}` : "";
|
|
1277
|
+
onNavigate(
|
|
1278
|
+
`${setPasswordLink}?identifier=${encodeURIComponent(normalizedUsername)}${redirectParam}`
|
|
1279
|
+
);
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1005
1282
|
setUsername(normalizedUsername);
|
|
1006
1283
|
form.setValue("username", normalizedUsername);
|
|
1007
1284
|
setShowPasswordField(true);
|
|
1008
1285
|
} else {
|
|
1009
1286
|
const email = isPhone(normalizedUsername) ? "" : normalizedUsername;
|
|
1287
|
+
const redirectParam = defaultRedirect ? `&redirect=${encodeURIComponent(defaultRedirect)}` : "";
|
|
1010
1288
|
if (email) {
|
|
1011
|
-
onNavigate(
|
|
1289
|
+
onNavigate(
|
|
1290
|
+
`${signUpLink}?email=${encodeURIComponent(email)}${redirectParam}`
|
|
1291
|
+
);
|
|
1012
1292
|
} else {
|
|
1013
1293
|
onNavigate(
|
|
1014
|
-
`${signUpLink}?phone=${encodeURIComponent(normalizedUsername)}`
|
|
1294
|
+
`${signUpLink}?phone=${encodeURIComponent(normalizedUsername)}${redirectParam}`
|
|
1015
1295
|
);
|
|
1016
1296
|
}
|
|
1017
1297
|
}
|
|
@@ -1044,7 +1324,8 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1044
1324
|
}
|
|
1045
1325
|
});
|
|
1046
1326
|
if ("verificationId" in res && res.verificationId) {
|
|
1047
|
-
const
|
|
1327
|
+
const redirectParam = defaultRedirect ? `&redirect=${encodeURIComponent(defaultRedirect)}` : "";
|
|
1328
|
+
const verifyPath = isPhone(username) ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(username)}${redirectParam}` : `/auth/verify-email?verificationId=${res.verificationId}${redirectParam}`;
|
|
1048
1329
|
onNavigate(verifyPath);
|
|
1049
1330
|
return;
|
|
1050
1331
|
}
|
|
@@ -1053,6 +1334,15 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1053
1334
|
}
|
|
1054
1335
|
onNavigate(defaultRedirect);
|
|
1055
1336
|
} catch (err) {
|
|
1337
|
+
const authError = err;
|
|
1338
|
+
const errorCode = authError.code || authError.message;
|
|
1339
|
+
if (errorCode === "HAS_NO_PASSWORD") {
|
|
1340
|
+
const redirectParam = defaultRedirect ? `&redirect=${encodeURIComponent(defaultRedirect)}` : "";
|
|
1341
|
+
onNavigate(
|
|
1342
|
+
`${setPasswordLink}?identifier=${encodeURIComponent(username)}${redirectParam}`
|
|
1343
|
+
);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1056
1346
|
handleError(err, setError, t);
|
|
1057
1347
|
} finally {
|
|
1058
1348
|
setIsLoading(false);
|
|
@@ -1078,19 +1368,19 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1078
1368
|
errorContent = error;
|
|
1079
1369
|
}
|
|
1080
1370
|
}
|
|
1081
|
-
const formContent = /* @__PURE__ */
|
|
1371
|
+
const formContent = /* @__PURE__ */ jsx7(Form4, { ...form, children: /* @__PURE__ */ jsxs5(
|
|
1082
1372
|
"form",
|
|
1083
1373
|
{
|
|
1084
1374
|
id: "sign-in-form",
|
|
1085
1375
|
onSubmit: form.handleSubmit(onSubmit),
|
|
1086
1376
|
className: "space-y-4",
|
|
1087
1377
|
children: [
|
|
1088
|
-
showPasswordField ? /* @__PURE__ */
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1378
|
+
showPasswordField ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1379
|
+
/* @__PURE__ */ jsxs5(FormItem4, { children: [
|
|
1380
|
+
/* @__PURE__ */ jsxs5(FormLabel4, { className: "flex justify-between items-center", children: [
|
|
1091
1381
|
t("form.accountLabel"),
|
|
1092
|
-
/* @__PURE__ */
|
|
1093
|
-
|
|
1382
|
+
/* @__PURE__ */ jsx7(
|
|
1383
|
+
Button4,
|
|
1094
1384
|
{
|
|
1095
1385
|
type: "button",
|
|
1096
1386
|
variant: "link",
|
|
@@ -1101,58 +1391,50 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1101
1391
|
}
|
|
1102
1392
|
)
|
|
1103
1393
|
] }),
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
|
|
1394
|
+
/* @__PURE__ */ jsx7(
|
|
1395
|
+
Input4,
|
|
1106
1396
|
{
|
|
1107
1397
|
id: "sign-in-username",
|
|
1108
1398
|
type: "text",
|
|
1109
1399
|
value: username,
|
|
1400
|
+
autoComplete: "username",
|
|
1110
1401
|
disabled: true
|
|
1111
1402
|
}
|
|
1112
1403
|
)
|
|
1113
1404
|
] }),
|
|
1114
|
-
/* @__PURE__ */
|
|
1115
|
-
|
|
1405
|
+
/* @__PURE__ */ jsx7(
|
|
1406
|
+
FormField4,
|
|
1116
1407
|
{
|
|
1117
1408
|
control: form.control,
|
|
1118
1409
|
name: "password",
|
|
1119
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
|
|
1410
|
+
render: ({ field }) => /* @__PURE__ */ jsxs5(FormItem4, { children: [
|
|
1411
|
+
/* @__PURE__ */ jsx7(FormLabel4, { children: t("form.passwordLabel") }),
|
|
1412
|
+
/* @__PURE__ */ jsx7(
|
|
1413
|
+
PasswordInput3,
|
|
1123
1414
|
{
|
|
1124
1415
|
field: { ...field, value: field.value ?? "" },
|
|
1125
1416
|
show: showPassword,
|
|
1126
|
-
onToggle: () => setShowPassword(!showPassword)
|
|
1127
|
-
placeholder: t("form.passwordPlaceholder")
|
|
1417
|
+
onToggle: () => setShowPassword(!showPassword)
|
|
1128
1418
|
}
|
|
1129
1419
|
),
|
|
1130
|
-
/* @__PURE__ */
|
|
1420
|
+
/* @__PURE__ */ jsx7(FormMessage4, {})
|
|
1131
1421
|
] })
|
|
1132
1422
|
}
|
|
1133
1423
|
)
|
|
1134
|
-
] }) : /* @__PURE__ */
|
|
1135
|
-
|
|
1424
|
+
] }) : /* @__PURE__ */ jsx7(
|
|
1425
|
+
FormField4,
|
|
1136
1426
|
{
|
|
1137
1427
|
control: form.control,
|
|
1138
1428
|
name: "username",
|
|
1139
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1140
|
-
/* @__PURE__ */
|
|
1141
|
-
/* @__PURE__ */
|
|
1142
|
-
|
|
1143
|
-
{
|
|
1144
|
-
...field,
|
|
1145
|
-
type: "text",
|
|
1146
|
-
placeholder: t("form.accountPlaceholder"),
|
|
1147
|
-
autoComplete: "username"
|
|
1148
|
-
}
|
|
1149
|
-
) }),
|
|
1150
|
-
/* @__PURE__ */ jsx6(FormMessage3, {})
|
|
1429
|
+
render: ({ field }) => /* @__PURE__ */ jsxs5(FormItem4, { children: [
|
|
1430
|
+
/* @__PURE__ */ jsx7(FormLabel4, { children: t("form.accountLabel") }),
|
|
1431
|
+
/* @__PURE__ */ jsx7(FormControl4, { children: /* @__PURE__ */ jsx7(Input4, { ...field, type: "text", autoComplete: "username" }) }),
|
|
1432
|
+
/* @__PURE__ */ jsx7(FormMessage4, {})
|
|
1151
1433
|
] })
|
|
1152
1434
|
}
|
|
1153
1435
|
),
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
|
|
1436
|
+
/* @__PURE__ */ jsx7(
|
|
1437
|
+
Button4,
|
|
1156
1438
|
{
|
|
1157
1439
|
type: "submit",
|
|
1158
1440
|
className: "w-full",
|
|
@@ -1164,20 +1446,20 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1164
1446
|
]
|
|
1165
1447
|
}
|
|
1166
1448
|
) });
|
|
1167
|
-
return /* @__PURE__ */
|
|
1449
|
+
return /* @__PURE__ */ jsx7("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs5(
|
|
1168
1450
|
AuthLayout,
|
|
1169
1451
|
{
|
|
1170
|
-
title:
|
|
1452
|
+
title: config.ui.name,
|
|
1171
1453
|
description: t("description"),
|
|
1172
1454
|
logoImage,
|
|
1173
|
-
footer: showPasswordField ? /* @__PURE__ */
|
|
1455
|
+
footer: showPasswordField ? /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center w-full", children: Link ? /* @__PURE__ */ jsx7(
|
|
1174
1456
|
Link,
|
|
1175
1457
|
{
|
|
1176
1458
|
href: forgotPasswordLink,
|
|
1177
1459
|
className: "text-primary inline-block hover:underline",
|
|
1178
1460
|
children: t("footer.forgotPassword")
|
|
1179
1461
|
}
|
|
1180
|
-
) : /* @__PURE__ */
|
|
1462
|
+
) : /* @__PURE__ */ jsx7(
|
|
1181
1463
|
"a",
|
|
1182
1464
|
{
|
|
1183
1465
|
href: forgotPasswordLink,
|
|
@@ -1191,10 +1473,10 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1191
1473
|
) }) : void 0,
|
|
1192
1474
|
children: [
|
|
1193
1475
|
formContent,
|
|
1194
|
-
errorContent && /* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1476
|
+
errorContent && /* @__PURE__ */ jsxs5(Alert4, { variant: "destructive", className: "mt-4", children: [
|
|
1477
|
+
/* @__PURE__ */ jsx7(IconAlertCircle4, { className: "h-4 w-4" }),
|
|
1478
|
+
/* @__PURE__ */ jsx7(AlertTitle4, { children: errorContent.title }),
|
|
1479
|
+
/* @__PURE__ */ jsx7(AlertDescription4, { children: errorContent.description })
|
|
1198
1480
|
] })
|
|
1199
1481
|
]
|
|
1200
1482
|
}
|
|
@@ -1202,50 +1484,44 @@ var SignIn = ({ redirectUrl } = {}) => {
|
|
|
1202
1484
|
};
|
|
1203
1485
|
|
|
1204
1486
|
// src/components/auth/sign-up.tsx
|
|
1205
|
-
import { zodResolver as
|
|
1487
|
+
import { zodResolver as zodResolver5 } from "@hookform/resolvers/zod";
|
|
1206
1488
|
import {
|
|
1207
|
-
Alert as
|
|
1208
|
-
AlertDescription as
|
|
1209
|
-
AlertTitle as
|
|
1210
|
-
Button as
|
|
1211
|
-
Form as
|
|
1212
|
-
FormControl as
|
|
1213
|
-
FormField as
|
|
1214
|
-
FormItem as
|
|
1215
|
-
FormLabel as
|
|
1216
|
-
FormMessage as
|
|
1217
|
-
Input as
|
|
1218
|
-
useFormField as
|
|
1489
|
+
Alert as Alert5,
|
|
1490
|
+
AlertDescription as AlertDescription5,
|
|
1491
|
+
AlertTitle as AlertTitle5,
|
|
1492
|
+
Button as Button5,
|
|
1493
|
+
Form as Form5,
|
|
1494
|
+
FormControl as FormControl5,
|
|
1495
|
+
FormField as FormField5,
|
|
1496
|
+
FormItem as FormItem5,
|
|
1497
|
+
FormLabel as FormLabel5,
|
|
1498
|
+
FormMessage as FormMessage5,
|
|
1499
|
+
Input as Input5,
|
|
1500
|
+
useFormField as useFormField4
|
|
1219
1501
|
} from "@mesob/ui/components";
|
|
1220
|
-
import { useMesob as
|
|
1221
|
-
import { IconAlertCircle as
|
|
1222
|
-
import { useEffect as
|
|
1223
|
-
import { useForm as
|
|
1224
|
-
import { toast as
|
|
1225
|
-
import { z as
|
|
1226
|
-
import { jsx as
|
|
1502
|
+
import { useMesob as useMesob6 } from "@mesob/ui/providers";
|
|
1503
|
+
import { IconAlertCircle as IconAlertCircle5, IconEye as IconEye4, IconEyeOff as IconEyeOff4 } from "@tabler/icons-react";
|
|
1504
|
+
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
1505
|
+
import { useForm as useForm5 } from "react-hook-form";
|
|
1506
|
+
import { toast as toast5 } from "sonner";
|
|
1507
|
+
import { z as z5 } from "zod";
|
|
1508
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1227
1509
|
var isPhone2 = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
|
|
1228
|
-
function
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
}) {
|
|
1234
|
-
const { formItemId, error } = useFormField3();
|
|
1235
|
-
return /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
1236
|
-
/* @__PURE__ */ jsx7(
|
|
1237
|
-
Input4,
|
|
1510
|
+
function PasswordInput4({ field, show, onToggle }) {
|
|
1511
|
+
const { formItemId, error } = useFormField4();
|
|
1512
|
+
return /* @__PURE__ */ jsxs6("div", { className: "relative", children: [
|
|
1513
|
+
/* @__PURE__ */ jsx8(
|
|
1514
|
+
Input5,
|
|
1238
1515
|
{
|
|
1239
1516
|
...field,
|
|
1240
1517
|
id: formItemId,
|
|
1241
1518
|
type: show ? "text" : "password",
|
|
1242
|
-
placeholder,
|
|
1243
1519
|
"aria-invalid": !!error,
|
|
1244
1520
|
className: "pr-10"
|
|
1245
1521
|
}
|
|
1246
1522
|
),
|
|
1247
|
-
/* @__PURE__ */
|
|
1248
|
-
|
|
1523
|
+
/* @__PURE__ */ jsx8(
|
|
1524
|
+
Button5,
|
|
1249
1525
|
{
|
|
1250
1526
|
type: "button",
|
|
1251
1527
|
variant: "ghost",
|
|
@@ -1253,14 +1529,14 @@ function PasswordInput3({
|
|
|
1253
1529
|
className: "absolute right-0 top-0 h-full px-3 text-muted-foreground hover:text-foreground",
|
|
1254
1530
|
onClick: onToggle,
|
|
1255
1531
|
"aria-label": show ? "Hide password" : "Show password",
|
|
1256
|
-
children: show ? /* @__PURE__ */
|
|
1532
|
+
children: show ? /* @__PURE__ */ jsx8(IconEyeOff4, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx8(IconEye4, { className: "h-4 w-4" })
|
|
1257
1533
|
}
|
|
1258
1534
|
)
|
|
1259
1535
|
] });
|
|
1260
1536
|
}
|
|
1261
|
-
var signUpSchema = (t) =>
|
|
1262
|
-
fullName:
|
|
1263
|
-
identifier:
|
|
1537
|
+
var signUpSchema = (t) => z5.object({
|
|
1538
|
+
fullName: z5.string().min(1, t("errors.fullNameRequired")),
|
|
1539
|
+
identifier: z5.string().min(1, t("errors.contactRequired")).refine(
|
|
1264
1540
|
(val) => {
|
|
1265
1541
|
if (!val) {
|
|
1266
1542
|
return false;
|
|
@@ -1271,8 +1547,8 @@ var signUpSchema = (t) => z4.object({
|
|
|
1271
1547
|
message: t("errors.invalidEmailOrPhone")
|
|
1272
1548
|
}
|
|
1273
1549
|
),
|
|
1274
|
-
password:
|
|
1275
|
-
confirmPassword:
|
|
1550
|
+
password: z5.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError")),
|
|
1551
|
+
confirmPassword: z5.string()
|
|
1276
1552
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
1277
1553
|
message: t("errors.passwordsMismatch"),
|
|
1278
1554
|
path: ["confirmPassword"]
|
|
@@ -1283,13 +1559,13 @@ var SignUp = ({
|
|
|
1283
1559
|
} = {}) => {
|
|
1284
1560
|
const { hooks, setAuth } = useApi();
|
|
1285
1561
|
const { config } = useConfig();
|
|
1286
|
-
const mesob =
|
|
1562
|
+
const mesob = useMesob6();
|
|
1287
1563
|
const t = useTranslator("Auth.signUp");
|
|
1288
1564
|
const Link = mesob?.navigation?.Link;
|
|
1289
|
-
const [isLoading, setIsLoading] =
|
|
1290
|
-
const [error, setError] =
|
|
1291
|
-
const [showPassword, setShowPassword] =
|
|
1292
|
-
const [showConfirmPassword, setShowConfirmPassword] =
|
|
1565
|
+
const [isLoading, setIsLoading] = useState6(false);
|
|
1566
|
+
const [error, setError] = useState6(null);
|
|
1567
|
+
const [showPassword, setShowPassword] = useState6(false);
|
|
1568
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState6(false);
|
|
1293
1569
|
const signUpMutation = hooks.useMutation("post", "/sign-up");
|
|
1294
1570
|
const signInLink = config.navigation?.links?.signIn || "/auth/sign-in";
|
|
1295
1571
|
const onNavigate = config.navigation?.onNavigate || ((path) => {
|
|
@@ -1300,8 +1576,8 @@ var SignUp = ({
|
|
|
1300
1576
|
const logoImage = config.ui.logoImage;
|
|
1301
1577
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1302
1578
|
const hasInitialIdentifier = !!initialIdentifier;
|
|
1303
|
-
const form =
|
|
1304
|
-
resolver:
|
|
1579
|
+
const form = useForm5({
|
|
1580
|
+
resolver: zodResolver5(signUpSchema(t)),
|
|
1305
1581
|
defaultValues: {
|
|
1306
1582
|
fullName: "",
|
|
1307
1583
|
identifier: initialIdentifier || "",
|
|
@@ -1309,14 +1585,14 @@ var SignUp = ({
|
|
|
1309
1585
|
confirmPassword: ""
|
|
1310
1586
|
}
|
|
1311
1587
|
});
|
|
1312
|
-
|
|
1588
|
+
useEffect5(() => {
|
|
1313
1589
|
if (initialIdentifier) {
|
|
1314
1590
|
form.setValue("identifier", initialIdentifier);
|
|
1315
1591
|
}
|
|
1316
1592
|
}, [initialIdentifier, form]);
|
|
1317
|
-
|
|
1593
|
+
useEffect5(() => {
|
|
1318
1594
|
if (error) {
|
|
1319
|
-
|
|
1595
|
+
toast5.error(error.title || "Error", {
|
|
1320
1596
|
description: error.description
|
|
1321
1597
|
});
|
|
1322
1598
|
}
|
|
@@ -1331,23 +1607,22 @@ var SignUp = ({
|
|
|
1331
1607
|
body: usingPhone ? {
|
|
1332
1608
|
phone: identifier,
|
|
1333
1609
|
password: values.password,
|
|
1334
|
-
fullName: values.fullName
|
|
1335
|
-
handle: values.handle
|
|
1610
|
+
fullName: values.fullName
|
|
1336
1611
|
} : {
|
|
1337
1612
|
email: identifier,
|
|
1338
1613
|
password: values.password,
|
|
1339
|
-
fullName: values.fullName
|
|
1340
|
-
handle: values.handle
|
|
1614
|
+
fullName: values.fullName
|
|
1341
1615
|
}
|
|
1342
1616
|
});
|
|
1343
1617
|
if ("verificationId" in res && res.verificationId) {
|
|
1618
|
+
const redirectParam = defaultRedirect ? `&redirect=${encodeURIComponent(defaultRedirect)}` : "";
|
|
1344
1619
|
if (usingPhone) {
|
|
1345
1620
|
onNavigate(
|
|
1346
|
-
`/auth/verify-phone?context=sign-up&verificationId=${res.verificationId}&phone=${encodeURIComponent(identifier)}`
|
|
1621
|
+
`/auth/verify-phone?context=sign-up&verificationId=${res.verificationId}&phone=${encodeURIComponent(identifier)}${redirectParam}`
|
|
1347
1622
|
);
|
|
1348
1623
|
} else {
|
|
1349
1624
|
onNavigate(
|
|
1350
|
-
`/auth/verify-email?verificationId=${res.verificationId}&email=${encodeURIComponent(identifier)}`
|
|
1625
|
+
`/auth/verify-email?verificationId=${res.verificationId}&email=${encodeURIComponent(identifier)}${redirectParam}`
|
|
1351
1626
|
);
|
|
1352
1627
|
}
|
|
1353
1628
|
return;
|
|
@@ -1380,16 +1655,16 @@ var SignUp = ({
|
|
|
1380
1655
|
errorContent = error;
|
|
1381
1656
|
}
|
|
1382
1657
|
}
|
|
1383
|
-
return /* @__PURE__ */
|
|
1658
|
+
return /* @__PURE__ */ jsxs6(
|
|
1384
1659
|
AuthLayout,
|
|
1385
1660
|
{
|
|
1386
|
-
title:
|
|
1661
|
+
title: config.ui.name,
|
|
1387
1662
|
description: t("description"),
|
|
1388
1663
|
logoImage,
|
|
1389
|
-
footer: /* @__PURE__ */
|
|
1664
|
+
footer: /* @__PURE__ */ jsxs6("p", { children: [
|
|
1390
1665
|
t("footer.hasAccount"),
|
|
1391
1666
|
" ",
|
|
1392
|
-
Link ? /* @__PURE__ */
|
|
1667
|
+
Link ? /* @__PURE__ */ jsx8(Link, { href: signInLink, className: "text-primary hover:underline", children: t("footer.signInCta") }) : /* @__PURE__ */ jsx8(
|
|
1393
1668
|
"a",
|
|
1394
1669
|
{
|
|
1395
1670
|
href: signInLink,
|
|
@@ -1403,93 +1678,84 @@ var SignUp = ({
|
|
|
1403
1678
|
)
|
|
1404
1679
|
] }),
|
|
1405
1680
|
children: [
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
|
|
1681
|
+
/* @__PURE__ */ jsx8(Form5, { ...form, children: /* @__PURE__ */ jsxs6("form", { id: "sign-up-form", onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1682
|
+
/* @__PURE__ */ jsx8(
|
|
1683
|
+
FormField5,
|
|
1409
1684
|
{
|
|
1410
1685
|
control: form.control,
|
|
1411
1686
|
name: "fullName",
|
|
1412
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
1414
|
-
/* @__PURE__ */
|
|
1415
|
-
|
|
1416
|
-
{
|
|
1417
|
-
...field,
|
|
1418
|
-
placeholder: t("form.fullNamePlaceholder")
|
|
1419
|
-
}
|
|
1420
|
-
) }),
|
|
1421
|
-
/* @__PURE__ */ jsx7(FormMessage4, {})
|
|
1687
|
+
render: ({ field }) => /* @__PURE__ */ jsxs6(FormItem5, { children: [
|
|
1688
|
+
/* @__PURE__ */ jsx8(FormLabel5, { children: t("form.fullNameLabel") }),
|
|
1689
|
+
/* @__PURE__ */ jsx8(FormControl5, { children: /* @__PURE__ */ jsx8(Input5, { ...field }) }),
|
|
1690
|
+
/* @__PURE__ */ jsx8(FormMessage5, {})
|
|
1422
1691
|
] })
|
|
1423
1692
|
}
|
|
1424
1693
|
),
|
|
1425
|
-
/* @__PURE__ */
|
|
1426
|
-
|
|
1694
|
+
/* @__PURE__ */ jsx8(
|
|
1695
|
+
FormField5,
|
|
1427
1696
|
{
|
|
1428
1697
|
control: form.control,
|
|
1429
1698
|
name: "identifier",
|
|
1430
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1431
|
-
/* @__PURE__ */
|
|
1432
|
-
|
|
1699
|
+
render: ({ field }) => /* @__PURE__ */ jsxs6(FormItem5, { children: [
|
|
1700
|
+
/* @__PURE__ */ jsx8(
|
|
1701
|
+
FormLabel5,
|
|
1433
1702
|
{
|
|
1434
1703
|
className: hasInitialIdentifier ? "block" : void 0,
|
|
1435
1704
|
children: identifierLabel
|
|
1436
1705
|
}
|
|
1437
1706
|
),
|
|
1438
|
-
/* @__PURE__ */
|
|
1439
|
-
|
|
1707
|
+
/* @__PURE__ */ jsx8(FormControl5, { children: /* @__PURE__ */ jsx8(
|
|
1708
|
+
Input5,
|
|
1440
1709
|
{
|
|
1441
1710
|
...field,
|
|
1442
1711
|
type: field.value.includes("@") ? "email" : "tel",
|
|
1443
|
-
placeholder: hasInitialIdentifier ? void 0 : t("form.accountPlaceholder") || "Email or phone number",
|
|
1444
1712
|
disabled: hasInitialIdentifier
|
|
1445
1713
|
}
|
|
1446
1714
|
) }),
|
|
1447
|
-
/* @__PURE__ */
|
|
1715
|
+
/* @__PURE__ */ jsx8(FormMessage5, {})
|
|
1448
1716
|
] })
|
|
1449
1717
|
}
|
|
1450
1718
|
),
|
|
1451
|
-
/* @__PURE__ */
|
|
1452
|
-
|
|
1719
|
+
/* @__PURE__ */ jsx8(
|
|
1720
|
+
FormField5,
|
|
1453
1721
|
{
|
|
1454
1722
|
control: form.control,
|
|
1455
1723
|
name: "password",
|
|
1456
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1457
|
-
/* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
|
|
1724
|
+
render: ({ field }) => /* @__PURE__ */ jsxs6(FormItem5, { children: [
|
|
1725
|
+
/* @__PURE__ */ jsx8(FormLabel5, { children: t("form.passwordLabel") }),
|
|
1726
|
+
/* @__PURE__ */ jsx8(
|
|
1727
|
+
PasswordInput4,
|
|
1460
1728
|
{
|
|
1461
1729
|
field,
|
|
1462
1730
|
show: showPassword,
|
|
1463
|
-
onToggle: () => setShowPassword(!showPassword)
|
|
1464
|
-
placeholder: t("form.passwordPlaceholder")
|
|
1731
|
+
onToggle: () => setShowPassword(!showPassword)
|
|
1465
1732
|
}
|
|
1466
1733
|
),
|
|
1467
|
-
/* @__PURE__ */
|
|
1734
|
+
/* @__PURE__ */ jsx8(FormMessage5, {})
|
|
1468
1735
|
] })
|
|
1469
1736
|
}
|
|
1470
1737
|
),
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
|
|
1738
|
+
/* @__PURE__ */ jsx8(
|
|
1739
|
+
FormField5,
|
|
1473
1740
|
{
|
|
1474
1741
|
control: form.control,
|
|
1475
1742
|
name: "confirmPassword",
|
|
1476
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1478
|
-
/* @__PURE__ */
|
|
1479
|
-
|
|
1743
|
+
render: ({ field }) => /* @__PURE__ */ jsxs6(FormItem5, { children: [
|
|
1744
|
+
/* @__PURE__ */ jsx8(FormLabel5, { children: t("form.confirmPasswordLabel") }),
|
|
1745
|
+
/* @__PURE__ */ jsx8(
|
|
1746
|
+
PasswordInput4,
|
|
1480
1747
|
{
|
|
1481
1748
|
field,
|
|
1482
1749
|
show: showConfirmPassword,
|
|
1483
|
-
onToggle: () => setShowConfirmPassword(!showConfirmPassword)
|
|
1484
|
-
placeholder: t("form.passwordPlaceholder")
|
|
1750
|
+
onToggle: () => setShowConfirmPassword(!showConfirmPassword)
|
|
1485
1751
|
}
|
|
1486
1752
|
),
|
|
1487
|
-
/* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ jsx8(FormMessage5, {})
|
|
1488
1754
|
] })
|
|
1489
1755
|
}
|
|
1490
1756
|
),
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
|
|
1757
|
+
/* @__PURE__ */ jsx8(
|
|
1758
|
+
Button5,
|
|
1493
1759
|
{
|
|
1494
1760
|
type: "submit",
|
|
1495
1761
|
form: "sign-up-form",
|
|
@@ -1499,10 +1765,10 @@ var SignUp = ({
|
|
|
1499
1765
|
}
|
|
1500
1766
|
)
|
|
1501
1767
|
] }) }),
|
|
1502
|
-
errorContent && /* @__PURE__ */
|
|
1503
|
-
/* @__PURE__ */
|
|
1504
|
-
/* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1768
|
+
errorContent && /* @__PURE__ */ jsxs6(Alert5, { variant: "destructive", className: "mt-4", children: [
|
|
1769
|
+
/* @__PURE__ */ jsx8(IconAlertCircle5, { className: "h-4 w-4" }),
|
|
1770
|
+
/* @__PURE__ */ jsx8(AlertTitle5, { children: errorContent.title }),
|
|
1771
|
+
/* @__PURE__ */ jsx8(AlertDescription5, { children: errorContent.description })
|
|
1506
1772
|
] })
|
|
1507
1773
|
]
|
|
1508
1774
|
}
|
|
@@ -1510,36 +1776,35 @@ var SignUp = ({
|
|
|
1510
1776
|
};
|
|
1511
1777
|
|
|
1512
1778
|
// src/components/auth/verification-form.tsx
|
|
1513
|
-
import { zodResolver as
|
|
1779
|
+
import { zodResolver as zodResolver6 } from "@hookform/resolvers/zod";
|
|
1514
1780
|
import {
|
|
1515
1781
|
Button as Button6,
|
|
1516
|
-
Form as
|
|
1517
|
-
FormControl as
|
|
1518
|
-
FormField as
|
|
1519
|
-
FormItem as
|
|
1520
|
-
FormLabel as
|
|
1521
|
-
FormMessage as
|
|
1782
|
+
Form as Form6,
|
|
1783
|
+
FormControl as FormControl6,
|
|
1784
|
+
FormField as FormField6,
|
|
1785
|
+
FormItem as FormItem6,
|
|
1786
|
+
FormLabel as FormLabel6,
|
|
1787
|
+
FormMessage as FormMessage6,
|
|
1522
1788
|
InputOTP as InputOTP2,
|
|
1523
1789
|
InputOTPGroup as InputOTPGroup2,
|
|
1524
|
-
InputOTPSlot as InputOTPSlot2
|
|
1525
|
-
Spinner as Spinner4
|
|
1790
|
+
InputOTPSlot as InputOTPSlot2
|
|
1526
1791
|
} from "@mesob/ui/components";
|
|
1527
|
-
import { useForm as
|
|
1528
|
-
import { z as
|
|
1792
|
+
import { useForm as useForm6 } from "react-hook-form";
|
|
1793
|
+
import { z as z6 } from "zod";
|
|
1529
1794
|
|
|
1530
1795
|
// src/components/auth/countdown.tsx
|
|
1531
|
-
import {
|
|
1532
|
-
import { useEffect as
|
|
1533
|
-
import { jsx as
|
|
1796
|
+
import { Spinner } from "@mesob/ui/components";
|
|
1797
|
+
import { useEffect as useEffect6, useState as useState7 } from "react";
|
|
1798
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1534
1799
|
var Countdown = ({
|
|
1535
1800
|
initialSeconds = 60,
|
|
1536
1801
|
onResend,
|
|
1537
1802
|
resending = false
|
|
1538
1803
|
}) => {
|
|
1539
1804
|
const t = useTranslator("Common");
|
|
1540
|
-
const [seconds, setSeconds] =
|
|
1541
|
-
const [isResending, setIsResending] =
|
|
1542
|
-
|
|
1805
|
+
const [seconds, setSeconds] = useState7(initialSeconds);
|
|
1806
|
+
const [isResending, setIsResending] = useState7(false);
|
|
1807
|
+
useEffect6(() => {
|
|
1543
1808
|
if (seconds <= 0) {
|
|
1544
1809
|
return;
|
|
1545
1810
|
}
|
|
@@ -1564,17 +1829,19 @@ var Countdown = ({
|
|
|
1564
1829
|
setIsResending(false);
|
|
1565
1830
|
}
|
|
1566
1831
|
};
|
|
1832
|
+
const busy = isResending || resending;
|
|
1567
1833
|
if (seconds > 0) {
|
|
1568
|
-
return /* @__PURE__ */
|
|
1834
|
+
return /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: t("resendIn", { seconds }) });
|
|
1569
1835
|
}
|
|
1570
|
-
return /* @__PURE__ */
|
|
1571
|
-
|
|
1836
|
+
return /* @__PURE__ */ jsxs7(
|
|
1837
|
+
"button",
|
|
1572
1838
|
{
|
|
1573
|
-
|
|
1839
|
+
type: "button",
|
|
1574
1840
|
onClick: handleResend,
|
|
1575
|
-
disabled:
|
|
1841
|
+
disabled: busy,
|
|
1842
|
+
className: "text-sm text-primary hover:underline disabled:opacity-50 flex items-center gap-1",
|
|
1576
1843
|
children: [
|
|
1577
|
-
|
|
1844
|
+
busy && /* @__PURE__ */ jsx9(Spinner, { className: "h-3 w-3" }),
|
|
1578
1845
|
t("resend")
|
|
1579
1846
|
]
|
|
1580
1847
|
}
|
|
@@ -1582,9 +1849,9 @@ var Countdown = ({
|
|
|
1582
1849
|
};
|
|
1583
1850
|
|
|
1584
1851
|
// src/components/auth/verification-form.tsx
|
|
1585
|
-
import { jsx as
|
|
1586
|
-
var verificationSchema = (t) =>
|
|
1587
|
-
code:
|
|
1852
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1853
|
+
var verificationSchema = (t) => z6.object({
|
|
1854
|
+
code: z6.string().length(6, t("form.codeLength"))
|
|
1588
1855
|
});
|
|
1589
1856
|
var VerificationForm = ({
|
|
1590
1857
|
onSubmit,
|
|
@@ -1592,30 +1859,29 @@ var VerificationForm = ({
|
|
|
1592
1859
|
isLoading = false
|
|
1593
1860
|
}) => {
|
|
1594
1861
|
const t = useTranslator("Auth.verification");
|
|
1595
|
-
const form =
|
|
1596
|
-
resolver:
|
|
1597
|
-
defaultValues: {
|
|
1598
|
-
code: ""
|
|
1599
|
-
}
|
|
1862
|
+
const form = useForm6({
|
|
1863
|
+
resolver: zodResolver6(verificationSchema(t)),
|
|
1864
|
+
defaultValues: { code: "" }
|
|
1600
1865
|
});
|
|
1601
1866
|
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1602
1867
|
await onSubmit(values);
|
|
1603
1868
|
});
|
|
1604
|
-
|
|
1869
|
+
const codeLength = form.watch("code").length;
|
|
1870
|
+
return /* @__PURE__ */ jsx10(Form6, { ...form, children: /* @__PURE__ */ jsxs8(
|
|
1605
1871
|
"form",
|
|
1606
1872
|
{
|
|
1607
1873
|
id: "verification-form",
|
|
1608
1874
|
onSubmit: handleSubmit,
|
|
1609
1875
|
className: "space-y-4",
|
|
1610
1876
|
children: [
|
|
1611
|
-
/* @__PURE__ */
|
|
1612
|
-
|
|
1877
|
+
/* @__PURE__ */ jsx10(
|
|
1878
|
+
FormField6,
|
|
1613
1879
|
{
|
|
1614
1880
|
control: form.control,
|
|
1615
1881
|
name: "code",
|
|
1616
|
-
render: ({ field }) => /* @__PURE__ */
|
|
1617
|
-
/* @__PURE__ */
|
|
1618
|
-
/* @__PURE__ */
|
|
1882
|
+
render: ({ field }) => /* @__PURE__ */ jsxs8(FormItem6, { children: [
|
|
1883
|
+
/* @__PURE__ */ jsx10("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx10(FormLabel6, { children: t("form.codeLabel") }) }),
|
|
1884
|
+
/* @__PURE__ */ jsx10(FormControl6, { children: /* @__PURE__ */ jsx10(
|
|
1619
1885
|
InputOTP2,
|
|
1620
1886
|
{
|
|
1621
1887
|
maxLength: 6,
|
|
@@ -1624,47 +1890,44 @@ var VerificationForm = ({
|
|
|
1624
1890
|
onChange: field.onChange,
|
|
1625
1891
|
onBlur: field.onBlur,
|
|
1626
1892
|
containerClassName: "gap-4 justify-center mb-2 flex items-center",
|
|
1627
|
-
children: /* @__PURE__ */
|
|
1628
|
-
/* @__PURE__ */
|
|
1629
|
-
/* @__PURE__ */
|
|
1630
|
-
/* @__PURE__ */
|
|
1631
|
-
/* @__PURE__ */
|
|
1632
|
-
/* @__PURE__ */
|
|
1633
|
-
/* @__PURE__ */
|
|
1893
|
+
children: /* @__PURE__ */ jsxs8(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: [
|
|
1894
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 0 }),
|
|
1895
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 1 }),
|
|
1896
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 2 }),
|
|
1897
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 3 }),
|
|
1898
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 4 }),
|
|
1899
|
+
/* @__PURE__ */ jsx10(InputOTPSlot2, { className: "h-12", index: 5 })
|
|
1634
1900
|
] })
|
|
1635
1901
|
}
|
|
1636
1902
|
) }),
|
|
1637
|
-
/* @__PURE__ */
|
|
1903
|
+
/* @__PURE__ */ jsx10(FormMessage6, {})
|
|
1638
1904
|
] })
|
|
1639
1905
|
}
|
|
1640
1906
|
),
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
}
|
|
1654
|
-
)
|
|
1655
|
-
] })
|
|
1907
|
+
/* @__PURE__ */ jsx10(
|
|
1908
|
+
Button6,
|
|
1909
|
+
{
|
|
1910
|
+
type: "submit",
|
|
1911
|
+
form: "verification-form",
|
|
1912
|
+
className: "w-full",
|
|
1913
|
+
disabled: isLoading || codeLength !== 6,
|
|
1914
|
+
loading: isLoading,
|
|
1915
|
+
children: t("form.confirm")
|
|
1916
|
+
}
|
|
1917
|
+
),
|
|
1918
|
+
/* @__PURE__ */ jsx10("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx10(Countdown, { onResend, resending: isLoading }) })
|
|
1656
1919
|
]
|
|
1657
1920
|
}
|
|
1658
1921
|
) });
|
|
1659
1922
|
};
|
|
1660
1923
|
|
|
1661
1924
|
// src/components/auth/verify-email.tsx
|
|
1662
|
-
import { Alert as
|
|
1663
|
-
import { useMesob as
|
|
1664
|
-
import { IconAlertCircle as
|
|
1665
|
-
import { useEffect as
|
|
1666
|
-
import { toast as
|
|
1667
|
-
import { jsx as
|
|
1925
|
+
import { Alert as Alert6, AlertDescription as AlertDescription6, AlertTitle as AlertTitle6 } from "@mesob/ui/components";
|
|
1926
|
+
import { useMesob as useMesob7 } from "@mesob/ui/providers";
|
|
1927
|
+
import { IconAlertCircle as IconAlertCircle6 } from "@tabler/icons-react";
|
|
1928
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
1929
|
+
import { toast as toast6 } from "sonner";
|
|
1930
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1668
1931
|
var VerifyEmail = ({
|
|
1669
1932
|
verificationId,
|
|
1670
1933
|
email,
|
|
@@ -1672,13 +1935,13 @@ var VerifyEmail = ({
|
|
|
1672
1935
|
}) => {
|
|
1673
1936
|
const { hooks, setAuth } = useApi();
|
|
1674
1937
|
const { config } = useConfig();
|
|
1675
|
-
const mesob =
|
|
1938
|
+
const mesob = useMesob7();
|
|
1676
1939
|
const t = useTranslator("Auth.verification");
|
|
1677
1940
|
const common = useTranslator("Common");
|
|
1678
1941
|
const footer = useTranslator("Auth.forgotPassword.footer");
|
|
1679
1942
|
const Link = mesob?.navigation?.Link;
|
|
1680
|
-
const [isLoading, setIsLoading] =
|
|
1681
|
-
const [error, setError] =
|
|
1943
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1944
|
+
const [error, setError] = useState8(null);
|
|
1682
1945
|
const verifyEmailMutation = hooks.useMutation(
|
|
1683
1946
|
"post",
|
|
1684
1947
|
"/email/verification/confirm"
|
|
@@ -1695,9 +1958,9 @@ var VerifyEmail = ({
|
|
|
1695
1958
|
});
|
|
1696
1959
|
const logoImage = config.ui.logoImage;
|
|
1697
1960
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1698
|
-
|
|
1961
|
+
useEffect7(() => {
|
|
1699
1962
|
if (error) {
|
|
1700
|
-
|
|
1963
|
+
toast6.error(error.title || "Error", {
|
|
1701
1964
|
description: error.description
|
|
1702
1965
|
});
|
|
1703
1966
|
}
|
|
@@ -1752,12 +2015,12 @@ var VerifyEmail = ({
|
|
|
1752
2015
|
}
|
|
1753
2016
|
};
|
|
1754
2017
|
if (!verificationId) {
|
|
1755
|
-
return /* @__PURE__ */
|
|
2018
|
+
return /* @__PURE__ */ jsx11(
|
|
1756
2019
|
AuthLayout,
|
|
1757
2020
|
{
|
|
1758
2021
|
title: common("invalidLinkTitle"),
|
|
1759
2022
|
description: common("invalidLinkDescription"),
|
|
1760
|
-
footer: Link ? /* @__PURE__ */
|
|
2023
|
+
footer: Link ? /* @__PURE__ */ jsx11(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx11(
|
|
1761
2024
|
"a",
|
|
1762
2025
|
{
|
|
1763
2026
|
href: signInLink,
|
|
@@ -1769,7 +2032,7 @@ var VerifyEmail = ({
|
|
|
1769
2032
|
children: footer("backToSignIn")
|
|
1770
2033
|
}
|
|
1771
2034
|
),
|
|
1772
|
-
children: /* @__PURE__ */
|
|
2035
|
+
children: /* @__PURE__ */ jsx11("div", {})
|
|
1773
2036
|
}
|
|
1774
2037
|
);
|
|
1775
2038
|
}
|
|
@@ -1781,13 +2044,13 @@ var VerifyEmail = ({
|
|
|
1781
2044
|
errorContent = error;
|
|
1782
2045
|
}
|
|
1783
2046
|
}
|
|
1784
|
-
return /* @__PURE__ */
|
|
2047
|
+
return /* @__PURE__ */ jsxs9(
|
|
1785
2048
|
AuthLayout,
|
|
1786
2049
|
{
|
|
1787
|
-
title:
|
|
2050
|
+
title: config.ui.name,
|
|
1788
2051
|
description: t("email.description"),
|
|
1789
2052
|
logoImage,
|
|
1790
|
-
footer: Link ? /* @__PURE__ */
|
|
2053
|
+
footer: Link ? /* @__PURE__ */ jsx11(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx11(
|
|
1791
2054
|
"a",
|
|
1792
2055
|
{
|
|
1793
2056
|
href: signInLink,
|
|
@@ -1800,7 +2063,7 @@ var VerifyEmail = ({
|
|
|
1800
2063
|
}
|
|
1801
2064
|
),
|
|
1802
2065
|
children: [
|
|
1803
|
-
/* @__PURE__ */
|
|
2066
|
+
/* @__PURE__ */ jsx11(
|
|
1804
2067
|
VerificationForm,
|
|
1805
2068
|
{
|
|
1806
2069
|
verificationId,
|
|
@@ -1810,10 +2073,10 @@ var VerifyEmail = ({
|
|
|
1810
2073
|
error
|
|
1811
2074
|
}
|
|
1812
2075
|
),
|
|
1813
|
-
errorContent && /* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
2076
|
+
errorContent && /* @__PURE__ */ jsxs9(Alert6, { variant: "destructive", className: "mt-4", children: [
|
|
2077
|
+
/* @__PURE__ */ jsx11(IconAlertCircle6, { className: "h-4 w-4" }),
|
|
2078
|
+
/* @__PURE__ */ jsx11(AlertTitle6, { children: errorContent.title }),
|
|
2079
|
+
/* @__PURE__ */ jsx11(AlertDescription6, { children: errorContent.description })
|
|
1817
2080
|
] })
|
|
1818
2081
|
]
|
|
1819
2082
|
}
|
|
@@ -1821,12 +2084,12 @@ var VerifyEmail = ({
|
|
|
1821
2084
|
};
|
|
1822
2085
|
|
|
1823
2086
|
// src/components/auth/verify-phone.tsx
|
|
1824
|
-
import { Alert as
|
|
1825
|
-
import { useMesob as
|
|
1826
|
-
import { IconAlertCircle as
|
|
1827
|
-
import { useEffect as
|
|
1828
|
-
import { toast as
|
|
1829
|
-
import { jsx as
|
|
2087
|
+
import { Alert as Alert7, AlertDescription as AlertDescription7, AlertTitle as AlertTitle7 } from "@mesob/ui/components";
|
|
2088
|
+
import { useMesob as useMesob8 } from "@mesob/ui/providers";
|
|
2089
|
+
import { IconAlertCircle as IconAlertCircle7 } from "@tabler/icons-react";
|
|
2090
|
+
import { useEffect as useEffect8, useState as useState9 } from "react";
|
|
2091
|
+
import { toast as toast7 } from "sonner";
|
|
2092
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1830
2093
|
var VerifyPhone = ({
|
|
1831
2094
|
verificationId,
|
|
1832
2095
|
context,
|
|
@@ -1835,13 +2098,13 @@ var VerifyPhone = ({
|
|
|
1835
2098
|
}) => {
|
|
1836
2099
|
const { hooks, refresh, setAuth } = useApi();
|
|
1837
2100
|
const { config } = useConfig();
|
|
1838
|
-
const mesob =
|
|
2101
|
+
const mesob = useMesob8();
|
|
1839
2102
|
const Link = mesob?.navigation?.Link;
|
|
1840
2103
|
const t = useTranslator("Auth.verification");
|
|
1841
2104
|
const common = useTranslator("Common");
|
|
1842
2105
|
const footer = useTranslator("Auth.forgotPassword.footer");
|
|
1843
|
-
const [isLoading, setIsLoading] =
|
|
1844
|
-
const [error, setError] =
|
|
2106
|
+
const [isLoading, setIsLoading] = useState9(false);
|
|
2107
|
+
const [error, setError] = useState9(null);
|
|
1845
2108
|
const verifyPhoneMutation = hooks.useMutation(
|
|
1846
2109
|
"post",
|
|
1847
2110
|
"/phone/verification/confirm"
|
|
@@ -1858,9 +2121,9 @@ var VerifyPhone = ({
|
|
|
1858
2121
|
});
|
|
1859
2122
|
const logoImage = config.ui.logoImage;
|
|
1860
2123
|
const defaultRedirect = redirectUrl || config.navigation?.defaultRedirectUrl || "/";
|
|
1861
|
-
|
|
2124
|
+
useEffect8(() => {
|
|
1862
2125
|
if (error) {
|
|
1863
|
-
|
|
2126
|
+
toast7.error(error.title || "Error", {
|
|
1864
2127
|
description: error.description
|
|
1865
2128
|
});
|
|
1866
2129
|
}
|
|
@@ -1928,13 +2191,13 @@ var VerifyPhone = ({
|
|
|
1928
2191
|
}
|
|
1929
2192
|
};
|
|
1930
2193
|
if (!verificationId) {
|
|
1931
|
-
return /* @__PURE__ */
|
|
2194
|
+
return /* @__PURE__ */ jsx12(
|
|
1932
2195
|
AuthLayout,
|
|
1933
2196
|
{
|
|
1934
2197
|
title: common("invalidLinkTitle"),
|
|
1935
2198
|
description: common("invalidLinkDescription"),
|
|
1936
|
-
footer: /* @__PURE__ */
|
|
1937
|
-
children: /* @__PURE__ */
|
|
2199
|
+
footer: /* @__PURE__ */ jsx12(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }),
|
|
2200
|
+
children: /* @__PURE__ */ jsx12("div", {})
|
|
1938
2201
|
}
|
|
1939
2202
|
);
|
|
1940
2203
|
}
|
|
@@ -1946,15 +2209,15 @@ var VerifyPhone = ({
|
|
|
1946
2209
|
errorContent = error;
|
|
1947
2210
|
}
|
|
1948
2211
|
}
|
|
1949
|
-
return /* @__PURE__ */
|
|
2212
|
+
return /* @__PURE__ */ jsxs10(
|
|
1950
2213
|
AuthLayout,
|
|
1951
2214
|
{
|
|
1952
|
-
title:
|
|
2215
|
+
title: config.ui.name,
|
|
1953
2216
|
description: t("phone.description", {
|
|
1954
2217
|
target: phone || t("phone.missingPhone")
|
|
1955
2218
|
}),
|
|
1956
2219
|
logoImage,
|
|
1957
|
-
footer: Link ? /* @__PURE__ */
|
|
2220
|
+
footer: Link ? /* @__PURE__ */ jsx12(Link, { href: signInLink, className: "text-primary hover:underline", children: footer("backToSignIn") }) : /* @__PURE__ */ jsx12(
|
|
1958
2221
|
"a",
|
|
1959
2222
|
{
|
|
1960
2223
|
href: signInLink,
|
|
@@ -1967,7 +2230,7 @@ var VerifyPhone = ({
|
|
|
1967
2230
|
}
|
|
1968
2231
|
),
|
|
1969
2232
|
children: [
|
|
1970
|
-
/* @__PURE__ */
|
|
2233
|
+
/* @__PURE__ */ jsx12(
|
|
1971
2234
|
VerificationForm,
|
|
1972
2235
|
{
|
|
1973
2236
|
verificationId,
|
|
@@ -1977,20 +2240,55 @@ var VerifyPhone = ({
|
|
|
1977
2240
|
error
|
|
1978
2241
|
}
|
|
1979
2242
|
),
|
|
1980
|
-
errorContent && /* @__PURE__ */
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
1983
|
-
/* @__PURE__ */
|
|
2243
|
+
errorContent && /* @__PURE__ */ jsxs10(Alert7, { variant: "destructive", className: "mt-4", children: [
|
|
2244
|
+
/* @__PURE__ */ jsx12(IconAlertCircle7, { className: "h-4 w-4" }),
|
|
2245
|
+
/* @__PURE__ */ jsx12(AlertTitle7, { children: errorContent.title }),
|
|
2246
|
+
/* @__PURE__ */ jsx12(AlertDescription7, { children: errorContent.description })
|
|
1984
2247
|
] })
|
|
1985
2248
|
]
|
|
1986
2249
|
}
|
|
1987
2250
|
);
|
|
1988
2251
|
};
|
|
1989
2252
|
|
|
2253
|
+
// src/components/authorization/deny.tsx
|
|
2254
|
+
import { deny as canDeny } from "@mesob/common";
|
|
2255
|
+
import { Fragment as Fragment2, jsx as jsx13 } from "react/jsx-runtime";
|
|
2256
|
+
function Deny({ permissions, userPermissions, children }) {
|
|
2257
|
+
const { isLoading, user } = useSession();
|
|
2258
|
+
if (userPermissions === void 0 && isLoading) {
|
|
2259
|
+
return null;
|
|
2260
|
+
}
|
|
2261
|
+
const resolvedPermissions = userPermissions ?? user?.permissions ?? [];
|
|
2262
|
+
if (canDeny(permissions, resolvedPermissions)) {
|
|
2263
|
+
return /* @__PURE__ */ jsx13(Fragment2, { children });
|
|
2264
|
+
}
|
|
2265
|
+
return null;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
// src/components/authorization/grant.tsx
|
|
2269
|
+
import { grant as canGrant } from "@mesob/common";
|
|
2270
|
+
import { Fragment as Fragment3, jsx as jsx14 } from "react/jsx-runtime";
|
|
2271
|
+
function Grant({
|
|
2272
|
+
permissions,
|
|
2273
|
+
userPermissions,
|
|
2274
|
+
fallback = null,
|
|
2275
|
+
children
|
|
2276
|
+
}) {
|
|
2277
|
+
const { isLoading, user } = useSession();
|
|
2278
|
+
if (userPermissions === void 0 && isLoading) {
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
const resolvedPermissions = userPermissions ?? user?.permissions ?? [];
|
|
2282
|
+
if (canGrant(permissions, resolvedPermissions)) {
|
|
2283
|
+
return /* @__PURE__ */ jsx14(Fragment3, { children });
|
|
2284
|
+
}
|
|
2285
|
+
return /* @__PURE__ */ jsx14(Fragment3, { children: fallback });
|
|
2286
|
+
}
|
|
2287
|
+
|
|
1990
2288
|
// src/components/error-boundary.tsx
|
|
1991
2289
|
import { Button as Button7 } from "@mesob/ui/components";
|
|
1992
2290
|
import { Component } from "react";
|
|
1993
|
-
import { jsx as
|
|
2291
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1994
2292
|
var ErrorBoundary = class extends Component {
|
|
1995
2293
|
constructor(props) {
|
|
1996
2294
|
super(props);
|
|
@@ -2012,28 +2310,112 @@ var ErrorBoundary = class extends Component {
|
|
|
2012
2310
|
reset: this.reset
|
|
2013
2311
|
});
|
|
2014
2312
|
}
|
|
2015
|
-
return /* @__PURE__ */
|
|
2313
|
+
return /* @__PURE__ */ jsx15(ErrorFallback, { error: this.state.error, reset: this.reset });
|
|
2016
2314
|
}
|
|
2017
2315
|
return this.props.children;
|
|
2018
2316
|
}
|
|
2019
2317
|
};
|
|
2020
2318
|
function ErrorFallback({ error, reset }) {
|
|
2021
|
-
return /* @__PURE__ */
|
|
2022
|
-
/* @__PURE__ */
|
|
2023
|
-
/* @__PURE__ */
|
|
2024
|
-
/* @__PURE__ */
|
|
2319
|
+
return /* @__PURE__ */ jsx15("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: /* @__PURE__ */ jsxs11("div", { className: "max-w-md w-full space-y-4 text-center", children: [
|
|
2320
|
+
/* @__PURE__ */ jsxs11("div", { className: "space-y-2", children: [
|
|
2321
|
+
/* @__PURE__ */ jsx15("h2", { className: "text-2xl font-bold text-destructive", children: "Something went wrong" }),
|
|
2322
|
+
/* @__PURE__ */ jsx15("p", { className: "text-muted-foreground", children: error.message || "An unexpected error occurred" })
|
|
2025
2323
|
] }),
|
|
2026
|
-
/* @__PURE__ */
|
|
2324
|
+
/* @__PURE__ */ jsx15(Button7, { onClick: reset, variant: "outline", children: "Try again" })
|
|
2027
2325
|
] }) });
|
|
2028
2326
|
}
|
|
2029
2327
|
function AuthErrorBoundary({ children }) {
|
|
2030
|
-
return /* @__PURE__ */
|
|
2328
|
+
return /* @__PURE__ */ jsx15(ErrorBoundary, { children });
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
// src/components/iam/permission-selector.tsx
|
|
2332
|
+
import {
|
|
2333
|
+
Badge,
|
|
2334
|
+
EntitySelector,
|
|
2335
|
+
useEntitySectionState
|
|
2336
|
+
} from "@mesob/ui/components";
|
|
2337
|
+
import { IconKey } from "@tabler/icons-react";
|
|
2338
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2339
|
+
var permissionColumns = [
|
|
2340
|
+
{
|
|
2341
|
+
key: "permission",
|
|
2342
|
+
header: "Permission",
|
|
2343
|
+
cell: (permission) => /* @__PURE__ */ jsxs12("div", { className: "space-y-1", children: [
|
|
2344
|
+
/* @__PURE__ */ jsx16("p", { className: "font-medium", children: permission.activity }),
|
|
2345
|
+
/* @__PURE__ */ jsx16("p", { className: "font-mono text-xs text-muted-foreground", children: permission.id })
|
|
2346
|
+
] })
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
key: "scope",
|
|
2350
|
+
header: "Scope",
|
|
2351
|
+
cell: (permission) => /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-2", children: [
|
|
2352
|
+
/* @__PURE__ */ jsx16(Badge, { variant: "secondary", children: permission.application }),
|
|
2353
|
+
/* @__PURE__ */ jsx16(Badge, { variant: "outline", children: permission.feature })
|
|
2354
|
+
] })
|
|
2355
|
+
}
|
|
2356
|
+
];
|
|
2357
|
+
function PermissionSelector({
|
|
2358
|
+
trigger,
|
|
2359
|
+
multiple = true,
|
|
2360
|
+
onSelect,
|
|
2361
|
+
excludeIds = []
|
|
2362
|
+
}) {
|
|
2363
|
+
const { hooks } = useApi();
|
|
2364
|
+
const state = useEntitySectionState({
|
|
2365
|
+
defaultSort: "id",
|
|
2366
|
+
defaultOrder: "asc",
|
|
2367
|
+
defaultPageSize: 10,
|
|
2368
|
+
searchParamName: "search"
|
|
2369
|
+
});
|
|
2370
|
+
const permissionsQuery = state.queryConfig;
|
|
2371
|
+
const { data, isPending, isFetching } = hooks.useQuery(
|
|
2372
|
+
"get",
|
|
2373
|
+
"/permissions",
|
|
2374
|
+
permissionsQuery
|
|
2375
|
+
);
|
|
2376
|
+
const items = (data?.permissions ?? []).filter(
|
|
2377
|
+
(permission) => !excludeIds.includes(permission.id)
|
|
2378
|
+
);
|
|
2379
|
+
const config = {
|
|
2380
|
+
title: "Select permission(s)",
|
|
2381
|
+
multiple,
|
|
2382
|
+
entityName: "permission",
|
|
2383
|
+
entityIcon: IconKey,
|
|
2384
|
+
columns: permissionColumns,
|
|
2385
|
+
getItemLabel: (permission) => permission.id,
|
|
2386
|
+
searchPlaceholder: "Search permissions...",
|
|
2387
|
+
filterOptions: [
|
|
2388
|
+
{ label: "All", value: "" },
|
|
2389
|
+
{ label: "Application", value: "application" },
|
|
2390
|
+
{ label: "Feature", value: "feature" },
|
|
2391
|
+
{ label: "Activity", value: "activity" }
|
|
2392
|
+
],
|
|
2393
|
+
sortOptions: [
|
|
2394
|
+
{ label: "ID", value: "id" },
|
|
2395
|
+
{ label: "Application", value: "application" },
|
|
2396
|
+
{ label: "Feature", value: "feature" },
|
|
2397
|
+
{ label: "Activity", value: "activity" }
|
|
2398
|
+
],
|
|
2399
|
+
showViewToggle: false,
|
|
2400
|
+
wrapHeaderInCard: false
|
|
2401
|
+
};
|
|
2402
|
+
return /* @__PURE__ */ jsx16(
|
|
2403
|
+
EntitySelector,
|
|
2404
|
+
{
|
|
2405
|
+
trigger,
|
|
2406
|
+
config,
|
|
2407
|
+
onSelect,
|
|
2408
|
+
items,
|
|
2409
|
+
total: items.length,
|
|
2410
|
+
isLoading: isPending || isFetching,
|
|
2411
|
+
state
|
|
2412
|
+
}
|
|
2413
|
+
);
|
|
2031
2414
|
}
|
|
2032
2415
|
|
|
2033
2416
|
// src/components/iam/permissions.tsx
|
|
2034
|
-
import { Badge, Button as Button8 } from "@mesob/ui/components";
|
|
2035
|
-
import {
|
|
2036
|
-
import { useState as useState9 } from "react";
|
|
2417
|
+
import { Badge as Badge2, Button as Button8 } from "@mesob/ui/components";
|
|
2418
|
+
import { useState as useState10 } from "react";
|
|
2037
2419
|
|
|
2038
2420
|
// src/components/shared/data-table.tsx
|
|
2039
2421
|
import {
|
|
@@ -2047,7 +2429,7 @@ import {
|
|
|
2047
2429
|
|
|
2048
2430
|
// src/components/skeletons/table-skeleton.tsx
|
|
2049
2431
|
import { Skeleton } from "@mesob/ui/components";
|
|
2050
|
-
import { jsx as
|
|
2432
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2051
2433
|
function TableSkeleton({ columns = 5, rows = 10 }) {
|
|
2052
2434
|
const headerKeys = Array.from({ length: columns }, (_, i) => `header-${i}`);
|
|
2053
2435
|
const rowKeys = Array.from({ length: rows }, (_, i) => `row-${i}`);
|
|
@@ -2055,32 +2437,32 @@ function TableSkeleton({ columns = 5, rows = 10 }) {
|
|
|
2055
2437
|
{ length: rows },
|
|
2056
2438
|
(_, rowIdx) => Array.from({ length: columns }, (_2, colIdx) => `cell-${rowIdx}-${colIdx}`)
|
|
2057
2439
|
);
|
|
2058
|
-
return /* @__PURE__ */
|
|
2059
|
-
/* @__PURE__ */
|
|
2060
|
-
/* @__PURE__ */
|
|
2061
|
-
/* @__PURE__ */
|
|
2440
|
+
return /* @__PURE__ */ jsxs13("div", { className: "w-full space-y-4", children: [
|
|
2441
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex justify-between items-center", children: [
|
|
2442
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-8 w-48" }),
|
|
2443
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-32" })
|
|
2062
2444
|
] }),
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
/* @__PURE__ */
|
|
2065
|
-
/* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2445
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-4", children: [
|
|
2446
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 flex-1 max-w-sm" }),
|
|
2447
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-24" }),
|
|
2448
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-24" })
|
|
2067
2449
|
] }),
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
2070
|
-
rowKeys.map((rowKey, rowIdx) => /* @__PURE__ */
|
|
2450
|
+
/* @__PURE__ */ jsxs13("div", { className: "border rounded-lg overflow-hidden", children: [
|
|
2451
|
+
/* @__PURE__ */ jsx17("div", { className: "flex gap-4 p-4 bg-muted", children: headerKeys.map((key) => /* @__PURE__ */ jsx17(Skeleton, { className: "h-4 flex-1" }, key)) }),
|
|
2452
|
+
rowKeys.map((rowKey, rowIdx) => /* @__PURE__ */ jsx17("div", { className: "flex gap-4 p-4 border-t", children: cellKeys[rowIdx]?.map((cellKey) => /* @__PURE__ */ jsx17(Skeleton, { className: "h-4 flex-1" }, cellKey)) }, rowKey))
|
|
2071
2453
|
] }),
|
|
2072
|
-
/* @__PURE__ */
|
|
2073
|
-
/* @__PURE__ */
|
|
2074
|
-
/* @__PURE__ */
|
|
2075
|
-
/* @__PURE__ */
|
|
2076
|
-
/* @__PURE__ */
|
|
2454
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex justify-between items-center", children: [
|
|
2455
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-4 w-32" }),
|
|
2456
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-2", children: [
|
|
2457
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-20" }),
|
|
2458
|
+
/* @__PURE__ */ jsx17(Skeleton, { className: "h-10 w-20" })
|
|
2077
2459
|
] })
|
|
2078
2460
|
] })
|
|
2079
2461
|
] });
|
|
2080
2462
|
}
|
|
2081
2463
|
|
|
2082
2464
|
// src/components/shared/data-table.tsx
|
|
2083
|
-
import { jsx as
|
|
2465
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2084
2466
|
function DataTable({
|
|
2085
2467
|
data,
|
|
2086
2468
|
columns,
|
|
@@ -2090,24 +2472,24 @@ function DataTable({
|
|
|
2090
2472
|
actions
|
|
2091
2473
|
}) {
|
|
2092
2474
|
if (isLoading) {
|
|
2093
|
-
return /* @__PURE__ */
|
|
2475
|
+
return /* @__PURE__ */ jsx18(TableSkeleton, { columns: columns.length, rows: 5 });
|
|
2094
2476
|
}
|
|
2095
2477
|
if (data.length === 0) {
|
|
2096
|
-
return /* @__PURE__ */
|
|
2097
|
-
/* @__PURE__ */
|
|
2098
|
-
actions && /* @__PURE__ */
|
|
2478
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col items-center justify-center min-h-[400px] p-6", children: [
|
|
2479
|
+
/* @__PURE__ */ jsx18("p", { className: "text-muted-foreground", children: emptyMessage }),
|
|
2480
|
+
actions && /* @__PURE__ */ jsx18("div", { className: "mt-4", children: actions })
|
|
2099
2481
|
] });
|
|
2100
2482
|
}
|
|
2101
|
-
return /* @__PURE__ */
|
|
2102
|
-
actions && /* @__PURE__ */
|
|
2103
|
-
/* @__PURE__ */
|
|
2104
|
-
/* @__PURE__ */
|
|
2105
|
-
/* @__PURE__ */
|
|
2483
|
+
return /* @__PURE__ */ jsxs14("div", { className: "w-full space-y-4", children: [
|
|
2484
|
+
actions && /* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: actions }),
|
|
2485
|
+
/* @__PURE__ */ jsx18("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs14(Table, { children: [
|
|
2486
|
+
/* @__PURE__ */ jsx18(TableHeader, { children: /* @__PURE__ */ jsx18(TableRow, { children: columns.map((column) => /* @__PURE__ */ jsx18(TableHead, { children: column.header }, column.key)) }) }),
|
|
2487
|
+
/* @__PURE__ */ jsx18(TableBody, { children: data.map((row) => /* @__PURE__ */ jsx18(
|
|
2106
2488
|
TableRow,
|
|
2107
2489
|
{
|
|
2108
2490
|
onClick: () => onRowClick?.(row),
|
|
2109
2491
|
className: onRowClick ? "cursor-pointer hover:bg-muted/50" : "",
|
|
2110
|
-
children: columns.map((column) => /* @__PURE__ */
|
|
2492
|
+
children: columns.map((column) => /* @__PURE__ */ jsx18(TableCell, { children: column.cell(row) }, `${row.id}-${column.key}`))
|
|
2111
2493
|
},
|
|
2112
2494
|
row.id
|
|
2113
2495
|
)) })
|
|
@@ -2116,23 +2498,10 @@ function DataTable({
|
|
|
2116
2498
|
}
|
|
2117
2499
|
|
|
2118
2500
|
// src/components/iam/permissions.tsx
|
|
2119
|
-
import { jsx as
|
|
2120
|
-
function getTranslation(value, locale) {
|
|
2121
|
-
if (!value) {
|
|
2122
|
-
return "";
|
|
2123
|
-
}
|
|
2124
|
-
if (typeof value === "string") {
|
|
2125
|
-
return value;
|
|
2126
|
-
}
|
|
2127
|
-
if (typeof value === "object") {
|
|
2128
|
-
return value[locale] ?? value.en ?? value.am ?? "";
|
|
2129
|
-
}
|
|
2130
|
-
return "";
|
|
2131
|
-
}
|
|
2501
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2132
2502
|
function Permissions() {
|
|
2133
2503
|
const { hooks } = useApi();
|
|
2134
|
-
const
|
|
2135
|
-
const [page, setPage] = useState9(1);
|
|
2504
|
+
const [page, setPage] = useState10(1);
|
|
2136
2505
|
const limit = 20;
|
|
2137
2506
|
const { data, isLoading, error } = hooks.useQuery("get", "/permissions", {
|
|
2138
2507
|
params: {
|
|
@@ -2142,81 +2511,636 @@ function Permissions() {
|
|
|
2142
2511
|
}
|
|
2143
2512
|
}
|
|
2144
2513
|
});
|
|
2145
|
-
const columns = [
|
|
2146
|
-
{
|
|
2147
|
-
key: "
|
|
2148
|
-
header: "Permission",
|
|
2149
|
-
cell: (permission) => /* @__PURE__ */
|
|
2150
|
-
/* @__PURE__ */
|
|
2151
|
-
/* @__PURE__ */
|
|
2152
|
-
] })
|
|
2153
|
-
},
|
|
2154
|
-
{
|
|
2155
|
-
key: "
|
|
2156
|
-
header: "
|
|
2157
|
-
cell: (permission) => /* @__PURE__ */
|
|
2158
|
-
},
|
|
2159
|
-
{
|
|
2160
|
-
key: "
|
|
2161
|
-
header: "
|
|
2162
|
-
cell: (permission) => /* @__PURE__ */
|
|
2163
|
-
},
|
|
2514
|
+
const columns = [
|
|
2515
|
+
{
|
|
2516
|
+
key: "activity",
|
|
2517
|
+
header: "Permission",
|
|
2518
|
+
cell: (permission) => /* @__PURE__ */ jsxs15("div", { children: [
|
|
2519
|
+
/* @__PURE__ */ jsx19("p", { className: "font-medium", children: permission.activity }),
|
|
2520
|
+
/* @__PURE__ */ jsx19(Badge2, { variant: "outline", className: "mt-1 font-mono text-xs", children: permission.id })
|
|
2521
|
+
] })
|
|
2522
|
+
},
|
|
2523
|
+
{
|
|
2524
|
+
key: "application",
|
|
2525
|
+
header: "Application",
|
|
2526
|
+
cell: (permission) => /* @__PURE__ */ jsx19(Badge2, { variant: "secondary", children: permission.application })
|
|
2527
|
+
},
|
|
2528
|
+
{
|
|
2529
|
+
key: "feature",
|
|
2530
|
+
header: "Feature",
|
|
2531
|
+
cell: (permission) => /* @__PURE__ */ jsx19(Badge2, { variant: "outline", children: permission.feature })
|
|
2532
|
+
},
|
|
2533
|
+
{
|
|
2534
|
+
key: "description",
|
|
2535
|
+
header: "Description",
|
|
2536
|
+
cell: (permission) => /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground max-w-xs truncate", children: String(permission.description ?? "\u2014") })
|
|
2537
|
+
}
|
|
2538
|
+
];
|
|
2539
|
+
if (error) {
|
|
2540
|
+
return /* @__PURE__ */ jsx19("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx19("p", { className: "text-destructive", children: "Error loading permissions" }) });
|
|
2541
|
+
}
|
|
2542
|
+
return /* @__PURE__ */ jsxs15("div", { className: "w-full p-6 space-y-4", children: [
|
|
2543
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between items-center", children: [
|
|
2544
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
2545
|
+
/* @__PURE__ */ jsx19("h1", { className: "text-3xl font-bold", children: "Permissions" }),
|
|
2546
|
+
/* @__PURE__ */ jsx19("p", { className: "text-muted-foreground", children: "View the permission catalog for this tenant" })
|
|
2547
|
+
] }),
|
|
2548
|
+
/* @__PURE__ */ jsx19(Button8, { variant: "outline", children: "Seed Permissions" })
|
|
2549
|
+
] }),
|
|
2550
|
+
/* @__PURE__ */ jsx19(
|
|
2551
|
+
DataTable,
|
|
2552
|
+
{
|
|
2553
|
+
data: data?.permissions || [],
|
|
2554
|
+
columns,
|
|
2555
|
+
isLoading,
|
|
2556
|
+
emptyMessage: "No permissions found"
|
|
2557
|
+
}
|
|
2558
|
+
),
|
|
2559
|
+
data && "permissions" in data && data.permissions && data.permissions.length >= limit && /* @__PURE__ */ jsxs15("div", { className: "flex justify-between items-center", children: [
|
|
2560
|
+
/* @__PURE__ */ jsx19(
|
|
2561
|
+
Button8,
|
|
2562
|
+
{
|
|
2563
|
+
variant: "outline",
|
|
2564
|
+
disabled: page === 1,
|
|
2565
|
+
onClick: () => setPage((prev) => prev - 1),
|
|
2566
|
+
children: "Previous"
|
|
2567
|
+
}
|
|
2568
|
+
),
|
|
2569
|
+
/* @__PURE__ */ jsxs15("span", { className: "text-sm text-muted-foreground", children: [
|
|
2570
|
+
"Page ",
|
|
2571
|
+
page
|
|
2572
|
+
] }),
|
|
2573
|
+
/* @__PURE__ */ jsx19(
|
|
2574
|
+
Button8,
|
|
2575
|
+
{
|
|
2576
|
+
variant: "outline",
|
|
2577
|
+
onClick: () => setPage((prev) => prev + 1),
|
|
2578
|
+
children: "Next"
|
|
2579
|
+
}
|
|
2580
|
+
)
|
|
2581
|
+
] })
|
|
2582
|
+
] });
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
// src/components/iam/role-detail-layout.tsx
|
|
2586
|
+
import {
|
|
2587
|
+
EntityDetailHeader,
|
|
2588
|
+
EntityEmptyState,
|
|
2589
|
+
PageContainer,
|
|
2590
|
+
useBreadcrumbs
|
|
2591
|
+
} from "@mesob/ui/components";
|
|
2592
|
+
import { IconShield } from "@tabler/icons-react";
|
|
2593
|
+
import { useMemo as useMemo2 } from "react";
|
|
2594
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2595
|
+
function str(value) {
|
|
2596
|
+
if (value == null) {
|
|
2597
|
+
return "";
|
|
2598
|
+
}
|
|
2599
|
+
if (typeof value === "string") {
|
|
2600
|
+
return value;
|
|
2601
|
+
}
|
|
2602
|
+
if (typeof value === "object" && value !== null && "en" in value) {
|
|
2603
|
+
const localized = value;
|
|
2604
|
+
return localized.en ?? localized.am ?? "";
|
|
2605
|
+
}
|
|
2606
|
+
return String(value);
|
|
2607
|
+
}
|
|
2608
|
+
function RoleDetailLayout({
|
|
2609
|
+
roleId,
|
|
2610
|
+
basePath = "/iam/roles",
|
|
2611
|
+
children
|
|
2612
|
+
}) {
|
|
2613
|
+
const { hooks } = useApi();
|
|
2614
|
+
const { config } = useConfig();
|
|
2615
|
+
const { data, isLoading, isFetching, isError } = hooks.useQuery(
|
|
2616
|
+
"get",
|
|
2617
|
+
"/roles/{id}",
|
|
2618
|
+
{ params: { path: { id: roleId } } },
|
|
2619
|
+
{ enabled: !!roleId }
|
|
2620
|
+
);
|
|
2621
|
+
const role = data?.role;
|
|
2622
|
+
const title = role ? str(role.name) || role.code : roleId ?? "Role";
|
|
2623
|
+
useBreadcrumbs({
|
|
2624
|
+
items: [
|
|
2625
|
+
{ label: "Home", href: "/dashboard" },
|
|
2626
|
+
{ label: "IAM", href: "/iam" },
|
|
2627
|
+
{ label: "Roles", href: basePath },
|
|
2628
|
+
{ label: title }
|
|
2629
|
+
]
|
|
2630
|
+
});
|
|
2631
|
+
const tabs = useMemo2(
|
|
2632
|
+
() => [
|
|
2633
|
+
{ value: "detail", name: "Detail", href: `${basePath}/${roleId}` },
|
|
2634
|
+
{
|
|
2635
|
+
value: "permissions",
|
|
2636
|
+
name: "Permissions",
|
|
2637
|
+
href: `${basePath}/${roleId}/permissions`
|
|
2638
|
+
},
|
|
2639
|
+
{
|
|
2640
|
+
value: "users",
|
|
2641
|
+
name: "Users",
|
|
2642
|
+
href: `${basePath}/${roleId}/users`
|
|
2643
|
+
}
|
|
2644
|
+
],
|
|
2645
|
+
[basePath, roleId]
|
|
2646
|
+
);
|
|
2647
|
+
if (!roleId) {
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
const loading = isLoading || isFetching;
|
|
2651
|
+
if (!(loading || role)) {
|
|
2652
|
+
return /* @__PURE__ */ jsx20(PageContainer, { className: "flex flex-1 flex-col gap-4 p-4 pt-0", children: /* @__PURE__ */ jsx20(
|
|
2653
|
+
EntityEmptyState,
|
|
2654
|
+
{
|
|
2655
|
+
icon: IconShield,
|
|
2656
|
+
entityName: "role",
|
|
2657
|
+
title: isError ? "Role unavailable" : "Role not found",
|
|
2658
|
+
description: isError ? "Failed to load this role." : "This role no longer exists.",
|
|
2659
|
+
actionLabel: "Back to roles",
|
|
2660
|
+
onAction: () => config.navigation?.onNavigate?.(basePath) ?? window.history.back()
|
|
2661
|
+
}
|
|
2662
|
+
) });
|
|
2663
|
+
}
|
|
2664
|
+
return /* @__PURE__ */ jsxs16(PageContainer, { className: "flex flex-1 flex-col gap-4 p-4 pt-0", children: [
|
|
2665
|
+
/* @__PURE__ */ jsx20(
|
|
2666
|
+
EntityDetailHeader,
|
|
2667
|
+
{
|
|
2668
|
+
title,
|
|
2669
|
+
icon: /* @__PURE__ */ jsx20(IconShield, { className: "h-5 w-5" }),
|
|
2670
|
+
loading,
|
|
2671
|
+
tabs
|
|
2672
|
+
}
|
|
2673
|
+
),
|
|
2674
|
+
children
|
|
2675
|
+
] });
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// src/components/iam/role-detail-page.tsx
|
|
2679
|
+
import { zodResolver as zodResolver7 } from "@hookform/resolvers/zod";
|
|
2680
|
+
import {
|
|
2681
|
+
EntityFormActions,
|
|
2682
|
+
Form as Form7,
|
|
2683
|
+
FormControl as FormControl7,
|
|
2684
|
+
FormField as FormField7,
|
|
2685
|
+
FormItem as FormItem7,
|
|
2686
|
+
FormLabel as FormLabel7,
|
|
2687
|
+
FormMessage as FormMessage7,
|
|
2688
|
+
Input as Input6,
|
|
2689
|
+
LocaleInputText,
|
|
2690
|
+
LocaleInputTextarea,
|
|
2691
|
+
Section,
|
|
2692
|
+
Skeleton as Skeleton2
|
|
2693
|
+
} from "@mesob/ui/components";
|
|
2694
|
+
import { useLocaleSchemas } from "@mesob/ui/providers";
|
|
2695
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2696
|
+
import { useEffect as useEffect9, useMemo as useMemo3 } from "react";
|
|
2697
|
+
import { useForm as useForm7 } from "react-hook-form";
|
|
2698
|
+
import { toast as toast8 } from "sonner";
|
|
2699
|
+
import { z as z7 } from "zod";
|
|
2700
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2701
|
+
function RoleDetailPage({
|
|
2702
|
+
roleId,
|
|
2703
|
+
basePath = "/iam/roles"
|
|
2704
|
+
}) {
|
|
2705
|
+
const { hooks } = useApi();
|
|
2706
|
+
const { config } = useConfig();
|
|
2707
|
+
const qc = useQueryClient();
|
|
2708
|
+
const { localeInputDefault, requiredSchema, optionalSchema } = useLocaleSchemas();
|
|
2709
|
+
const schema = useMemo3(
|
|
2710
|
+
() => z7.object({
|
|
2711
|
+
name: requiredSchema,
|
|
2712
|
+
code: z7.string().min(1, "Code is required"),
|
|
2713
|
+
description: optionalSchema
|
|
2714
|
+
}),
|
|
2715
|
+
[requiredSchema, optionalSchema]
|
|
2716
|
+
);
|
|
2717
|
+
const defaults = useMemo3(
|
|
2718
|
+
() => ({
|
|
2719
|
+
name: { ...localeInputDefault },
|
|
2720
|
+
code: "",
|
|
2721
|
+
description: { ...localeInputDefault }
|
|
2722
|
+
}),
|
|
2723
|
+
[localeInputDefault]
|
|
2724
|
+
);
|
|
2725
|
+
const { data, isLoading } = hooks.useQuery(
|
|
2726
|
+
"get",
|
|
2727
|
+
"/roles/{id}",
|
|
2728
|
+
{ params: { path: { id: roleId } } },
|
|
2729
|
+
{ enabled: !!roleId }
|
|
2730
|
+
);
|
|
2731
|
+
const update = hooks.useMutation("put", "/roles/{id}", {
|
|
2732
|
+
onSuccess: () => {
|
|
2733
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles"] });
|
|
2734
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles/{id}"] });
|
|
2735
|
+
toast8.success("Role updated");
|
|
2736
|
+
},
|
|
2737
|
+
onError: () => {
|
|
2738
|
+
toast8.error("Failed to update role");
|
|
2739
|
+
}
|
|
2740
|
+
});
|
|
2741
|
+
const remove = hooks.useMutation("delete", "/roles/{id}", {
|
|
2742
|
+
onSuccess: () => {
|
|
2743
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles"] });
|
|
2744
|
+
toast8.success("Role deleted");
|
|
2745
|
+
config.navigation?.onNavigate?.(basePath);
|
|
2746
|
+
},
|
|
2747
|
+
onError: () => {
|
|
2748
|
+
toast8.error("Failed to delete role");
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
const form = useForm7({
|
|
2752
|
+
resolver: zodResolver7(schema),
|
|
2753
|
+
defaultValues: defaults
|
|
2754
|
+
});
|
|
2755
|
+
const { reset, formState, control, register } = form;
|
|
2756
|
+
useEffect9(() => {
|
|
2757
|
+
if (!data?.role) {
|
|
2758
|
+
return;
|
|
2759
|
+
}
|
|
2760
|
+
const r = data.role;
|
|
2761
|
+
reset({
|
|
2762
|
+
name: r.name ?? {},
|
|
2763
|
+
code: r.code,
|
|
2764
|
+
description: r.description ?? {}
|
|
2765
|
+
});
|
|
2766
|
+
}, [data?.role, reset]);
|
|
2767
|
+
if (!roleId) {
|
|
2768
|
+
return null;
|
|
2769
|
+
}
|
|
2770
|
+
const role = data?.role;
|
|
2771
|
+
const editable = role?.isEditable !== false;
|
|
2772
|
+
const deletable = role?.isDeletable !== false;
|
|
2773
|
+
const onSubmit = form.handleSubmit(async (d) => {
|
|
2774
|
+
await update.mutateAsync({
|
|
2775
|
+
params: { path: { id: roleId } },
|
|
2776
|
+
body: {
|
|
2777
|
+
name: d.name,
|
|
2778
|
+
code: d.code,
|
|
2779
|
+
description: d.description ?? void 0
|
|
2780
|
+
}
|
|
2781
|
+
});
|
|
2782
|
+
});
|
|
2783
|
+
const footer = role ? /* @__PURE__ */ jsx21(
|
|
2784
|
+
EntityFormActions,
|
|
2785
|
+
{
|
|
2786
|
+
mode: "edit",
|
|
2787
|
+
onSubmit,
|
|
2788
|
+
onDelete: deletable ? () => remove.mutate({
|
|
2789
|
+
params: { path: { id: roleId } }
|
|
2790
|
+
}) : void 0,
|
|
2791
|
+
isSubmitting: update.isPending,
|
|
2792
|
+
isDeleting: remove.isPending,
|
|
2793
|
+
disabled: !editable,
|
|
2794
|
+
itemName: "role"
|
|
2795
|
+
}
|
|
2796
|
+
) : null;
|
|
2797
|
+
return /* @__PURE__ */ jsx21(Section, { title: "Role details", footer, defaultOpen: true, children: isLoading || !role ? /* @__PURE__ */ jsx21(RoleDetailSkeleton, {}) : /* @__PURE__ */ jsx21(Form7, { ...form, children: /* @__PURE__ */ jsxs17("form", { onSubmit, className: "space-y-4", children: [
|
|
2798
|
+
/* @__PURE__ */ jsx21(
|
|
2799
|
+
LocaleInputText,
|
|
2800
|
+
{
|
|
2801
|
+
label: "Name",
|
|
2802
|
+
field: "name",
|
|
2803
|
+
required: true,
|
|
2804
|
+
register,
|
|
2805
|
+
errors: formState.errors,
|
|
2806
|
+
placeholder: "e.g. Administrator",
|
|
2807
|
+
disabled: !editable
|
|
2808
|
+
}
|
|
2809
|
+
),
|
|
2810
|
+
/* @__PURE__ */ jsx21(
|
|
2811
|
+
FormField7,
|
|
2812
|
+
{
|
|
2813
|
+
control,
|
|
2814
|
+
name: "code",
|
|
2815
|
+
render: ({ field }) => /* @__PURE__ */ jsxs17(FormItem7, { children: [
|
|
2816
|
+
/* @__PURE__ */ jsxs17(FormLabel7, { children: [
|
|
2817
|
+
"Code ",
|
|
2818
|
+
/* @__PURE__ */ jsx21("span", { className: "text-destructive", children: "*" })
|
|
2819
|
+
] }),
|
|
2820
|
+
/* @__PURE__ */ jsx21(FormControl7, { children: /* @__PURE__ */ jsx21(
|
|
2821
|
+
Input6,
|
|
2822
|
+
{
|
|
2823
|
+
placeholder: "e.g. admin",
|
|
2824
|
+
disabled: !editable,
|
|
2825
|
+
...field
|
|
2826
|
+
}
|
|
2827
|
+
) }),
|
|
2828
|
+
/* @__PURE__ */ jsx21(FormMessage7, {})
|
|
2829
|
+
] })
|
|
2830
|
+
}
|
|
2831
|
+
),
|
|
2832
|
+
/* @__PURE__ */ jsx21(
|
|
2833
|
+
LocaleInputTextarea,
|
|
2834
|
+
{
|
|
2835
|
+
label: "Description",
|
|
2836
|
+
field: "description",
|
|
2837
|
+
register,
|
|
2838
|
+
errors: formState.errors,
|
|
2839
|
+
placeholder: "Description",
|
|
2840
|
+
rows: 3,
|
|
2841
|
+
disabled: !editable
|
|
2842
|
+
}
|
|
2843
|
+
)
|
|
2844
|
+
] }) }) });
|
|
2845
|
+
}
|
|
2846
|
+
function RoleDetailSkeleton() {
|
|
2847
|
+
return /* @__PURE__ */ jsxs17("div", { className: "space-y-4", children: [
|
|
2848
|
+
/* @__PURE__ */ jsxs17("div", { className: "space-y-2", children: [
|
|
2849
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-4 w-16" }),
|
|
2850
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-10 w-full" })
|
|
2851
|
+
] }),
|
|
2852
|
+
/* @__PURE__ */ jsxs17("div", { className: "space-y-2", children: [
|
|
2853
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-4 w-14" }),
|
|
2854
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-10 w-full" })
|
|
2855
|
+
] }),
|
|
2856
|
+
/* @__PURE__ */ jsxs17("div", { className: "space-y-2", children: [
|
|
2857
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-4 w-24" }),
|
|
2858
|
+
/* @__PURE__ */ jsx21(Skeleton2, { className: "h-20 w-full" })
|
|
2859
|
+
] })
|
|
2860
|
+
] });
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
// src/components/iam/role-permissions-page.tsx
|
|
2864
|
+
import {
|
|
2865
|
+
Badge as Badge3,
|
|
2866
|
+
Button as Button9,
|
|
2867
|
+
DataTablePagination,
|
|
2868
|
+
DeleteConfirmButton,
|
|
2869
|
+
DisplayTable,
|
|
2870
|
+
EntityEmptyState as EntityEmptyState2,
|
|
2871
|
+
EntityFilter,
|
|
2872
|
+
EntityHeader,
|
|
2873
|
+
EntityLoadingState,
|
|
2874
|
+
EntitySearch,
|
|
2875
|
+
EntitySort,
|
|
2876
|
+
EntityViewToggle,
|
|
2877
|
+
PageBody,
|
|
2878
|
+
Tbody,
|
|
2879
|
+
Td,
|
|
2880
|
+
Th,
|
|
2881
|
+
Thead,
|
|
2882
|
+
Tr,
|
|
2883
|
+
useEntityPagination,
|
|
2884
|
+
useEntityParams
|
|
2885
|
+
} from "@mesob/ui/components";
|
|
2886
|
+
import { IconKey as IconKey2, IconPlus, IconTrash } from "@tabler/icons-react";
|
|
2887
|
+
import { useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
2888
|
+
import { useMemo as useMemo4 } from "react";
|
|
2889
|
+
import { toast as toast9 } from "sonner";
|
|
2890
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2891
|
+
var TABLE_COLUMN_COUNT = 4;
|
|
2892
|
+
function RolePermissionsPage({ roleId }) {
|
|
2893
|
+
const { hooks } = useApi();
|
|
2894
|
+
const qc = useQueryClient2();
|
|
2895
|
+
const { queryConfig, params, setParams } = useEntityParams({
|
|
2896
|
+
searchKey: "search",
|
|
2897
|
+
defaultSort: "application",
|
|
2898
|
+
defaultOrder: "asc"
|
|
2899
|
+
});
|
|
2900
|
+
const permissionsQuery = useMemo4(
|
|
2901
|
+
() => ({
|
|
2902
|
+
params: {
|
|
2903
|
+
path: { id: roleId },
|
|
2904
|
+
query: queryConfig.params.query
|
|
2905
|
+
}
|
|
2906
|
+
}),
|
|
2907
|
+
[queryConfig, roleId]
|
|
2908
|
+
);
|
|
2909
|
+
const { data, isPending, isFetching } = hooks.useQuery(
|
|
2910
|
+
"get",
|
|
2911
|
+
"/roles/{id}/permissions",
|
|
2912
|
+
permissionsQuery,
|
|
2913
|
+
{ enabled: !!roleId }
|
|
2914
|
+
);
|
|
2915
|
+
const assignPermissions = hooks.useMutation(
|
|
2916
|
+
"post",
|
|
2917
|
+
"/roles/{id}/permissions",
|
|
2164
2918
|
{
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2919
|
+
onSuccess: (result) => {
|
|
2920
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles"] });
|
|
2921
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles/{id}"] });
|
|
2922
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles/{id}/permissions"] });
|
|
2923
|
+
toast9.success(
|
|
2924
|
+
result?.created ? `${result.created} permission(s) added` : "No changes"
|
|
2925
|
+
);
|
|
2926
|
+
},
|
|
2927
|
+
onError: () => {
|
|
2928
|
+
toast9.error("Failed to assign permissions");
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
);
|
|
2932
|
+
const revokePermission = hooks.useMutation(
|
|
2933
|
+
"delete",
|
|
2934
|
+
"/roles/{id}/permissions/{permissionId}",
|
|
2169
2935
|
{
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2936
|
+
onSuccess: () => {
|
|
2937
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles"] });
|
|
2938
|
+
qc.invalidateQueries({ queryKey: ["get", "/roles/{id}"] });
|
|
2939
|
+
qc.invalidateQueries({
|
|
2940
|
+
queryKey: ["get", "/roles/{id}/permissions"]
|
|
2941
|
+
});
|
|
2942
|
+
toast9.success("Permission removed");
|
|
2943
|
+
},
|
|
2944
|
+
onError: () => {
|
|
2945
|
+
toast9.error("Failed to remove permission");
|
|
2946
|
+
}
|
|
2173
2947
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2948
|
+
);
|
|
2949
|
+
const permissions = data?.permissions ?? [];
|
|
2950
|
+
const { total, pageCount } = useEntityPagination({
|
|
2951
|
+
items: permissions,
|
|
2952
|
+
total: data?.total,
|
|
2953
|
+
pageSize: params.pageSize
|
|
2954
|
+
});
|
|
2955
|
+
const isLoading = isPending || isFetching;
|
|
2956
|
+
const currentView = params.view || "table";
|
|
2957
|
+
if (!roleId) {
|
|
2958
|
+
return null;
|
|
2177
2959
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
/* @__PURE__ */ jsx15("p", { className: "text-muted-foreground", children: "Manage system permissions" })
|
|
2183
|
-
] }),
|
|
2184
|
-
/* @__PURE__ */ jsx15(Button8, { children: "Create Permission" })
|
|
2185
|
-
] }),
|
|
2186
|
-
/* @__PURE__ */ jsx15(
|
|
2187
|
-
DataTable,
|
|
2960
|
+
let content;
|
|
2961
|
+
if (isLoading) {
|
|
2962
|
+
content = /* @__PURE__ */ jsx22(
|
|
2963
|
+
EntityLoadingState,
|
|
2188
2964
|
{
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2965
|
+
view: currentView,
|
|
2966
|
+
rowCount: params.pageSize,
|
|
2967
|
+
columnCount: TABLE_COLUMN_COUNT,
|
|
2968
|
+
cardCount: params.pageSize
|
|
2193
2969
|
}
|
|
2194
|
-
)
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2970
|
+
);
|
|
2971
|
+
} else if (total === 0) {
|
|
2972
|
+
content = /* @__PURE__ */ jsx22(
|
|
2973
|
+
EntityEmptyState2,
|
|
2974
|
+
{
|
|
2975
|
+
icon: IconKey2,
|
|
2976
|
+
entityName: "permission",
|
|
2977
|
+
title: "No permissions assigned",
|
|
2978
|
+
description: "Assign permissions from the selector to grant access to this role."
|
|
2979
|
+
}
|
|
2980
|
+
);
|
|
2981
|
+
} else if (currentView === "table") {
|
|
2982
|
+
content = /* @__PURE__ */ jsxs18("div", { className: "space-y-4", children: [
|
|
2983
|
+
/* @__PURE__ */ jsxs18(DisplayTable, { withTableBorder: true, children: [
|
|
2984
|
+
/* @__PURE__ */ jsx22(Thead, { children: /* @__PURE__ */ jsxs18(Tr, { children: [
|
|
2985
|
+
/* @__PURE__ */ jsx22(Th, { children: "Permission" }),
|
|
2986
|
+
/* @__PURE__ */ jsx22(Th, { children: "Application" }),
|
|
2987
|
+
/* @__PURE__ */ jsx22(Th, { children: "Feature" }),
|
|
2988
|
+
/* @__PURE__ */ jsx22(Th, { className: "w-[60px]" })
|
|
2989
|
+
] }) }),
|
|
2990
|
+
/* @__PURE__ */ jsx22(Tbody, { children: permissions.map((permission) => /* @__PURE__ */ jsxs18(Tr, { children: [
|
|
2991
|
+
/* @__PURE__ */ jsx22(Td, { children: /* @__PURE__ */ jsxs18("div", { className: "space-y-1", children: [
|
|
2992
|
+
/* @__PURE__ */ jsx22("p", { className: "font-medium", children: permission.activity }),
|
|
2993
|
+
/* @__PURE__ */ jsx22("p", { className: "font-mono text-xs text-muted-foreground", children: permission.id })
|
|
2994
|
+
] }) }),
|
|
2995
|
+
/* @__PURE__ */ jsx22(Td, { children: /* @__PURE__ */ jsx22(Badge3, { variant: "secondary", children: permission.application }) }),
|
|
2996
|
+
/* @__PURE__ */ jsx22(Td, { children: /* @__PURE__ */ jsx22(Badge3, { variant: "outline", children: permission.feature }) }),
|
|
2997
|
+
/* @__PURE__ */ jsx22(Td, { children: /* @__PURE__ */ jsx22(
|
|
2998
|
+
DeleteConfirmButton,
|
|
2999
|
+
{
|
|
3000
|
+
entityName: "permission",
|
|
3001
|
+
onConfirm: () => revokePermission.mutate({
|
|
3002
|
+
params: {
|
|
3003
|
+
path: { id: roleId, permissionId: permission.id }
|
|
3004
|
+
}
|
|
3005
|
+
}),
|
|
3006
|
+
triggerClassName: "size-8 text-destructive hover:text-destructive"
|
|
3007
|
+
}
|
|
3008
|
+
) })
|
|
3009
|
+
] }, permission.id)) })
|
|
3010
|
+
] }),
|
|
3011
|
+
/* @__PURE__ */ jsx22(
|
|
3012
|
+
DataTablePagination,
|
|
2198
3013
|
{
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
3014
|
+
pageIndex: params.page - 1,
|
|
3015
|
+
pageSize: params.pageSize,
|
|
3016
|
+
pageCount,
|
|
3017
|
+
totalRows: total,
|
|
3018
|
+
onPageChange: (page) => setParams({ page: page + 1 }),
|
|
3019
|
+
onPageSizeChange: (pageSize) => setParams({ pageSize, page: 1 })
|
|
2203
3020
|
}
|
|
2204
|
-
)
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
3021
|
+
)
|
|
3022
|
+
] });
|
|
3023
|
+
} else {
|
|
3024
|
+
content = /* @__PURE__ */ jsxs18("div", { className: "space-y-4", children: [
|
|
3025
|
+
/* @__PURE__ */ jsx22("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", children: permissions.map((permission) => /* @__PURE__ */ jsx22(
|
|
3026
|
+
"div",
|
|
3027
|
+
{
|
|
3028
|
+
className: "rounded-xl border border-border/60 bg-card p-4 shadow-sm",
|
|
3029
|
+
children: /* @__PURE__ */ jsxs18("div", { className: "flex items-start justify-between gap-3", children: [
|
|
3030
|
+
/* @__PURE__ */ jsxs18("div", { className: "space-y-2", children: [
|
|
3031
|
+
/* @__PURE__ */ jsx22("p", { className: "font-semibold", children: permission.activity }),
|
|
3032
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap gap-2", children: [
|
|
3033
|
+
/* @__PURE__ */ jsx22(Badge3, { variant: "secondary", children: permission.application }),
|
|
3034
|
+
/* @__PURE__ */ jsx22(Badge3, { variant: "outline", children: permission.feature })
|
|
3035
|
+
] }),
|
|
3036
|
+
/* @__PURE__ */ jsx22("p", { className: "font-mono text-xs text-muted-foreground", children: permission.id })
|
|
3037
|
+
] }),
|
|
3038
|
+
/* @__PURE__ */ jsx22(
|
|
3039
|
+
Button9,
|
|
3040
|
+
{
|
|
3041
|
+
type: "button",
|
|
3042
|
+
variant: "ghost",
|
|
3043
|
+
size: "icon",
|
|
3044
|
+
onClick: () => revokePermission.mutate({
|
|
3045
|
+
params: {
|
|
3046
|
+
path: { id: roleId, permissionId: permission.id }
|
|
3047
|
+
}
|
|
3048
|
+
}),
|
|
3049
|
+
disabled: revokePermission.isPending,
|
|
3050
|
+
children: /* @__PURE__ */ jsx22(IconTrash, { className: "h-4 w-4" })
|
|
3051
|
+
}
|
|
3052
|
+
)
|
|
3053
|
+
] })
|
|
3054
|
+
},
|
|
3055
|
+
permission.id
|
|
3056
|
+
)) }),
|
|
3057
|
+
/* @__PURE__ */ jsx22(
|
|
3058
|
+
DataTablePagination,
|
|
3059
|
+
{
|
|
3060
|
+
pageIndex: params.page - 1,
|
|
3061
|
+
pageSize: params.pageSize,
|
|
3062
|
+
pageCount,
|
|
3063
|
+
totalRows: total,
|
|
3064
|
+
onPageChange: (page) => setParams({ page: page + 1 }),
|
|
3065
|
+
onPageSizeChange: (pageSize) => setParams({ pageSize, page: 1 })
|
|
3066
|
+
}
|
|
3067
|
+
)
|
|
3068
|
+
] });
|
|
3069
|
+
}
|
|
3070
|
+
return /* @__PURE__ */ jsxs18(PageBody, { className: "px-0 pb-6", children: [
|
|
3071
|
+
/* @__PURE__ */ jsx22(
|
|
3072
|
+
EntityHeader,
|
|
3073
|
+
{
|
|
3074
|
+
icon: /* @__PURE__ */ jsx22(IconKey2, { className: "h-5 w-5" }),
|
|
3075
|
+
title: "Role permissions",
|
|
3076
|
+
actions: /* @__PURE__ */ jsx22(
|
|
3077
|
+
PermissionSelector,
|
|
3078
|
+
{
|
|
3079
|
+
trigger: /* @__PURE__ */ jsxs18(Button9, { size: "sm", loading: assignPermissions.isPending, children: [
|
|
3080
|
+
/* @__PURE__ */ jsx22(IconPlus, { className: "h-4 w-4" }),
|
|
3081
|
+
"Add permissions"
|
|
3082
|
+
] }),
|
|
3083
|
+
onSelect: (selectedPermissions) => {
|
|
3084
|
+
if (!selectedPermissions.length) {
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3087
|
+
assignPermissions.mutate({
|
|
3088
|
+
params: { path: { id: roleId } },
|
|
3089
|
+
body: {
|
|
3090
|
+
permissionIds: selectedPermissions.map(
|
|
3091
|
+
(permission) => permission.id
|
|
3092
|
+
)
|
|
3093
|
+
}
|
|
3094
|
+
});
|
|
3095
|
+
},
|
|
3096
|
+
excludeIds: permissions.map((permission) => permission.id)
|
|
3097
|
+
}
|
|
3098
|
+
),
|
|
3099
|
+
search: /* @__PURE__ */ jsx22(
|
|
3100
|
+
EntitySearch,
|
|
3101
|
+
{
|
|
3102
|
+
paramKey: "search",
|
|
3103
|
+
placeholder: "Search assigned permissions..."
|
|
3104
|
+
}
|
|
3105
|
+
),
|
|
3106
|
+
filter: /* @__PURE__ */ jsx22(
|
|
3107
|
+
EntityFilter,
|
|
3108
|
+
{
|
|
3109
|
+
options: [
|
|
3110
|
+
{ label: "All", value: "" },
|
|
3111
|
+
{ label: "Application", value: "application" },
|
|
3112
|
+
{ label: "Feature", value: "feature" },
|
|
3113
|
+
{ label: "Activity", value: "activity" }
|
|
3114
|
+
],
|
|
3115
|
+
placeholder: "Search field"
|
|
3116
|
+
}
|
|
3117
|
+
),
|
|
3118
|
+
sort: /* @__PURE__ */ jsx22(
|
|
3119
|
+
EntitySort,
|
|
3120
|
+
{
|
|
3121
|
+
defaultSort: "application",
|
|
3122
|
+
defaultOrder: "asc",
|
|
3123
|
+
options: [
|
|
3124
|
+
{ label: "ID", value: "id" },
|
|
3125
|
+
{ label: "Application", value: "application" },
|
|
3126
|
+
{ label: "Feature", value: "feature" },
|
|
3127
|
+
{ label: "Activity", value: "activity" }
|
|
3128
|
+
]
|
|
3129
|
+
}
|
|
3130
|
+
),
|
|
3131
|
+
view: /* @__PURE__ */ jsx22(EntityViewToggle, { views: ["table", "card"] })
|
|
3132
|
+
}
|
|
3133
|
+
),
|
|
3134
|
+
content
|
|
2211
3135
|
] });
|
|
2212
3136
|
}
|
|
2213
3137
|
|
|
2214
3138
|
// src/components/iam/roles.tsx
|
|
2215
|
-
import { Badge as
|
|
2216
|
-
import { useLocale
|
|
2217
|
-
import { useState as
|
|
2218
|
-
import { jsx as
|
|
2219
|
-
function
|
|
3139
|
+
import { Badge as Badge4, Button as Button10 } from "@mesob/ui/components";
|
|
3140
|
+
import { useLocale } from "next-intl";
|
|
3141
|
+
import { useState as useState11 } from "react";
|
|
3142
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3143
|
+
function getTranslation(value, locale) {
|
|
2220
3144
|
if (!value) {
|
|
2221
3145
|
return "";
|
|
2222
3146
|
}
|
|
@@ -2230,8 +3154,8 @@ function getTranslation2(value, locale) {
|
|
|
2230
3154
|
}
|
|
2231
3155
|
function Roles() {
|
|
2232
3156
|
const { hooks } = useApi();
|
|
2233
|
-
const locale =
|
|
2234
|
-
const [page, setPage] =
|
|
3157
|
+
const locale = useLocale();
|
|
3158
|
+
const [page, setPage] = useState11(1);
|
|
2235
3159
|
const limit = 20;
|
|
2236
3160
|
const { data, isLoading, error } = hooks.useQuery("get", "/roles", {
|
|
2237
3161
|
params: {
|
|
@@ -2245,42 +3169,45 @@ function Roles() {
|
|
|
2245
3169
|
{
|
|
2246
3170
|
key: "name",
|
|
2247
3171
|
header: "Role",
|
|
2248
|
-
cell: (role) => /* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
3172
|
+
cell: (role) => /* @__PURE__ */ jsxs19("div", { children: [
|
|
3173
|
+
/* @__PURE__ */ jsx23("p", { className: "font-medium", children: getTranslation(role.name, locale) }),
|
|
3174
|
+
/* @__PURE__ */ jsx23(Badge4, { variant: "outline", className: "mt-1", children: role.code })
|
|
2251
3175
|
] })
|
|
2252
3176
|
},
|
|
2253
3177
|
{
|
|
2254
|
-
key: "
|
|
2255
|
-
header: "
|
|
2256
|
-
cell: (role) => /* @__PURE__ */
|
|
3178
|
+
key: "access",
|
|
3179
|
+
header: "Access",
|
|
3180
|
+
cell: (role) => /* @__PURE__ */ jsxs19("div", { className: "flex flex-wrap gap-2", children: [
|
|
3181
|
+
role.isSystem ? /* @__PURE__ */ jsx23(Badge4, { children: "System" }) : null,
|
|
3182
|
+
/* @__PURE__ */ jsxs19(Badge4, { variant: "secondary", children: [
|
|
3183
|
+
role.permissionCount ?? 0,
|
|
3184
|
+
" permissions"
|
|
3185
|
+
] })
|
|
3186
|
+
] })
|
|
2257
3187
|
},
|
|
2258
3188
|
{
|
|
2259
3189
|
key: "createdAt",
|
|
2260
3190
|
header: "Created",
|
|
2261
|
-
cell: (role) => /* @__PURE__ */
|
|
3191
|
+
cell: (role) => /* @__PURE__ */ jsx23("p", { className: "text-sm", children: new Date(role.createdAt).toLocaleDateString() })
|
|
2262
3192
|
},
|
|
2263
3193
|
{
|
|
2264
3194
|
key: "actions",
|
|
2265
3195
|
header: "Actions",
|
|
2266
|
-
cell: (_role) => /* @__PURE__ */
|
|
2267
|
-
/* @__PURE__ */ jsx16(Button9, { variant: "outline", size: "sm", children: "Permissions" }),
|
|
2268
|
-
/* @__PURE__ */ jsx16(Button9, { variant: "outline", size: "sm", children: "Edit" })
|
|
2269
|
-
] })
|
|
3196
|
+
cell: (_role) => /* @__PURE__ */ jsx23("div", { className: "flex gap-2", children: /* @__PURE__ */ jsx23(Button10, { variant: "outline", size: "sm", children: "Edit" }) })
|
|
2270
3197
|
}
|
|
2271
3198
|
];
|
|
2272
3199
|
if (error) {
|
|
2273
|
-
return /* @__PURE__ */
|
|
3200
|
+
return /* @__PURE__ */ jsx23("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx23("p", { className: "text-destructive", children: "Error loading roles" }) });
|
|
2274
3201
|
}
|
|
2275
|
-
return /* @__PURE__ */
|
|
2276
|
-
/* @__PURE__ */
|
|
2277
|
-
/* @__PURE__ */
|
|
2278
|
-
/* @__PURE__ */
|
|
2279
|
-
/* @__PURE__ */
|
|
3202
|
+
return /* @__PURE__ */ jsxs19("div", { className: "w-full p-6 space-y-4", children: [
|
|
3203
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex justify-between items-center", children: [
|
|
3204
|
+
/* @__PURE__ */ jsxs19("div", { children: [
|
|
3205
|
+
/* @__PURE__ */ jsx23("h1", { className: "text-3xl font-bold", children: "Roles" }),
|
|
3206
|
+
/* @__PURE__ */ jsx23("p", { className: "text-muted-foreground", children: "Manage roles and assigned permissions" })
|
|
2280
3207
|
] }),
|
|
2281
|
-
/* @__PURE__ */
|
|
3208
|
+
/* @__PURE__ */ jsx23(Button10, { children: "Create Role" })
|
|
2282
3209
|
] }),
|
|
2283
|
-
/* @__PURE__ */
|
|
3210
|
+
/* @__PURE__ */ jsx23(
|
|
2284
3211
|
DataTable,
|
|
2285
3212
|
{
|
|
2286
3213
|
data: data?.roles || [],
|
|
@@ -2289,32 +3216,39 @@ function Roles() {
|
|
|
2289
3216
|
emptyMessage: "No roles found"
|
|
2290
3217
|
}
|
|
2291
3218
|
),
|
|
2292
|
-
data && "roles" in data && data.roles && data.roles.length >= limit && /* @__PURE__ */
|
|
2293
|
-
/* @__PURE__ */
|
|
2294
|
-
|
|
3219
|
+
data && "roles" in data && data.roles && data.roles.length >= limit && /* @__PURE__ */ jsxs19("div", { className: "flex justify-between items-center", children: [
|
|
3220
|
+
/* @__PURE__ */ jsx23(
|
|
3221
|
+
Button10,
|
|
2295
3222
|
{
|
|
2296
3223
|
variant: "outline",
|
|
2297
3224
|
disabled: page === 1,
|
|
2298
|
-
onClick: () => setPage(
|
|
3225
|
+
onClick: () => setPage((prev) => prev - 1),
|
|
2299
3226
|
children: "Previous"
|
|
2300
3227
|
}
|
|
2301
3228
|
),
|
|
2302
|
-
/* @__PURE__ */
|
|
3229
|
+
/* @__PURE__ */ jsxs19("span", { className: "text-sm text-muted-foreground", children: [
|
|
2303
3230
|
"Page ",
|
|
2304
3231
|
page
|
|
2305
3232
|
] }),
|
|
2306
|
-
/* @__PURE__ */
|
|
3233
|
+
/* @__PURE__ */ jsx23(
|
|
3234
|
+
Button10,
|
|
3235
|
+
{
|
|
3236
|
+
variant: "outline",
|
|
3237
|
+
onClick: () => setPage((prev) => prev + 1),
|
|
3238
|
+
children: "Next"
|
|
3239
|
+
}
|
|
3240
|
+
)
|
|
2307
3241
|
] })
|
|
2308
3242
|
] });
|
|
2309
3243
|
}
|
|
2310
3244
|
|
|
2311
3245
|
// src/components/iam/sessions.tsx
|
|
2312
|
-
import { Button as
|
|
2313
|
-
import { useState as
|
|
2314
|
-
import { jsx as
|
|
3246
|
+
import { Button as Button11 } from "@mesob/ui/components";
|
|
3247
|
+
import { useState as useState12 } from "react";
|
|
3248
|
+
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2315
3249
|
function Sessions() {
|
|
2316
3250
|
const { hooks } = useApi();
|
|
2317
|
-
const [selectedSessionId] =
|
|
3251
|
+
const [selectedSessionId] = useState12(null);
|
|
2318
3252
|
const { data, isLoading, error, refetch } = hooks.useQuery(
|
|
2319
3253
|
"get",
|
|
2320
3254
|
"/sessions"
|
|
@@ -2340,31 +3274,31 @@ function Sessions() {
|
|
|
2340
3274
|
{
|
|
2341
3275
|
key: "createdAt",
|
|
2342
3276
|
header: "Created",
|
|
2343
|
-
cell: (session) => /* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2345
|
-
/* @__PURE__ */
|
|
3277
|
+
cell: (session) => /* @__PURE__ */ jsxs20("div", { children: [
|
|
3278
|
+
/* @__PURE__ */ jsx24("p", { className: "text-sm font-medium", children: new Date(session.createdAt).toLocaleDateString() }),
|
|
3279
|
+
/* @__PURE__ */ jsx24("p", { className: "text-xs text-muted-foreground", children: new Date(session.createdAt).toLocaleTimeString() })
|
|
2346
3280
|
] })
|
|
2347
3281
|
},
|
|
2348
3282
|
{
|
|
2349
3283
|
key: "expiresAt",
|
|
2350
3284
|
header: "Expires",
|
|
2351
|
-
cell: (session) => /* @__PURE__ */
|
|
3285
|
+
cell: (session) => /* @__PURE__ */ jsx24("p", { className: "text-sm", children: new Date(session.expiresAt).toLocaleDateString() })
|
|
2352
3286
|
},
|
|
2353
3287
|
{
|
|
2354
3288
|
key: "userAgent",
|
|
2355
3289
|
header: "Device",
|
|
2356
|
-
cell: (session) => /* @__PURE__ */
|
|
3290
|
+
cell: (session) => /* @__PURE__ */ jsx24("p", { className: "text-sm truncate max-w-xs", children: session.userAgent || "Unknown" })
|
|
2357
3291
|
},
|
|
2358
3292
|
{
|
|
2359
3293
|
key: "ip",
|
|
2360
3294
|
header: "IP Address",
|
|
2361
|
-
cell: (session) => /* @__PURE__ */
|
|
3295
|
+
cell: (session) => /* @__PURE__ */ jsx24("p", { className: "text-sm font-mono", children: session.ip || "Unknown" })
|
|
2362
3296
|
},
|
|
2363
3297
|
{
|
|
2364
3298
|
key: "actions",
|
|
2365
3299
|
header: "Actions",
|
|
2366
|
-
cell: (session) => /* @__PURE__ */
|
|
2367
|
-
|
|
3300
|
+
cell: (session) => /* @__PURE__ */ jsx24(
|
|
3301
|
+
Button11,
|
|
2368
3302
|
{
|
|
2369
3303
|
variant: "destructive",
|
|
2370
3304
|
size: "sm",
|
|
@@ -2376,14 +3310,14 @@ function Sessions() {
|
|
|
2376
3310
|
}
|
|
2377
3311
|
];
|
|
2378
3312
|
if (error) {
|
|
2379
|
-
return /* @__PURE__ */
|
|
3313
|
+
return /* @__PURE__ */ jsx24("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx24("p", { className: "text-destructive", children: "Error loading sessions" }) });
|
|
2380
3314
|
}
|
|
2381
|
-
return /* @__PURE__ */
|
|
2382
|
-
/* @__PURE__ */
|
|
2383
|
-
/* @__PURE__ */
|
|
2384
|
-
/* @__PURE__ */
|
|
3315
|
+
return /* @__PURE__ */ jsxs20("div", { className: "w-full p-6 space-y-4", children: [
|
|
3316
|
+
/* @__PURE__ */ jsxs20("div", { children: [
|
|
3317
|
+
/* @__PURE__ */ jsx24("h1", { className: "text-3xl font-bold", children: "Sessions" }),
|
|
3318
|
+
/* @__PURE__ */ jsx24("p", { className: "text-muted-foreground", children: "View and manage active sessions" })
|
|
2385
3319
|
] }),
|
|
2386
|
-
/* @__PURE__ */
|
|
3320
|
+
/* @__PURE__ */ jsx24(
|
|
2387
3321
|
DataTable,
|
|
2388
3322
|
{
|
|
2389
3323
|
data: data?.sessions || [],
|
|
@@ -2396,12 +3330,12 @@ function Sessions() {
|
|
|
2396
3330
|
}
|
|
2397
3331
|
|
|
2398
3332
|
// src/components/iam/tenants.tsx
|
|
2399
|
-
import { Badge as
|
|
2400
|
-
import { useState as
|
|
2401
|
-
import { jsx as
|
|
3333
|
+
import { Badge as Badge5, Button as Button12 } from "@mesob/ui/components";
|
|
3334
|
+
import { useState as useState13 } from "react";
|
|
3335
|
+
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2402
3336
|
function Tenants() {
|
|
2403
3337
|
const { hooks } = useApi();
|
|
2404
|
-
const [page, setPage] =
|
|
3338
|
+
const [page, setPage] = useState13(1);
|
|
2405
3339
|
const limit = 20;
|
|
2406
3340
|
const { data, isLoading, error } = hooks.useQuery("get", "/tenants", {
|
|
2407
3341
|
params: {
|
|
@@ -2415,9 +3349,9 @@ function Tenants() {
|
|
|
2415
3349
|
{
|
|
2416
3350
|
key: "name",
|
|
2417
3351
|
header: "Tenant",
|
|
2418
|
-
cell: (tenant) => /* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
3352
|
+
cell: (tenant) => /* @__PURE__ */ jsxs21("div", { children: [
|
|
3353
|
+
/* @__PURE__ */ jsx25("p", { className: "font-medium", children: tenant.name }),
|
|
3354
|
+
/* @__PURE__ */ jsxs21("p", { className: "text-sm text-muted-foreground", children: [
|
|
2421
3355
|
"/",
|
|
2422
3356
|
tenant.slug
|
|
2423
3357
|
] })
|
|
@@ -2426,34 +3360,34 @@ function Tenants() {
|
|
|
2426
3360
|
{
|
|
2427
3361
|
key: "status",
|
|
2428
3362
|
header: "Status",
|
|
2429
|
-
cell: (tenant) => /* @__PURE__ */
|
|
3363
|
+
cell: (tenant) => /* @__PURE__ */ jsx25(Badge5, { variant: tenant.status === "active" ? "default" : "secondary", children: tenant.status })
|
|
2430
3364
|
},
|
|
2431
3365
|
{
|
|
2432
3366
|
key: "createdAt",
|
|
2433
3367
|
header: "Created",
|
|
2434
|
-
cell: (tenant) => /* @__PURE__ */
|
|
3368
|
+
cell: (tenant) => /* @__PURE__ */ jsx25("p", { className: "text-sm", children: new Date(tenant.createdAt).toLocaleDateString() })
|
|
2435
3369
|
},
|
|
2436
3370
|
{
|
|
2437
3371
|
key: "actions",
|
|
2438
3372
|
header: "Actions",
|
|
2439
|
-
cell: (_tenant) => /* @__PURE__ */
|
|
2440
|
-
/* @__PURE__ */
|
|
2441
|
-
/* @__PURE__ */
|
|
3373
|
+
cell: (_tenant) => /* @__PURE__ */ jsxs21("div", { className: "flex gap-2", children: [
|
|
3374
|
+
/* @__PURE__ */ jsx25(Button12, { variant: "outline", size: "sm", children: "Domains" }),
|
|
3375
|
+
/* @__PURE__ */ jsx25(Button12, { variant: "outline", size: "sm", children: "Edit" })
|
|
2442
3376
|
] })
|
|
2443
3377
|
}
|
|
2444
3378
|
];
|
|
2445
3379
|
if (error) {
|
|
2446
|
-
return /* @__PURE__ */
|
|
3380
|
+
return /* @__PURE__ */ jsx25("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx25("p", { className: "text-destructive", children: "Error loading tenants" }) });
|
|
2447
3381
|
}
|
|
2448
|
-
return /* @__PURE__ */
|
|
2449
|
-
/* @__PURE__ */
|
|
2450
|
-
/* @__PURE__ */
|
|
2451
|
-
/* @__PURE__ */
|
|
2452
|
-
/* @__PURE__ */
|
|
3382
|
+
return /* @__PURE__ */ jsxs21("div", { className: "w-full p-6 space-y-4", children: [
|
|
3383
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex justify-between items-center", children: [
|
|
3384
|
+
/* @__PURE__ */ jsxs21("div", { children: [
|
|
3385
|
+
/* @__PURE__ */ jsx25("h1", { className: "text-3xl font-bold", children: "Tenants" }),
|
|
3386
|
+
/* @__PURE__ */ jsx25("p", { className: "text-muted-foreground", children: "Manage tenant organizations" })
|
|
2453
3387
|
] }),
|
|
2454
|
-
/* @__PURE__ */
|
|
3388
|
+
/* @__PURE__ */ jsx25(Button12, { children: "Create Tenant" })
|
|
2455
3389
|
] }),
|
|
2456
|
-
/* @__PURE__ */
|
|
3390
|
+
/* @__PURE__ */ jsx25(
|
|
2457
3391
|
DataTable,
|
|
2458
3392
|
{
|
|
2459
3393
|
data: data?.tenants || [],
|
|
@@ -2462,32 +3396,39 @@ function Tenants() {
|
|
|
2462
3396
|
emptyMessage: "No tenants found"
|
|
2463
3397
|
}
|
|
2464
3398
|
),
|
|
2465
|
-
data && "tenants" in data && data.tenants && data.tenants.length >= limit && /* @__PURE__ */
|
|
2466
|
-
/* @__PURE__ */
|
|
2467
|
-
|
|
3399
|
+
data && "tenants" in data && data.tenants && data.tenants.length >= limit && /* @__PURE__ */ jsxs21("div", { className: "flex justify-between items-center", children: [
|
|
3400
|
+
/* @__PURE__ */ jsx25(
|
|
3401
|
+
Button12,
|
|
2468
3402
|
{
|
|
2469
3403
|
variant: "outline",
|
|
2470
3404
|
disabled: page === 1,
|
|
2471
|
-
onClick: () => setPage(
|
|
3405
|
+
onClick: () => setPage((prev) => prev - 1),
|
|
2472
3406
|
children: "Previous"
|
|
2473
3407
|
}
|
|
2474
3408
|
),
|
|
2475
|
-
/* @__PURE__ */
|
|
3409
|
+
/* @__PURE__ */ jsxs21("span", { className: "text-sm text-muted-foreground", children: [
|
|
2476
3410
|
"Page ",
|
|
2477
3411
|
page
|
|
2478
3412
|
] }),
|
|
2479
|
-
/* @__PURE__ */
|
|
3413
|
+
/* @__PURE__ */ jsx25(
|
|
3414
|
+
Button12,
|
|
3415
|
+
{
|
|
3416
|
+
variant: "outline",
|
|
3417
|
+
onClick: () => setPage((prev) => prev + 1),
|
|
3418
|
+
children: "Next"
|
|
3419
|
+
}
|
|
3420
|
+
)
|
|
2480
3421
|
] })
|
|
2481
3422
|
] });
|
|
2482
3423
|
}
|
|
2483
3424
|
|
|
2484
3425
|
// src/components/iam/users.tsx
|
|
2485
|
-
import { Badge as
|
|
2486
|
-
import { useState as
|
|
2487
|
-
import { jsx as
|
|
3426
|
+
import { Badge as Badge6, Button as Button13 } from "@mesob/ui/components";
|
|
3427
|
+
import { useState as useState14 } from "react";
|
|
3428
|
+
import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2488
3429
|
function Users() {
|
|
2489
3430
|
const { hooks } = useApi();
|
|
2490
|
-
const [page, setPage] =
|
|
3431
|
+
const [page, setPage] = useState14(1);
|
|
2491
3432
|
const limit = 20;
|
|
2492
3433
|
const { data, isLoading, error } = hooks.useQuery("get", "/users", {
|
|
2493
3434
|
params: {
|
|
@@ -2501,54 +3442,48 @@ function Users() {
|
|
|
2501
3442
|
{
|
|
2502
3443
|
key: "fullName",
|
|
2503
3444
|
header: "Name",
|
|
2504
|
-
cell: (user) => /* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */ jsx19("p", { className: "font-medium", children: user.fullName }),
|
|
2506
|
-
/* @__PURE__ */ jsxs17("p", { className: "text-sm text-muted-foreground", children: [
|
|
2507
|
-
"@",
|
|
2508
|
-
user.handle
|
|
2509
|
-
] })
|
|
2510
|
-
] })
|
|
3445
|
+
cell: (user) => /* @__PURE__ */ jsx26("div", { children: /* @__PURE__ */ jsx26("p", { className: "font-medium", children: user.fullName }) })
|
|
2511
3446
|
},
|
|
2512
3447
|
{
|
|
2513
3448
|
key: "contact",
|
|
2514
3449
|
header: "Contact",
|
|
2515
|
-
cell: (user) => /* @__PURE__ */
|
|
2516
|
-
user.email && /* @__PURE__ */
|
|
2517
|
-
/* @__PURE__ */
|
|
2518
|
-
user.emailVerified && /* @__PURE__ */
|
|
3450
|
+
cell: (user) => /* @__PURE__ */ jsxs22("div", { className: "space-y-1", children: [
|
|
3451
|
+
user.email && /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
3452
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm", children: user.email }),
|
|
3453
|
+
user.emailVerified && /* @__PURE__ */ jsx26(Badge6, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2519
3454
|
] }),
|
|
2520
|
-
user.phone && /* @__PURE__ */
|
|
2521
|
-
/* @__PURE__ */
|
|
2522
|
-
user.phoneVerified && /* @__PURE__ */
|
|
3455
|
+
user.phone && /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
3456
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm", children: user.phone }),
|
|
3457
|
+
user.phoneVerified && /* @__PURE__ */ jsx26(Badge6, { variant: "outline", className: "text-xs", children: "Verified" })
|
|
2523
3458
|
] })
|
|
2524
3459
|
] })
|
|
2525
3460
|
},
|
|
2526
3461
|
{
|
|
2527
3462
|
key: "lastSignIn",
|
|
2528
3463
|
header: "Last Sign In",
|
|
2529
|
-
cell: (user) => /* @__PURE__ */
|
|
3464
|
+
cell: (user) => /* @__PURE__ */ jsx26("p", { className: "text-sm", children: user.lastSignInAt ? new Date(user.lastSignInAt).toLocaleDateString() : "Never" })
|
|
2530
3465
|
},
|
|
2531
3466
|
{
|
|
2532
3467
|
key: "actions",
|
|
2533
3468
|
header: "Actions",
|
|
2534
|
-
cell: (_user) => /* @__PURE__ */
|
|
2535
|
-
/* @__PURE__ */
|
|
2536
|
-
/* @__PURE__ */
|
|
3469
|
+
cell: (_user) => /* @__PURE__ */ jsxs22("div", { className: "flex gap-2", children: [
|
|
3470
|
+
/* @__PURE__ */ jsx26(Button13, { variant: "outline", size: "sm", children: "View" }),
|
|
3471
|
+
/* @__PURE__ */ jsx26(Button13, { variant: "outline", size: "sm", children: "Edit" })
|
|
2537
3472
|
] })
|
|
2538
3473
|
}
|
|
2539
3474
|
];
|
|
2540
3475
|
if (error) {
|
|
2541
|
-
return /* @__PURE__ */
|
|
3476
|
+
return /* @__PURE__ */ jsx26("div", { className: "p-6 text-center", children: /* @__PURE__ */ jsx26("p", { className: "text-destructive", children: "Error loading users" }) });
|
|
2542
3477
|
}
|
|
2543
|
-
return /* @__PURE__ */
|
|
2544
|
-
/* @__PURE__ */
|
|
2545
|
-
/* @__PURE__ */
|
|
2546
|
-
/* @__PURE__ */
|
|
2547
|
-
/* @__PURE__ */
|
|
3478
|
+
return /* @__PURE__ */ jsxs22("div", { className: "w-full p-6 space-y-4", children: [
|
|
3479
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex justify-between items-center", children: [
|
|
3480
|
+
/* @__PURE__ */ jsxs22("div", { children: [
|
|
3481
|
+
/* @__PURE__ */ jsx26("h1", { className: "text-3xl font-bold", children: "Users" }),
|
|
3482
|
+
/* @__PURE__ */ jsx26("p", { className: "text-muted-foreground", children: "Manage user accounts" })
|
|
2548
3483
|
] }),
|
|
2549
|
-
/* @__PURE__ */
|
|
3484
|
+
/* @__PURE__ */ jsx26(Button13, { children: "Create User" })
|
|
2550
3485
|
] }),
|
|
2551
|
-
/* @__PURE__ */
|
|
3486
|
+
/* @__PURE__ */ jsx26(
|
|
2552
3487
|
DataTable,
|
|
2553
3488
|
{
|
|
2554
3489
|
data: data?.users || [],
|
|
@@ -2557,76 +3492,179 @@ function Users() {
|
|
|
2557
3492
|
emptyMessage: "No users found"
|
|
2558
3493
|
}
|
|
2559
3494
|
),
|
|
2560
|
-
data && "users" in data && data.users && data.users.length >= limit && /* @__PURE__ */
|
|
2561
|
-
/* @__PURE__ */
|
|
2562
|
-
|
|
3495
|
+
data && "users" in data && data.users && data.users.length >= limit && /* @__PURE__ */ jsxs22("div", { className: "flex justify-between items-center", children: [
|
|
3496
|
+
/* @__PURE__ */ jsx26(
|
|
3497
|
+
Button13,
|
|
2563
3498
|
{
|
|
2564
3499
|
variant: "outline",
|
|
2565
3500
|
disabled: page === 1,
|
|
2566
|
-
onClick: () => setPage(
|
|
3501
|
+
onClick: () => setPage((prev) => prev - 1),
|
|
2567
3502
|
children: "Previous"
|
|
2568
3503
|
}
|
|
2569
3504
|
),
|
|
2570
|
-
/* @__PURE__ */
|
|
3505
|
+
/* @__PURE__ */ jsxs22("span", { className: "text-sm text-muted-foreground", children: [
|
|
2571
3506
|
"Page ",
|
|
2572
3507
|
page
|
|
2573
3508
|
] }),
|
|
2574
|
-
/* @__PURE__ */
|
|
3509
|
+
/* @__PURE__ */ jsx26(
|
|
3510
|
+
Button13,
|
|
3511
|
+
{
|
|
3512
|
+
variant: "outline",
|
|
3513
|
+
onClick: () => setPage((prev) => prev + 1),
|
|
3514
|
+
children: "Next"
|
|
3515
|
+
}
|
|
3516
|
+
)
|
|
2575
3517
|
] })
|
|
2576
3518
|
] });
|
|
2577
3519
|
}
|
|
2578
3520
|
|
|
2579
3521
|
// src/components/profile/account.tsx
|
|
2580
|
-
import { Separator } from "@mesob/ui/components";
|
|
2581
|
-
|
|
3522
|
+
import { Badge as Badge8, Card as Card2, CardContent, Separator } from "@mesob/ui/components";
|
|
3523
|
+
|
|
3524
|
+
// src/components/profile/change-profile.tsx
|
|
3525
|
+
import {
|
|
3526
|
+
Avatar,
|
|
3527
|
+
AvatarFallback,
|
|
3528
|
+
AvatarImage,
|
|
3529
|
+
Badge as Badge7,
|
|
3530
|
+
Button as Button14
|
|
3531
|
+
} from "@mesob/ui/components";
|
|
3532
|
+
import { useState as useState15 } from "react";
|
|
3533
|
+
import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3534
|
+
var ChangeProfile = ({ user }) => {
|
|
3535
|
+
const [isEditing, setIsEditing] = useState15(false);
|
|
3536
|
+
const initials = user.fullName?.split(" ").map((part) => part[0]).join("").toUpperCase().slice(0, 2) || "U";
|
|
3537
|
+
return /* @__PURE__ */ jsxs23("div", { className: "w-full rounded-[1.5rem] border border-border/60 bg-background/80 p-5 shadow-sm backdrop-blur", children: [
|
|
3538
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
|
|
3539
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-4", children: [
|
|
3540
|
+
/* @__PURE__ */ jsxs23(Avatar, { className: "h-14 w-14 ring-4 ring-primary/10", children: [
|
|
3541
|
+
/* @__PURE__ */ jsx27(AvatarImage, { src: user.image || "", alt: user.fullName || "" }),
|
|
3542
|
+
/* @__PURE__ */ jsx27(AvatarFallback, { children: initials })
|
|
3543
|
+
] }),
|
|
3544
|
+
/* @__PURE__ */ jsxs23("div", { className: "space-y-1", children: [
|
|
3545
|
+
/* @__PURE__ */ jsx27("div", { className: "text-base font-semibold", children: user.fullName }),
|
|
3546
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap gap-2 text-xs text-muted-foreground", children: [
|
|
3547
|
+
/* @__PURE__ */ jsx27(Badge7, { variant: "outline", children: user.emailVerified ? "Email verified" : "Email unverified" }),
|
|
3548
|
+
/* @__PURE__ */ jsx27(Badge7, { variant: "outline", children: user.phoneVerified ? "Phone verified" : "Phone unverified" })
|
|
3549
|
+
] })
|
|
3550
|
+
] })
|
|
3551
|
+
] }),
|
|
3552
|
+
/* @__PURE__ */ jsx27(
|
|
3553
|
+
Button14,
|
|
3554
|
+
{
|
|
3555
|
+
variant: "secondary",
|
|
3556
|
+
className: "rounded-full px-5 text-primary hover:text-primary/80",
|
|
3557
|
+
onClick: () => setIsEditing((v) => !v),
|
|
3558
|
+
children: isEditing ? "Hide editor" : "Update profile"
|
|
3559
|
+
}
|
|
3560
|
+
)
|
|
3561
|
+
] }),
|
|
3562
|
+
isEditing && /* @__PURE__ */ jsx27("div", { className: "mt-4 rounded-2xl border border-dashed border-border bg-muted/30 px-4 py-3 text-sm text-muted-foreground", children: "Profile editing is not wired yet. Contact and password flows below are live." })
|
|
3563
|
+
] });
|
|
3564
|
+
};
|
|
3565
|
+
|
|
3566
|
+
// src/components/profile/account.tsx
|
|
3567
|
+
import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2582
3568
|
function Account() {
|
|
2583
3569
|
const { user, isAuthenticated } = useSession();
|
|
2584
3570
|
if (!(isAuthenticated && user)) {
|
|
2585
|
-
return /* @__PURE__ */
|
|
3571
|
+
return /* @__PURE__ */ jsx28("div", { className: "rounded-[1.75rem] border border-dashed border-border bg-muted/30 p-8 text-sm text-muted-foreground", children: "Sign in required." });
|
|
2586
3572
|
}
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
3573
|
+
const contactItems = [
|
|
3574
|
+
{
|
|
3575
|
+
label: "Email",
|
|
3576
|
+
value: user.email ?? "No email address",
|
|
3577
|
+
status: user.emailVerified ? "Verified" : "Needs verification"
|
|
3578
|
+
},
|
|
3579
|
+
{
|
|
3580
|
+
label: "Phone",
|
|
3581
|
+
value: user.phone ?? "No phone number",
|
|
3582
|
+
status: user.phoneVerified ? "Verified" : "Needs verification"
|
|
3583
|
+
}
|
|
3584
|
+
];
|
|
3585
|
+
return /* @__PURE__ */ jsxs24("div", { className: "mx-auto flex w-full max-w-6xl flex-col gap-6", children: [
|
|
3586
|
+
/* @__PURE__ */ jsxs24("div", { className: "relative overflow-hidden rounded-[2rem] border border-border/60 bg-gradient-to-br from-background via-background to-primary/5 p-6 shadow-sm", children: [
|
|
3587
|
+
/* @__PURE__ */ jsx28("div", { className: "absolute inset-y-0 right-0 w-1/3 bg-[radial-gradient(circle_at_top,_hsl(var(--primary)/0.16),_transparent_60%)]" }),
|
|
3588
|
+
/* @__PURE__ */ jsxs24("div", { className: "relative flex flex-col gap-5", children: [
|
|
3589
|
+
/* @__PURE__ */ jsxs24("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3590
|
+
/* @__PURE__ */ jsx28(Badge8, { variant: "outline", children: "Profile console" }),
|
|
3591
|
+
/* @__PURE__ */ jsx28(Badge8, { variant: "secondary", children: "Live session data" })
|
|
3592
|
+
] }),
|
|
3593
|
+
/* @__PURE__ */ jsxs24("div", { className: "max-w-2xl space-y-2", children: [
|
|
3594
|
+
/* @__PURE__ */ jsx28("h2", { className: "text-2xl font-semibold tracking-tight", children: "Account details, contact state, and verification status." }),
|
|
3595
|
+
/* @__PURE__ */ jsx28("p", { className: "text-sm text-muted-foreground", children: "Keep the identity surface minimal here. Contact updates and sensitive changes stay in security." })
|
|
3596
|
+
] }),
|
|
3597
|
+
/* @__PURE__ */ jsx28(ChangeProfile, { user })
|
|
2603
3598
|
] })
|
|
3599
|
+
] }),
|
|
3600
|
+
/* @__PURE__ */ jsxs24("div", { className: "grid gap-4 lg:grid-cols-[1.5fr_0.9fr]", children: [
|
|
3601
|
+
/* @__PURE__ */ jsx28(Card2, { className: "rounded-[1.75rem] border-border/60 shadow-sm", children: /* @__PURE__ */ jsxs24(CardContent, { className: "space-y-5 p-6", children: [
|
|
3602
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-1", children: [
|
|
3603
|
+
/* @__PURE__ */ jsx28("div", { className: "text-sm font-medium text-muted-foreground", children: "Contact channels" }),
|
|
3604
|
+
/* @__PURE__ */ jsx28("div", { className: "text-lg font-semibold", children: "Primary profile data" })
|
|
3605
|
+
] }),
|
|
3606
|
+
/* @__PURE__ */ jsx28(Separator, {}),
|
|
3607
|
+
/* @__PURE__ */ jsx28("div", { className: "space-y-4", children: contactItems.map((item) => /* @__PURE__ */ jsxs24(
|
|
3608
|
+
"div",
|
|
3609
|
+
{
|
|
3610
|
+
className: "flex flex-col gap-3 rounded-2xl border border-border/60 bg-muted/20 p-4 md:flex-row md:items-center md:justify-between",
|
|
3611
|
+
children: [
|
|
3612
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-1", children: [
|
|
3613
|
+
/* @__PURE__ */ jsx28("div", { className: "text-sm font-medium", children: item.label }),
|
|
3614
|
+
/* @__PURE__ */ jsx28("div", { className: "text-sm text-muted-foreground", children: item.value })
|
|
3615
|
+
] }),
|
|
3616
|
+
/* @__PURE__ */ jsx28(Badge8, { variant: "outline", children: item.status })
|
|
3617
|
+
]
|
|
3618
|
+
},
|
|
3619
|
+
item.label
|
|
3620
|
+
)) })
|
|
3621
|
+
] }) }),
|
|
3622
|
+
/* @__PURE__ */ jsx28(Card2, { className: "rounded-[1.75rem] border-border/60 shadow-sm", children: /* @__PURE__ */ jsxs24(CardContent, { className: "space-y-5 p-6", children: [
|
|
3623
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-1", children: [
|
|
3624
|
+
/* @__PURE__ */ jsx28("div", { className: "text-sm font-medium text-muted-foreground", children: "Snapshot" }),
|
|
3625
|
+
/* @__PURE__ */ jsx28("div", { className: "text-lg font-semibold", children: "Session-facing identity" })
|
|
3626
|
+
] }),
|
|
3627
|
+
/* @__PURE__ */ jsx28(Separator, {}),
|
|
3628
|
+
/* @__PURE__ */ jsxs24("div", { className: "grid gap-3", children: [
|
|
3629
|
+
/* @__PURE__ */ jsxs24("div", { className: "rounded-2xl bg-primary/[0.06] p-4", children: [
|
|
3630
|
+
/* @__PURE__ */ jsx28("div", { className: "text-xs uppercase tracking-[0.18em] text-muted-foreground", children: "Full name" }),
|
|
3631
|
+
/* @__PURE__ */ jsx28("div", { className: "mt-2 text-base font-semibold", children: user.fullName })
|
|
3632
|
+
] }),
|
|
3633
|
+
/* @__PURE__ */ jsxs24("div", { className: "rounded-2xl bg-muted/25 p-4", children: [
|
|
3634
|
+
/* @__PURE__ */ jsx28("div", { className: "text-xs uppercase tracking-[0.18em] text-muted-foreground", children: "Last sign in" }),
|
|
3635
|
+
/* @__PURE__ */ jsx28("div", { className: "mt-2 text-base font-semibold", children: user.lastSignInAt ? new Date(user.lastSignInAt).toLocaleString() : "No activity recorded" })
|
|
3636
|
+
] })
|
|
3637
|
+
] })
|
|
3638
|
+
] }) })
|
|
2604
3639
|
] })
|
|
2605
3640
|
] });
|
|
2606
3641
|
}
|
|
2607
3642
|
|
|
3643
|
+
// src/components/profile/security.tsx
|
|
3644
|
+
import { Badge as Badge9, Card as Card3, CardContent as CardContent2, Separator as Separator2 } from "@mesob/ui/components";
|
|
3645
|
+
|
|
2608
3646
|
// src/components/profile/change-email-form.tsx
|
|
2609
3647
|
import {
|
|
2610
|
-
Button as
|
|
3648
|
+
Button as Button16,
|
|
2611
3649
|
Collapsible,
|
|
2612
3650
|
CollapsibleContent,
|
|
2613
3651
|
CollapsibleTrigger
|
|
2614
3652
|
} from "@mesob/ui/components";
|
|
2615
3653
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
2616
|
-
import { useState as
|
|
3654
|
+
import { useState as useState18 } from "react";
|
|
2617
3655
|
|
|
2618
3656
|
// src/components/profile/request-change-email-form.tsx
|
|
2619
|
-
import { zodResolver as
|
|
2620
|
-
import { Button as
|
|
2621
|
-
import { IconEye as
|
|
2622
|
-
import { useEffect as
|
|
2623
|
-
import { useForm as
|
|
2624
|
-
import { toast as
|
|
2625
|
-
import { z as
|
|
2626
|
-
import { jsx as
|
|
2627
|
-
var emailPasswordSchema =
|
|
2628
|
-
email:
|
|
2629
|
-
password:
|
|
3657
|
+
import { zodResolver as zodResolver8 } from "@hookform/resolvers/zod";
|
|
3658
|
+
import { Button as Button15, Input as Input7, Label, Spinner as Spinner2 } from "@mesob/ui/components";
|
|
3659
|
+
import { IconEye as IconEye5, IconEyeOff as IconEyeOff5 } from "@tabler/icons-react";
|
|
3660
|
+
import { useEffect as useEffect10, useState as useState16 } from "react";
|
|
3661
|
+
import { useForm as useForm8 } from "react-hook-form";
|
|
3662
|
+
import { toast as toast10 } from "sonner";
|
|
3663
|
+
import { z as z8 } from "zod";
|
|
3664
|
+
import { jsx as jsx29, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3665
|
+
var emailPasswordSchema = z8.object({
|
|
3666
|
+
email: z8.string().email("Invalid email address"),
|
|
3667
|
+
password: z8.string().min(8, "Password must be at least 8 characters").max(128, "Password too long")
|
|
2630
3668
|
});
|
|
2631
3669
|
function isAuthError2(error) {
|
|
2632
3670
|
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
@@ -2681,9 +3719,9 @@ function RequestChangeEmailForm({
|
|
|
2681
3719
|
}) {
|
|
2682
3720
|
const { user } = useSession();
|
|
2683
3721
|
const { hooks } = useApi();
|
|
2684
|
-
const [isSubmitting, setIsSubmitting] =
|
|
2685
|
-
const [isChecking, setIsChecking] =
|
|
2686
|
-
const [showPassword, setShowPassword] =
|
|
3722
|
+
const [isSubmitting, setIsSubmitting] = useState16(false);
|
|
3723
|
+
const [isChecking, setIsChecking] = useState16(true);
|
|
3724
|
+
const [showPassword, setShowPassword] = useState16(false);
|
|
2687
3725
|
const getPendingAccountChangeQuery = hooks.useQuery(
|
|
2688
3726
|
"get",
|
|
2689
3727
|
"/account-change/pending",
|
|
@@ -2696,8 +3734,8 @@ function RequestChangeEmailForm({
|
|
|
2696
3734
|
"post",
|
|
2697
3735
|
"/email/verification/request"
|
|
2698
3736
|
);
|
|
2699
|
-
const emailPasswordForm =
|
|
2700
|
-
resolver:
|
|
3737
|
+
const emailPasswordForm = useForm8({
|
|
3738
|
+
resolver: zodResolver8(emailPasswordSchema),
|
|
2701
3739
|
defaultValues: {
|
|
2702
3740
|
email: "",
|
|
2703
3741
|
password: ""
|
|
@@ -2710,7 +3748,7 @@ function RequestChangeEmailForm({
|
|
|
2710
3748
|
setValue,
|
|
2711
3749
|
formState: { errors }
|
|
2712
3750
|
} = emailPasswordForm;
|
|
2713
|
-
|
|
3751
|
+
useEffect10(() => {
|
|
2714
3752
|
let active = true;
|
|
2715
3753
|
const run = async () => {
|
|
2716
3754
|
try {
|
|
@@ -2734,7 +3772,7 @@ function RequestChangeEmailForm({
|
|
|
2734
3772
|
}
|
|
2735
3773
|
setValue("email", accountChange.newEmail, { shouldValidate: true });
|
|
2736
3774
|
if (verificationId) {
|
|
2737
|
-
|
|
3775
|
+
toast10.message("Resuming verification\u2026");
|
|
2738
3776
|
onSuccess(verificationId, accountChange.newEmail);
|
|
2739
3777
|
return;
|
|
2740
3778
|
}
|
|
@@ -2750,7 +3788,7 @@ function RequestChangeEmailForm({
|
|
|
2750
3788
|
}, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);
|
|
2751
3789
|
const onEmailPasswordSubmit = async (data) => {
|
|
2752
3790
|
if (!user) {
|
|
2753
|
-
|
|
3791
|
+
toast10.error("User not found");
|
|
2754
3792
|
return;
|
|
2755
3793
|
}
|
|
2756
3794
|
try {
|
|
@@ -2763,10 +3801,10 @@ function RequestChangeEmailForm({
|
|
|
2763
3801
|
});
|
|
2764
3802
|
if (checkResult.data?.exists) {
|
|
2765
3803
|
if (user?.email?.toLowerCase() === data.email.toLowerCase()) {
|
|
2766
|
-
|
|
3804
|
+
toast10.error("This is already your current email address.");
|
|
2767
3805
|
return;
|
|
2768
3806
|
}
|
|
2769
|
-
|
|
3807
|
+
toast10.error(
|
|
2770
3808
|
"This email is already taken. Please use a different email."
|
|
2771
3809
|
);
|
|
2772
3810
|
return;
|
|
@@ -2774,34 +3812,34 @@ function RequestChangeEmailForm({
|
|
|
2774
3812
|
const verification = await requestEmailVerificationMutation.mutateAsync({
|
|
2775
3813
|
body: { email: data.email }
|
|
2776
3814
|
});
|
|
2777
|
-
|
|
3815
|
+
toast10.success("Verification code sent to your email");
|
|
2778
3816
|
onSuccess(verification.data?.verificationId ?? "", data.email);
|
|
2779
3817
|
} catch (error) {
|
|
2780
3818
|
const errorMessage = getErrorMessage(error);
|
|
2781
3819
|
if (isAuthError2(error)) {
|
|
2782
3820
|
const errorCode = getErrorCode(error);
|
|
2783
3821
|
if (errorCode === "INVALID_PASSWORD" || errorCode === "USER_NOT_FOUND") {
|
|
2784
|
-
|
|
3822
|
+
toast10.error("Incorrect password. Please try again.");
|
|
2785
3823
|
return;
|
|
2786
3824
|
}
|
|
2787
3825
|
}
|
|
2788
|
-
|
|
3826
|
+
toast10.error(errorMessage);
|
|
2789
3827
|
} finally {
|
|
2790
3828
|
setIsSubmitting(false);
|
|
2791
3829
|
}
|
|
2792
3830
|
};
|
|
2793
3831
|
const isLoading = isSubmitting || isChecking;
|
|
2794
|
-
return /* @__PURE__ */
|
|
3832
|
+
return /* @__PURE__ */ jsxs25(
|
|
2795
3833
|
"form",
|
|
2796
3834
|
{
|
|
2797
3835
|
onSubmit: handleSubmit(onEmailPasswordSubmit),
|
|
2798
3836
|
className: "p-4 space-y-4 border-t",
|
|
2799
3837
|
children: [
|
|
2800
|
-
/* @__PURE__ */
|
|
2801
|
-
/* @__PURE__ */
|
|
2802
|
-
/* @__PURE__ */
|
|
2803
|
-
/* @__PURE__ */
|
|
2804
|
-
|
|
3838
|
+
/* @__PURE__ */ jsxs25("div", { className: "space-y-4 w-full md:w-1/2", children: [
|
|
3839
|
+
/* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
|
|
3840
|
+
/* @__PURE__ */ jsx29(Label, { htmlFor: "email", children: "New Email Address" }),
|
|
3841
|
+
/* @__PURE__ */ jsx29(
|
|
3842
|
+
Input7,
|
|
2805
3843
|
{
|
|
2806
3844
|
id: "email",
|
|
2807
3845
|
type: "email",
|
|
@@ -2810,13 +3848,13 @@ function RequestChangeEmailForm({
|
|
|
2810
3848
|
disabled: isLoading
|
|
2811
3849
|
}
|
|
2812
3850
|
),
|
|
2813
|
-
errors.email && /* @__PURE__ */
|
|
3851
|
+
errors.email && /* @__PURE__ */ jsx29("p", { className: "text-sm text-destructive", children: errors.email.message })
|
|
2814
3852
|
] }),
|
|
2815
|
-
/* @__PURE__ */
|
|
2816
|
-
/* @__PURE__ */
|
|
2817
|
-
/* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2819
|
-
|
|
3853
|
+
/* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
|
|
3854
|
+
/* @__PURE__ */ jsx29(Label, { htmlFor: "password", children: "Password" }),
|
|
3855
|
+
/* @__PURE__ */ jsxs25("div", { className: "relative", children: [
|
|
3856
|
+
/* @__PURE__ */ jsx29(
|
|
3857
|
+
Input7,
|
|
2820
3858
|
{
|
|
2821
3859
|
id: "password",
|
|
2822
3860
|
type: showPassword ? "text" : "password",
|
|
@@ -2826,23 +3864,23 @@ function RequestChangeEmailForm({
|
|
|
2826
3864
|
disabled: isLoading
|
|
2827
3865
|
}
|
|
2828
3866
|
),
|
|
2829
|
-
/* @__PURE__ */
|
|
3867
|
+
/* @__PURE__ */ jsx29(
|
|
2830
3868
|
"button",
|
|
2831
3869
|
{
|
|
2832
3870
|
type: "button",
|
|
2833
3871
|
onClick: () => setShowPassword(!showPassword),
|
|
2834
3872
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
2835
3873
|
disabled: isLoading,
|
|
2836
|
-
children: showPassword ? /* @__PURE__ */
|
|
3874
|
+
children: showPassword ? /* @__PURE__ */ jsx29(IconEyeOff5, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx29(IconEye5, { className: "h-4 w-4" })
|
|
2837
3875
|
}
|
|
2838
3876
|
)
|
|
2839
3877
|
] }),
|
|
2840
|
-
errors.password && /* @__PURE__ */
|
|
3878
|
+
errors.password && /* @__PURE__ */ jsx29("p", { className: "text-sm text-destructive", children: errors.password.message })
|
|
2841
3879
|
] })
|
|
2842
3880
|
] }),
|
|
2843
|
-
/* @__PURE__ */
|
|
2844
|
-
/* @__PURE__ */
|
|
2845
|
-
|
|
3881
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex justify-end gap-2", children: [
|
|
3882
|
+
/* @__PURE__ */ jsx29(
|
|
3883
|
+
Button15,
|
|
2846
3884
|
{
|
|
2847
3885
|
type: "button",
|
|
2848
3886
|
variant: "outline",
|
|
@@ -2851,8 +3889,8 @@ function RequestChangeEmailForm({
|
|
|
2851
3889
|
children: "Cancel"
|
|
2852
3890
|
}
|
|
2853
3891
|
),
|
|
2854
|
-
/* @__PURE__ */
|
|
2855
|
-
isLoading && /* @__PURE__ */
|
|
3892
|
+
/* @__PURE__ */ jsxs25(Button15, { type: "submit", disabled: isLoading, children: [
|
|
3893
|
+
isLoading && /* @__PURE__ */ jsx29(Spinner2, { className: "mr-2 h-4 w-4" }),
|
|
2856
3894
|
isChecking ? "Checking\u2026" : buttonText
|
|
2857
3895
|
] })
|
|
2858
3896
|
] })
|
|
@@ -2862,8 +3900,8 @@ function RequestChangeEmailForm({
|
|
|
2862
3900
|
}
|
|
2863
3901
|
|
|
2864
3902
|
// src/components/profile/verify-change-email-form.tsx
|
|
2865
|
-
import { useState as
|
|
2866
|
-
import { toast as
|
|
3903
|
+
import { useState as useState17 } from "react";
|
|
3904
|
+
import { toast as toast11 } from "sonner";
|
|
2867
3905
|
|
|
2868
3906
|
// src/components/profile/otp-verification-modal.tsx
|
|
2869
3907
|
import {
|
|
@@ -2873,7 +3911,7 @@ import {
|
|
|
2873
3911
|
DialogHeader,
|
|
2874
3912
|
DialogTitle
|
|
2875
3913
|
} from "@mesob/ui/components";
|
|
2876
|
-
import { jsx as
|
|
3914
|
+
import { jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2877
3915
|
function OtpVerificationModal({
|
|
2878
3916
|
open,
|
|
2879
3917
|
title,
|
|
@@ -2884,7 +3922,7 @@ function OtpVerificationModal({
|
|
|
2884
3922
|
onResend,
|
|
2885
3923
|
onCancel
|
|
2886
3924
|
}) {
|
|
2887
|
-
return /* @__PURE__ */
|
|
3925
|
+
return /* @__PURE__ */ jsx30(
|
|
2888
3926
|
Dialog,
|
|
2889
3927
|
{
|
|
2890
3928
|
open,
|
|
@@ -2893,12 +3931,12 @@ function OtpVerificationModal({
|
|
|
2893
3931
|
onCancel?.();
|
|
2894
3932
|
}
|
|
2895
3933
|
},
|
|
2896
|
-
children: /* @__PURE__ */
|
|
2897
|
-
/* @__PURE__ */
|
|
2898
|
-
/* @__PURE__ */
|
|
2899
|
-
description && /* @__PURE__ */
|
|
3934
|
+
children: /* @__PURE__ */ jsxs26(DialogContent, { children: [
|
|
3935
|
+
/* @__PURE__ */ jsxs26(DialogHeader, { children: [
|
|
3936
|
+
/* @__PURE__ */ jsx30(DialogTitle, { children: title }),
|
|
3937
|
+
description && /* @__PURE__ */ jsx30(DialogDescription, { children: description })
|
|
2900
3938
|
] }),
|
|
2901
|
-
/* @__PURE__ */
|
|
3939
|
+
/* @__PURE__ */ jsx30(
|
|
2902
3940
|
VerificationForm,
|
|
2903
3941
|
{
|
|
2904
3942
|
verificationId,
|
|
@@ -2913,7 +3951,7 @@ function OtpVerificationModal({
|
|
|
2913
3951
|
}
|
|
2914
3952
|
|
|
2915
3953
|
// src/components/profile/verify-change-email-form.tsx
|
|
2916
|
-
import { jsx as
|
|
3954
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
2917
3955
|
function isAuthError3(error) {
|
|
2918
3956
|
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
2919
3957
|
}
|
|
@@ -2968,8 +4006,8 @@ function VerifyChangeEmailForm({
|
|
|
2968
4006
|
}) {
|
|
2969
4007
|
const { refresh } = useSession();
|
|
2970
4008
|
const { hooks } = useApi();
|
|
2971
|
-
const [isSubmitting, setIsSubmitting] =
|
|
2972
|
-
const [currentVerificationId, setCurrentVerificationId] =
|
|
4009
|
+
const [isSubmitting, setIsSubmitting] = useState17(false);
|
|
4010
|
+
const [currentVerificationId, setCurrentVerificationId] = useState17(verificationId);
|
|
2973
4011
|
const verifyEmailMutation = hooks.useMutation(
|
|
2974
4012
|
"post",
|
|
2975
4013
|
"/email/verification/confirm"
|
|
@@ -2981,7 +4019,7 @@ function VerifyChangeEmailForm({
|
|
|
2981
4019
|
);
|
|
2982
4020
|
const onOtpSubmit = async (code) => {
|
|
2983
4021
|
if (!currentVerificationId) {
|
|
2984
|
-
|
|
4022
|
+
toast11.error("Verification not found. Please request a new code.");
|
|
2985
4023
|
return;
|
|
2986
4024
|
}
|
|
2987
4025
|
try {
|
|
@@ -2995,21 +4033,21 @@ function VerifyChangeEmailForm({
|
|
|
2995
4033
|
await updateEmailMutation.mutateAsync({
|
|
2996
4034
|
body: { email }
|
|
2997
4035
|
});
|
|
2998
|
-
|
|
4036
|
+
toast11.success("Email updated successfully");
|
|
2999
4037
|
await refresh();
|
|
3000
4038
|
onSuccess();
|
|
3001
4039
|
} catch (error) {
|
|
3002
4040
|
const errorMessage = getErrorMessage2(error);
|
|
3003
|
-
|
|
4041
|
+
toast11.error(errorMessage);
|
|
3004
4042
|
} finally {
|
|
3005
4043
|
setIsSubmitting(false);
|
|
3006
4044
|
}
|
|
3007
4045
|
};
|
|
3008
4046
|
if (!currentVerificationId) {
|
|
3009
|
-
|
|
4047
|
+
toast11.error("Verification not found. Please request a new code.");
|
|
3010
4048
|
return null;
|
|
3011
4049
|
}
|
|
3012
|
-
return /* @__PURE__ */
|
|
4050
|
+
return /* @__PURE__ */ jsx31(
|
|
3013
4051
|
OtpVerificationModal,
|
|
3014
4052
|
{
|
|
3015
4053
|
open: true,
|
|
@@ -3025,9 +4063,9 @@ function VerifyChangeEmailForm({
|
|
|
3025
4063
|
body: { email }
|
|
3026
4064
|
});
|
|
3027
4065
|
setCurrentVerificationId(next.data?.verificationId ?? null);
|
|
3028
|
-
|
|
4066
|
+
toast11.success("Verification code resent");
|
|
3029
4067
|
} catch (error) {
|
|
3030
|
-
|
|
4068
|
+
toast11.error(getErrorMessage2(error));
|
|
3031
4069
|
} finally {
|
|
3032
4070
|
setIsSubmitting(false);
|
|
3033
4071
|
}
|
|
@@ -3038,13 +4076,13 @@ function VerifyChangeEmailForm({
|
|
|
3038
4076
|
}
|
|
3039
4077
|
|
|
3040
4078
|
// src/components/profile/change-email-form.tsx
|
|
3041
|
-
import { jsx as
|
|
4079
|
+
import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3042
4080
|
function ChangeEmailForm() {
|
|
3043
4081
|
const { user } = useSession();
|
|
3044
|
-
const [isOpen, setIsOpen] =
|
|
3045
|
-
const [showOtp, setShowOtp] =
|
|
3046
|
-
const [verificationId, setVerificationId] =
|
|
3047
|
-
const [newEmail, setNewEmail] =
|
|
4082
|
+
const [isOpen, setIsOpen] = useState18(false);
|
|
4083
|
+
const [showOtp, setShowOtp] = useState18(false);
|
|
4084
|
+
const [verificationId, setVerificationId] = useState18(null);
|
|
4085
|
+
const [newEmail, setNewEmail] = useState18("");
|
|
3048
4086
|
const resetForms = () => {
|
|
3049
4087
|
setShowOtp(false);
|
|
3050
4088
|
setVerificationId(null);
|
|
@@ -3065,23 +4103,23 @@ function ChangeEmailForm() {
|
|
|
3065
4103
|
};
|
|
3066
4104
|
const title = user?.email ? "Change Email" : "Add Email";
|
|
3067
4105
|
const description = user?.email ? "Update your email address" : "Add an email address to your account";
|
|
3068
|
-
return /* @__PURE__ */
|
|
3069
|
-
/* @__PURE__ */
|
|
4106
|
+
return /* @__PURE__ */ jsx32(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs27("div", { className: "border rounded-lg", children: [
|
|
4107
|
+
/* @__PURE__ */ jsxs27(
|
|
3070
4108
|
CollapsibleTrigger,
|
|
3071
4109
|
{
|
|
3072
|
-
render: /* @__PURE__ */
|
|
3073
|
-
|
|
4110
|
+
render: /* @__PURE__ */ jsx32(
|
|
4111
|
+
Button16,
|
|
3074
4112
|
{
|
|
3075
4113
|
variant: "ghost",
|
|
3076
4114
|
className: "w-full justify-between p-4 h-auto"
|
|
3077
4115
|
}
|
|
3078
4116
|
),
|
|
3079
4117
|
children: [
|
|
3080
|
-
/* @__PURE__ */
|
|
3081
|
-
/* @__PURE__ */
|
|
3082
|
-
/* @__PURE__ */
|
|
4118
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col items-start", children: [
|
|
4119
|
+
/* @__PURE__ */ jsx32("span", { className: "font-medium", children: title }),
|
|
4120
|
+
/* @__PURE__ */ jsx32("span", { className: "text-sm text-muted-foreground", children: description })
|
|
3083
4121
|
] }),
|
|
3084
|
-
/* @__PURE__ */
|
|
4122
|
+
/* @__PURE__ */ jsx32(
|
|
3085
4123
|
IconChevronDown,
|
|
3086
4124
|
{
|
|
3087
4125
|
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
@@ -3090,7 +4128,7 @@ function ChangeEmailForm() {
|
|
|
3090
4128
|
]
|
|
3091
4129
|
}
|
|
3092
4130
|
),
|
|
3093
|
-
/* @__PURE__ */
|
|
4131
|
+
/* @__PURE__ */ jsx32(CollapsibleContent, { children: showOtp ? /* @__PURE__ */ jsx32(
|
|
3094
4132
|
VerifyChangeEmailForm,
|
|
3095
4133
|
{
|
|
3096
4134
|
email: newEmail,
|
|
@@ -3098,7 +4136,7 @@ function ChangeEmailForm() {
|
|
|
3098
4136
|
onSuccess: handleVerifySuccess,
|
|
3099
4137
|
onCancel: handleCancel
|
|
3100
4138
|
}
|
|
3101
|
-
) : /* @__PURE__ */
|
|
4139
|
+
) : /* @__PURE__ */ jsx32(
|
|
3102
4140
|
RequestChangeEmailForm,
|
|
3103
4141
|
{
|
|
3104
4142
|
onSuccess: handleRequestSuccess,
|
|
@@ -3110,26 +4148,26 @@ function ChangeEmailForm() {
|
|
|
3110
4148
|
}
|
|
3111
4149
|
|
|
3112
4150
|
// src/components/profile/change-password-form.tsx
|
|
3113
|
-
import { zodResolver as
|
|
4151
|
+
import { zodResolver as zodResolver9 } from "@hookform/resolvers/zod";
|
|
3114
4152
|
import {
|
|
3115
|
-
Button as
|
|
4153
|
+
Button as Button17,
|
|
3116
4154
|
Collapsible as Collapsible2,
|
|
3117
4155
|
CollapsibleContent as CollapsibleContent2,
|
|
3118
4156
|
CollapsibleTrigger as CollapsibleTrigger2,
|
|
3119
|
-
Input as
|
|
4157
|
+
Input as Input8,
|
|
3120
4158
|
Label as Label2,
|
|
3121
|
-
Spinner as
|
|
4159
|
+
Spinner as Spinner3
|
|
3122
4160
|
} from "@mesob/ui/components";
|
|
3123
|
-
import { IconChevronDown as IconChevronDown2, IconEye as
|
|
3124
|
-
import { useState as
|
|
3125
|
-
import { useForm as
|
|
3126
|
-
import { toast as
|
|
3127
|
-
import { z as
|
|
3128
|
-
import { jsx as
|
|
3129
|
-
var changePasswordSchema =
|
|
3130
|
-
currentPassword:
|
|
3131
|
-
newPassword:
|
|
3132
|
-
confirmPassword:
|
|
4161
|
+
import { IconChevronDown as IconChevronDown2, IconEye as IconEye6, IconEyeOff as IconEyeOff6 } from "@tabler/icons-react";
|
|
4162
|
+
import { useState as useState19 } from "react";
|
|
4163
|
+
import { useForm as useForm9 } from "react-hook-form";
|
|
4164
|
+
import { toast as toast12 } from "sonner";
|
|
4165
|
+
import { z as z9 } from "zod";
|
|
4166
|
+
import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
4167
|
+
var changePasswordSchema = z9.object({
|
|
4168
|
+
currentPassword: z9.string().min(8, "Password must be at least 8 characters"),
|
|
4169
|
+
newPassword: z9.string().min(8, "Password must be at least 8 characters"),
|
|
4170
|
+
confirmPassword: z9.string().min(8, "Password must be at least 8 characters")
|
|
3133
4171
|
}).refine((data) => data.newPassword === data.confirmPassword, {
|
|
3134
4172
|
message: "Passwords don't match",
|
|
3135
4173
|
path: ["confirmPassword"]
|
|
@@ -3183,13 +4221,13 @@ function getPasswordChangeErrorMessage(error) {
|
|
|
3183
4221
|
}
|
|
3184
4222
|
function ChangePasswordForm() {
|
|
3185
4223
|
const { user: _user } = useSession();
|
|
3186
|
-
const [isOpen, setIsOpen] =
|
|
3187
|
-
const [isSubmitting, setIsSubmitting] =
|
|
3188
|
-
const [showPassword, setShowPassword] =
|
|
3189
|
-
const [showNewPassword, setShowNewPassword] =
|
|
3190
|
-
const [showConfirmPassword, setShowConfirmPassword] =
|
|
3191
|
-
const form =
|
|
3192
|
-
resolver:
|
|
4224
|
+
const [isOpen, setIsOpen] = useState19(false);
|
|
4225
|
+
const [isSubmitting, setIsSubmitting] = useState19(false);
|
|
4226
|
+
const [showPassword, setShowPassword] = useState19(false);
|
|
4227
|
+
const [showNewPassword, setShowNewPassword] = useState19(false);
|
|
4228
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState19(false);
|
|
4229
|
+
const form = useForm9({
|
|
4230
|
+
resolver: zodResolver9(changePasswordSchema),
|
|
3193
4231
|
defaultValues: {
|
|
3194
4232
|
currentPassword: "",
|
|
3195
4233
|
newPassword: "",
|
|
@@ -3200,32 +4238,32 @@ function ChangePasswordForm() {
|
|
|
3200
4238
|
const onSubmit = (_data) => {
|
|
3201
4239
|
try {
|
|
3202
4240
|
setIsSubmitting(true);
|
|
3203
|
-
|
|
4241
|
+
toast12.error("Password change unavailable");
|
|
3204
4242
|
setIsOpen(false);
|
|
3205
4243
|
} catch (error) {
|
|
3206
4244
|
const errorMessage = getPasswordChangeErrorMessage(error);
|
|
3207
|
-
|
|
4245
|
+
toast12.error(errorMessage);
|
|
3208
4246
|
} finally {
|
|
3209
4247
|
setIsSubmitting(false);
|
|
3210
4248
|
}
|
|
3211
4249
|
};
|
|
3212
|
-
return /* @__PURE__ */
|
|
3213
|
-
/* @__PURE__ */
|
|
4250
|
+
return /* @__PURE__ */ jsx33(Collapsible2, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs28("div", { className: "border rounded-lg", children: [
|
|
4251
|
+
/* @__PURE__ */ jsxs28(
|
|
3214
4252
|
CollapsibleTrigger2,
|
|
3215
4253
|
{
|
|
3216
|
-
render: /* @__PURE__ */
|
|
3217
|
-
|
|
4254
|
+
render: /* @__PURE__ */ jsx33(
|
|
4255
|
+
Button17,
|
|
3218
4256
|
{
|
|
3219
4257
|
variant: "ghost",
|
|
3220
4258
|
className: "w-full justify-between p-4 h-auto"
|
|
3221
4259
|
}
|
|
3222
4260
|
),
|
|
3223
4261
|
children: [
|
|
3224
|
-
/* @__PURE__ */
|
|
3225
|
-
/* @__PURE__ */
|
|
3226
|
-
/* @__PURE__ */
|
|
4262
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-start", children: [
|
|
4263
|
+
/* @__PURE__ */ jsx33("span", { className: "font-medium", children: "Change Password" }),
|
|
4264
|
+
/* @__PURE__ */ jsx33("span", { className: "text-sm text-muted-foreground", children: "Update your account password" })
|
|
3227
4265
|
] }),
|
|
3228
|
-
/* @__PURE__ */
|
|
4266
|
+
/* @__PURE__ */ jsx33(
|
|
3229
4267
|
IconChevronDown2,
|
|
3230
4268
|
{
|
|
3231
4269
|
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
@@ -3234,17 +4272,17 @@ function ChangePasswordForm() {
|
|
|
3234
4272
|
]
|
|
3235
4273
|
}
|
|
3236
4274
|
),
|
|
3237
|
-
/* @__PURE__ */
|
|
4275
|
+
/* @__PURE__ */ jsx33(CollapsibleContent2, { children: /* @__PURE__ */ jsxs28(
|
|
3238
4276
|
"form",
|
|
3239
4277
|
{
|
|
3240
4278
|
onSubmit: handleSubmit(onSubmit),
|
|
3241
4279
|
className: "p-4 space-y-4 border-t",
|
|
3242
4280
|
children: [
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3245
|
-
/* @__PURE__ */
|
|
3246
|
-
/* @__PURE__ */
|
|
3247
|
-
|
|
4281
|
+
/* @__PURE__ */ jsxs28("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
4282
|
+
/* @__PURE__ */ jsx33(Label2, { htmlFor: "currentPassword", children: "Old Password" }),
|
|
4283
|
+
/* @__PURE__ */ jsxs28("div", { className: "relative", children: [
|
|
4284
|
+
/* @__PURE__ */ jsx33(
|
|
4285
|
+
Input8,
|
|
3248
4286
|
{
|
|
3249
4287
|
id: "currentPassword",
|
|
3250
4288
|
type: showPassword ? "text" : "password",
|
|
@@ -3253,23 +4291,23 @@ function ChangePasswordForm() {
|
|
|
3253
4291
|
...register("currentPassword")
|
|
3254
4292
|
}
|
|
3255
4293
|
),
|
|
3256
|
-
/* @__PURE__ */
|
|
4294
|
+
/* @__PURE__ */ jsx33(
|
|
3257
4295
|
"button",
|
|
3258
4296
|
{
|
|
3259
4297
|
type: "button",
|
|
3260
4298
|
onClick: () => setShowPassword(!showPassword),
|
|
3261
4299
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3262
|
-
children: showPassword ? /* @__PURE__ */
|
|
4300
|
+
children: showPassword ? /* @__PURE__ */ jsx33(IconEyeOff6, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(IconEye6, { className: "h-4 w-4" })
|
|
3263
4301
|
}
|
|
3264
4302
|
)
|
|
3265
4303
|
] }),
|
|
3266
|
-
formState.errors.currentPassword && /* @__PURE__ */
|
|
4304
|
+
formState.errors.currentPassword && /* @__PURE__ */ jsx33("p", { className: "text-sm text-destructive", children: formState.errors.currentPassword.message })
|
|
3267
4305
|
] }),
|
|
3268
|
-
/* @__PURE__ */
|
|
3269
|
-
/* @__PURE__ */
|
|
3270
|
-
/* @__PURE__ */
|
|
3271
|
-
/* @__PURE__ */
|
|
3272
|
-
|
|
4306
|
+
/* @__PURE__ */ jsxs28("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
4307
|
+
/* @__PURE__ */ jsx33(Label2, { htmlFor: "newPassword", children: "New Password" }),
|
|
4308
|
+
/* @__PURE__ */ jsxs28("div", { className: "relative", children: [
|
|
4309
|
+
/* @__PURE__ */ jsx33(
|
|
4310
|
+
Input8,
|
|
3273
4311
|
{
|
|
3274
4312
|
id: "newPassword",
|
|
3275
4313
|
type: showNewPassword ? "text" : "password",
|
|
@@ -3278,23 +4316,23 @@ function ChangePasswordForm() {
|
|
|
3278
4316
|
...register("newPassword")
|
|
3279
4317
|
}
|
|
3280
4318
|
),
|
|
3281
|
-
/* @__PURE__ */
|
|
4319
|
+
/* @__PURE__ */ jsx33(
|
|
3282
4320
|
"button",
|
|
3283
4321
|
{
|
|
3284
4322
|
type: "button",
|
|
3285
4323
|
onClick: () => setShowNewPassword(!showNewPassword),
|
|
3286
4324
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3287
|
-
children: showNewPassword ? /* @__PURE__ */
|
|
4325
|
+
children: showNewPassword ? /* @__PURE__ */ jsx33(IconEyeOff6, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(IconEye6, { className: "h-4 w-4" })
|
|
3288
4326
|
}
|
|
3289
4327
|
)
|
|
3290
4328
|
] }),
|
|
3291
|
-
formState.errors.newPassword && /* @__PURE__ */
|
|
4329
|
+
formState.errors.newPassword && /* @__PURE__ */ jsx33("p", { className: "text-sm text-destructive", children: formState.errors.newPassword.message })
|
|
3292
4330
|
] }),
|
|
3293
|
-
/* @__PURE__ */
|
|
3294
|
-
/* @__PURE__ */
|
|
3295
|
-
/* @__PURE__ */
|
|
3296
|
-
/* @__PURE__ */
|
|
3297
|
-
|
|
4331
|
+
/* @__PURE__ */ jsxs28("div", { className: "space-y-2 w-full md:w-1/2", children: [
|
|
4332
|
+
/* @__PURE__ */ jsx33(Label2, { htmlFor: "confirmPassword", children: "Confirm New Password" }),
|
|
4333
|
+
/* @__PURE__ */ jsxs28("div", { className: "relative", children: [
|
|
4334
|
+
/* @__PURE__ */ jsx33(
|
|
4335
|
+
Input8,
|
|
3298
4336
|
{
|
|
3299
4337
|
id: "confirmPassword",
|
|
3300
4338
|
type: showConfirmPassword ? "text" : "password",
|
|
@@ -3303,21 +4341,21 @@ function ChangePasswordForm() {
|
|
|
3303
4341
|
...register("confirmPassword")
|
|
3304
4342
|
}
|
|
3305
4343
|
),
|
|
3306
|
-
/* @__PURE__ */
|
|
4344
|
+
/* @__PURE__ */ jsx33(
|
|
3307
4345
|
"button",
|
|
3308
4346
|
{
|
|
3309
4347
|
type: "button",
|
|
3310
4348
|
onClick: () => setShowConfirmPassword(!showConfirmPassword),
|
|
3311
4349
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3312
|
-
children: showConfirmPassword ? /* @__PURE__ */
|
|
4350
|
+
children: showConfirmPassword ? /* @__PURE__ */ jsx33(IconEyeOff6, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(IconEye6, { className: "h-4 w-4" })
|
|
3313
4351
|
}
|
|
3314
4352
|
)
|
|
3315
4353
|
] }),
|
|
3316
|
-
formState.errors.confirmPassword && /* @__PURE__ */
|
|
4354
|
+
formState.errors.confirmPassword && /* @__PURE__ */ jsx33("p", { className: "text-sm text-destructive", children: formState.errors.confirmPassword.message })
|
|
3317
4355
|
] }),
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
/* @__PURE__ */
|
|
3320
|
-
|
|
4356
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex justify-end gap-2", children: [
|
|
4357
|
+
/* @__PURE__ */ jsx33(
|
|
4358
|
+
Button17,
|
|
3321
4359
|
{
|
|
3322
4360
|
type: "button",
|
|
3323
4361
|
variant: "outline",
|
|
@@ -3329,8 +4367,8 @@ function ChangePasswordForm() {
|
|
|
3329
4367
|
children: "Cancel"
|
|
3330
4368
|
}
|
|
3331
4369
|
),
|
|
3332
|
-
/* @__PURE__ */
|
|
3333
|
-
isSubmitting && /* @__PURE__ */
|
|
4370
|
+
/* @__PURE__ */ jsxs28(Button17, { type: "submit", disabled: isSubmitting, children: [
|
|
4371
|
+
isSubmitting && /* @__PURE__ */ jsx33(Spinner3, { className: "mr-2 h-4 w-4" }),
|
|
3334
4372
|
"Change Password"
|
|
3335
4373
|
] })
|
|
3336
4374
|
] })
|
|
@@ -3342,25 +4380,25 @@ function ChangePasswordForm() {
|
|
|
3342
4380
|
|
|
3343
4381
|
// src/components/profile/change-phone-form.tsx
|
|
3344
4382
|
import {
|
|
3345
|
-
Button as
|
|
4383
|
+
Button as Button19,
|
|
3346
4384
|
Collapsible as Collapsible3,
|
|
3347
4385
|
CollapsibleContent as CollapsibleContent3,
|
|
3348
4386
|
CollapsibleTrigger as CollapsibleTrigger3
|
|
3349
4387
|
} from "@mesob/ui/components";
|
|
3350
4388
|
import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
3351
|
-
import { useState as
|
|
4389
|
+
import { useState as useState22 } from "react";
|
|
3352
4390
|
|
|
3353
4391
|
// src/components/profile/request-change-phone-form.tsx
|
|
3354
|
-
import { zodResolver as
|
|
3355
|
-
import { Button as
|
|
3356
|
-
import { IconEye as
|
|
3357
|
-
import { useEffect as
|
|
3358
|
-
import { useForm as
|
|
3359
|
-
import { toast as
|
|
3360
|
-
import { z as
|
|
3361
|
-
import { jsx as
|
|
3362
|
-
var phonePasswordSchema = (phoneRegex) =>
|
|
3363
|
-
phone:
|
|
4392
|
+
import { zodResolver as zodResolver10 } from "@hookform/resolvers/zod";
|
|
4393
|
+
import { Button as Button18, Input as Input9, Label as Label3, Spinner as Spinner4 } from "@mesob/ui/components";
|
|
4394
|
+
import { IconEye as IconEye7, IconEyeOff as IconEyeOff7 } from "@tabler/icons-react";
|
|
4395
|
+
import { useEffect as useEffect11, useState as useState20 } from "react";
|
|
4396
|
+
import { useForm as useForm10 } from "react-hook-form";
|
|
4397
|
+
import { toast as toast13 } from "sonner";
|
|
4398
|
+
import { z as z10 } from "zod";
|
|
4399
|
+
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4400
|
+
var phonePasswordSchema = (phoneRegex) => z10.object({
|
|
4401
|
+
phone: z10.string().trim().min(1, { message: "Phone number is required" }).refine(
|
|
3364
4402
|
(val) => {
|
|
3365
4403
|
const isPhone3 = phoneRegex.test(val);
|
|
3366
4404
|
return isPhone3;
|
|
@@ -3369,7 +4407,7 @@ var phonePasswordSchema = (phoneRegex) => z8.object({
|
|
|
3369
4407
|
message: "Invalid phone number"
|
|
3370
4408
|
}
|
|
3371
4409
|
),
|
|
3372
|
-
password:
|
|
4410
|
+
password: z10.string().min(8, "Password must be at least 8 characters").max(128, "Password too long")
|
|
3373
4411
|
});
|
|
3374
4412
|
function isAuthError5(error) {
|
|
3375
4413
|
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
@@ -3425,9 +4463,9 @@ function RequestChangePhoneForm({
|
|
|
3425
4463
|
const { user } = useSession();
|
|
3426
4464
|
const { hooks } = useApi();
|
|
3427
4465
|
const { config } = useConfig();
|
|
3428
|
-
const [isSubmitting, setIsSubmitting] =
|
|
3429
|
-
const [isChecking, setIsChecking] =
|
|
3430
|
-
const [showPassword, setShowPassword] =
|
|
4466
|
+
const [isSubmitting, setIsSubmitting] = useState20(false);
|
|
4467
|
+
const [isChecking, setIsChecking] = useState20(true);
|
|
4468
|
+
const [showPassword, setShowPassword] = useState20(false);
|
|
3431
4469
|
const phoneRegex = typeof config.phoneRegex === "string" ? new RegExp(config.phoneRegex) : config.phoneRegex || /^(\+2519|\+2517|2519|2517|09|07)\d{8}$/;
|
|
3432
4470
|
const getPendingAccountChangeQuery = hooks.useQuery(
|
|
3433
4471
|
"get",
|
|
@@ -3441,8 +4479,8 @@ function RequestChangePhoneForm({
|
|
|
3441
4479
|
"post",
|
|
3442
4480
|
"/phone/verification/request"
|
|
3443
4481
|
);
|
|
3444
|
-
const phonePasswordForm =
|
|
3445
|
-
resolver:
|
|
4482
|
+
const phonePasswordForm = useForm10({
|
|
4483
|
+
resolver: zodResolver10(phonePasswordSchema(phoneRegex)),
|
|
3446
4484
|
defaultValues: {
|
|
3447
4485
|
phone: "",
|
|
3448
4486
|
password: ""
|
|
@@ -3455,7 +4493,7 @@ function RequestChangePhoneForm({
|
|
|
3455
4493
|
setValue,
|
|
3456
4494
|
formState: { errors }
|
|
3457
4495
|
} = phonePasswordForm;
|
|
3458
|
-
|
|
4496
|
+
useEffect11(() => {
|
|
3459
4497
|
let active = true;
|
|
3460
4498
|
const run = async () => {
|
|
3461
4499
|
try {
|
|
@@ -3479,7 +4517,7 @@ function RequestChangePhoneForm({
|
|
|
3479
4517
|
}
|
|
3480
4518
|
setValue("phone", accountChange.newPhone, { shouldValidate: true });
|
|
3481
4519
|
if (verificationId) {
|
|
3482
|
-
|
|
4520
|
+
toast13.message("Resuming verification\u2026");
|
|
3483
4521
|
onSuccess(verificationId, accountChange.newPhone);
|
|
3484
4522
|
return;
|
|
3485
4523
|
}
|
|
@@ -3495,7 +4533,7 @@ function RequestChangePhoneForm({
|
|
|
3495
4533
|
}, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);
|
|
3496
4534
|
const onPhonePasswordSubmit = async (data) => {
|
|
3497
4535
|
if (!user) {
|
|
3498
|
-
|
|
4536
|
+
toast13.error("User not found");
|
|
3499
4537
|
return;
|
|
3500
4538
|
}
|
|
3501
4539
|
try {
|
|
@@ -3509,10 +4547,10 @@ function RequestChangePhoneForm({
|
|
|
3509
4547
|
});
|
|
3510
4548
|
if (checkResult.data?.exists) {
|
|
3511
4549
|
if (user?.phone?.replace(/\s/g, "") === normalizedPhone.replace(/\s/g, "")) {
|
|
3512
|
-
|
|
4550
|
+
toast13.error("This is already your current phone number.");
|
|
3513
4551
|
return;
|
|
3514
4552
|
}
|
|
3515
|
-
|
|
4553
|
+
toast13.error(
|
|
3516
4554
|
"This phone number is already taken. Please use a different number."
|
|
3517
4555
|
);
|
|
3518
4556
|
return;
|
|
@@ -3523,34 +4561,34 @@ function RequestChangePhoneForm({
|
|
|
3523
4561
|
context: "change-phone"
|
|
3524
4562
|
}
|
|
3525
4563
|
});
|
|
3526
|
-
|
|
4564
|
+
toast13.success("Verification code sent to your phone");
|
|
3527
4565
|
onSuccess(verification.data?.verificationId ?? "", normalizedPhone);
|
|
3528
4566
|
} catch (error) {
|
|
3529
4567
|
const errorMessage = getErrorMessage3(error);
|
|
3530
4568
|
if (isAuthError5(error)) {
|
|
3531
4569
|
const errorCode = getErrorCode4(error);
|
|
3532
4570
|
if (errorCode === "INVALID_PASSWORD" || errorCode === "USER_NOT_FOUND") {
|
|
3533
|
-
|
|
4571
|
+
toast13.error("Incorrect password. Please try again.");
|
|
3534
4572
|
return;
|
|
3535
4573
|
}
|
|
3536
4574
|
}
|
|
3537
|
-
|
|
4575
|
+
toast13.error(errorMessage);
|
|
3538
4576
|
} finally {
|
|
3539
4577
|
setIsSubmitting(false);
|
|
3540
4578
|
}
|
|
3541
4579
|
};
|
|
3542
4580
|
const isLoading = isSubmitting || isChecking;
|
|
3543
|
-
return /* @__PURE__ */
|
|
4581
|
+
return /* @__PURE__ */ jsxs29(
|
|
3544
4582
|
"form",
|
|
3545
4583
|
{
|
|
3546
4584
|
onSubmit: handleSubmit(onPhonePasswordSubmit),
|
|
3547
4585
|
className: "p-4 space-y-4 border-t",
|
|
3548
4586
|
children: [
|
|
3549
|
-
/* @__PURE__ */
|
|
3550
|
-
/* @__PURE__ */
|
|
3551
|
-
/* @__PURE__ */
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
|
|
4587
|
+
/* @__PURE__ */ jsxs29("div", { className: "space-y-4 w-full md:w-1/2", children: [
|
|
4588
|
+
/* @__PURE__ */ jsxs29("div", { className: "space-y-2", children: [
|
|
4589
|
+
/* @__PURE__ */ jsx34(Label3, { htmlFor: "phone", children: "Phone Number" }),
|
|
4590
|
+
/* @__PURE__ */ jsx34(
|
|
4591
|
+
Input9,
|
|
3554
4592
|
{
|
|
3555
4593
|
id: "phone",
|
|
3556
4594
|
type: "tel",
|
|
@@ -3559,13 +4597,13 @@ function RequestChangePhoneForm({
|
|
|
3559
4597
|
disabled: isLoading
|
|
3560
4598
|
}
|
|
3561
4599
|
),
|
|
3562
|
-
errors.phone && /* @__PURE__ */
|
|
4600
|
+
errors.phone && /* @__PURE__ */ jsx34("p", { className: "text-sm text-destructive", children: errors.phone.message })
|
|
3563
4601
|
] }),
|
|
3564
|
-
/* @__PURE__ */
|
|
3565
|
-
/* @__PURE__ */
|
|
3566
|
-
/* @__PURE__ */
|
|
3567
|
-
/* @__PURE__ */
|
|
3568
|
-
|
|
4602
|
+
/* @__PURE__ */ jsxs29("div", { className: "space-y-2", children: [
|
|
4603
|
+
/* @__PURE__ */ jsx34(Label3, { htmlFor: "password", children: "Password" }),
|
|
4604
|
+
/* @__PURE__ */ jsxs29("div", { className: "relative", children: [
|
|
4605
|
+
/* @__PURE__ */ jsx34(
|
|
4606
|
+
Input9,
|
|
3569
4607
|
{
|
|
3570
4608
|
id: "password",
|
|
3571
4609
|
type: showPassword ? "text" : "password",
|
|
@@ -3575,22 +4613,22 @@ function RequestChangePhoneForm({
|
|
|
3575
4613
|
disabled: isLoading
|
|
3576
4614
|
}
|
|
3577
4615
|
),
|
|
3578
|
-
/* @__PURE__ */
|
|
4616
|
+
/* @__PURE__ */ jsx34(
|
|
3579
4617
|
"button",
|
|
3580
4618
|
{
|
|
3581
4619
|
type: "button",
|
|
3582
4620
|
onClick: () => setShowPassword(!showPassword),
|
|
3583
4621
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
3584
|
-
children: showPassword ? /* @__PURE__ */
|
|
4622
|
+
children: showPassword ? /* @__PURE__ */ jsx34(IconEyeOff7, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx34(IconEye7, { className: "h-4 w-4" })
|
|
3585
4623
|
}
|
|
3586
4624
|
)
|
|
3587
4625
|
] }),
|
|
3588
|
-
errors.password && /* @__PURE__ */
|
|
4626
|
+
errors.password && /* @__PURE__ */ jsx34("p", { className: "text-sm text-destructive", children: errors.password.message })
|
|
3589
4627
|
] })
|
|
3590
4628
|
] }),
|
|
3591
|
-
/* @__PURE__ */
|
|
3592
|
-
/* @__PURE__ */
|
|
3593
|
-
|
|
4629
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex justify-end gap-2", children: [
|
|
4630
|
+
/* @__PURE__ */ jsx34(
|
|
4631
|
+
Button18,
|
|
3594
4632
|
{
|
|
3595
4633
|
type: "button",
|
|
3596
4634
|
variant: "outline",
|
|
@@ -3599,8 +4637,8 @@ function RequestChangePhoneForm({
|
|
|
3599
4637
|
children: "Cancel"
|
|
3600
4638
|
}
|
|
3601
4639
|
),
|
|
3602
|
-
/* @__PURE__ */
|
|
3603
|
-
isLoading && /* @__PURE__ */
|
|
4640
|
+
/* @__PURE__ */ jsxs29(Button18, { type: "submit", disabled: isLoading, children: [
|
|
4641
|
+
isLoading && /* @__PURE__ */ jsx34(Spinner4, { className: "mr-2 h-4 w-4" }),
|
|
3604
4642
|
isChecking ? "Checking\u2026" : buttonText
|
|
3605
4643
|
] })
|
|
3606
4644
|
] })
|
|
@@ -3610,9 +4648,9 @@ function RequestChangePhoneForm({
|
|
|
3610
4648
|
}
|
|
3611
4649
|
|
|
3612
4650
|
// src/components/profile/verify-change-phone-form.tsx
|
|
3613
|
-
import { useState as
|
|
3614
|
-
import { toast as
|
|
3615
|
-
import { jsx as
|
|
4651
|
+
import { useState as useState21 } from "react";
|
|
4652
|
+
import { toast as toast14 } from "sonner";
|
|
4653
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3616
4654
|
function isAuthError6(error) {
|
|
3617
4655
|
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
3618
4656
|
}
|
|
@@ -3667,8 +4705,8 @@ function VerifyChangePhoneForm({
|
|
|
3667
4705
|
}) {
|
|
3668
4706
|
const { refresh } = useSession();
|
|
3669
4707
|
const { hooks } = useApi();
|
|
3670
|
-
const [isSubmitting, setIsSubmitting] =
|
|
3671
|
-
const [currentVerificationId, setCurrentVerificationId] =
|
|
4708
|
+
const [isSubmitting, setIsSubmitting] = useState21(false);
|
|
4709
|
+
const [currentVerificationId, setCurrentVerificationId] = useState21(verificationId);
|
|
3672
4710
|
const verifyPhoneOtpMutation = hooks.useMutation(
|
|
3673
4711
|
"post",
|
|
3674
4712
|
"/phone/verification/confirm"
|
|
@@ -3680,7 +4718,7 @@ function VerifyChangePhoneForm({
|
|
|
3680
4718
|
);
|
|
3681
4719
|
const onOtpSubmit = async (code) => {
|
|
3682
4720
|
if (!currentVerificationId) {
|
|
3683
|
-
|
|
4721
|
+
toast14.error("Verification not found. Please request a new code.");
|
|
3684
4722
|
return;
|
|
3685
4723
|
}
|
|
3686
4724
|
try {
|
|
@@ -3695,21 +4733,21 @@ function VerifyChangePhoneForm({
|
|
|
3695
4733
|
await updatePhoneMutation.mutateAsync({
|
|
3696
4734
|
body: { phone }
|
|
3697
4735
|
});
|
|
3698
|
-
|
|
4736
|
+
toast14.success("Phone number updated successfully");
|
|
3699
4737
|
await refresh();
|
|
3700
4738
|
onSuccess();
|
|
3701
4739
|
} catch (error) {
|
|
3702
4740
|
const errorMessage = getErrorMessage4(error);
|
|
3703
|
-
|
|
4741
|
+
toast14.error(errorMessage);
|
|
3704
4742
|
} finally {
|
|
3705
4743
|
setIsSubmitting(false);
|
|
3706
4744
|
}
|
|
3707
4745
|
};
|
|
3708
4746
|
if (!currentVerificationId) {
|
|
3709
|
-
|
|
4747
|
+
toast14.error("Verification not found. Please request a new code.");
|
|
3710
4748
|
return null;
|
|
3711
4749
|
}
|
|
3712
|
-
return /* @__PURE__ */
|
|
4750
|
+
return /* @__PURE__ */ jsx35(
|
|
3713
4751
|
OtpVerificationModal,
|
|
3714
4752
|
{
|
|
3715
4753
|
open: true,
|
|
@@ -3728,9 +4766,9 @@ function VerifyChangePhoneForm({
|
|
|
3728
4766
|
}
|
|
3729
4767
|
});
|
|
3730
4768
|
setCurrentVerificationId(next.data?.verificationId ?? null);
|
|
3731
|
-
|
|
4769
|
+
toast14.success("Verification code resent");
|
|
3732
4770
|
} catch (error) {
|
|
3733
|
-
|
|
4771
|
+
toast14.error(getErrorMessage4(error));
|
|
3734
4772
|
} finally {
|
|
3735
4773
|
setIsSubmitting(false);
|
|
3736
4774
|
}
|
|
@@ -3741,13 +4779,13 @@ function VerifyChangePhoneForm({
|
|
|
3741
4779
|
}
|
|
3742
4780
|
|
|
3743
4781
|
// src/components/profile/change-phone-form.tsx
|
|
3744
|
-
import { jsx as
|
|
4782
|
+
import { jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3745
4783
|
function ChangePhoneForm() {
|
|
3746
4784
|
const { user } = useSession();
|
|
3747
|
-
const [isOpen, setIsOpen] =
|
|
3748
|
-
const [showOtp, setShowOtp] =
|
|
3749
|
-
const [verificationId, setVerificationId] =
|
|
3750
|
-
const [newPhone, setNewPhone] =
|
|
4785
|
+
const [isOpen, setIsOpen] = useState22(false);
|
|
4786
|
+
const [showOtp, setShowOtp] = useState22(false);
|
|
4787
|
+
const [verificationId, setVerificationId] = useState22(null);
|
|
4788
|
+
const [newPhone, setNewPhone] = useState22("");
|
|
3751
4789
|
const resetForms = () => {
|
|
3752
4790
|
setShowOtp(false);
|
|
3753
4791
|
setVerificationId(null);
|
|
@@ -3768,23 +4806,23 @@ function ChangePhoneForm() {
|
|
|
3768
4806
|
};
|
|
3769
4807
|
const title = user?.phone ? "Change Phone" : "Add Phone";
|
|
3770
4808
|
const description = user?.phone ? "Update your phone number" : "Add a phone number to your account";
|
|
3771
|
-
return /* @__PURE__ */
|
|
3772
|
-
/* @__PURE__ */
|
|
4809
|
+
return /* @__PURE__ */ jsx36(Collapsible3, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs30("div", { className: "border rounded-lg", children: [
|
|
4810
|
+
/* @__PURE__ */ jsxs30(
|
|
3773
4811
|
CollapsibleTrigger3,
|
|
3774
4812
|
{
|
|
3775
|
-
render: /* @__PURE__ */
|
|
3776
|
-
|
|
4813
|
+
render: /* @__PURE__ */ jsx36(
|
|
4814
|
+
Button19,
|
|
3777
4815
|
{
|
|
3778
4816
|
variant: "ghost",
|
|
3779
4817
|
className: "w-full justify-between p-4 h-auto"
|
|
3780
4818
|
}
|
|
3781
4819
|
),
|
|
3782
4820
|
children: [
|
|
3783
|
-
/* @__PURE__ */
|
|
3784
|
-
/* @__PURE__ */
|
|
3785
|
-
/* @__PURE__ */
|
|
4821
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col items-start", children: [
|
|
4822
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium", children: title }),
|
|
4823
|
+
/* @__PURE__ */ jsx36("span", { className: "text-sm text-muted-foreground", children: description })
|
|
3786
4824
|
] }),
|
|
3787
|
-
/* @__PURE__ */
|
|
4825
|
+
/* @__PURE__ */ jsx36(
|
|
3788
4826
|
IconChevronDown3,
|
|
3789
4827
|
{
|
|
3790
4828
|
className: `h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
@@ -3793,7 +4831,7 @@ function ChangePhoneForm() {
|
|
|
3793
4831
|
]
|
|
3794
4832
|
}
|
|
3795
4833
|
),
|
|
3796
|
-
/* @__PURE__ */
|
|
4834
|
+
/* @__PURE__ */ jsx36(CollapsibleContent3, { children: showOtp ? /* @__PURE__ */ jsx36(
|
|
3797
4835
|
VerifyChangePhoneForm,
|
|
3798
4836
|
{
|
|
3799
4837
|
phone: newPhone,
|
|
@@ -3801,7 +4839,7 @@ function ChangePhoneForm() {
|
|
|
3801
4839
|
onSuccess: handleVerifySuccess,
|
|
3802
4840
|
onCancel: handleCancel
|
|
3803
4841
|
}
|
|
3804
|
-
) : /* @__PURE__ */
|
|
4842
|
+
) : /* @__PURE__ */ jsx36(
|
|
3805
4843
|
RequestChangePhoneForm,
|
|
3806
4844
|
{
|
|
3807
4845
|
onSuccess: handleRequestSuccess,
|
|
@@ -3813,70 +4851,101 @@ function ChangePhoneForm() {
|
|
|
3813
4851
|
}
|
|
3814
4852
|
|
|
3815
4853
|
// src/components/profile/security.tsx
|
|
3816
|
-
import { jsx as
|
|
4854
|
+
import { jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3817
4855
|
function Security() {
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
/* @__PURE__ */
|
|
4856
|
+
const { user } = useSession();
|
|
4857
|
+
return /* @__PURE__ */ jsxs31("div", { className: "mx-auto flex w-full max-w-6xl flex-col gap-6", children: [
|
|
4858
|
+
/* @__PURE__ */ jsxs31("div", { className: "relative overflow-hidden rounded-[2rem] border border-border/60 bg-gradient-to-br from-background via-background to-amber-500/5 p-6 shadow-sm", children: [
|
|
4859
|
+
/* @__PURE__ */ jsx37("div", { className: "absolute left-0 top-0 h-32 w-32 rounded-full bg-primary/10 blur-3xl" }),
|
|
4860
|
+
/* @__PURE__ */ jsxs31("div", { className: "relative flex flex-col gap-4", children: [
|
|
4861
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex flex-wrap gap-2", children: [
|
|
4862
|
+
/* @__PURE__ */ jsx37(Badge9, { variant: "outline", children: "Security center" }),
|
|
4863
|
+
/* @__PURE__ */ jsx37(Badge9, { variant: "secondary", children: user?.emailVerified || user?.phoneVerified ? "Recovery methods available" : "Add a recovery method" })
|
|
4864
|
+
] }),
|
|
4865
|
+
/* @__PURE__ */ jsxs31("div", { className: "space-y-2", children: [
|
|
4866
|
+
/* @__PURE__ */ jsx37("h1", { className: "text-2xl font-semibold tracking-tight", children: "Security" }),
|
|
4867
|
+
/* @__PURE__ */ jsx37("p", { className: "max-w-2xl text-sm text-muted-foreground", children: "Password, email, and phone updates all live here. Keep recovery channels current so account recovery stays predictable." })
|
|
4868
|
+
] })
|
|
4869
|
+
] })
|
|
3822
4870
|
] }),
|
|
3823
|
-
/* @__PURE__ */
|
|
3824
|
-
/* @__PURE__ */
|
|
3825
|
-
|
|
3826
|
-
|
|
4871
|
+
/* @__PURE__ */ jsxs31("div", { className: "grid gap-4 lg:grid-cols-[0.85fr_1.4fr]", children: [
|
|
4872
|
+
/* @__PURE__ */ jsx37(Card3, { className: "rounded-[1.75rem] border-border/60 shadow-sm", children: /* @__PURE__ */ jsxs31(CardContent2, { className: "space-y-5 p-6", children: [
|
|
4873
|
+
/* @__PURE__ */ jsxs31("div", { className: "space-y-1", children: [
|
|
4874
|
+
/* @__PURE__ */ jsx37("div", { className: "text-sm font-medium text-muted-foreground", children: "Verification state" }),
|
|
4875
|
+
/* @__PURE__ */ jsx37("div", { className: "text-lg font-semibold", children: "Recovery readiness" })
|
|
4876
|
+
] }),
|
|
4877
|
+
/* @__PURE__ */ jsx37(Separator2, {}),
|
|
4878
|
+
/* @__PURE__ */ jsxs31("div", { className: "space-y-3", children: [
|
|
4879
|
+
/* @__PURE__ */ jsxs31("div", { className: "rounded-2xl border border-border/60 bg-muted/20 p-4", children: [
|
|
4880
|
+
/* @__PURE__ */ jsx37("div", { className: "text-sm font-medium", children: "Email" }),
|
|
4881
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-1 text-sm text-muted-foreground", children: user?.email ?? "No email added" }),
|
|
4882
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-3", children: /* @__PURE__ */ jsx37(Badge9, { variant: "outline", children: user?.emailVerified ? "Verified" : "Unverified" }) })
|
|
4883
|
+
] }),
|
|
4884
|
+
/* @__PURE__ */ jsxs31("div", { className: "rounded-2xl border border-border/60 bg-muted/20 p-4", children: [
|
|
4885
|
+
/* @__PURE__ */ jsx37("div", { className: "text-sm font-medium", children: "Phone" }),
|
|
4886
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-1 text-sm text-muted-foreground", children: user?.phone ?? "No phone added" }),
|
|
4887
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-3", children: /* @__PURE__ */ jsx37(Badge9, { variant: "outline", children: user?.phoneVerified ? "Verified" : "Unverified" }) })
|
|
4888
|
+
] })
|
|
4889
|
+
] })
|
|
4890
|
+
] }) }),
|
|
4891
|
+
/* @__PURE__ */ jsxs31("div", { className: "space-y-4", children: [
|
|
4892
|
+
/* @__PURE__ */ jsx37(ChangePasswordForm, {}),
|
|
4893
|
+
/* @__PURE__ */ jsx37(ChangeEmailForm, {}),
|
|
4894
|
+
/* @__PURE__ */ jsx37(ChangePhoneForm, {})
|
|
4895
|
+
] })
|
|
3827
4896
|
] })
|
|
3828
4897
|
] });
|
|
3829
4898
|
}
|
|
3830
4899
|
|
|
3831
4900
|
// src/components/skeletons/auth-form-skeleton.tsx
|
|
3832
|
-
import { Skeleton as
|
|
3833
|
-
import { jsx as
|
|
4901
|
+
import { Skeleton as Skeleton3 } from "@mesob/ui/components";
|
|
4902
|
+
import { jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3834
4903
|
function AuthFormSkeleton() {
|
|
3835
|
-
return /* @__PURE__ */
|
|
3836
|
-
/* @__PURE__ */
|
|
3837
|
-
/* @__PURE__ */
|
|
3838
|
-
/* @__PURE__ */
|
|
4904
|
+
return /* @__PURE__ */ jsxs32("div", { className: "w-full max-w-md space-y-6 p-6", children: [
|
|
4905
|
+
/* @__PURE__ */ jsxs32("div", { className: "space-y-2 text-center", children: [
|
|
4906
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-8 w-48 mx-auto" }),
|
|
4907
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-4 w-64 mx-auto" })
|
|
3839
4908
|
] }),
|
|
3840
|
-
/* @__PURE__ */
|
|
3841
|
-
/* @__PURE__ */
|
|
3842
|
-
/* @__PURE__ */
|
|
3843
|
-
/* @__PURE__ */
|
|
4909
|
+
/* @__PURE__ */ jsxs32("div", { className: "space-y-4", children: [
|
|
4910
|
+
/* @__PURE__ */ jsxs32("div", { className: "space-y-2", children: [
|
|
4911
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-4 w-24" }),
|
|
4912
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-10 w-full" })
|
|
3844
4913
|
] }),
|
|
3845
|
-
/* @__PURE__ */
|
|
3846
|
-
/* @__PURE__ */
|
|
3847
|
-
/* @__PURE__ */
|
|
4914
|
+
/* @__PURE__ */ jsxs32("div", { className: "space-y-2", children: [
|
|
4915
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-4 w-24" }),
|
|
4916
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-10 w-full" })
|
|
3848
4917
|
] }),
|
|
3849
|
-
/* @__PURE__ */
|
|
4918
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-10 w-full" })
|
|
3850
4919
|
] }),
|
|
3851
|
-
/* @__PURE__ */
|
|
3852
|
-
/* @__PURE__ */
|
|
3853
|
-
/* @__PURE__ */
|
|
4920
|
+
/* @__PURE__ */ jsxs32("div", { className: "space-y-2", children: [
|
|
4921
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-px w-full" }),
|
|
4922
|
+
/* @__PURE__ */ jsx38(Skeleton3, { className: "h-4 w-32 mx-auto" })
|
|
3854
4923
|
] })
|
|
3855
4924
|
] });
|
|
3856
4925
|
}
|
|
3857
4926
|
|
|
3858
4927
|
// src/components/skeletons/profile-skeleton.tsx
|
|
3859
|
-
import { Skeleton as
|
|
3860
|
-
import { jsx as
|
|
4928
|
+
import { Skeleton as Skeleton4 } from "@mesob/ui/components";
|
|
4929
|
+
import { jsx as jsx39, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3861
4930
|
function ProfileSkeleton() {
|
|
3862
|
-
return /* @__PURE__ */
|
|
3863
|
-
/* @__PURE__ */
|
|
3864
|
-
/* @__PURE__ */
|
|
3865
|
-
/* @__PURE__ */
|
|
3866
|
-
/* @__PURE__ */
|
|
3867
|
-
/* @__PURE__ */
|
|
4931
|
+
return /* @__PURE__ */ jsxs33("div", { className: "w-full max-w-4xl space-y-8 p-6", children: [
|
|
4932
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-6", children: [
|
|
4933
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-24 w-24 rounded-full" }),
|
|
4934
|
+
/* @__PURE__ */ jsxs33("div", { className: "space-y-2 flex-1", children: [
|
|
4935
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-8 w-48" }),
|
|
4936
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-4 w-64" })
|
|
3868
4937
|
] })
|
|
3869
4938
|
] }),
|
|
3870
|
-
/* @__PURE__ */
|
|
3871
|
-
/* @__PURE__ */
|
|
3872
|
-
/* @__PURE__ */
|
|
3873
|
-
/* @__PURE__ */
|
|
3874
|
-
/* @__PURE__ */
|
|
3875
|
-
/* @__PURE__ */
|
|
4939
|
+
/* @__PURE__ */ jsx39("div", { className: "space-y-6", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs33("div", { className: "space-y-4", children: [
|
|
4940
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-6 w-32" }),
|
|
4941
|
+
/* @__PURE__ */ jsxs33("div", { className: "space-y-3", children: [
|
|
4942
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex justify-between items-center", children: [
|
|
4943
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-4 w-24" }),
|
|
4944
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-4 w-32" })
|
|
3876
4945
|
] }),
|
|
3877
|
-
/* @__PURE__ */
|
|
3878
|
-
/* @__PURE__ */
|
|
3879
|
-
/* @__PURE__ */
|
|
4946
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex justify-between items-center", children: [
|
|
4947
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-4 w-24" }),
|
|
4948
|
+
/* @__PURE__ */ jsx39(Skeleton4, { className: "h-4 w-40" })
|
|
3880
4949
|
] })
|
|
3881
4950
|
] })
|
|
3882
4951
|
] }, i)) })
|
|
@@ -3894,15 +4963,22 @@ export {
|
|
|
3894
4963
|
AuthErrorBoundary,
|
|
3895
4964
|
AuthFormSkeleton,
|
|
3896
4965
|
DataTable,
|
|
4966
|
+
Deny,
|
|
3897
4967
|
ErrorBoundary,
|
|
3898
4968
|
ForgotPassword,
|
|
4969
|
+
Grant,
|
|
3899
4970
|
MesobAuthProvider,
|
|
4971
|
+
PermissionSelector,
|
|
3900
4972
|
Permissions,
|
|
3901
4973
|
ProfileSkeleton,
|
|
3902
4974
|
ResetPasswordForm,
|
|
4975
|
+
RoleDetailLayout,
|
|
4976
|
+
RoleDetailPage,
|
|
4977
|
+
RolePermissionsPage,
|
|
3903
4978
|
Roles,
|
|
3904
4979
|
Security,
|
|
3905
4980
|
Sessions,
|
|
4981
|
+
SetPassword,
|
|
3906
4982
|
SignIn,
|
|
3907
4983
|
SignUp,
|
|
3908
4984
|
TableSkeleton,
|