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