@insforge/react 0.2.10 → 0.3.1
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/README.md +71 -32
- package/dist/atoms.d.mts +23 -2
- package/dist/atoms.d.ts +23 -2
- package/dist/atoms.js +138 -0
- package/dist/atoms.js.map +1 -1
- package/dist/atoms.mjs +139 -2
- package/dist/atoms.mjs.map +1 -1
- package/dist/components.d.mts +120 -3
- package/dist/components.d.ts +120 -3
- package/dist/components.js +993 -393
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +991 -395
- package/dist/components.mjs.map +1 -1
- package/dist/forms.d.mts +2 -2
- package/dist/forms.d.ts +2 -2
- package/dist/forms.js +318 -71
- package/dist/forms.js.map +1 -1
- package/dist/forms.mjs +319 -72
- package/dist/forms.mjs.map +1 -1
- package/dist/hooks.d.mts +4 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.d.mts +6 -11
- package/dist/index.d.ts +6 -11
- package/dist/index.js +986 -472
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +983 -473
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.d.mts +12 -1
- package/dist/types.d.ts +12 -1
- package/package.json +2 -2
package/dist/components.js
CHANGED
|
@@ -6,6 +6,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
8
8
|
var lucideReact = require('lucide-react');
|
|
9
|
+
var zod = require('zod');
|
|
9
10
|
|
|
10
11
|
var InsforgeContext = react.createContext(
|
|
11
12
|
void 0
|
|
@@ -685,6 +686,7 @@ function AuthVerificationCodeInput({
|
|
|
685
686
|
email,
|
|
686
687
|
onChange,
|
|
687
688
|
disabled = false,
|
|
689
|
+
onComplete,
|
|
688
690
|
appearance = {}
|
|
689
691
|
}) {
|
|
690
692
|
const inputRefs = react.useRef([]);
|
|
@@ -698,6 +700,9 @@ function AuthVerificationCodeInput({
|
|
|
698
700
|
if (digit && index < length - 1) {
|
|
699
701
|
inputRefs.current[index + 1]?.focus();
|
|
700
702
|
}
|
|
703
|
+
if (digit && index === length - 1 && updatedValue.length === length && onComplete) {
|
|
704
|
+
onComplete(updatedValue);
|
|
705
|
+
}
|
|
701
706
|
};
|
|
702
707
|
const handleKeyDown = (index, e) => {
|
|
703
708
|
if (e.key === "Backspace") {
|
|
@@ -718,6 +723,9 @@ function AuthVerificationCodeInput({
|
|
|
718
723
|
if (/^\d+$/.test(pastedData) && pastedData.length === length) {
|
|
719
724
|
onChange(pastedData);
|
|
720
725
|
inputRefs.current[length - 1]?.focus();
|
|
726
|
+
if (onComplete) {
|
|
727
|
+
onComplete(pastedData);
|
|
728
|
+
}
|
|
721
729
|
}
|
|
722
730
|
};
|
|
723
731
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
|
|
@@ -758,6 +766,125 @@ function AuthVerificationCodeInput({
|
|
|
758
766
|
)) })
|
|
759
767
|
] });
|
|
760
768
|
}
|
|
769
|
+
function AuthEmailVerificationStep({
|
|
770
|
+
email,
|
|
771
|
+
description,
|
|
772
|
+
method = "code",
|
|
773
|
+
onVerifyCode
|
|
774
|
+
}) {
|
|
775
|
+
const { baseUrl } = useInsforge();
|
|
776
|
+
const [insforge] = react.useState(() => sdk.createClient({ baseUrl }));
|
|
777
|
+
const [resendDisabled, setResendDisabled] = react.useState(true);
|
|
778
|
+
const [resendCountdown, setResendCountdown] = react.useState(60);
|
|
779
|
+
const [isSending, setIsSending] = react.useState(false);
|
|
780
|
+
const [verificationCode, setVerificationCode] = react.useState("");
|
|
781
|
+
const [isVerifying, setIsVerifying] = react.useState(false);
|
|
782
|
+
const [verificationError, setVerificationError] = react.useState("");
|
|
783
|
+
const defaultDescription = method === "code" ? "We've sent a 6-digit verification code to {email}. Please enter it below to verify your account. The code will expire in 10 minutes." : "We've sent a verification link to {email}. Please check your email and click the link to verify your account. The link will expire in 10 minutes.";
|
|
784
|
+
react.useEffect(() => {
|
|
785
|
+
const sendInitialEmail = async () => {
|
|
786
|
+
try {
|
|
787
|
+
if (method === "code") {
|
|
788
|
+
await insforge.auth.sendVerificationCode({ email });
|
|
789
|
+
} else {
|
|
790
|
+
await insforge.auth.sendVerificationLink({ email });
|
|
791
|
+
}
|
|
792
|
+
} catch {
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
void sendInitialEmail();
|
|
796
|
+
}, [email, method, insforge.auth]);
|
|
797
|
+
react.useEffect(() => {
|
|
798
|
+
if (resendCountdown > 0) {
|
|
799
|
+
const timer = setInterval(() => {
|
|
800
|
+
setResendCountdown((prev) => {
|
|
801
|
+
if (prev <= 1) {
|
|
802
|
+
setResendDisabled(false);
|
|
803
|
+
return 0;
|
|
804
|
+
}
|
|
805
|
+
return prev - 1;
|
|
806
|
+
});
|
|
807
|
+
}, 1e3);
|
|
808
|
+
return () => clearInterval(timer);
|
|
809
|
+
}
|
|
810
|
+
}, [resendCountdown]);
|
|
811
|
+
const handleResend = async () => {
|
|
812
|
+
setResendDisabled(true);
|
|
813
|
+
setResendCountdown(60);
|
|
814
|
+
setIsSending(true);
|
|
815
|
+
setVerificationError("");
|
|
816
|
+
try {
|
|
817
|
+
if (method === "code") {
|
|
818
|
+
await insforge.auth.sendVerificationCode({ email });
|
|
819
|
+
} else {
|
|
820
|
+
await insforge.auth.sendVerificationLink({ email });
|
|
821
|
+
}
|
|
822
|
+
} catch {
|
|
823
|
+
setResendDisabled(false);
|
|
824
|
+
setResendCountdown(0);
|
|
825
|
+
} finally {
|
|
826
|
+
setIsSending(false);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
const handleVerifyCode = async (code) => {
|
|
830
|
+
if (!onVerifyCode) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
setIsVerifying(true);
|
|
834
|
+
setVerificationError("");
|
|
835
|
+
try {
|
|
836
|
+
await onVerifyCode(code);
|
|
837
|
+
} catch (error) {
|
|
838
|
+
setVerificationError(
|
|
839
|
+
error instanceof Error ? error.message : "Invalid verification code. Please try again."
|
|
840
|
+
);
|
|
841
|
+
setVerificationCode("");
|
|
842
|
+
} finally {
|
|
843
|
+
setIsVerifying(false);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
const displayDescription = description || defaultDescription;
|
|
847
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6 items-stretch", children: [
|
|
848
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed", children: displayDescription.split("{email}").map((part, index, array) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
849
|
+
part,
|
|
850
|
+
index < array.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-black dark:text-white", children: email })
|
|
851
|
+
] }, index)) }),
|
|
852
|
+
verificationError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-3 py-2 pr-2 bg-red-50 border-2 border-red-600 rounded", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-6 h-6 text-red-500 shrink-0", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
|
|
854
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 flex-1", children: verificationError })
|
|
855
|
+
] }) }),
|
|
856
|
+
method === "code" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full bg-neutral-100 dark:bg-neutral-800 rounded-lg px-4 pt-4 pb-6 flex flex-col gap-4", children: [
|
|
857
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
858
|
+
AuthVerificationCodeInput,
|
|
859
|
+
{
|
|
860
|
+
value: verificationCode,
|
|
861
|
+
onChange: setVerificationCode,
|
|
862
|
+
email,
|
|
863
|
+
disabled: isVerifying,
|
|
864
|
+
onComplete: (code) => {
|
|
865
|
+
void handleVerifyCode(code);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
),
|
|
869
|
+
isVerifying && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: "Verifying..." })
|
|
870
|
+
] }),
|
|
871
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full text-sm text-center text-neutral-600 dark:text-neutral-400", children: [
|
|
872
|
+
"Didn't receive the email?",
|
|
873
|
+
" ",
|
|
874
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
875
|
+
"button",
|
|
876
|
+
{
|
|
877
|
+
onClick: () => {
|
|
878
|
+
void handleResend();
|
|
879
|
+
},
|
|
880
|
+
disabled: resendDisabled || isSending,
|
|
881
|
+
className: "text-black dark:text-white font-medium transition-colors disabled:cursor-not-allowed cursor-pointer hover:underline disabled:no-underline disabled:opacity-50",
|
|
882
|
+
children: isSending ? "Sending..." : resendDisabled ? `Retry in (${resendCountdown}s)` : "Click to resend"
|
|
883
|
+
}
|
|
884
|
+
)
|
|
885
|
+
] })
|
|
886
|
+
] });
|
|
887
|
+
}
|
|
761
888
|
function SignInForm({
|
|
762
889
|
email,
|
|
763
890
|
password,
|
|
@@ -784,7 +911,11 @@ function SignInForm({
|
|
|
784
911
|
signUpText = "Don't have an account?",
|
|
785
912
|
signUpLinkText = "Sign Up Now",
|
|
786
913
|
signUpUrl = "/sign-up",
|
|
787
|
-
dividerText = "or"
|
|
914
|
+
dividerText = "or",
|
|
915
|
+
// Email verification step props
|
|
916
|
+
showVerificationStep = false,
|
|
917
|
+
onVerifyCode,
|
|
918
|
+
verificationDescription
|
|
788
919
|
}) {
|
|
789
920
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
790
921
|
AuthContainer,
|
|
@@ -797,8 +928,8 @@ function SignInForm({
|
|
|
797
928
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
798
929
|
AuthHeader,
|
|
799
930
|
{
|
|
800
|
-
title,
|
|
801
|
-
subtitle,
|
|
931
|
+
title: showVerificationStep ? "Verify Your Email" : title,
|
|
932
|
+
subtitle: showVerificationStep ? "" : subtitle,
|
|
802
933
|
appearance: {
|
|
803
934
|
containerClassName: appearance.header?.container,
|
|
804
935
|
titleClassName: appearance.header?.title,
|
|
@@ -813,7 +944,14 @@ function SignInForm({
|
|
|
813
944
|
className: appearance.errorBanner
|
|
814
945
|
}
|
|
815
946
|
),
|
|
816
|
-
/* @__PURE__ */ jsxRuntime.
|
|
947
|
+
showVerificationStep ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
948
|
+
AuthEmailVerificationStep,
|
|
949
|
+
{
|
|
950
|
+
email,
|
|
951
|
+
description: verificationDescription,
|
|
952
|
+
onVerifyCode
|
|
953
|
+
}
|
|
954
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
817
955
|
"form",
|
|
818
956
|
{
|
|
819
957
|
onSubmit,
|
|
@@ -872,39 +1010,41 @@ function SignInForm({
|
|
|
872
1010
|
]
|
|
873
1011
|
}
|
|
874
1012
|
),
|
|
875
|
-
/* @__PURE__ */ jsxRuntime.
|
|
876
|
-
AuthLink,
|
|
877
|
-
{
|
|
878
|
-
text: signUpText,
|
|
879
|
-
linkText: signUpLinkText,
|
|
880
|
-
href: signUpUrl,
|
|
881
|
-
appearance: {
|
|
882
|
-
containerClassName: appearance.link?.container,
|
|
883
|
-
linkClassName: appearance.link?.link
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
),
|
|
887
|
-
availableProviders.length > 0 && onOAuthClick && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
888
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
889
|
-
AuthDivider,
|
|
890
|
-
{
|
|
891
|
-
text: dividerText,
|
|
892
|
-
className: appearance.divider
|
|
893
|
-
}
|
|
894
|
-
),
|
|
1013
|
+
!showVerificationStep && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
895
1014
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
896
|
-
|
|
1015
|
+
AuthLink,
|
|
897
1016
|
{
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
loading: oauthLoading,
|
|
1017
|
+
text: signUpText,
|
|
1018
|
+
linkText: signUpLinkText,
|
|
1019
|
+
href: signUpUrl,
|
|
902
1020
|
appearance: {
|
|
903
|
-
containerClassName: appearance.
|
|
904
|
-
|
|
1021
|
+
containerClassName: appearance.link?.container,
|
|
1022
|
+
linkClassName: appearance.link?.link
|
|
905
1023
|
}
|
|
906
1024
|
}
|
|
907
|
-
)
|
|
1025
|
+
),
|
|
1026
|
+
availableProviders.length > 0 && onOAuthClick && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1027
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
|
+
AuthDivider,
|
|
1029
|
+
{
|
|
1030
|
+
text: dividerText,
|
|
1031
|
+
className: appearance.divider
|
|
1032
|
+
}
|
|
1033
|
+
),
|
|
1034
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1035
|
+
AuthOAuthProviders,
|
|
1036
|
+
{
|
|
1037
|
+
providers: availableProviders,
|
|
1038
|
+
onClick: onOAuthClick,
|
|
1039
|
+
disabled: loading || oauthLoading !== null,
|
|
1040
|
+
loading: oauthLoading,
|
|
1041
|
+
appearance: {
|
|
1042
|
+
containerClassName: appearance.oauth?.container,
|
|
1043
|
+
buttonClassName: appearance.oauth?.button
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
)
|
|
1047
|
+
] })
|
|
908
1048
|
] })
|
|
909
1049
|
]
|
|
910
1050
|
}
|
|
@@ -922,6 +1062,7 @@ function SignIn({
|
|
|
922
1062
|
const [password, setPassword] = react.useState("");
|
|
923
1063
|
const [error, setError] = react.useState("");
|
|
924
1064
|
const [loading, setLoading] = react.useState(false);
|
|
1065
|
+
const [step, setStep] = react.useState("form");
|
|
925
1066
|
const [oauthLoading, setOauthLoading] = react.useState(
|
|
926
1067
|
null
|
|
927
1068
|
);
|
|
@@ -933,6 +1074,11 @@ function SignIn({
|
|
|
933
1074
|
try {
|
|
934
1075
|
const result = await signIn(email, password);
|
|
935
1076
|
if ("error" in result) {
|
|
1077
|
+
if (result.statusCode === 403) {
|
|
1078
|
+
setStep("awaiting-verification");
|
|
1079
|
+
setLoading(false);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
936
1082
|
throw new Error(result.error);
|
|
937
1083
|
}
|
|
938
1084
|
const { user, accessToken } = result;
|
|
@@ -947,6 +1093,21 @@ function SignIn({
|
|
|
947
1093
|
setLoading(false);
|
|
948
1094
|
}
|
|
949
1095
|
}
|
|
1096
|
+
async function handleVerifyCode(code) {
|
|
1097
|
+
try {
|
|
1098
|
+
const result = await insforge.auth.verifyEmail({ email, otp: code });
|
|
1099
|
+
if (result.error) {
|
|
1100
|
+
throw new Error(result.error.message || "Verification failed");
|
|
1101
|
+
}
|
|
1102
|
+
if (result.data?.accessToken) {
|
|
1103
|
+
if (onSuccess && result.data.user) {
|
|
1104
|
+
onSuccess(result.data.user, result.data.accessToken);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
} catch (err) {
|
|
1108
|
+
throw new Error(err.message || "Invalid verification code");
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
950
1111
|
async function handleOAuth(provider) {
|
|
951
1112
|
try {
|
|
952
1113
|
setOauthLoading(provider);
|
|
@@ -979,6 +1140,8 @@ function SignIn({
|
|
|
979
1140
|
availableProviders: emailConfig?.oAuthProviders || [],
|
|
980
1141
|
onOAuthClick: handleOAuth,
|
|
981
1142
|
emailAuthConfig: emailConfig,
|
|
1143
|
+
showVerificationStep: step === "awaiting-verification",
|
|
1144
|
+
onVerifyCode: handleVerifyCode,
|
|
982
1145
|
...uiProps
|
|
983
1146
|
}
|
|
984
1147
|
);
|
|
@@ -1007,7 +1170,11 @@ function SignUpForm({
|
|
|
1007
1170
|
signInText = "Already have an account?",
|
|
1008
1171
|
signInLinkText = "Login Now",
|
|
1009
1172
|
signInUrl = "/sign-in",
|
|
1010
|
-
dividerText = "or"
|
|
1173
|
+
dividerText = "or",
|
|
1174
|
+
// Email verification step props
|
|
1175
|
+
showVerificationStep = false,
|
|
1176
|
+
onVerifyCode,
|
|
1177
|
+
verificationDescription
|
|
1011
1178
|
}) {
|
|
1012
1179
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1013
1180
|
AuthContainer,
|
|
@@ -1020,8 +1187,8 @@ function SignUpForm({
|
|
|
1020
1187
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1021
1188
|
AuthHeader,
|
|
1022
1189
|
{
|
|
1023
|
-
title,
|
|
1024
|
-
subtitle,
|
|
1190
|
+
title: showVerificationStep ? "Verify Your Email" : title,
|
|
1191
|
+
subtitle: showVerificationStep ? "" : subtitle,
|
|
1025
1192
|
appearance: {
|
|
1026
1193
|
containerClassName: appearance.header?.container,
|
|
1027
1194
|
titleClassName: appearance.header?.title,
|
|
@@ -1036,7 +1203,14 @@ function SignUpForm({
|
|
|
1036
1203
|
className: appearance.errorBanner
|
|
1037
1204
|
}
|
|
1038
1205
|
),
|
|
1039
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1206
|
+
showVerificationStep ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1207
|
+
AuthEmailVerificationStep,
|
|
1208
|
+
{
|
|
1209
|
+
email,
|
|
1210
|
+
description: verificationDescription,
|
|
1211
|
+
onVerifyCode
|
|
1212
|
+
}
|
|
1213
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1040
1214
|
"form",
|
|
1041
1215
|
{
|
|
1042
1216
|
onSubmit,
|
|
@@ -1093,44 +1267,74 @@ function SignUpForm({
|
|
|
1093
1267
|
]
|
|
1094
1268
|
}
|
|
1095
1269
|
),
|
|
1096
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1097
|
-
AuthLink,
|
|
1098
|
-
{
|
|
1099
|
-
text: signInText,
|
|
1100
|
-
linkText: signInLinkText,
|
|
1101
|
-
href: signInUrl,
|
|
1102
|
-
appearance: {
|
|
1103
|
-
containerClassName: appearance.link?.container,
|
|
1104
|
-
linkClassName: appearance.link?.link
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
),
|
|
1108
|
-
availableProviders.length > 0 && onOAuthClick && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1109
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1110
|
-
AuthDivider,
|
|
1111
|
-
{
|
|
1112
|
-
text: dividerText,
|
|
1113
|
-
className: appearance.divider
|
|
1114
|
-
}
|
|
1115
|
-
),
|
|
1270
|
+
!showVerificationStep && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1116
1271
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1117
|
-
|
|
1272
|
+
AuthLink,
|
|
1118
1273
|
{
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
loading: oauthLoading,
|
|
1274
|
+
text: signInText,
|
|
1275
|
+
linkText: signInLinkText,
|
|
1276
|
+
href: signInUrl,
|
|
1123
1277
|
appearance: {
|
|
1124
|
-
containerClassName: appearance.
|
|
1125
|
-
|
|
1278
|
+
containerClassName: appearance.link?.container,
|
|
1279
|
+
linkClassName: appearance.link?.link
|
|
1126
1280
|
}
|
|
1127
1281
|
}
|
|
1128
|
-
)
|
|
1282
|
+
),
|
|
1283
|
+
availableProviders.length > 0 && onOAuthClick && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1284
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1285
|
+
AuthDivider,
|
|
1286
|
+
{
|
|
1287
|
+
text: dividerText,
|
|
1288
|
+
className: appearance.divider
|
|
1289
|
+
}
|
|
1290
|
+
),
|
|
1291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1292
|
+
AuthOAuthProviders,
|
|
1293
|
+
{
|
|
1294
|
+
providers: availableProviders,
|
|
1295
|
+
onClick: onOAuthClick,
|
|
1296
|
+
disabled: loading || oauthLoading !== null,
|
|
1297
|
+
loading: oauthLoading,
|
|
1298
|
+
appearance: {
|
|
1299
|
+
containerClassName: appearance.oauth?.container,
|
|
1300
|
+
buttonClassName: appearance.oauth?.button
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
)
|
|
1304
|
+
] })
|
|
1129
1305
|
] })
|
|
1130
1306
|
]
|
|
1131
1307
|
}
|
|
1132
1308
|
);
|
|
1133
1309
|
}
|
|
1310
|
+
var emailSchema = zod.z.string().min(1, "Email is required").email("Invalid email address");
|
|
1311
|
+
function createPasswordSchema(options) {
|
|
1312
|
+
const {
|
|
1313
|
+
minLength = 6,
|
|
1314
|
+
requireUppercase = false,
|
|
1315
|
+
requireLowercase = false,
|
|
1316
|
+
requireNumber = false,
|
|
1317
|
+
requireSpecialChar = false
|
|
1318
|
+
} = options || {};
|
|
1319
|
+
let schema = zod.z.string().min(minLength, `Password must be at least ${minLength} characters`);
|
|
1320
|
+
if (requireUppercase) {
|
|
1321
|
+
schema = schema.regex(/[A-Z]/, "Password must contain at least one uppercase letter");
|
|
1322
|
+
}
|
|
1323
|
+
if (requireLowercase) {
|
|
1324
|
+
schema = schema.regex(/[a-z]/, "Password must contain at least one lowercase letter");
|
|
1325
|
+
}
|
|
1326
|
+
if (requireNumber) {
|
|
1327
|
+
schema = schema.regex(/\d/, "Password must contain at least one number");
|
|
1328
|
+
}
|
|
1329
|
+
if (requireSpecialChar) {
|
|
1330
|
+
schema = schema.regex(
|
|
1331
|
+
/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/,
|
|
1332
|
+
"Password must contain at least one special character"
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
return schema;
|
|
1336
|
+
}
|
|
1337
|
+
createPasswordSchema();
|
|
1134
1338
|
function SignUp({
|
|
1135
1339
|
afterSignUpUrl,
|
|
1136
1340
|
onSuccess,
|
|
@@ -1143,6 +1347,7 @@ function SignUp({
|
|
|
1143
1347
|
const [password, setPassword] = react.useState("");
|
|
1144
1348
|
const [error, setError] = react.useState("");
|
|
1145
1349
|
const [loading, setLoading] = react.useState(false);
|
|
1350
|
+
const [step, setStep] = react.useState("form");
|
|
1146
1351
|
const [oauthLoading, setOauthLoading] = react.useState(
|
|
1147
1352
|
null
|
|
1148
1353
|
);
|
|
@@ -1151,19 +1356,46 @@ function SignUp({
|
|
|
1151
1356
|
e.preventDefault();
|
|
1152
1357
|
setLoading(true);
|
|
1153
1358
|
setError("");
|
|
1154
|
-
if (
|
|
1155
|
-
setError("
|
|
1359
|
+
if (!emailConfig) {
|
|
1360
|
+
setError("Configuration not loaded. Please refresh the page.");
|
|
1361
|
+
setLoading(false);
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const emailValidation = emailSchema.safeParse(email);
|
|
1365
|
+
if (!emailValidation.success) {
|
|
1366
|
+
const firstError = emailValidation.error.issues[0];
|
|
1367
|
+
setError(firstError.message);
|
|
1368
|
+
setLoading(false);
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
const passwordZodSchema = createPasswordSchema({
|
|
1372
|
+
minLength: emailConfig.passwordMinLength,
|
|
1373
|
+
requireUppercase: emailConfig.requireUppercase,
|
|
1374
|
+
requireLowercase: emailConfig.requireLowercase,
|
|
1375
|
+
requireNumber: emailConfig.requireNumber,
|
|
1376
|
+
requireSpecialChar: emailConfig.requireSpecialChar
|
|
1377
|
+
});
|
|
1378
|
+
const passwordValidation = passwordZodSchema.safeParse(password);
|
|
1379
|
+
if (!passwordValidation.success) {
|
|
1380
|
+
const firstError = passwordValidation.error.issues[0];
|
|
1381
|
+
setError(firstError.message);
|
|
1156
1382
|
setLoading(false);
|
|
1157
1383
|
return;
|
|
1158
1384
|
}
|
|
1159
1385
|
try {
|
|
1160
|
-
const result = await signUp(
|
|
1386
|
+
const result = await signUp(emailValidation.data, password);
|
|
1161
1387
|
if ("error" in result) {
|
|
1162
1388
|
throw new Error(result.error);
|
|
1163
1389
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1390
|
+
if (result.requiresEmailVerification && !result.accessToken) {
|
|
1391
|
+
setStep("awaiting-verification");
|
|
1392
|
+
setLoading(false);
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
if (result.accessToken && result.user) {
|
|
1396
|
+
if (onSuccess) {
|
|
1397
|
+
onSuccess(result.user, result.accessToken);
|
|
1398
|
+
}
|
|
1167
1399
|
}
|
|
1168
1400
|
} catch (err) {
|
|
1169
1401
|
const errorMessage = err.message || "Sign up failed";
|
|
@@ -1173,6 +1405,21 @@ function SignUp({
|
|
|
1173
1405
|
setLoading(false);
|
|
1174
1406
|
}
|
|
1175
1407
|
}
|
|
1408
|
+
async function handleVerifyCode(code) {
|
|
1409
|
+
try {
|
|
1410
|
+
const result = await insforge.auth.verifyEmail({ email, otp: code });
|
|
1411
|
+
if (result.error) {
|
|
1412
|
+
throw new Error(result.error.message || "Verification failed");
|
|
1413
|
+
}
|
|
1414
|
+
if (result.data?.accessToken) {
|
|
1415
|
+
if (onSuccess && result.data.user) {
|
|
1416
|
+
onSuccess(result.data.user, result.data.accessToken);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
} catch (err) {
|
|
1420
|
+
throw new Error(err.message || "Invalid verification code");
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1176
1423
|
async function handleOAuth(provider) {
|
|
1177
1424
|
try {
|
|
1178
1425
|
setOauthLoading(provider);
|
|
@@ -1205,81 +1452,691 @@ function SignUp({
|
|
|
1205
1452
|
availableProviders: emailConfig?.oAuthProviders || [],
|
|
1206
1453
|
onOAuthClick: handleOAuth,
|
|
1207
1454
|
emailAuthConfig: emailConfig,
|
|
1455
|
+
showVerificationStep: step === "awaiting-verification",
|
|
1456
|
+
onVerifyCode: handleVerifyCode,
|
|
1208
1457
|
...uiProps
|
|
1209
1458
|
}
|
|
1210
1459
|
);
|
|
1211
1460
|
}
|
|
1212
|
-
function
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1461
|
+
function ForgotPasswordForm({
|
|
1462
|
+
email,
|
|
1463
|
+
onEmailChange,
|
|
1464
|
+
onSubmit,
|
|
1465
|
+
error,
|
|
1466
|
+
loading = false,
|
|
1467
|
+
success = false,
|
|
1468
|
+
appearance = {},
|
|
1469
|
+
title = "Forgot Password?",
|
|
1470
|
+
subtitle = "Enter your email address and we'll send you a code to reset your password.",
|
|
1471
|
+
emailLabel = "Email",
|
|
1472
|
+
emailPlaceholder = "example@email.com",
|
|
1473
|
+
submitButtonText = "Send Reset Code",
|
|
1474
|
+
loadingButtonText = "Sending...",
|
|
1475
|
+
backToSignInText = "Remember your password?",
|
|
1476
|
+
backToSignInUrl = "/sign-in",
|
|
1477
|
+
successTitle = "Check Your Email",
|
|
1478
|
+
successMessage
|
|
1216
1479
|
}) {
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
})
|
|
1231
|
-
if (!response.ok) {
|
|
1232
|
-
setImageError(true);
|
|
1233
|
-
}
|
|
1234
|
-
} catch (error) {
|
|
1235
|
-
setImageError(true);
|
|
1236
|
-
}
|
|
1237
|
-
};
|
|
1238
|
-
checkImageUrl();
|
|
1239
|
-
}, [user?.avatarUrl]);
|
|
1240
|
-
react.useEffect(() => {
|
|
1241
|
-
function handleClickOutside(event) {
|
|
1242
|
-
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
1243
|
-
setIsOpen(false);
|
|
1480
|
+
if (success) {
|
|
1481
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1482
|
+
AuthContainer,
|
|
1483
|
+
{
|
|
1484
|
+
appearance: {
|
|
1485
|
+
containerClassName: appearance.container,
|
|
1486
|
+
cardClassName: appearance.card
|
|
1487
|
+
},
|
|
1488
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-8 h-8 text-green-600 dark:text-green-400", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7" }) }) }),
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
1491
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: successMessage || `We've sent a password reset link to ${email}. Please check your email and follow the instructions.` }),
|
|
1492
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: backToSignInUrl, className: "mt-4 text-black dark:text-white font-medium", children: "Back to Sign In" })
|
|
1493
|
+
] })
|
|
1244
1494
|
}
|
|
1245
|
-
|
|
1246
|
-
if (isOpen) {
|
|
1247
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1248
|
-
}
|
|
1249
|
-
return () => {
|
|
1250
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
1251
|
-
};
|
|
1252
|
-
}, [isOpen]);
|
|
1253
|
-
async function handleSignOut() {
|
|
1254
|
-
await signOut();
|
|
1255
|
-
setIsOpen(false);
|
|
1256
|
-
window.location.href = afterSignOutUrl;
|
|
1495
|
+
);
|
|
1257
1496
|
}
|
|
1258
|
-
if (!user) return null;
|
|
1259
|
-
const initials = user.name ? user.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
|
|
1260
1497
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1261
|
-
|
|
1498
|
+
AuthContainer,
|
|
1262
1499
|
{
|
|
1263
|
-
|
|
1264
|
-
|
|
1500
|
+
appearance: {
|
|
1501
|
+
containerClassName: appearance.container,
|
|
1502
|
+
cardClassName: appearance.card
|
|
1503
|
+
},
|
|
1265
1504
|
children: [
|
|
1505
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1506
|
+
AuthHeader,
|
|
1507
|
+
{
|
|
1508
|
+
title,
|
|
1509
|
+
subtitle,
|
|
1510
|
+
appearance: {
|
|
1511
|
+
containerClassName: appearance.header?.container,
|
|
1512
|
+
titleClassName: appearance.header?.title,
|
|
1513
|
+
subtitleClassName: appearance.header?.subtitle
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
),
|
|
1517
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1518
|
+
AuthErrorBanner,
|
|
1519
|
+
{
|
|
1520
|
+
error: error || "",
|
|
1521
|
+
className: appearance.errorBanner
|
|
1522
|
+
}
|
|
1523
|
+
),
|
|
1266
1524
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1267
|
-
"
|
|
1525
|
+
"form",
|
|
1268
1526
|
{
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
"hover:bg-black/5",
|
|
1273
|
-
mode === "detailed" && "rounded-lg p-2",
|
|
1274
|
-
appearance.buttonClassName
|
|
1275
|
-
),
|
|
1276
|
-
onClick: () => setIsOpen(!isOpen),
|
|
1277
|
-
"aria-expanded": isOpen,
|
|
1278
|
-
"aria-haspopup": "true",
|
|
1527
|
+
onSubmit,
|
|
1528
|
+
noValidate: true,
|
|
1529
|
+
className: appearance.form?.container || "flex flex-col items-stretch justify-center gap-6",
|
|
1279
1530
|
children: [
|
|
1280
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1281
|
-
|
|
1282
|
-
{
|
|
1531
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1532
|
+
AuthFormField,
|
|
1533
|
+
{
|
|
1534
|
+
id: "email",
|
|
1535
|
+
type: "email",
|
|
1536
|
+
label: emailLabel,
|
|
1537
|
+
placeholder: emailPlaceholder,
|
|
1538
|
+
value: email,
|
|
1539
|
+
onChange: (e) => onEmailChange(e.target.value),
|
|
1540
|
+
required: true,
|
|
1541
|
+
autoComplete: "email",
|
|
1542
|
+
appearance: {
|
|
1543
|
+
containerClassName: appearance.form?.emailField?.container,
|
|
1544
|
+
labelClassName: appearance.form?.emailField?.label,
|
|
1545
|
+
inputClassName: appearance.form?.emailField?.input
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
),
|
|
1549
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1550
|
+
AuthSubmitButton,
|
|
1551
|
+
{
|
|
1552
|
+
isLoading: loading,
|
|
1553
|
+
disabled: loading,
|
|
1554
|
+
className: appearance.button,
|
|
1555
|
+
children: loading ? loadingButtonText : submitButtonText
|
|
1556
|
+
}
|
|
1557
|
+
)
|
|
1558
|
+
]
|
|
1559
|
+
}
|
|
1560
|
+
),
|
|
1561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1562
|
+
AuthLink,
|
|
1563
|
+
{
|
|
1564
|
+
text: backToSignInText,
|
|
1565
|
+
linkText: "Back to Sign In",
|
|
1566
|
+
href: backToSignInUrl,
|
|
1567
|
+
appearance: {
|
|
1568
|
+
containerClassName: appearance.link?.container,
|
|
1569
|
+
linkClassName: appearance.link?.link
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
)
|
|
1573
|
+
]
|
|
1574
|
+
}
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
function ResetPasswordForm({
|
|
1578
|
+
newPassword,
|
|
1579
|
+
confirmPassword,
|
|
1580
|
+
onNewPasswordChange,
|
|
1581
|
+
onConfirmPasswordChange,
|
|
1582
|
+
onSubmit,
|
|
1583
|
+
error,
|
|
1584
|
+
loading = false,
|
|
1585
|
+
emailAuthConfig,
|
|
1586
|
+
appearance = {},
|
|
1587
|
+
title = "Reset Password",
|
|
1588
|
+
subtitle = "Enter your new password below.",
|
|
1589
|
+
newPasswordLabel = "New Password",
|
|
1590
|
+
newPasswordPlaceholder = "\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1591
|
+
confirmPasswordLabel = "Confirm Password",
|
|
1592
|
+
confirmPasswordPlaceholder = "\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1593
|
+
submitButtonText = "Reset Password",
|
|
1594
|
+
loadingButtonText = "Resetting...",
|
|
1595
|
+
backToSignInText = "",
|
|
1596
|
+
backToSignInUrl = "/sign-in"
|
|
1597
|
+
}) {
|
|
1598
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1599
|
+
AuthContainer,
|
|
1600
|
+
{
|
|
1601
|
+
appearance: {
|
|
1602
|
+
containerClassName: appearance.container,
|
|
1603
|
+
cardClassName: appearance.card
|
|
1604
|
+
},
|
|
1605
|
+
children: [
|
|
1606
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1607
|
+
AuthHeader,
|
|
1608
|
+
{
|
|
1609
|
+
title,
|
|
1610
|
+
subtitle,
|
|
1611
|
+
appearance: {
|
|
1612
|
+
containerClassName: appearance.header?.container,
|
|
1613
|
+
titleClassName: appearance.header?.title,
|
|
1614
|
+
subtitleClassName: appearance.header?.subtitle
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
),
|
|
1618
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1619
|
+
AuthErrorBanner,
|
|
1620
|
+
{
|
|
1621
|
+
error: error || "",
|
|
1622
|
+
className: appearance.errorBanner
|
|
1623
|
+
}
|
|
1624
|
+
),
|
|
1625
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1626
|
+
"form",
|
|
1627
|
+
{
|
|
1628
|
+
onSubmit,
|
|
1629
|
+
noValidate: true,
|
|
1630
|
+
className: appearance.form?.container || "flex flex-col items-stretch justify-center gap-6",
|
|
1631
|
+
children: [
|
|
1632
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1633
|
+
AuthPasswordField,
|
|
1634
|
+
{
|
|
1635
|
+
id: "newPassword",
|
|
1636
|
+
label: newPasswordLabel,
|
|
1637
|
+
placeholder: newPasswordPlaceholder,
|
|
1638
|
+
value: newPassword,
|
|
1639
|
+
onChange: (e) => onNewPasswordChange(e.target.value),
|
|
1640
|
+
required: true,
|
|
1641
|
+
autoComplete: "new-password",
|
|
1642
|
+
showStrengthIndicator: true,
|
|
1643
|
+
emailAuthConfig,
|
|
1644
|
+
appearance: {
|
|
1645
|
+
containerClassName: appearance.form?.newPasswordField?.container,
|
|
1646
|
+
labelClassName: appearance.form?.newPasswordField?.label,
|
|
1647
|
+
inputClassName: appearance.form?.newPasswordField?.input
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
),
|
|
1651
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1652
|
+
AuthPasswordField,
|
|
1653
|
+
{
|
|
1654
|
+
id: "confirmPassword",
|
|
1655
|
+
label: confirmPasswordLabel,
|
|
1656
|
+
placeholder: confirmPasswordPlaceholder,
|
|
1657
|
+
value: confirmPassword,
|
|
1658
|
+
onChange: (e) => onConfirmPasswordChange(e.target.value),
|
|
1659
|
+
required: true,
|
|
1660
|
+
autoComplete: "new-password",
|
|
1661
|
+
emailAuthConfig,
|
|
1662
|
+
appearance: {
|
|
1663
|
+
containerClassName: appearance.form?.confirmPasswordField?.container,
|
|
1664
|
+
labelClassName: appearance.form?.confirmPasswordField?.label,
|
|
1665
|
+
inputClassName: appearance.form?.confirmPasswordField?.input
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
),
|
|
1669
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1670
|
+
AuthSubmitButton,
|
|
1671
|
+
{
|
|
1672
|
+
isLoading: loading,
|
|
1673
|
+
disabled: loading,
|
|
1674
|
+
className: appearance.button,
|
|
1675
|
+
children: loading ? loadingButtonText : submitButtonText
|
|
1676
|
+
}
|
|
1677
|
+
)
|
|
1678
|
+
]
|
|
1679
|
+
}
|
|
1680
|
+
),
|
|
1681
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1682
|
+
AuthLink,
|
|
1683
|
+
{
|
|
1684
|
+
text: backToSignInText,
|
|
1685
|
+
linkText: "Back to Sign In",
|
|
1686
|
+
href: backToSignInUrl,
|
|
1687
|
+
appearance: {
|
|
1688
|
+
containerClassName: appearance.link?.container,
|
|
1689
|
+
linkClassName: appearance.link?.link
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
)
|
|
1693
|
+
]
|
|
1694
|
+
}
|
|
1695
|
+
);
|
|
1696
|
+
}
|
|
1697
|
+
function ResetPassword({
|
|
1698
|
+
token,
|
|
1699
|
+
backToSignInUrl = "/sign-in",
|
|
1700
|
+
onSuccess,
|
|
1701
|
+
onError,
|
|
1702
|
+
...uiProps
|
|
1703
|
+
}) {
|
|
1704
|
+
const { resetPassword } = useInsforge();
|
|
1705
|
+
const { emailConfig } = usePublicAuthConfig();
|
|
1706
|
+
const [newPassword, setNewPassword] = react.useState("");
|
|
1707
|
+
const [confirmPassword, setConfirmPassword] = react.useState("");
|
|
1708
|
+
const [error, setError] = react.useState("");
|
|
1709
|
+
const [loading, setLoading] = react.useState(false);
|
|
1710
|
+
async function handleSubmit(e) {
|
|
1711
|
+
e.preventDefault();
|
|
1712
|
+
setLoading(true);
|
|
1713
|
+
setError("");
|
|
1714
|
+
if (!emailConfig) {
|
|
1715
|
+
setError("Configuration not loaded. Please refresh the page.");
|
|
1716
|
+
setLoading(false);
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
if (newPassword !== confirmPassword) {
|
|
1720
|
+
setError("Passwords do not match");
|
|
1721
|
+
setLoading(false);
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
if (!token) {
|
|
1725
|
+
setError("Reset token is missing");
|
|
1726
|
+
setLoading(false);
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
const passwordZodSchema = createPasswordSchema({
|
|
1730
|
+
minLength: emailConfig.passwordMinLength,
|
|
1731
|
+
requireUppercase: emailConfig.requireUppercase,
|
|
1732
|
+
requireLowercase: emailConfig.requireLowercase,
|
|
1733
|
+
requireNumber: emailConfig.requireNumber,
|
|
1734
|
+
requireSpecialChar: emailConfig.requireSpecialChar
|
|
1735
|
+
});
|
|
1736
|
+
const passwordValidation = passwordZodSchema.safeParse(newPassword);
|
|
1737
|
+
if (!passwordValidation.success) {
|
|
1738
|
+
const firstError = passwordValidation.error.issues[0];
|
|
1739
|
+
setError(firstError.message);
|
|
1740
|
+
setLoading(false);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
try {
|
|
1744
|
+
const result = await resetPassword(token, newPassword);
|
|
1745
|
+
if (result?.message) {
|
|
1746
|
+
if (onSuccess) {
|
|
1747
|
+
onSuccess(result.redirectTo);
|
|
1748
|
+
}
|
|
1749
|
+
} else {
|
|
1750
|
+
const errorMessage = "Failed to reset password";
|
|
1751
|
+
setError(errorMessage);
|
|
1752
|
+
if (onError) {
|
|
1753
|
+
onError(new Error(errorMessage));
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
} catch (err) {
|
|
1757
|
+
const errorMessage = err.message || "Failed to reset password";
|
|
1758
|
+
setError(errorMessage);
|
|
1759
|
+
if (onError) {
|
|
1760
|
+
onError(new Error(errorMessage));
|
|
1761
|
+
}
|
|
1762
|
+
} finally {
|
|
1763
|
+
setLoading(false);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
if (!emailConfig) {
|
|
1767
|
+
return null;
|
|
1768
|
+
}
|
|
1769
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1770
|
+
ResetPasswordForm,
|
|
1771
|
+
{
|
|
1772
|
+
newPassword,
|
|
1773
|
+
confirmPassword,
|
|
1774
|
+
onNewPasswordChange: setNewPassword,
|
|
1775
|
+
onConfirmPasswordChange: setConfirmPassword,
|
|
1776
|
+
onSubmit: handleSubmit,
|
|
1777
|
+
error,
|
|
1778
|
+
loading,
|
|
1779
|
+
emailAuthConfig: emailConfig,
|
|
1780
|
+
backToSignInUrl,
|
|
1781
|
+
...uiProps
|
|
1782
|
+
}
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
function ForgotPassword({
|
|
1786
|
+
backToSignInUrl = "/sign-in",
|
|
1787
|
+
onSuccess,
|
|
1788
|
+
onError,
|
|
1789
|
+
...uiProps
|
|
1790
|
+
}) {
|
|
1791
|
+
const { sendPasswordResetCode, baseUrl } = useInsforge();
|
|
1792
|
+
const { emailConfig } = usePublicAuthConfig();
|
|
1793
|
+
const [insforge] = react.useState(() => sdk.createClient({ baseUrl }));
|
|
1794
|
+
const [step, setStep] = react.useState("email");
|
|
1795
|
+
const [email, setEmail] = react.useState("");
|
|
1796
|
+
const [verificationCode, setVerificationCode] = react.useState("");
|
|
1797
|
+
const [resetToken, setResetToken] = react.useState("");
|
|
1798
|
+
const [error, setError] = react.useState("");
|
|
1799
|
+
const [loading, setLoading] = react.useState(false);
|
|
1800
|
+
const [success, setSuccess] = react.useState(false);
|
|
1801
|
+
const [resendDisabled, setResendDisabled] = react.useState(true);
|
|
1802
|
+
const [resendCountdown, setResendCountdown] = react.useState(60);
|
|
1803
|
+
const [isSendingCode, setIsSendingCode] = react.useState(false);
|
|
1804
|
+
const [isVerifyingCode, setIsVerifyingCode] = react.useState(false);
|
|
1805
|
+
react.useEffect(() => {
|
|
1806
|
+
if (resendCountdown > 0 && step === "code") {
|
|
1807
|
+
const timer = setInterval(() => {
|
|
1808
|
+
setResendCountdown((prev) => {
|
|
1809
|
+
if (prev <= 1) {
|
|
1810
|
+
setResendDisabled(false);
|
|
1811
|
+
return 0;
|
|
1812
|
+
}
|
|
1813
|
+
return prev - 1;
|
|
1814
|
+
});
|
|
1815
|
+
}, 1e3);
|
|
1816
|
+
return () => clearInterval(timer);
|
|
1817
|
+
}
|
|
1818
|
+
}, [resendCountdown, step]);
|
|
1819
|
+
async function handleEmailSubmit(e) {
|
|
1820
|
+
e.preventDefault();
|
|
1821
|
+
setLoading(true);
|
|
1822
|
+
setError("");
|
|
1823
|
+
const emailValidation = emailSchema.safeParse(email);
|
|
1824
|
+
if (!emailValidation.success) {
|
|
1825
|
+
const firstError = emailValidation.error.issues[0];
|
|
1826
|
+
setError(firstError.message);
|
|
1827
|
+
setLoading(false);
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
try {
|
|
1831
|
+
const result = await sendPasswordResetCode(emailValidation.data);
|
|
1832
|
+
if (result?.success) {
|
|
1833
|
+
if (emailConfig?.resetPasswordMethod === "link") {
|
|
1834
|
+
setSuccess(true);
|
|
1835
|
+
if (onSuccess) {
|
|
1836
|
+
onSuccess();
|
|
1837
|
+
}
|
|
1838
|
+
} else {
|
|
1839
|
+
setStep("code");
|
|
1840
|
+
setResendDisabled(true);
|
|
1841
|
+
setResendCountdown(60);
|
|
1842
|
+
}
|
|
1843
|
+
} else {
|
|
1844
|
+
const errorMessage = result?.message || "Failed to send reset code";
|
|
1845
|
+
setError(errorMessage);
|
|
1846
|
+
if (onError) {
|
|
1847
|
+
onError(new Error(errorMessage));
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
} catch (err) {
|
|
1851
|
+
const errorMessage = err.message || "Failed to send reset code";
|
|
1852
|
+
setError(errorMessage);
|
|
1853
|
+
if (onError) {
|
|
1854
|
+
onError(new Error(errorMessage));
|
|
1855
|
+
}
|
|
1856
|
+
} finally {
|
|
1857
|
+
setLoading(false);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
async function handleVerifyCode(code) {
|
|
1861
|
+
setIsVerifyingCode(true);
|
|
1862
|
+
setError("");
|
|
1863
|
+
setVerificationCode(code);
|
|
1864
|
+
try {
|
|
1865
|
+
const result = await insforge.auth.verifyResetPasswordCode({ email, code });
|
|
1866
|
+
if (result.error) {
|
|
1867
|
+
throw new Error(result.error.message || "Failed to verify code");
|
|
1868
|
+
}
|
|
1869
|
+
if (result.data) {
|
|
1870
|
+
setResetToken(result.data.resetToken);
|
|
1871
|
+
setStep("password");
|
|
1872
|
+
}
|
|
1873
|
+
} catch (err) {
|
|
1874
|
+
setError(err.message || "Invalid verification code");
|
|
1875
|
+
setVerificationCode("");
|
|
1876
|
+
} finally {
|
|
1877
|
+
setIsVerifyingCode(false);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const handleResendCode = react.useCallback(async () => {
|
|
1881
|
+
setResendDisabled(true);
|
|
1882
|
+
setResendCountdown(60);
|
|
1883
|
+
setIsSendingCode(true);
|
|
1884
|
+
setError("");
|
|
1885
|
+
try {
|
|
1886
|
+
await sendPasswordResetCode(email);
|
|
1887
|
+
} catch (err) {
|
|
1888
|
+
setError(err.message || "Failed to resend code");
|
|
1889
|
+
setResendDisabled(false);
|
|
1890
|
+
setResendCountdown(0);
|
|
1891
|
+
} finally {
|
|
1892
|
+
setIsSendingCode(false);
|
|
1893
|
+
}
|
|
1894
|
+
}, [email, sendPasswordResetCode]);
|
|
1895
|
+
function handlePasswordResetSuccess() {
|
|
1896
|
+
if (onSuccess) {
|
|
1897
|
+
onSuccess();
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
if (!emailConfig) {
|
|
1901
|
+
return null;
|
|
1902
|
+
}
|
|
1903
|
+
if (step === "email") {
|
|
1904
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1905
|
+
ForgotPasswordForm,
|
|
1906
|
+
{
|
|
1907
|
+
email,
|
|
1908
|
+
onEmailChange: setEmail,
|
|
1909
|
+
onSubmit: handleEmailSubmit,
|
|
1910
|
+
error,
|
|
1911
|
+
loading,
|
|
1912
|
+
success,
|
|
1913
|
+
backToSignInUrl,
|
|
1914
|
+
...uiProps
|
|
1915
|
+
}
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
if (step === "code") {
|
|
1919
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1920
|
+
AuthContainer,
|
|
1921
|
+
{
|
|
1922
|
+
appearance: {
|
|
1923
|
+
containerClassName: uiProps.appearance?.container,
|
|
1924
|
+
cardClassName: uiProps.appearance?.card
|
|
1925
|
+
},
|
|
1926
|
+
children: [
|
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1928
|
+
AuthHeader,
|
|
1929
|
+
{
|
|
1930
|
+
title: "Enter Reset Code",
|
|
1931
|
+
subtitle: `We've sent a 6-digit verification code to ${email}. Please enter it below to reset your password. The code will expire in 10 minutes.`,
|
|
1932
|
+
appearance: {
|
|
1933
|
+
containerClassName: uiProps.appearance?.header?.container,
|
|
1934
|
+
titleClassName: uiProps.appearance?.header?.title,
|
|
1935
|
+
subtitleClassName: uiProps.appearance?.header?.subtitle
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
),
|
|
1939
|
+
/* @__PURE__ */ jsxRuntime.jsx(AuthErrorBanner, { error, className: uiProps.appearance?.errorBanner }),
|
|
1940
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col gap-6 items-center", children: [
|
|
1941
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-neutral-100 dark:bg-neutral-800 rounded-lg px-4 pt-4 pb-6 flex flex-col gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 mt-2", children: [
|
|
1942
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1943
|
+
AuthVerificationCodeInput,
|
|
1944
|
+
{
|
|
1945
|
+
value: verificationCode,
|
|
1946
|
+
onChange: setVerificationCode,
|
|
1947
|
+
email,
|
|
1948
|
+
disabled: isVerifyingCode,
|
|
1949
|
+
onComplete: (code) => {
|
|
1950
|
+
void handleVerifyCode(code);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
),
|
|
1954
|
+
isVerifyingCode && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: "Verifying..." })
|
|
1955
|
+
] }) }),
|
|
1956
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full text-sm text-center text-neutral-600 dark:text-neutral-400", children: [
|
|
1957
|
+
"Didn't receive the email?",
|
|
1958
|
+
" ",
|
|
1959
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1960
|
+
"button",
|
|
1961
|
+
{
|
|
1962
|
+
onClick: () => {
|
|
1963
|
+
void handleResendCode();
|
|
1964
|
+
},
|
|
1965
|
+
disabled: resendDisabled || isSendingCode,
|
|
1966
|
+
className: "text-black dark:text-white font-medium transition-colors disabled:cursor-not-allowed cursor-pointer hover:underline disabled:no-underline disabled:opacity-50",
|
|
1967
|
+
children: isSendingCode ? "Sending..." : resendDisabled ? `Retry in (${resendCountdown}s)` : "Click to resend"
|
|
1968
|
+
}
|
|
1969
|
+
)
|
|
1970
|
+
] })
|
|
1971
|
+
] }),
|
|
1972
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-sm text-gray-600 dark:text-gray-400", children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: backToSignInUrl, className: "text-black dark:text-white font-medium", children: "Back to Sign In" }) })
|
|
1973
|
+
]
|
|
1974
|
+
}
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1978
|
+
ResetPassword,
|
|
1979
|
+
{
|
|
1980
|
+
token: resetToken,
|
|
1981
|
+
backToSignInUrl,
|
|
1982
|
+
onSuccess: handlePasswordResetSuccess,
|
|
1983
|
+
onError,
|
|
1984
|
+
appearance: uiProps.appearance
|
|
1985
|
+
}
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
function VerifyEmailStatus({
|
|
1989
|
+
status,
|
|
1990
|
+
error,
|
|
1991
|
+
appearance = {},
|
|
1992
|
+
verifyingTitle = "Verifying your email...",
|
|
1993
|
+
successTitle = "Email Verified!",
|
|
1994
|
+
successMessage = "Your email has been verified successfully. You can close this page and return to your app.",
|
|
1995
|
+
errorTitle = "Verification Failed"
|
|
1996
|
+
}) {
|
|
1997
|
+
if (status === "verifying") {
|
|
1998
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center gap-6", children: [
|
|
1999
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white", children: verifyingTitle }),
|
|
2000
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-black dark:border-white" })
|
|
2001
|
+
] }) });
|
|
2002
|
+
}
|
|
2003
|
+
if (status === "error") {
|
|
2004
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex flex-col items-stretch justify-center gap-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start justify-center gap-2", children: [
|
|
2005
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold text-black dark:text-white", children: errorTitle }),
|
|
2006
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed", children: [
|
|
2007
|
+
error || "The verification link is invalid or has expired.",
|
|
2008
|
+
" Please try again or contact support if the problem persists. You can close this page and return to your app."
|
|
2009
|
+
] })
|
|
2010
|
+
] }) }) });
|
|
2011
|
+
}
|
|
2012
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex flex-col items-stretch justify-center gap-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
2013
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-8 h-8 text-green-600 dark:text-green-400", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7" }) }) }),
|
|
2014
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
2015
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: successMessage })
|
|
2016
|
+
] }) }) });
|
|
2017
|
+
}
|
|
2018
|
+
function VerifyEmail({
|
|
2019
|
+
token,
|
|
2020
|
+
onSuccess,
|
|
2021
|
+
onError,
|
|
2022
|
+
...uiProps
|
|
2023
|
+
}) {
|
|
2024
|
+
const { verifyEmail } = useInsforge();
|
|
2025
|
+
const [status, setStatus] = react.useState("verifying");
|
|
2026
|
+
const [error, setError] = react.useState("");
|
|
2027
|
+
react.useEffect(() => {
|
|
2028
|
+
const verifyEmailFn = async () => {
|
|
2029
|
+
if (!token) {
|
|
2030
|
+
const errorMessage = "Invalid verification link. Missing required token.";
|
|
2031
|
+
setError(errorMessage);
|
|
2032
|
+
setStatus("error");
|
|
2033
|
+
if (onError) {
|
|
2034
|
+
onError(new Error(errorMessage));
|
|
2035
|
+
}
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
try {
|
|
2039
|
+
const result = await verifyEmail(token);
|
|
2040
|
+
if (!result?.accessToken) {
|
|
2041
|
+
const errorMessage = result ? "Verification succeeded but no access token received" : "Email verification failed";
|
|
2042
|
+
setError(errorMessage);
|
|
2043
|
+
setStatus("error");
|
|
2044
|
+
if (onError) {
|
|
2045
|
+
onError(new Error(errorMessage));
|
|
2046
|
+
}
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
setStatus("success");
|
|
2050
|
+
if (onSuccess) {
|
|
2051
|
+
onSuccess({
|
|
2052
|
+
accessToken: result.accessToken,
|
|
2053
|
+
user: result.user
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
} catch (err) {
|
|
2057
|
+
const errorMessage = err.message || "Email verification failed";
|
|
2058
|
+
setError(errorMessage);
|
|
2059
|
+
setStatus("error");
|
|
2060
|
+
if (onError) {
|
|
2061
|
+
onError(new Error(errorMessage));
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
};
|
|
2065
|
+
void verifyEmailFn();
|
|
2066
|
+
}, [token, verifyEmail, onSuccess, onError]);
|
|
2067
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VerifyEmailStatus, { status, error, ...uiProps });
|
|
2068
|
+
}
|
|
2069
|
+
function UserButton({
|
|
2070
|
+
afterSignOutUrl = "/",
|
|
2071
|
+
mode = "detailed",
|
|
2072
|
+
appearance = {}
|
|
2073
|
+
}) {
|
|
2074
|
+
const { user, signOut } = useInsforge();
|
|
2075
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
2076
|
+
const [imageError, setImageError] = react.useState(false);
|
|
2077
|
+
const dropdownRef = react.useRef(null);
|
|
2078
|
+
react.useEffect(() => {
|
|
2079
|
+
setImageError(false);
|
|
2080
|
+
const avatarUrl = user?.avatarUrl;
|
|
2081
|
+
if (!avatarUrl) return;
|
|
2082
|
+
const checkImageUrl = async () => {
|
|
2083
|
+
try {
|
|
2084
|
+
const response = await fetch(avatarUrl, {
|
|
2085
|
+
method: "HEAD",
|
|
2086
|
+
cache: "no-cache"
|
|
2087
|
+
});
|
|
2088
|
+
if (!response.ok) {
|
|
2089
|
+
setImageError(true);
|
|
2090
|
+
}
|
|
2091
|
+
} catch (error) {
|
|
2092
|
+
setImageError(true);
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2095
|
+
checkImageUrl();
|
|
2096
|
+
}, [user?.avatarUrl]);
|
|
2097
|
+
react.useEffect(() => {
|
|
2098
|
+
function handleClickOutside(event) {
|
|
2099
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
2100
|
+
setIsOpen(false);
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
if (isOpen) {
|
|
2104
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2105
|
+
}
|
|
2106
|
+
return () => {
|
|
2107
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2108
|
+
};
|
|
2109
|
+
}, [isOpen]);
|
|
2110
|
+
async function handleSignOut() {
|
|
2111
|
+
await signOut();
|
|
2112
|
+
setIsOpen(false);
|
|
2113
|
+
window.location.href = afterSignOutUrl;
|
|
2114
|
+
}
|
|
2115
|
+
if (!user) return null;
|
|
2116
|
+
const initials = user.name ? user.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
|
|
2117
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2118
|
+
"div",
|
|
2119
|
+
{
|
|
2120
|
+
className: cn("relative inline-block", appearance.containerClassName),
|
|
2121
|
+
ref: dropdownRef,
|
|
2122
|
+
children: [
|
|
2123
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2124
|
+
"button",
|
|
2125
|
+
{
|
|
2126
|
+
className: cn(
|
|
2127
|
+
"p-1 bg-transparent border-0 rounded-full cursor-pointer transition-all duration-200",
|
|
2128
|
+
"flex items-center justify-center gap-2",
|
|
2129
|
+
"hover:bg-black/5",
|
|
2130
|
+
mode === "detailed" && "rounded-lg p-2",
|
|
2131
|
+
appearance.buttonClassName
|
|
2132
|
+
),
|
|
2133
|
+
onClick: () => setIsOpen(!isOpen),
|
|
2134
|
+
"aria-expanded": isOpen,
|
|
2135
|
+
"aria-haspopup": "true",
|
|
2136
|
+
children: [
|
|
2137
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-10 h-10 bg-blue-500 rounded-full", children: user.avatarUrl && !imageError ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2138
|
+
"img",
|
|
2139
|
+
{
|
|
1283
2140
|
src: user.avatarUrl,
|
|
1284
2141
|
alt: user.email,
|
|
1285
2142
|
onError: () => setImageError(true),
|
|
@@ -1446,271 +2303,11 @@ function InsforgeCallback({
|
|
|
1446
2303
|
] }) });
|
|
1447
2304
|
return loadingComponent || defaultLoading;
|
|
1448
2305
|
}
|
|
1449
|
-
function ForgotPasswordForm({
|
|
1450
|
-
email,
|
|
1451
|
-
onEmailChange,
|
|
1452
|
-
onSubmit,
|
|
1453
|
-
error,
|
|
1454
|
-
loading = false,
|
|
1455
|
-
success = false,
|
|
1456
|
-
appearance = {},
|
|
1457
|
-
title = "Forgot Password?",
|
|
1458
|
-
subtitle = "Enter your email address and we'll send you a code to reset your password.",
|
|
1459
|
-
emailLabel = "Email",
|
|
1460
|
-
emailPlaceholder = "example@email.com",
|
|
1461
|
-
submitButtonText = "Send Reset Code",
|
|
1462
|
-
loadingButtonText = "Sending...",
|
|
1463
|
-
backToSignInText = "Remember your password?",
|
|
1464
|
-
backToSignInUrl = "/sign-in",
|
|
1465
|
-
successTitle = "Check Your Email",
|
|
1466
|
-
successMessage
|
|
1467
|
-
}) {
|
|
1468
|
-
if (success) {
|
|
1469
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
|
-
AuthContainer,
|
|
1471
|
-
{
|
|
1472
|
-
appearance: {
|
|
1473
|
-
containerClassName: appearance.container,
|
|
1474
|
-
cardClassName: appearance.card
|
|
1475
|
-
},
|
|
1476
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1477
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-8 h-8 text-green-600 dark:text-green-400", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7" }) }) }),
|
|
1478
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
1479
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: successMessage || `We've sent a password reset link to ${email}. Please check your email and follow the instructions.` }),
|
|
1480
|
-
/* @__PURE__ */ jsxRuntime.jsx("a", { href: backToSignInUrl, className: "mt-4 text-black dark:text-white font-medium", children: "Back to Sign In" })
|
|
1481
|
-
] })
|
|
1482
|
-
}
|
|
1483
|
-
);
|
|
1484
|
-
}
|
|
1485
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1486
|
-
AuthContainer,
|
|
1487
|
-
{
|
|
1488
|
-
appearance: {
|
|
1489
|
-
containerClassName: appearance.container,
|
|
1490
|
-
cardClassName: appearance.card
|
|
1491
|
-
},
|
|
1492
|
-
children: [
|
|
1493
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1494
|
-
AuthHeader,
|
|
1495
|
-
{
|
|
1496
|
-
title,
|
|
1497
|
-
subtitle,
|
|
1498
|
-
appearance: {
|
|
1499
|
-
containerClassName: appearance.header?.container,
|
|
1500
|
-
titleClassName: appearance.header?.title,
|
|
1501
|
-
subtitleClassName: appearance.header?.subtitle
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
),
|
|
1505
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1506
|
-
AuthErrorBanner,
|
|
1507
|
-
{
|
|
1508
|
-
error: error || "",
|
|
1509
|
-
className: appearance.errorBanner
|
|
1510
|
-
}
|
|
1511
|
-
),
|
|
1512
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1513
|
-
"form",
|
|
1514
|
-
{
|
|
1515
|
-
onSubmit,
|
|
1516
|
-
noValidate: true,
|
|
1517
|
-
className: appearance.form?.container || "flex flex-col items-stretch justify-center gap-6",
|
|
1518
|
-
children: [
|
|
1519
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1520
|
-
AuthFormField,
|
|
1521
|
-
{
|
|
1522
|
-
id: "email",
|
|
1523
|
-
type: "email",
|
|
1524
|
-
label: emailLabel,
|
|
1525
|
-
placeholder: emailPlaceholder,
|
|
1526
|
-
value: email,
|
|
1527
|
-
onChange: (e) => onEmailChange(e.target.value),
|
|
1528
|
-
required: true,
|
|
1529
|
-
autoComplete: "email",
|
|
1530
|
-
appearance: {
|
|
1531
|
-
containerClassName: appearance.form?.emailField?.container,
|
|
1532
|
-
labelClassName: appearance.form?.emailField?.label,
|
|
1533
|
-
inputClassName: appearance.form?.emailField?.input
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
),
|
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1538
|
-
AuthSubmitButton,
|
|
1539
|
-
{
|
|
1540
|
-
isLoading: loading,
|
|
1541
|
-
disabled: loading,
|
|
1542
|
-
className: appearance.button,
|
|
1543
|
-
children: loading ? loadingButtonText : submitButtonText
|
|
1544
|
-
}
|
|
1545
|
-
)
|
|
1546
|
-
]
|
|
1547
|
-
}
|
|
1548
|
-
),
|
|
1549
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1550
|
-
AuthLink,
|
|
1551
|
-
{
|
|
1552
|
-
text: backToSignInText,
|
|
1553
|
-
linkText: "Back to Sign In",
|
|
1554
|
-
href: backToSignInUrl,
|
|
1555
|
-
appearance: {
|
|
1556
|
-
containerClassName: appearance.link?.container,
|
|
1557
|
-
linkClassName: appearance.link?.link
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
)
|
|
1561
|
-
]
|
|
1562
|
-
}
|
|
1563
|
-
);
|
|
1564
|
-
}
|
|
1565
|
-
function ResetPasswordForm({
|
|
1566
|
-
newPassword,
|
|
1567
|
-
confirmPassword,
|
|
1568
|
-
onNewPasswordChange,
|
|
1569
|
-
onConfirmPasswordChange,
|
|
1570
|
-
onSubmit,
|
|
1571
|
-
error,
|
|
1572
|
-
loading = false,
|
|
1573
|
-
emailAuthConfig,
|
|
1574
|
-
appearance = {},
|
|
1575
|
-
title = "Reset Password",
|
|
1576
|
-
subtitle = "Enter your new password below.",
|
|
1577
|
-
newPasswordLabel = "New Password",
|
|
1578
|
-
newPasswordPlaceholder = "\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1579
|
-
confirmPasswordLabel = "Confirm Password",
|
|
1580
|
-
confirmPasswordPlaceholder = "\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1581
|
-
submitButtonText = "Reset Password",
|
|
1582
|
-
loadingButtonText = "Resetting...",
|
|
1583
|
-
backToSignInText = "",
|
|
1584
|
-
backToSignInUrl = "/sign-in"
|
|
1585
|
-
}) {
|
|
1586
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1587
|
-
AuthContainer,
|
|
1588
|
-
{
|
|
1589
|
-
appearance: {
|
|
1590
|
-
containerClassName: appearance.container,
|
|
1591
|
-
cardClassName: appearance.card
|
|
1592
|
-
},
|
|
1593
|
-
children: [
|
|
1594
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1595
|
-
AuthHeader,
|
|
1596
|
-
{
|
|
1597
|
-
title,
|
|
1598
|
-
subtitle,
|
|
1599
|
-
appearance: {
|
|
1600
|
-
containerClassName: appearance.header?.container,
|
|
1601
|
-
titleClassName: appearance.header?.title,
|
|
1602
|
-
subtitleClassName: appearance.header?.subtitle
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
),
|
|
1606
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1607
|
-
AuthErrorBanner,
|
|
1608
|
-
{
|
|
1609
|
-
error: error || "",
|
|
1610
|
-
className: appearance.errorBanner
|
|
1611
|
-
}
|
|
1612
|
-
),
|
|
1613
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1614
|
-
"form",
|
|
1615
|
-
{
|
|
1616
|
-
onSubmit,
|
|
1617
|
-
noValidate: true,
|
|
1618
|
-
className: appearance.form?.container || "flex flex-col items-stretch justify-center gap-6",
|
|
1619
|
-
children: [
|
|
1620
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1621
|
-
AuthPasswordField,
|
|
1622
|
-
{
|
|
1623
|
-
id: "newPassword",
|
|
1624
|
-
label: newPasswordLabel,
|
|
1625
|
-
placeholder: newPasswordPlaceholder,
|
|
1626
|
-
value: newPassword,
|
|
1627
|
-
onChange: (e) => onNewPasswordChange(e.target.value),
|
|
1628
|
-
required: true,
|
|
1629
|
-
autoComplete: "new-password",
|
|
1630
|
-
showStrengthIndicator: true,
|
|
1631
|
-
emailAuthConfig,
|
|
1632
|
-
appearance: {
|
|
1633
|
-
containerClassName: appearance.form?.newPasswordField?.container,
|
|
1634
|
-
labelClassName: appearance.form?.newPasswordField?.label,
|
|
1635
|
-
inputClassName: appearance.form?.newPasswordField?.input
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
),
|
|
1639
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1640
|
-
AuthPasswordField,
|
|
1641
|
-
{
|
|
1642
|
-
id: "confirmPassword",
|
|
1643
|
-
label: confirmPasswordLabel,
|
|
1644
|
-
placeholder: confirmPasswordPlaceholder,
|
|
1645
|
-
value: confirmPassword,
|
|
1646
|
-
onChange: (e) => onConfirmPasswordChange(e.target.value),
|
|
1647
|
-
required: true,
|
|
1648
|
-
autoComplete: "new-password",
|
|
1649
|
-
emailAuthConfig,
|
|
1650
|
-
appearance: {
|
|
1651
|
-
containerClassName: appearance.form?.confirmPasswordField?.container,
|
|
1652
|
-
labelClassName: appearance.form?.confirmPasswordField?.label,
|
|
1653
|
-
inputClassName: appearance.form?.confirmPasswordField?.input
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
),
|
|
1657
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1658
|
-
AuthSubmitButton,
|
|
1659
|
-
{
|
|
1660
|
-
isLoading: loading,
|
|
1661
|
-
disabled: loading,
|
|
1662
|
-
className: appearance.button,
|
|
1663
|
-
children: loading ? loadingButtonText : submitButtonText
|
|
1664
|
-
}
|
|
1665
|
-
)
|
|
1666
|
-
]
|
|
1667
|
-
}
|
|
1668
|
-
),
|
|
1669
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: appearance.backToSignIn || "text-center text-sm text-gray-600 dark:text-gray-400", children: [
|
|
1670
|
-
backToSignInText && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1671
|
-
backToSignInText,
|
|
1672
|
-
" "
|
|
1673
|
-
] }),
|
|
1674
|
-
/* @__PURE__ */ jsxRuntime.jsx("a", { href: backToSignInUrl, className: "text-black dark:text-white font-medium", children: "Back to Sign In" })
|
|
1675
|
-
] })
|
|
1676
|
-
]
|
|
1677
|
-
}
|
|
1678
|
-
);
|
|
1679
|
-
}
|
|
1680
|
-
function VerifyEmailStatus({
|
|
1681
|
-
status,
|
|
1682
|
-
error,
|
|
1683
|
-
appearance = {},
|
|
1684
|
-
verifyingTitle = "Verifying your email...",
|
|
1685
|
-
successTitle = "Email Verified!",
|
|
1686
|
-
successMessage = "Your email has been verified successfully. You can close this page and return to your app.",
|
|
1687
|
-
errorTitle = "Verification Failed"
|
|
1688
|
-
}) {
|
|
1689
|
-
if (status === "verifying") {
|
|
1690
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center gap-6", children: [
|
|
1691
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white", children: verifyingTitle }),
|
|
1692
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-black dark:border-white" })
|
|
1693
|
-
] }) });
|
|
1694
|
-
}
|
|
1695
|
-
if (status === "error") {
|
|
1696
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex flex-col items-stretch justify-center gap-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start justify-center gap-2", children: [
|
|
1697
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold text-black dark:text-white", children: errorTitle }),
|
|
1698
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed", children: [
|
|
1699
|
-
error || "The verification link is invalid or has expired.",
|
|
1700
|
-
" Please try again or contact support if the problem persists. You can close this page and return to your app."
|
|
1701
|
-
] })
|
|
1702
|
-
] }) }) });
|
|
1703
|
-
}
|
|
1704
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex flex-col items-stretch justify-center gap-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1705
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-8 h-8 text-green-600 dark:text-green-400", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7" }) }) }),
|
|
1706
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
1707
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: successMessage })
|
|
1708
|
-
] }) }) });
|
|
1709
|
-
}
|
|
1710
2306
|
|
|
1711
2307
|
exports.AuthBranding = AuthBranding;
|
|
1712
2308
|
exports.AuthContainer = AuthContainer;
|
|
1713
2309
|
exports.AuthDivider = AuthDivider;
|
|
2310
|
+
exports.AuthEmailVerificationStep = AuthEmailVerificationStep;
|
|
1714
2311
|
exports.AuthErrorBanner = AuthErrorBanner;
|
|
1715
2312
|
exports.AuthFormField = AuthFormField;
|
|
1716
2313
|
exports.AuthHeader = AuthHeader;
|
|
@@ -1721,9 +2318,11 @@ exports.AuthPasswordField = AuthPasswordField;
|
|
|
1721
2318
|
exports.AuthPasswordStrengthIndicator = AuthPasswordStrengthIndicator;
|
|
1722
2319
|
exports.AuthSubmitButton = AuthSubmitButton;
|
|
1723
2320
|
exports.AuthVerificationCodeInput = AuthVerificationCodeInput;
|
|
2321
|
+
exports.ForgotPassword = ForgotPassword;
|
|
1724
2322
|
exports.ForgotPasswordForm = ForgotPasswordForm;
|
|
1725
2323
|
exports.InsforgeCallback = InsforgeCallback;
|
|
1726
2324
|
exports.Protect = Protect;
|
|
2325
|
+
exports.ResetPassword = ResetPassword;
|
|
1727
2326
|
exports.ResetPasswordForm = ResetPasswordForm;
|
|
1728
2327
|
exports.SignIn = SignIn;
|
|
1729
2328
|
exports.SignInForm = SignInForm;
|
|
@@ -1732,6 +2331,7 @@ exports.SignUpForm = SignUpForm;
|
|
|
1732
2331
|
exports.SignedIn = SignedIn;
|
|
1733
2332
|
exports.SignedOut = SignedOut;
|
|
1734
2333
|
exports.UserButton = UserButton;
|
|
2334
|
+
exports.VerifyEmail = VerifyEmail;
|
|
1735
2335
|
exports.VerifyEmailStatus = VerifyEmailStatus;
|
|
1736
2336
|
exports.validatePasswordStrength = validatePasswordStrength;
|
|
1737
2337
|
//# sourceMappingURL=components.js.map
|