tremor-tracker/src/components/AuthModal.tsx

123 lines
4.0 KiB
TypeScript
Raw Normal View History

2025-03-19 19:20:18 +00:00
"use client";
2025-05-04 16:04:44 +01:00
import axios from "axios";
import { FormEvent, MouseEvent, useEffect, useRef, useState } from "react";
2025-04-28 19:03:29 +01:00
2025-03-19 19:20:18 +00:00
interface AuthModalProps {
2025-04-28 19:03:29 +01:00
isOpen: boolean; // bool for if the modal should be visible
onClose: () => void; //A function that will be executed to close the modal
2025-03-19 19:20:18 +00:00
}
2025-04-29 18:07:25 +01:00
2025-04-28 19:03:29 +01:00
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);
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
useEffect(() => {
if (isOpen) setIsLogin(true); // runs when isOpen changes, if it is true, the login is shown
}, [isOpen]);
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
if (!isOpen) return null; // if is open is false, the model isnt shown
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
const handleOverlayClick = (e: MouseEvent<HTMLDivElement>) => {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
onClose();
}
};
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); // stops page from refreshing
setIsFailed(false);
2025-04-29 18:07:25 +01:00
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);
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
try {
2025-04-29 18:07:25 +01:00
const res = await axios.post(`/api/${isLogin ? "login" : "signup"}`, {
headers: { "Content-Type": "application/json" },
body: isLogin ? { email, password } : { name: name!, email, password },
2025-04-28 19:03:29 +01:00
});
2025-04-29 18:07:25 +01:00
if (res.status) {
onClose();
2025-04-28 19:03:29 +01:00
} else if (res.status >= 400 && res.status < 500) {
2025-04-29 18:07:25 +01:00
console.log("4xx error:", res.data);
setFailMessage(res.data.message);
2025-04-28 19:03:29 +01:00
setIsFailed(true);
} else {
2025-04-29 18:07:25 +01:00
console.error("Error:", await res.data.message);
2025-04-28 19:03:29 +01:00
}
} catch (error) {
console.error("Request failed:", error instanceof Error ? error.message : String(error));
}
};
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
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>
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
{/* 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>
2025-03-19 19:20:18 +00:00
2025-04-28 19:03:29 +01:00
<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>
);
2025-03-19 19:20:18 +00:00
}