UNPKG

@salad-labs/loopz-typescript

Version:
295 lines 14.4 kB
"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