tremor-tracker/src/components/AuthModal.tsx

123 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import axios from "axios";
import { FormEvent, MouseEvent, useEffect, useRef, useState } from "react";
interface AuthModalProps {
isOpen: boolean; // bool for if the modal should be visible
onClose: () => void; //A function that will be executed to close the modal
}
export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const [isLogin, setIsLogin] = useState<boolean>(true);
const modalRef = useRef<HTMLDivElement>(null);
const [isFailed, setIsFailed] = useState<boolean>(false);
const [failMessage, setFailMessage] = useState<boolean>(false);
useEffect(() => {
if (isOpen) setIsLogin(true); // runs when isOpen changes, if it is true, the login is shown
}, [isOpen]);
if (!isOpen) return null; // if is open is false, the model isnt shown
const handleOverlayClick = (e: MouseEvent<HTMLDivElement>) => {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
onClose();
}
};
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); // stops page from refreshing
setIsFailed(false);
const formData = new FormData(e.currentTarget);
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const name = isLogin ? undefined : (formData.get("name") as string);
try {
const res = await axios.post(`/api/${isLogin ? "login" : "signup"}`, {
headers: { "Content-Type": "application/json" },
body: isLogin ? { email, password } : { name: name!, email, password },
});
if (res.status) {
onClose();
} else if (res.status >= 400 && res.status < 500) {
console.log("4xx error:", res.data);
setFailMessage(res.data.message);
setIsFailed(true);
} else {
console.error("Error:", await res.data.message);
}
} catch (error) {
console.error("Request failed:", error instanceof Error ? error.message : String(error));
}
};
return (
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50" onClick={handleOverlayClick}>
<div ref={modalRef} className="bg-white rounded-lg shadow-lg p-6 w-full max-w-md relative">
<button
onClick={() => {
setIsFailed(false);
onClose();
}}
className="absolute text-xl top-0 right-2 text-neutral-500 hover:text-neutral-700"
aria-label="Close modal"
>
×
</button>
<h2 className="text-2xl font-bold text-center mb-4">{isLogin ? "Login" : "Sign Up"}</h2>
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-4">
{!isLogin && (
<div>
<label className="block text-sm font-medium text-neutral-700">Full Name</label>
<input
type="text"
name="name"
className="mt-1 w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required={!isLogin}
/>
</div>
)}
<div>
<label className="block text-sm font-medium text-neutral-700">Email</label>
<input
type="email"
name="email"
className="mt-1 w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-neutral-700">Password</label>
<input
type="password"
name="password"
className="mt-1 w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
<div>
{isFailed && (
<div>
<label className="block text-sm font-medium text-red-700">{failMessage}</label>
</div>
)}
</div>
<button type="submit" className="w-full bg-blue-600 text-white p-2 rounded-md hover:bg-blue-700 transition">
{isLogin ? "Login" : "Sign Up"}
</button>
</form>
<p className="mt-4 text-center text-sm">
{isLogin ? "Need an account?" : "Already have an account?"}{" "}
<button onClick={() => setIsLogin(!isLogin)} className="text-blue-600 hover:underline">
{isLogin ? "Sign Up" : "Login"}
</button>
</p>
</div>
</div>
);
}