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