@insforge/react 0.2.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -32
- package/dist/atoms.d.mts +23 -2
- package/dist/atoms.d.ts +23 -2
- package/dist/atoms.js +139 -0
- package/dist/atoms.js.map +1 -1
- package/dist/atoms.mjs +140 -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 +900 -322
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +898 -324
- package/dist/components.mjs.map +1 -1
- package/dist/forms.js +4 -0
- package/dist/forms.js.map +1 -1
- package/dist/forms.mjs +5 -1
- 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 +930 -438
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +927 -439
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.d.mts +1 -0
- package/dist/types.d.ts +1 -0
- 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,126 @@ function AuthVerificationCodeInput({
|
|
|
758
766
|
)) })
|
|
759
767
|
] });
|
|
760
768
|
}
|
|
769
|
+
function AuthEmailVerificationStep({
|
|
770
|
+
email,
|
|
771
|
+
title = "Verify Your Email",
|
|
772
|
+
description,
|
|
773
|
+
method = "code",
|
|
774
|
+
onVerifyCode
|
|
775
|
+
}) {
|
|
776
|
+
const { baseUrl } = useInsforge();
|
|
777
|
+
const [insforge] = react.useState(() => sdk.createClient({ baseUrl }));
|
|
778
|
+
const [resendDisabled, setResendDisabled] = react.useState(true);
|
|
779
|
+
const [resendCountdown, setResendCountdown] = react.useState(60);
|
|
780
|
+
const [isSending, setIsSending] = react.useState(false);
|
|
781
|
+
const [verificationCode, setVerificationCode] = react.useState("");
|
|
782
|
+
const [isVerifying, setIsVerifying] = react.useState(false);
|
|
783
|
+
const [verificationError, setVerificationError] = react.useState("");
|
|
784
|
+
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.";
|
|
785
|
+
react.useEffect(() => {
|
|
786
|
+
const sendInitialEmail = async () => {
|
|
787
|
+
try {
|
|
788
|
+
if (method === "code") {
|
|
789
|
+
await insforge.auth.sendVerificationCode({ email });
|
|
790
|
+
} else {
|
|
791
|
+
await insforge.auth.sendVerificationLink({ email });
|
|
792
|
+
}
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
void sendInitialEmail();
|
|
797
|
+
}, [email, method, insforge.auth]);
|
|
798
|
+
react.useEffect(() => {
|
|
799
|
+
if (resendCountdown > 0) {
|
|
800
|
+
const timer = setInterval(() => {
|
|
801
|
+
setResendCountdown((prev) => {
|
|
802
|
+
if (prev <= 1) {
|
|
803
|
+
setResendDisabled(false);
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
return prev - 1;
|
|
807
|
+
});
|
|
808
|
+
}, 1e3);
|
|
809
|
+
return () => clearInterval(timer);
|
|
810
|
+
}
|
|
811
|
+
}, [resendCountdown]);
|
|
812
|
+
const handleResend = async () => {
|
|
813
|
+
setResendDisabled(true);
|
|
814
|
+
setResendCountdown(60);
|
|
815
|
+
setIsSending(true);
|
|
816
|
+
setVerificationError("");
|
|
817
|
+
try {
|
|
818
|
+
if (method === "code") {
|
|
819
|
+
await insforge.auth.sendVerificationCode({ email });
|
|
820
|
+
} else {
|
|
821
|
+
await insforge.auth.sendVerificationLink({ email });
|
|
822
|
+
}
|
|
823
|
+
} catch {
|
|
824
|
+
setResendDisabled(false);
|
|
825
|
+
setResendCountdown(0);
|
|
826
|
+
} finally {
|
|
827
|
+
setIsSending(false);
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
const handleVerifyCode = async (code) => {
|
|
831
|
+
if (!onVerifyCode) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
setIsVerifying(true);
|
|
835
|
+
setVerificationError("");
|
|
836
|
+
try {
|
|
837
|
+
await onVerifyCode(code);
|
|
838
|
+
} catch (error) {
|
|
839
|
+
setVerificationError(
|
|
840
|
+
error instanceof Error ? error.message : "Invalid verification code. Please try again."
|
|
841
|
+
);
|
|
842
|
+
setVerificationCode("");
|
|
843
|
+
} finally {
|
|
844
|
+
setIsVerifying(false);
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
const displayDescription = description || defaultDescription;
|
|
848
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col gap-6 items-center", children: [
|
|
849
|
+
/* @__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: [
|
|
850
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-black dark:text-white", children: title }),
|
|
851
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-neutral-600 dark:text-neutral-400 text-sm leading-relaxed", children: displayDescription.split("{email}").map((part, index, array) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
852
|
+
part,
|
|
853
|
+
index < array.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-black dark:text-white", children: email })
|
|
854
|
+
] }, index)) }),
|
|
855
|
+
method === "code" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 mt-2", children: [
|
|
856
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
857
|
+
AuthVerificationCodeInput,
|
|
858
|
+
{
|
|
859
|
+
value: verificationCode,
|
|
860
|
+
onChange: setVerificationCode,
|
|
861
|
+
email,
|
|
862
|
+
disabled: isVerifying,
|
|
863
|
+
onComplete: (code) => {
|
|
864
|
+
void handleVerifyCode(code);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
),
|
|
868
|
+
verificationError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 dark:text-red-400 text-center", children: verificationError }),
|
|
869
|
+
isVerifying && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: "Verifying..." })
|
|
870
|
+
] })
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full text-sm text-center text-neutral-600 dark:text-neutral-400", children: [
|
|
873
|
+
"Didn't receive the email?",
|
|
874
|
+
" ",
|
|
875
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
876
|
+
"button",
|
|
877
|
+
{
|
|
878
|
+
onClick: () => {
|
|
879
|
+
void handleResend();
|
|
880
|
+
},
|
|
881
|
+
disabled: resendDisabled || isSending,
|
|
882
|
+
className: "text-black dark:text-white font-medium transition-colors disabled:cursor-not-allowed cursor-pointer hover:underline disabled:no-underline disabled:opacity-50",
|
|
883
|
+
children: isSending ? "Sending..." : resendDisabled ? `Retry in (${resendCountdown}s)` : "Click to resend"
|
|
884
|
+
}
|
|
885
|
+
)
|
|
886
|
+
] })
|
|
887
|
+
] });
|
|
888
|
+
}
|
|
761
889
|
function SignInForm({
|
|
762
890
|
email,
|
|
763
891
|
password,
|
|
@@ -922,6 +1050,7 @@ function SignIn({
|
|
|
922
1050
|
const [password, setPassword] = react.useState("");
|
|
923
1051
|
const [error, setError] = react.useState("");
|
|
924
1052
|
const [loading, setLoading] = react.useState(false);
|
|
1053
|
+
const [step, setStep] = react.useState("form");
|
|
925
1054
|
const [oauthLoading, setOauthLoading] = react.useState(
|
|
926
1055
|
null
|
|
927
1056
|
);
|
|
@@ -933,6 +1062,11 @@ function SignIn({
|
|
|
933
1062
|
try {
|
|
934
1063
|
const result = await signIn(email, password);
|
|
935
1064
|
if ("error" in result) {
|
|
1065
|
+
if (result.statusCode === 403) {
|
|
1066
|
+
setStep("awaiting-verification");
|
|
1067
|
+
setLoading(false);
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
936
1070
|
throw new Error(result.error);
|
|
937
1071
|
}
|
|
938
1072
|
const { user, accessToken } = result;
|
|
@@ -947,6 +1081,21 @@ function SignIn({
|
|
|
947
1081
|
setLoading(false);
|
|
948
1082
|
}
|
|
949
1083
|
}
|
|
1084
|
+
async function handleVerifyCode(code) {
|
|
1085
|
+
try {
|
|
1086
|
+
const result = await insforge.auth.verifyEmail({ email, otp: code });
|
|
1087
|
+
if (result.error) {
|
|
1088
|
+
throw new Error(result.error.message || "Verification failed");
|
|
1089
|
+
}
|
|
1090
|
+
if (result.data?.accessToken) {
|
|
1091
|
+
if (onSuccess && result.data.user) {
|
|
1092
|
+
onSuccess(result.data.user, result.data.accessToken);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
} catch (err) {
|
|
1096
|
+
throw new Error(err.message || "Invalid verification code");
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
950
1099
|
async function handleOAuth(provider) {
|
|
951
1100
|
try {
|
|
952
1101
|
setOauthLoading(provider);
|
|
@@ -965,7 +1114,7 @@ function SignIn({
|
|
|
965
1114
|
if (!emailConfig) {
|
|
966
1115
|
return null;
|
|
967
1116
|
}
|
|
968
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1117
|
+
return step === "form" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
969
1118
|
SignInForm,
|
|
970
1119
|
{
|
|
971
1120
|
email,
|
|
@@ -981,6 +1130,12 @@ function SignIn({
|
|
|
981
1130
|
emailAuthConfig: emailConfig,
|
|
982
1131
|
...uiProps
|
|
983
1132
|
}
|
|
1133
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1134
|
+
AuthEmailVerificationStep,
|
|
1135
|
+
{
|
|
1136
|
+
email,
|
|
1137
|
+
onVerifyCode: handleVerifyCode
|
|
1138
|
+
}
|
|
984
1139
|
);
|
|
985
1140
|
}
|
|
986
1141
|
function SignUpForm({
|
|
@@ -1131,6 +1286,34 @@ function SignUpForm({
|
|
|
1131
1286
|
}
|
|
1132
1287
|
);
|
|
1133
1288
|
}
|
|
1289
|
+
var emailSchema = zod.z.string().min(1, "Email is required").email("Invalid email address");
|
|
1290
|
+
function createPasswordSchema(options) {
|
|
1291
|
+
const {
|
|
1292
|
+
minLength = 6,
|
|
1293
|
+
requireUppercase = false,
|
|
1294
|
+
requireLowercase = false,
|
|
1295
|
+
requireNumber = false,
|
|
1296
|
+
requireSpecialChar = false
|
|
1297
|
+
} = options || {};
|
|
1298
|
+
let schema = zod.z.string().min(minLength, `Password must be at least ${minLength} characters`);
|
|
1299
|
+
if (requireUppercase) {
|
|
1300
|
+
schema = schema.regex(/[A-Z]/, "Password must contain at least one uppercase letter");
|
|
1301
|
+
}
|
|
1302
|
+
if (requireLowercase) {
|
|
1303
|
+
schema = schema.regex(/[a-z]/, "Password must contain at least one lowercase letter");
|
|
1304
|
+
}
|
|
1305
|
+
if (requireNumber) {
|
|
1306
|
+
schema = schema.regex(/\d/, "Password must contain at least one number");
|
|
1307
|
+
}
|
|
1308
|
+
if (requireSpecialChar) {
|
|
1309
|
+
schema = schema.regex(
|
|
1310
|
+
/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/,
|
|
1311
|
+
"Password must contain at least one special character"
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
return schema;
|
|
1315
|
+
}
|
|
1316
|
+
createPasswordSchema();
|
|
1134
1317
|
function SignUp({
|
|
1135
1318
|
afterSignUpUrl,
|
|
1136
1319
|
onSuccess,
|
|
@@ -1143,6 +1326,7 @@ function SignUp({
|
|
|
1143
1326
|
const [password, setPassword] = react.useState("");
|
|
1144
1327
|
const [error, setError] = react.useState("");
|
|
1145
1328
|
const [loading, setLoading] = react.useState(false);
|
|
1329
|
+
const [step, setStep] = react.useState("form");
|
|
1146
1330
|
const [oauthLoading, setOauthLoading] = react.useState(
|
|
1147
1331
|
null
|
|
1148
1332
|
);
|
|
@@ -1151,19 +1335,46 @@ function SignUp({
|
|
|
1151
1335
|
e.preventDefault();
|
|
1152
1336
|
setLoading(true);
|
|
1153
1337
|
setError("");
|
|
1154
|
-
if (
|
|
1155
|
-
setError("
|
|
1338
|
+
if (!emailConfig) {
|
|
1339
|
+
setError("Configuration not loaded. Please refresh the page.");
|
|
1340
|
+
setLoading(false);
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
const emailValidation = emailSchema.safeParse(email);
|
|
1344
|
+
if (!emailValidation.success) {
|
|
1345
|
+
const firstError = emailValidation.error.issues[0];
|
|
1346
|
+
setError(firstError.message);
|
|
1347
|
+
setLoading(false);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
const passwordZodSchema = createPasswordSchema({
|
|
1351
|
+
minLength: emailConfig.passwordMinLength,
|
|
1352
|
+
requireUppercase: emailConfig.requireUppercase,
|
|
1353
|
+
requireLowercase: emailConfig.requireLowercase,
|
|
1354
|
+
requireNumber: emailConfig.requireNumber,
|
|
1355
|
+
requireSpecialChar: emailConfig.requireSpecialChar
|
|
1356
|
+
});
|
|
1357
|
+
const passwordValidation = passwordZodSchema.safeParse(password);
|
|
1358
|
+
if (!passwordValidation.success) {
|
|
1359
|
+
const firstError = passwordValidation.error.issues[0];
|
|
1360
|
+
setError(firstError.message);
|
|
1156
1361
|
setLoading(false);
|
|
1157
1362
|
return;
|
|
1158
1363
|
}
|
|
1159
1364
|
try {
|
|
1160
|
-
const result = await signUp(
|
|
1365
|
+
const result = await signUp(emailValidation.data, password);
|
|
1161
1366
|
if ("error" in result) {
|
|
1162
1367
|
throw new Error(result.error);
|
|
1163
1368
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1369
|
+
if (result.requiresEmailVerification && !result.accessToken) {
|
|
1370
|
+
setStep("awaiting-verification");
|
|
1371
|
+
setLoading(false);
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
if (result.accessToken && result.user) {
|
|
1375
|
+
if (onSuccess) {
|
|
1376
|
+
onSuccess(result.user, result.accessToken);
|
|
1377
|
+
}
|
|
1167
1378
|
}
|
|
1168
1379
|
} catch (err) {
|
|
1169
1380
|
const errorMessage = err.message || "Sign up failed";
|
|
@@ -1173,6 +1384,21 @@ function SignUp({
|
|
|
1173
1384
|
setLoading(false);
|
|
1174
1385
|
}
|
|
1175
1386
|
}
|
|
1387
|
+
async function handleVerifyCode(code) {
|
|
1388
|
+
try {
|
|
1389
|
+
const result = await insforge.auth.verifyEmail({ email, otp: code });
|
|
1390
|
+
if (result.error) {
|
|
1391
|
+
throw new Error(result.error.message || "Verification failed");
|
|
1392
|
+
}
|
|
1393
|
+
if (result.data?.accessToken) {
|
|
1394
|
+
if (onSuccess && result.data.user) {
|
|
1395
|
+
onSuccess(result.data.user, result.data.accessToken);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
} catch (err) {
|
|
1399
|
+
throw new Error(err.message || "Invalid verification code");
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1176
1402
|
async function handleOAuth(provider) {
|
|
1177
1403
|
try {
|
|
1178
1404
|
setOauthLoading(provider);
|
|
@@ -1191,7 +1417,7 @@ function SignUp({
|
|
|
1191
1417
|
if (!emailConfig) {
|
|
1192
1418
|
return null;
|
|
1193
1419
|
}
|
|
1194
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1420
|
+
return step === "form" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1195
1421
|
SignUpForm,
|
|
1196
1422
|
{
|
|
1197
1423
|
email,
|
|
@@ -1207,306 +1433,75 @@ function SignUp({
|
|
|
1207
1433
|
emailAuthConfig: emailConfig,
|
|
1208
1434
|
...uiProps
|
|
1209
1435
|
}
|
|
1436
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1437
|
+
AuthEmailVerificationStep,
|
|
1438
|
+
{
|
|
1439
|
+
email,
|
|
1440
|
+
onVerifyCode: handleVerifyCode
|
|
1441
|
+
}
|
|
1210
1442
|
);
|
|
1211
1443
|
}
|
|
1212
|
-
function
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1444
|
+
function ForgotPasswordForm({
|
|
1445
|
+
email,
|
|
1446
|
+
onEmailChange,
|
|
1447
|
+
onSubmit,
|
|
1448
|
+
error,
|
|
1449
|
+
loading = false,
|
|
1450
|
+
success = false,
|
|
1451
|
+
appearance = {},
|
|
1452
|
+
title = "Forgot Password?",
|
|
1453
|
+
subtitle = "Enter your email address and we'll send you a code to reset your password.",
|
|
1454
|
+
emailLabel = "Email",
|
|
1455
|
+
emailPlaceholder = "example@email.com",
|
|
1456
|
+
submitButtonText = "Send Reset Code",
|
|
1457
|
+
loadingButtonText = "Sending...",
|
|
1458
|
+
backToSignInText = "Remember your password?",
|
|
1459
|
+
backToSignInUrl = "/sign-in",
|
|
1460
|
+
successTitle = "Check Your Email",
|
|
1461
|
+
successMessage
|
|
1216
1462
|
}) {
|
|
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);
|
|
1463
|
+
if (success) {
|
|
1464
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1465
|
+
AuthContainer,
|
|
1466
|
+
{
|
|
1467
|
+
appearance: {
|
|
1468
|
+
containerClassName: appearance.container,
|
|
1469
|
+
cardClassName: appearance.card
|
|
1470
|
+
},
|
|
1471
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1472
|
+
/* @__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" }) }) }),
|
|
1473
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
1474
|
+
/* @__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.` }),
|
|
1475
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: backToSignInUrl, className: "mt-4 text-black dark:text-white font-medium", children: "Back to Sign In" })
|
|
1476
|
+
] })
|
|
1244
1477
|
}
|
|
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;
|
|
1478
|
+
);
|
|
1257
1479
|
}
|
|
1258
|
-
if (!user) return null;
|
|
1259
|
-
const initials = user.name ? user.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
|
|
1260
1480
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1261
|
-
|
|
1481
|
+
AuthContainer,
|
|
1262
1482
|
{
|
|
1263
|
-
|
|
1264
|
-
|
|
1483
|
+
appearance: {
|
|
1484
|
+
containerClassName: appearance.container,
|
|
1485
|
+
cardClassName: appearance.card
|
|
1486
|
+
},
|
|
1265
1487
|
children: [
|
|
1266
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1267
|
-
|
|
1488
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1489
|
+
AuthHeader,
|
|
1268
1490
|
{
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
appearance.
|
|
1275
|
-
|
|
1276
|
-
onClick: () => setIsOpen(!isOpen),
|
|
1277
|
-
"aria-expanded": isOpen,
|
|
1278
|
-
"aria-haspopup": "true",
|
|
1279
|
-
children: [
|
|
1280
|
-
/* @__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(
|
|
1281
|
-
"img",
|
|
1282
|
-
{
|
|
1283
|
-
src: user.avatarUrl,
|
|
1284
|
-
alt: user.email,
|
|
1285
|
-
onError: () => setImageError(true),
|
|
1286
|
-
className: "rounded-full object-cover w-full h-full"
|
|
1287
|
-
}
|
|
1288
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white font-semibold text-sm", children: initials }) }),
|
|
1289
|
-
mode === "detailed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-0.5", children: [
|
|
1290
|
-
user.name && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1291
|
-
"div",
|
|
1292
|
-
{
|
|
1293
|
-
className: cn(
|
|
1294
|
-
"text-sm font-semibold text-gray-900 leading-5 text-left",
|
|
1295
|
-
appearance.nameClassName
|
|
1296
|
-
),
|
|
1297
|
-
children: user.name
|
|
1298
|
-
}
|
|
1299
|
-
),
|
|
1300
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1301
|
-
"div",
|
|
1302
|
-
{
|
|
1303
|
-
className: cn(
|
|
1304
|
-
"text-xs text-gray-500 leading-4 text-left",
|
|
1305
|
-
appearance.emailClassName
|
|
1306
|
-
),
|
|
1307
|
-
children: user.email
|
|
1308
|
-
}
|
|
1309
|
-
)
|
|
1310
|
-
] })
|
|
1311
|
-
]
|
|
1491
|
+
title,
|
|
1492
|
+
subtitle,
|
|
1493
|
+
appearance: {
|
|
1494
|
+
containerClassName: appearance.header?.container,
|
|
1495
|
+
titleClassName: appearance.header?.title,
|
|
1496
|
+
subtitleClassName: appearance.header?.subtitle
|
|
1497
|
+
}
|
|
1312
1498
|
}
|
|
1313
1499
|
),
|
|
1314
|
-
|
|
1315
|
-
|
|
1500
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1501
|
+
AuthErrorBanner,
|
|
1316
1502
|
{
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
"bg-white border border-gray-200 rounded-lg",
|
|
1320
|
-
"shadow-lg z-50 overflow-hidden p-1",
|
|
1321
|
-
appearance.dropdownClassName
|
|
1322
|
-
),
|
|
1323
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1324
|
-
"button",
|
|
1325
|
-
{
|
|
1326
|
-
onClick: handleSignOut,
|
|
1327
|
-
className: "flex items-center justify-start gap-2 w-full px-3 py-2 text-sm font-normal text-red-600 bg-transparent border-0 rounded-md cursor-pointer transition-colors hover:bg-red-50 text-left",
|
|
1328
|
-
children: [
|
|
1329
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LogOut, { className: "w-5 h-5" }),
|
|
1330
|
-
"Sign out"
|
|
1331
|
-
]
|
|
1332
|
-
}
|
|
1333
|
-
)
|
|
1334
|
-
}
|
|
1335
|
-
)
|
|
1336
|
-
]
|
|
1337
|
-
}
|
|
1338
|
-
);
|
|
1339
|
-
}
|
|
1340
|
-
function Protect({
|
|
1341
|
-
children,
|
|
1342
|
-
fallback,
|
|
1343
|
-
redirectTo = "/sign-in",
|
|
1344
|
-
condition,
|
|
1345
|
-
onRedirect
|
|
1346
|
-
}) {
|
|
1347
|
-
const { isSignedIn, isLoaded, user } = useInsforge();
|
|
1348
|
-
react.useEffect(() => {
|
|
1349
|
-
if (isLoaded && !isSignedIn) {
|
|
1350
|
-
if (onRedirect) {
|
|
1351
|
-
onRedirect(redirectTo);
|
|
1352
|
-
} else {
|
|
1353
|
-
window.location.href = redirectTo;
|
|
1354
|
-
}
|
|
1355
|
-
} else if (isLoaded && isSignedIn && condition && user) {
|
|
1356
|
-
if (!condition(user)) {
|
|
1357
|
-
if (onRedirect) {
|
|
1358
|
-
onRedirect(redirectTo);
|
|
1359
|
-
} else {
|
|
1360
|
-
window.location.href = redirectTo;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}, [isLoaded, isSignedIn, redirectTo, condition, user, onRedirect]);
|
|
1365
|
-
if (!isLoaded) {
|
|
1366
|
-
return fallback || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "insforge-loading", children: "Loading..." });
|
|
1367
|
-
}
|
|
1368
|
-
if (!isSignedIn) {
|
|
1369
|
-
return fallback || null;
|
|
1370
|
-
}
|
|
1371
|
-
if (condition && user && !condition(user)) {
|
|
1372
|
-
return fallback || null;
|
|
1373
|
-
}
|
|
1374
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
1375
|
-
}
|
|
1376
|
-
function SignedIn({ children }) {
|
|
1377
|
-
const { isSignedIn, isLoaded } = useInsforge();
|
|
1378
|
-
if (!isLoaded) return null;
|
|
1379
|
-
if (!isSignedIn) return null;
|
|
1380
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
1381
|
-
}
|
|
1382
|
-
function SignedOut({ children }) {
|
|
1383
|
-
const { isSignedIn, isLoaded } = useInsforge();
|
|
1384
|
-
if (!isLoaded) return null;
|
|
1385
|
-
if (isSignedIn) return null;
|
|
1386
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
1387
|
-
}
|
|
1388
|
-
function InsforgeCallback({
|
|
1389
|
-
redirectTo = "/",
|
|
1390
|
-
onSuccess,
|
|
1391
|
-
onError,
|
|
1392
|
-
loadingComponent,
|
|
1393
|
-
onRedirect
|
|
1394
|
-
}) {
|
|
1395
|
-
const isProcessingRef = react.useRef(false);
|
|
1396
|
-
const { isLoaded, isSignedIn } = useInsforge();
|
|
1397
|
-
react.useEffect(() => {
|
|
1398
|
-
if (!isLoaded) return;
|
|
1399
|
-
if (isProcessingRef.current) return;
|
|
1400
|
-
isProcessingRef.current = true;
|
|
1401
|
-
const processCallback = async () => {
|
|
1402
|
-
const searchParams = new URLSearchParams(window.location.search);
|
|
1403
|
-
const error = searchParams.get("error");
|
|
1404
|
-
if (error) {
|
|
1405
|
-
if (onError) {
|
|
1406
|
-
onError(error);
|
|
1407
|
-
} else {
|
|
1408
|
-
const errorUrl = "/?error=" + encodeURIComponent(error);
|
|
1409
|
-
if (onRedirect) {
|
|
1410
|
-
onRedirect(errorUrl);
|
|
1411
|
-
} else {
|
|
1412
|
-
window.location.href = errorUrl;
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
if (!isSignedIn) {
|
|
1418
|
-
const errorMsg = "authentication_failed";
|
|
1419
|
-
if (onError) {
|
|
1420
|
-
onError(errorMsg);
|
|
1421
|
-
} else {
|
|
1422
|
-
const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
|
|
1423
|
-
if (onRedirect) {
|
|
1424
|
-
onRedirect(errorUrl);
|
|
1425
|
-
} else {
|
|
1426
|
-
window.location.href = errorUrl;
|
|
1427
|
-
}
|
|
1428
|
-
}
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
window.history.replaceState({}, "", window.location.pathname);
|
|
1432
|
-
if (onSuccess) {
|
|
1433
|
-
onSuccess();
|
|
1434
|
-
}
|
|
1435
|
-
if (onRedirect) {
|
|
1436
|
-
onRedirect(redirectTo);
|
|
1437
|
-
} else {
|
|
1438
|
-
window.location.href = redirectTo;
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
1441
|
-
processCallback();
|
|
1442
|
-
}, [isLoaded, isSignedIn, redirectTo, onSuccess, onError, onRedirect]);
|
|
1443
|
-
const defaultLoading = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
1444
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold mb-4", children: "Completing authentication..." }),
|
|
1445
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto" })
|
|
1446
|
-
] }) });
|
|
1447
|
-
return loadingComponent || defaultLoading;
|
|
1448
|
-
}
|
|
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
|
|
1503
|
+
error: error || "",
|
|
1504
|
+
className: appearance.errorBanner
|
|
1510
1505
|
}
|
|
1511
1506
|
),
|
|
1512
1507
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1677,40 +1672,620 @@ function ResetPasswordForm({
|
|
|
1677
1672
|
}
|
|
1678
1673
|
);
|
|
1679
1674
|
}
|
|
1680
|
-
function
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
successMessage = "Your email has been verified successfully. You can close this page and return to your app.",
|
|
1687
|
-
errorTitle = "Verification Failed"
|
|
1675
|
+
function ResetPassword({
|
|
1676
|
+
token,
|
|
1677
|
+
backToSignInUrl = "/sign-in",
|
|
1678
|
+
onSuccess,
|
|
1679
|
+
onError,
|
|
1680
|
+
...uiProps
|
|
1688
1681
|
}) {
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1682
|
+
const { resetPassword } = useInsforge();
|
|
1683
|
+
const { emailConfig } = usePublicAuthConfig();
|
|
1684
|
+
const [newPassword, setNewPassword] = react.useState("");
|
|
1685
|
+
const [confirmPassword, setConfirmPassword] = react.useState("");
|
|
1686
|
+
const [error, setError] = react.useState("");
|
|
1687
|
+
const [loading, setLoading] = react.useState(false);
|
|
1688
|
+
async function handleSubmit(e) {
|
|
1689
|
+
e.preventDefault();
|
|
1690
|
+
setLoading(true);
|
|
1691
|
+
setError("");
|
|
1692
|
+
if (!emailConfig) {
|
|
1693
|
+
setError("Configuration not loaded. Please refresh the page.");
|
|
1694
|
+
setLoading(false);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
if (newPassword !== confirmPassword) {
|
|
1698
|
+
setError("Passwords do not match");
|
|
1699
|
+
setLoading(false);
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
if (!token) {
|
|
1703
|
+
setError("Reset token is missing");
|
|
1704
|
+
setLoading(false);
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
const passwordZodSchema = createPasswordSchema({
|
|
1708
|
+
minLength: emailConfig.passwordMinLength,
|
|
1709
|
+
requireUppercase: emailConfig.requireUppercase,
|
|
1710
|
+
requireLowercase: emailConfig.requireLowercase,
|
|
1711
|
+
requireNumber: emailConfig.requireNumber,
|
|
1712
|
+
requireSpecialChar: emailConfig.requireSpecialChar
|
|
1713
|
+
});
|
|
1714
|
+
const passwordValidation = passwordZodSchema.safeParse(newPassword);
|
|
1715
|
+
if (!passwordValidation.success) {
|
|
1716
|
+
const firstError = passwordValidation.error.issues[0];
|
|
1717
|
+
setError(firstError.message);
|
|
1718
|
+
setLoading(false);
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
try {
|
|
1722
|
+
const result = await resetPassword(token, newPassword);
|
|
1723
|
+
if (result?.message) {
|
|
1724
|
+
if (onSuccess) {
|
|
1725
|
+
onSuccess(result.redirectTo);
|
|
1726
|
+
}
|
|
1727
|
+
} else {
|
|
1728
|
+
const errorMessage = "Failed to reset password";
|
|
1729
|
+
setError(errorMessage);
|
|
1730
|
+
if (onError) {
|
|
1731
|
+
onError(new Error(errorMessage));
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
} catch (err) {
|
|
1735
|
+
const errorMessage = err.message || "Failed to reset password";
|
|
1736
|
+
setError(errorMessage);
|
|
1737
|
+
if (onError) {
|
|
1738
|
+
onError(new Error(errorMessage));
|
|
1739
|
+
}
|
|
1740
|
+
} finally {
|
|
1741
|
+
setLoading(false);
|
|
1742
|
+
}
|
|
1694
1743
|
}
|
|
1695
|
-
if (
|
|
1696
|
-
return
|
|
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
|
-
] }) }) });
|
|
1744
|
+
if (!emailConfig) {
|
|
1745
|
+
return null;
|
|
1703
1746
|
}
|
|
1704
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1747
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1748
|
+
ResetPasswordForm,
|
|
1749
|
+
{
|
|
1750
|
+
newPassword,
|
|
1751
|
+
confirmPassword,
|
|
1752
|
+
onNewPasswordChange: setNewPassword,
|
|
1753
|
+
onConfirmPasswordChange: setConfirmPassword,
|
|
1754
|
+
onSubmit: handleSubmit,
|
|
1755
|
+
error,
|
|
1756
|
+
loading,
|
|
1757
|
+
emailAuthConfig: emailConfig,
|
|
1758
|
+
backToSignInUrl,
|
|
1759
|
+
...uiProps
|
|
1760
|
+
}
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1763
|
+
function ForgotPassword({
|
|
1764
|
+
backToSignInUrl = "/sign-in",
|
|
1765
|
+
onSuccess,
|
|
1766
|
+
onError,
|
|
1767
|
+
...uiProps
|
|
1768
|
+
}) {
|
|
1769
|
+
const { sendPasswordResetCode, baseUrl } = useInsforge();
|
|
1770
|
+
const { emailConfig } = usePublicAuthConfig();
|
|
1771
|
+
const [insforge] = react.useState(() => sdk.createClient({ baseUrl }));
|
|
1772
|
+
const [step, setStep] = react.useState("email");
|
|
1773
|
+
const [email, setEmail] = react.useState("");
|
|
1774
|
+
const [verificationCode, setVerificationCode] = react.useState("");
|
|
1775
|
+
const [resetToken, setResetToken] = react.useState("");
|
|
1776
|
+
const [error, setError] = react.useState("");
|
|
1777
|
+
const [loading, setLoading] = react.useState(false);
|
|
1778
|
+
const [success, setSuccess] = react.useState(false);
|
|
1779
|
+
const [resendDisabled, setResendDisabled] = react.useState(true);
|
|
1780
|
+
const [resendCountdown, setResendCountdown] = react.useState(60);
|
|
1781
|
+
const [isSendingCode, setIsSendingCode] = react.useState(false);
|
|
1782
|
+
const [isVerifyingCode, setIsVerifyingCode] = react.useState(false);
|
|
1783
|
+
react.useEffect(() => {
|
|
1784
|
+
if (resendCountdown > 0 && step === "code") {
|
|
1785
|
+
const timer = setInterval(() => {
|
|
1786
|
+
setResendCountdown((prev) => {
|
|
1787
|
+
if (prev <= 1) {
|
|
1788
|
+
setResendDisabled(false);
|
|
1789
|
+
return 0;
|
|
1790
|
+
}
|
|
1791
|
+
return prev - 1;
|
|
1792
|
+
});
|
|
1793
|
+
}, 1e3);
|
|
1794
|
+
return () => clearInterval(timer);
|
|
1795
|
+
}
|
|
1796
|
+
}, [resendCountdown, step]);
|
|
1797
|
+
async function handleEmailSubmit(e) {
|
|
1798
|
+
e.preventDefault();
|
|
1799
|
+
setLoading(true);
|
|
1800
|
+
setError("");
|
|
1801
|
+
const emailValidation = emailSchema.safeParse(email);
|
|
1802
|
+
if (!emailValidation.success) {
|
|
1803
|
+
const firstError = emailValidation.error.issues[0];
|
|
1804
|
+
setError(firstError.message);
|
|
1805
|
+
setLoading(false);
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
try {
|
|
1809
|
+
const result = await sendPasswordResetCode(emailValidation.data);
|
|
1810
|
+
if (result?.success) {
|
|
1811
|
+
if (emailConfig?.resetPasswordMethod === "link") {
|
|
1812
|
+
setSuccess(true);
|
|
1813
|
+
if (onSuccess) {
|
|
1814
|
+
onSuccess();
|
|
1815
|
+
}
|
|
1816
|
+
} else {
|
|
1817
|
+
setStep("code");
|
|
1818
|
+
setResendDisabled(true);
|
|
1819
|
+
setResendCountdown(60);
|
|
1820
|
+
}
|
|
1821
|
+
} else {
|
|
1822
|
+
const errorMessage = result?.message || "Failed to send reset code";
|
|
1823
|
+
setError(errorMessage);
|
|
1824
|
+
if (onError) {
|
|
1825
|
+
onError(new Error(errorMessage));
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
} catch (err) {
|
|
1829
|
+
const errorMessage = err.message || "Failed to send reset code";
|
|
1830
|
+
setError(errorMessage);
|
|
1831
|
+
if (onError) {
|
|
1832
|
+
onError(new Error(errorMessage));
|
|
1833
|
+
}
|
|
1834
|
+
} finally {
|
|
1835
|
+
setLoading(false);
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
async function handleVerifyCode(code) {
|
|
1839
|
+
setIsVerifyingCode(true);
|
|
1840
|
+
setError("");
|
|
1841
|
+
setVerificationCode(code);
|
|
1842
|
+
try {
|
|
1843
|
+
const result = await insforge.auth.verifyResetPasswordCode({ email, code });
|
|
1844
|
+
if (result.error) {
|
|
1845
|
+
throw new Error(result.error.message || "Failed to verify code");
|
|
1846
|
+
}
|
|
1847
|
+
if (result.data) {
|
|
1848
|
+
setResetToken(result.data.resetToken);
|
|
1849
|
+
setStep("password");
|
|
1850
|
+
}
|
|
1851
|
+
} catch (err) {
|
|
1852
|
+
setError(err.message || "Invalid verification code");
|
|
1853
|
+
setVerificationCode("");
|
|
1854
|
+
} finally {
|
|
1855
|
+
setIsVerifyingCode(false);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
const handleResendCode = react.useCallback(async () => {
|
|
1859
|
+
setResendDisabled(true);
|
|
1860
|
+
setResendCountdown(60);
|
|
1861
|
+
setIsSendingCode(true);
|
|
1862
|
+
setError("");
|
|
1863
|
+
try {
|
|
1864
|
+
await sendPasswordResetCode(email);
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
setError(err.message || "Failed to resend code");
|
|
1867
|
+
setResendDisabled(false);
|
|
1868
|
+
setResendCountdown(0);
|
|
1869
|
+
} finally {
|
|
1870
|
+
setIsSendingCode(false);
|
|
1871
|
+
}
|
|
1872
|
+
}, [email, sendPasswordResetCode]);
|
|
1873
|
+
function handlePasswordResetSuccess() {
|
|
1874
|
+
if (onSuccess) {
|
|
1875
|
+
onSuccess();
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
if (!emailConfig) {
|
|
1879
|
+
return null;
|
|
1880
|
+
}
|
|
1881
|
+
if (step === "email") {
|
|
1882
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1883
|
+
ForgotPasswordForm,
|
|
1884
|
+
{
|
|
1885
|
+
email,
|
|
1886
|
+
onEmailChange: setEmail,
|
|
1887
|
+
onSubmit: handleEmailSubmit,
|
|
1888
|
+
error,
|
|
1889
|
+
loading,
|
|
1890
|
+
success,
|
|
1891
|
+
backToSignInUrl,
|
|
1892
|
+
...uiProps
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
if (step === "code") {
|
|
1897
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1898
|
+
AuthContainer,
|
|
1899
|
+
{
|
|
1900
|
+
appearance: {
|
|
1901
|
+
containerClassName: uiProps.appearance?.container,
|
|
1902
|
+
cardClassName: uiProps.appearance?.card
|
|
1903
|
+
},
|
|
1904
|
+
children: [
|
|
1905
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1906
|
+
AuthHeader,
|
|
1907
|
+
{
|
|
1908
|
+
title: "Enter Reset Code",
|
|
1909
|
+
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.`,
|
|
1910
|
+
appearance: {
|
|
1911
|
+
containerClassName: uiProps.appearance?.header?.container,
|
|
1912
|
+
titleClassName: uiProps.appearance?.header?.title,
|
|
1913
|
+
subtitleClassName: uiProps.appearance?.header?.subtitle
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
),
|
|
1917
|
+
/* @__PURE__ */ jsxRuntime.jsx(AuthErrorBanner, { error, className: uiProps.appearance?.errorBanner }),
|
|
1918
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col gap-6 items-center", children: [
|
|
1919
|
+
/* @__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: [
|
|
1920
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1921
|
+
AuthVerificationCodeInput,
|
|
1922
|
+
{
|
|
1923
|
+
value: verificationCode,
|
|
1924
|
+
onChange: setVerificationCode,
|
|
1925
|
+
email,
|
|
1926
|
+
disabled: isVerifyingCode,
|
|
1927
|
+
onComplete: (code) => {
|
|
1928
|
+
void handleVerifyCode(code);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1932
|
+
isVerifyingCode && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: "Verifying..." })
|
|
1933
|
+
] }) }),
|
|
1934
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full text-sm text-center text-neutral-600 dark:text-neutral-400", children: [
|
|
1935
|
+
"Didn't receive the email?",
|
|
1936
|
+
" ",
|
|
1937
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1938
|
+
"button",
|
|
1939
|
+
{
|
|
1940
|
+
onClick: () => {
|
|
1941
|
+
void handleResendCode();
|
|
1942
|
+
},
|
|
1943
|
+
disabled: resendDisabled || isSendingCode,
|
|
1944
|
+
className: "text-black dark:text-white font-medium transition-colors disabled:cursor-not-allowed cursor-pointer hover:underline disabled:no-underline disabled:opacity-50",
|
|
1945
|
+
children: isSendingCode ? "Sending..." : resendDisabled ? `Retry in (${resendCountdown}s)` : "Click to resend"
|
|
1946
|
+
}
|
|
1947
|
+
)
|
|
1948
|
+
] })
|
|
1949
|
+
] }),
|
|
1950
|
+
/* @__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" }) })
|
|
1951
|
+
]
|
|
1952
|
+
}
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1956
|
+
ResetPassword,
|
|
1957
|
+
{
|
|
1958
|
+
token: resetToken,
|
|
1959
|
+
backToSignInUrl,
|
|
1960
|
+
onSuccess: handlePasswordResetSuccess,
|
|
1961
|
+
onError,
|
|
1962
|
+
appearance: uiProps.appearance
|
|
1963
|
+
}
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
function VerifyEmailStatus({
|
|
1967
|
+
status,
|
|
1968
|
+
error,
|
|
1969
|
+
appearance = {},
|
|
1970
|
+
verifyingTitle = "Verifying your email...",
|
|
1971
|
+
successTitle = "Email Verified!",
|
|
1972
|
+
successMessage = "Your email has been verified successfully. You can close this page and return to your app.",
|
|
1973
|
+
errorTitle = "Verification Failed"
|
|
1974
|
+
}) {
|
|
1975
|
+
if (status === "verifying") {
|
|
1976
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContainer, { appearance, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center gap-6", children: [
|
|
1977
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white", children: verifyingTitle }),
|
|
1978
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-black dark:border-white" })
|
|
1979
|
+
] }) });
|
|
1980
|
+
}
|
|
1981
|
+
if (status === "error") {
|
|
1982
|
+
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: [
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold text-black dark:text-white", children: errorTitle }),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed", children: [
|
|
1985
|
+
error || "The verification link is invalid or has expired.",
|
|
1986
|
+
" Please try again or contact support if the problem persists. You can close this page and return to your app."
|
|
1987
|
+
] })
|
|
1988
|
+
] }) }) });
|
|
1989
|
+
}
|
|
1990
|
+
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: [
|
|
1991
|
+
/* @__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" }) }) }),
|
|
1992
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white text-center", children: successTitle }),
|
|
1993
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 text-center", children: successMessage })
|
|
1994
|
+
] }) }) });
|
|
1995
|
+
}
|
|
1996
|
+
function VerifyEmail({
|
|
1997
|
+
token,
|
|
1998
|
+
onSuccess,
|
|
1999
|
+
onError,
|
|
2000
|
+
...uiProps
|
|
2001
|
+
}) {
|
|
2002
|
+
const { verifyEmail } = useInsforge();
|
|
2003
|
+
const [status, setStatus] = react.useState("verifying");
|
|
2004
|
+
const [error, setError] = react.useState("");
|
|
2005
|
+
react.useEffect(() => {
|
|
2006
|
+
const verifyEmailFn = async () => {
|
|
2007
|
+
if (!token) {
|
|
2008
|
+
const errorMessage = "Invalid verification link. Missing required token.";
|
|
2009
|
+
setError(errorMessage);
|
|
2010
|
+
setStatus("error");
|
|
2011
|
+
if (onError) {
|
|
2012
|
+
onError(new Error(errorMessage));
|
|
2013
|
+
}
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
2016
|
+
try {
|
|
2017
|
+
const result = await verifyEmail(token);
|
|
2018
|
+
if (!result?.accessToken) {
|
|
2019
|
+
const errorMessage = result ? "Verification succeeded but no access token received" : "Email verification failed";
|
|
2020
|
+
setError(errorMessage);
|
|
2021
|
+
setStatus("error");
|
|
2022
|
+
if (onError) {
|
|
2023
|
+
onError(new Error(errorMessage));
|
|
2024
|
+
}
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
setStatus("success");
|
|
2028
|
+
if (onSuccess) {
|
|
2029
|
+
onSuccess({
|
|
2030
|
+
accessToken: result.accessToken,
|
|
2031
|
+
user: result.user
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
} catch (err) {
|
|
2035
|
+
const errorMessage = err.message || "Email verification failed";
|
|
2036
|
+
setError(errorMessage);
|
|
2037
|
+
setStatus("error");
|
|
2038
|
+
if (onError) {
|
|
2039
|
+
onError(new Error(errorMessage));
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
void verifyEmailFn();
|
|
2044
|
+
}, [token, verifyEmail, onSuccess, onError]);
|
|
2045
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VerifyEmailStatus, { status, error, ...uiProps });
|
|
2046
|
+
}
|
|
2047
|
+
function UserButton({
|
|
2048
|
+
afterSignOutUrl = "/",
|
|
2049
|
+
mode = "detailed",
|
|
2050
|
+
appearance = {}
|
|
2051
|
+
}) {
|
|
2052
|
+
const { user, signOut } = useInsforge();
|
|
2053
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
2054
|
+
const [imageError, setImageError] = react.useState(false);
|
|
2055
|
+
const dropdownRef = react.useRef(null);
|
|
2056
|
+
react.useEffect(() => {
|
|
2057
|
+
setImageError(false);
|
|
2058
|
+
const avatarUrl = user?.avatarUrl;
|
|
2059
|
+
if (!avatarUrl) return;
|
|
2060
|
+
const checkImageUrl = async () => {
|
|
2061
|
+
try {
|
|
2062
|
+
const response = await fetch(avatarUrl, {
|
|
2063
|
+
method: "HEAD",
|
|
2064
|
+
cache: "no-cache"
|
|
2065
|
+
});
|
|
2066
|
+
if (!response.ok) {
|
|
2067
|
+
setImageError(true);
|
|
2068
|
+
}
|
|
2069
|
+
} catch (error) {
|
|
2070
|
+
setImageError(true);
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
checkImageUrl();
|
|
2074
|
+
}, [user?.avatarUrl]);
|
|
2075
|
+
react.useEffect(() => {
|
|
2076
|
+
function handleClickOutside(event) {
|
|
2077
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
2078
|
+
setIsOpen(false);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
if (isOpen) {
|
|
2082
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2083
|
+
}
|
|
2084
|
+
return () => {
|
|
2085
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2086
|
+
};
|
|
2087
|
+
}, [isOpen]);
|
|
2088
|
+
async function handleSignOut() {
|
|
2089
|
+
await signOut();
|
|
2090
|
+
setIsOpen(false);
|
|
2091
|
+
window.location.href = afterSignOutUrl;
|
|
2092
|
+
}
|
|
2093
|
+
if (!user) return null;
|
|
2094
|
+
const initials = user.name ? user.name.charAt(0).toUpperCase() : user.email.split("@")[0].slice(0, 2).toUpperCase();
|
|
2095
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2096
|
+
"div",
|
|
2097
|
+
{
|
|
2098
|
+
className: cn("relative inline-block", appearance.containerClassName),
|
|
2099
|
+
ref: dropdownRef,
|
|
2100
|
+
children: [
|
|
2101
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2102
|
+
"button",
|
|
2103
|
+
{
|
|
2104
|
+
className: cn(
|
|
2105
|
+
"p-1 bg-transparent border-0 rounded-full cursor-pointer transition-all duration-200",
|
|
2106
|
+
"flex items-center justify-center gap-2",
|
|
2107
|
+
"hover:bg-black/5",
|
|
2108
|
+
mode === "detailed" && "rounded-lg p-2",
|
|
2109
|
+
appearance.buttonClassName
|
|
2110
|
+
),
|
|
2111
|
+
onClick: () => setIsOpen(!isOpen),
|
|
2112
|
+
"aria-expanded": isOpen,
|
|
2113
|
+
"aria-haspopup": "true",
|
|
2114
|
+
children: [
|
|
2115
|
+
/* @__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(
|
|
2116
|
+
"img",
|
|
2117
|
+
{
|
|
2118
|
+
src: user.avatarUrl,
|
|
2119
|
+
alt: user.email,
|
|
2120
|
+
onError: () => setImageError(true),
|
|
2121
|
+
className: "rounded-full object-cover w-full h-full"
|
|
2122
|
+
}
|
|
2123
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white font-semibold text-sm", children: initials }) }),
|
|
2124
|
+
mode === "detailed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-0.5", children: [
|
|
2125
|
+
user.name && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2126
|
+
"div",
|
|
2127
|
+
{
|
|
2128
|
+
className: cn(
|
|
2129
|
+
"text-sm font-semibold text-gray-900 leading-5 text-left",
|
|
2130
|
+
appearance.nameClassName
|
|
2131
|
+
),
|
|
2132
|
+
children: user.name
|
|
2133
|
+
}
|
|
2134
|
+
),
|
|
2135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2136
|
+
"div",
|
|
2137
|
+
{
|
|
2138
|
+
className: cn(
|
|
2139
|
+
"text-xs text-gray-500 leading-4 text-left",
|
|
2140
|
+
appearance.emailClassName
|
|
2141
|
+
),
|
|
2142
|
+
children: user.email
|
|
2143
|
+
}
|
|
2144
|
+
)
|
|
2145
|
+
] })
|
|
2146
|
+
]
|
|
2147
|
+
}
|
|
2148
|
+
),
|
|
2149
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2150
|
+
"div",
|
|
2151
|
+
{
|
|
2152
|
+
className: cn(
|
|
2153
|
+
"absolute top-full right-0 mt-2 min-w-40",
|
|
2154
|
+
"bg-white border border-gray-200 rounded-lg",
|
|
2155
|
+
"shadow-lg z-50 overflow-hidden p-1",
|
|
2156
|
+
appearance.dropdownClassName
|
|
2157
|
+
),
|
|
2158
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2159
|
+
"button",
|
|
2160
|
+
{
|
|
2161
|
+
onClick: handleSignOut,
|
|
2162
|
+
className: "flex items-center justify-start gap-2 w-full px-3 py-2 text-sm font-normal text-red-600 bg-transparent border-0 rounded-md cursor-pointer transition-colors hover:bg-red-50 text-left",
|
|
2163
|
+
children: [
|
|
2164
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LogOut, { className: "w-5 h-5" }),
|
|
2165
|
+
"Sign out"
|
|
2166
|
+
]
|
|
2167
|
+
}
|
|
2168
|
+
)
|
|
2169
|
+
}
|
|
2170
|
+
)
|
|
2171
|
+
]
|
|
2172
|
+
}
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
function Protect({
|
|
2176
|
+
children,
|
|
2177
|
+
fallback,
|
|
2178
|
+
redirectTo = "/sign-in",
|
|
2179
|
+
condition,
|
|
2180
|
+
onRedirect
|
|
2181
|
+
}) {
|
|
2182
|
+
const { isSignedIn, isLoaded, user } = useInsforge();
|
|
2183
|
+
react.useEffect(() => {
|
|
2184
|
+
if (isLoaded && !isSignedIn) {
|
|
2185
|
+
if (onRedirect) {
|
|
2186
|
+
onRedirect(redirectTo);
|
|
2187
|
+
} else {
|
|
2188
|
+
window.location.href = redirectTo;
|
|
2189
|
+
}
|
|
2190
|
+
} else if (isLoaded && isSignedIn && condition && user) {
|
|
2191
|
+
if (!condition(user)) {
|
|
2192
|
+
if (onRedirect) {
|
|
2193
|
+
onRedirect(redirectTo);
|
|
2194
|
+
} else {
|
|
2195
|
+
window.location.href = redirectTo;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
}, [isLoaded, isSignedIn, redirectTo, condition, user, onRedirect]);
|
|
2200
|
+
if (!isLoaded) {
|
|
2201
|
+
return fallback || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "insforge-loading", children: "Loading..." });
|
|
2202
|
+
}
|
|
2203
|
+
if (!isSignedIn) {
|
|
2204
|
+
return fallback || null;
|
|
2205
|
+
}
|
|
2206
|
+
if (condition && user && !condition(user)) {
|
|
2207
|
+
return fallback || null;
|
|
2208
|
+
}
|
|
2209
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2210
|
+
}
|
|
2211
|
+
function SignedIn({ children }) {
|
|
2212
|
+
const { isSignedIn, isLoaded } = useInsforge();
|
|
2213
|
+
if (!isLoaded) return null;
|
|
2214
|
+
if (!isSignedIn) return null;
|
|
2215
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2216
|
+
}
|
|
2217
|
+
function SignedOut({ children }) {
|
|
2218
|
+
const { isSignedIn, isLoaded } = useInsforge();
|
|
2219
|
+
if (!isLoaded) return null;
|
|
2220
|
+
if (isSignedIn) return null;
|
|
2221
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2222
|
+
}
|
|
2223
|
+
function InsforgeCallback({
|
|
2224
|
+
redirectTo = "/",
|
|
2225
|
+
onSuccess,
|
|
2226
|
+
onError,
|
|
2227
|
+
loadingComponent,
|
|
2228
|
+
onRedirect
|
|
2229
|
+
}) {
|
|
2230
|
+
const isProcessingRef = react.useRef(false);
|
|
2231
|
+
const { isLoaded, isSignedIn } = useInsforge();
|
|
2232
|
+
react.useEffect(() => {
|
|
2233
|
+
if (!isLoaded) return;
|
|
2234
|
+
if (isProcessingRef.current) return;
|
|
2235
|
+
isProcessingRef.current = true;
|
|
2236
|
+
const processCallback = async () => {
|
|
2237
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
2238
|
+
const error = searchParams.get("error");
|
|
2239
|
+
if (error) {
|
|
2240
|
+
if (onError) {
|
|
2241
|
+
onError(error);
|
|
2242
|
+
} else {
|
|
2243
|
+
const errorUrl = "/?error=" + encodeURIComponent(error);
|
|
2244
|
+
if (onRedirect) {
|
|
2245
|
+
onRedirect(errorUrl);
|
|
2246
|
+
} else {
|
|
2247
|
+
window.location.href = errorUrl;
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
if (!isSignedIn) {
|
|
2253
|
+
const errorMsg = "authentication_failed";
|
|
2254
|
+
if (onError) {
|
|
2255
|
+
onError(errorMsg);
|
|
2256
|
+
} else {
|
|
2257
|
+
const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
|
|
2258
|
+
if (onRedirect) {
|
|
2259
|
+
onRedirect(errorUrl);
|
|
2260
|
+
} else {
|
|
2261
|
+
window.location.href = errorUrl;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2266
|
+
window.history.replaceState({}, "", window.location.pathname);
|
|
2267
|
+
if (onSuccess) {
|
|
2268
|
+
onSuccess();
|
|
2269
|
+
}
|
|
2270
|
+
if (onRedirect) {
|
|
2271
|
+
onRedirect(redirectTo);
|
|
2272
|
+
} else {
|
|
2273
|
+
window.location.href = redirectTo;
|
|
2274
|
+
}
|
|
2275
|
+
};
|
|
2276
|
+
processCallback();
|
|
2277
|
+
}, [isLoaded, isSignedIn, redirectTo, onSuccess, onError, onRedirect]);
|
|
2278
|
+
const defaultLoading = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
2279
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold mb-4", children: "Completing authentication..." }),
|
|
2280
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto" })
|
|
2281
|
+
] }) });
|
|
2282
|
+
return loadingComponent || defaultLoading;
|
|
1709
2283
|
}
|
|
1710
2284
|
|
|
1711
2285
|
exports.AuthBranding = AuthBranding;
|
|
1712
2286
|
exports.AuthContainer = AuthContainer;
|
|
1713
2287
|
exports.AuthDivider = AuthDivider;
|
|
2288
|
+
exports.AuthEmailVerificationStep = AuthEmailVerificationStep;
|
|
1714
2289
|
exports.AuthErrorBanner = AuthErrorBanner;
|
|
1715
2290
|
exports.AuthFormField = AuthFormField;
|
|
1716
2291
|
exports.AuthHeader = AuthHeader;
|
|
@@ -1721,9 +2296,11 @@ exports.AuthPasswordField = AuthPasswordField;
|
|
|
1721
2296
|
exports.AuthPasswordStrengthIndicator = AuthPasswordStrengthIndicator;
|
|
1722
2297
|
exports.AuthSubmitButton = AuthSubmitButton;
|
|
1723
2298
|
exports.AuthVerificationCodeInput = AuthVerificationCodeInput;
|
|
2299
|
+
exports.ForgotPassword = ForgotPassword;
|
|
1724
2300
|
exports.ForgotPasswordForm = ForgotPasswordForm;
|
|
1725
2301
|
exports.InsforgeCallback = InsforgeCallback;
|
|
1726
2302
|
exports.Protect = Protect;
|
|
2303
|
+
exports.ResetPassword = ResetPassword;
|
|
1727
2304
|
exports.ResetPasswordForm = ResetPasswordForm;
|
|
1728
2305
|
exports.SignIn = SignIn;
|
|
1729
2306
|
exports.SignInForm = SignInForm;
|
|
@@ -1732,6 +2309,7 @@ exports.SignUpForm = SignUpForm;
|
|
|
1732
2309
|
exports.SignedIn = SignedIn;
|
|
1733
2310
|
exports.SignedOut = SignedOut;
|
|
1734
2311
|
exports.UserButton = UserButton;
|
|
2312
|
+
exports.VerifyEmail = VerifyEmail;
|
|
1735
2313
|
exports.VerifyEmailStatus = VerifyEmailStatus;
|
|
1736
2314
|
exports.validatePasswordStrength = validatePasswordStrength;
|
|
1737
2315
|
//# sourceMappingURL=components.js.map
|