@salad-labs/loopz-typescript
Version:
The Official Loopz TypeScript SDK
295 lines • 14.4 kB
JavaScript
"use client";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import React, { useCallback, useEffect, useState } from "react";
import { Auth, useLoopz } from "../../";
import { LoopzAuthContext } from "../context";
import LoopzEmailForm from "./loopzemailform";
import { BACKEND_URLS, CLIENT_DB_KEY_REFRESH_TOKEN, CLIENT_DB_KEY_TOKEN, } from "../../constants/app";
import { jwtDecode } from "jwt-decode";
import fetchApi from "../../core/utilities/fetchapi";
import refreshToken from "../../core/auth/refreshtoken";
export const LoopzAuth = ({ devMode, children, intl, apiKey, logoURL, tosURL, privacyURL }) => {
const ENDPOINT = devMode ? BACKEND_URLS.development : BACKEND_URLS.production;
const { instance, initialized } = useLoopz();
const [authToken, setAuthToken] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [showEmailForm, setShowEmailForm] = useState(false);
const [email, setEmail] = useState("");
const [code, setCode] = useState("");
const [step, setStep] = useState("email");
const [success, setSuccess] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [isFormVisible, setIsFormVisible] = useState(false);
const [referralCode, setReferralCode] = useState(null);
useEffect(() => {
if (typeof window !== "undefined") {
const params = new URLSearchParams(window.location.search);
const referralCode = params.get("code");
if (referralCode)
setReferralCode(referralCode);
}
}, []);
const verifyToken = (token) => {
try {
const decoded = jwtDecode(token);
if (!decoded.email || !decoded.did)
return false;
const currentTime = Date.now() / 1000;
if (decoded.exp && decoded.exp < currentTime)
return false;
if (!decoded.iat)
return false;
const maxAgeSeconds = 18 * 60 * 60; // 64800
if (currentTime - decoded.iat > maxAgeSeconds)
return false;
return true;
}
catch (error) {
console.error("Invalid token:", error);
return false;
}
};
const requestOtpCode = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
setLoading(true);
setError(null);
try {
const { data, response } = yield fetchApi(`${ENDPOINT}/auth/request-code`, {
method: "POST",
body: JSON.stringify({ email }),
});
if (response.ok) {
setSuccess((intl === null || intl === void 0 ? void 0 : intl.successRequestOtpCode)
? intl.successRequestOtpCode
: "Verification code sent to your email");
setStep("code");
}
else {
setError((_b = (_a = data.message) !== null && _a !== void 0 ? _a : intl === null || intl === void 0 ? void 0 : intl.failedSendRequestOtpCode) !== null && _b !== void 0 ? _b : "Failed to send verification code");
}
}
catch (err) {
console.log(err);
setError((intl === null || intl === void 0 ? void 0 : intl.networkError)
? intl.networkError
: "Network error. Please try again.");
if (Auth && typeof Auth._emit === "function") {
Auth._emit("__onLoginError", err);
}
}
finally {
setLoading(false);
}
}), [email, ENDPOINT, intl]);
const verifyOtpCode = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
setLoading(true);
setError(null);
try {
const { data: r, response } = yield fetchApi(`${ENDPOINT}/auth/verify-code`, {
method: "POST",
body: JSON.stringify({ email, code }),
headers: {
"x-api-key": apiKey,
},
});
if (response.ok) {
const { data } = r;
// Save JWT token to localStorage
localStorage.setItem(CLIENT_DB_KEY_TOKEN, data.token);
localStorage.setItem(CLIENT_DB_KEY_REFRESH_TOKEN, data.refreshToken);
setSuccess((intl === null || intl === void 0 ? void 0 : intl.authSuccess) ? intl.authSuccess : "Authentication successful");
if (Auth && typeof Auth._emit === "function") {
Auth._emit("__onLoginComplete", {
user: {
email: data.email,
id: data.did,
},
authToken: data.token,
referralCode,
});
}
setTimeout(() => {
closeEmailForm();
}, 1500);
}
else {
setError((_b = (_a = r.data.message) !== null && _a !== void 0 ? _a : intl === null || intl === void 0 ? void 0 : intl.invalidOtpCode) !== null && _b !== void 0 ? _b : "Failed to send verification code");
}
}
catch (err) {
setError((intl === null || intl === void 0 ? void 0 : intl.networkError)
? intl.networkError
: "Network error. Please try again.");
if (Auth && typeof Auth._emit === "function") {
Auth._emit("__onLoginError", err);
}
}
finally {
setLoading(false);
}
}), [email, code, ENDPOINT, apiKey, intl, referralCode]);
const closeEmailForm = useCallback(() => {
setIsFormVisible(false);
if (typeof document === "undefined")
return;
document.body.style.overflow = "auto";
setTimeout(() => {
setShowEmailForm(false);
setEmail("");
setCode("");
setStep("email");
setSuccess("");
setError(null);
}, 300);
Auth._emit("__onLoginError", {
error: "user_exit_auth_flow",
});
}, []);
const logout = useCallback(() => {
setAuthToken(null);
setIsAuthenticated(false);
closeEmailForm();
setLoading(false);
if (Auth && typeof Auth._emit === "function") {
Auth._emit("__onLogoutComplete", true);
}
}, [closeEmailForm]);
const handleAuthenticate = useCallback(() => {
try {
if (typeof document === "undefined")
return;
document.body.style.overflow = "hidden";
setShowEmailForm(true);
setTimeout(() => {
setIsFormVisible(true);
}, 50);
}
catch (error) {
console.error("Error handling authentication:", error);
}
}, []);
useEffect(() => {
if (initialized && instance) {
if (instance.auth && typeof instance.auth.on === "function") {
instance.auth.on("__authenticate", handleAuthenticate);
instance.auth.on("__dismiss", closeEmailForm);
instance.auth.on("__onAccountReady", () => {
console.log("emitting auth...");
if (Auth && typeof Auth._emit === "function") {
Auth._emit("auth");
}
}, true);
instance.auth.on("logout", logout);
}
try {
const token = localStorage.getItem(CLIENT_DB_KEY_TOKEN);
if (token) {
const isValidToken = verifyToken(token);
if (isValidToken) {
setAuthToken(token);
setIsAuthenticated(true);
}
else {
refreshToken(devMode)
.then((token) => {
setAuthToken(token);
setIsAuthenticated(true);
})
.catch((error) => {
console.log(error);
localStorage.removeItem(CLIENT_DB_KEY_TOKEN);
localStorage.removeItem(CLIENT_DB_KEY_REFRESH_TOKEN);
setAuthToken(null);
setIsAuthenticated(false);
});
}
}
}
catch (error) {
console.error("Error checking token:", error);
}
}
return () => {
if (initialized &&
instance &&
instance.auth &&
typeof instance.auth.off === "function") {
instance.auth.off("__authenticate", handleAuthenticate);
instance.auth.off("logout", logout);
}
};
}, [initialized, instance, handleAuthenticate, logout]);
useEffect(() => {
if (isAuthenticated && Auth && typeof Auth._emit === "function") {
Auth._emit("__tryRebuildAccountOnRefresh");
}
else if (Auth && typeof Auth._emit === "function") {
Auth._emit("__onLoginError");
}
}, [authToken, isAuthenticated]);
if (!initialized)
return null;
return (React.createElement(LoopzAuthContext.Provider, { value: null },
showEmailForm && (React.createElement("div", { className: "fixed inset-0 flex items-center justify-center", style: {
zIndex: 9999999,
} },
React.createElement("div", { className: `absolute inset-0 bg-black/40 backdrop-blur-2xl transition-opacity duration-300 ${isFormVisible ? "opacity-100" : "opacity-0"}`, onClick: closeEmailForm }),
React.createElement("div", { className: `relative transform transition-all duration-300 ease-out ${isFormVisible
? "opacity-100 scale-100 translate-y-0"
: "opacity-0 scale-95 translate-y-4"}`, style: {
width: 360,
} },
React.createElement(LoopzEmailForm, { handleRequestCode: (e) => __awaiter(void 0, void 0, void 0, function* () {
e.preventDefault();
requestOtpCode();
}), handleVerifyCode: (e) => __awaiter(void 0, void 0, void 0, function* () {
e.preventDefault();
verifyOtpCode();
}), setEmail: setEmail, setCode: setCode, setStep: setStep, email: email, code: code, step: step, logoURL: logoURL, tosURL: tosURL, privacyURL: privacyURL, translations: {
titleApp: (intl === null || intl === void 0 ? void 0 : intl.titleApp) ? intl === null || intl === void 0 ? void 0 : intl.titleApp : "App",
stepVerificationCodeLabel: (intl === null || intl === void 0 ? void 0 : intl.stepVerificationCodeLabel)
? intl.stepVerificationCodeLabel
: "Enter Verification Code",
stepVerificationCodeDescriptionLabel: (intl === null || intl === void 0 ? void 0 : intl.stepVerificationCodeDescriptionLabel)
? intl.stepVerificationCodeDescriptionLabel
: "We've sent you an email with an OTP code. Please check and enter your code below.",
emailAddressFieldLabel: (intl === null || intl === void 0 ? void 0 : intl.emailAddressFieldLabel)
? intl.emailAddressFieldLabel
: "Email Address",
buttonSendingVerificationLabel: (intl === null || intl === void 0 ? void 0 : intl.buttonSendingVerificationLabel)
? intl.buttonSendingVerificationLabel
: "Sending...",
buttonSendVerificationLabel: (intl === null || intl === void 0 ? void 0 : intl.buttonSendVerificationLabel)
? intl.buttonSendVerificationLabel
: "Send Verification Code",
sixDigitDescriptionLabel: (intl === null || intl === void 0 ? void 0 : intl.sixDigitDescriptionLabel)
? intl === null || intl === void 0 ? void 0 : intl.sixDigitDescriptionLabel
: "Please enter the 6-digit code sent to",
backLabel: (intl === null || intl === void 0 ? void 0 : intl.backLabel) ? intl.backLabel : "Back",
buttonVerifyingCodeLabel: (intl === null || intl === void 0 ? void 0 : intl.buttonSendingVerificationLabel)
? intl.buttonSendingVerificationLabel
: "Verifying...",
buttonVerifyCodeLabel: (intl === null || intl === void 0 ? void 0 : intl.buttonVerifyCodeLabel)
? intl.buttonVerifyCodeLabel
: "Verify Code",
resendVerificationCodeLabel: (intl === null || intl === void 0 ? void 0 : intl.resendVerificationCodeLabel)
? intl.resendVerificationCodeLabel
: "Resend Verification Code",
}, loading: loading, error: error, success: success, onClose: closeEmailForm, onBack: () => {
setSuccess("");
setError(null);
setCode("");
} })))),
children));
};
//# sourceMappingURL=loopzauth.js.map