Removed sidebar ,navbar from authentication page. Added confirmation component.

This commit is contained in:
ATUL GUNJAL 2025-04-11 09:37:35 +05:30
parent 26b8410da0
commit 8f931a7403
7 changed files with 604 additions and 87 deletions

View File

@ -1,7 +1,7 @@
'use client';
import { useState, useEffect } from "react";
import { account } from "./lib/appwrite";
import { useRouter } from "next/navigation";
import { useRouter, usePathname } from "next/navigation";
import Sidebar from "./components/Sidebar";
import Navbar from "./components/Navbar";
import { Menu } from 'lucide-react';
@ -12,21 +12,34 @@ export default function ClientLayout({ children }) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);
const router = useRouter();
const pathname = usePathname();
// List of routes where we don't want sidebar/navbar
const authRoutes = ['/login', '/register', '/forgot-password'];
useEffect(() => {
const checkAuth = async () => {
try {
await account.get();
setIsLoggedIn(true);
// If on auth route but logged in, redirect to dashboard
if (authRoutes.includes(pathname)) {
router.push('/dashboard');
}
} catch (error) {
setIsLoggedIn(false);
router.push('/login');
// If not on auth route and not logged in, redirect to login
if (!authRoutes.includes(pathname)) {
router.push('/login');
}
} finally {
setLoading(false);
}
};
checkAuth();
}, [router]);
}, [router, pathname]);
const toggleMobileSidebar = () => {
setIsMobileOpen(!isMobileOpen);
@ -36,19 +49,24 @@ export default function ClientLayout({ children }) {
return <div className="flex items-center justify-center min-h-screen">Loading...</div>;
}
if (!isLoggedIn) {
// If on auth route, render only the children without layout
if (authRoutes.includes(pathname)) {
return (
<div className="min-h-screen">
<main className="p-4 md:p-6">
{children}
</main>
<div className="min-h-screen bg-gray-50">
{children}
</div>
);
}
// If not logged in but not on auth route (shouldn't happen due to redirect above)
if (!isLoggedIn) {
return null; // or redirect to login
}
// Normal layout with sidebar and navbar
return (
<div className="flex min-h-screen">
{/* Mobile Toggle Button (outside sidebar) */}
{/* Mobile Toggle Button */}
<button
onClick={toggleMobileSidebar}
className="md:hidden fixed top-4 left-4 z-50 bg-white dark:bg-gray-800 p-2 rounded-md shadow-md"

View File

@ -0,0 +1,41 @@
'use client';
import { useState } from 'react';
export default function ConfirmationModal({
isOpen,
onClose,
onConfirm,
title = "Confirm Action",
message = "Are you sure you want to perform this action?",
confirmText = "Confirm",
cancelText = "Cancel"
}) {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg shadow-xl max-w-md w-full">
<div className="p-6">
<h3 className="text-lg font-medium text-gray-900 mb-2">{title}</h3>
<p className="text-gray-600 mb-6">{message}</p>
<div className="flex justify-end space-x-3">
<button
onClick={onClose}
className="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
{cancelText}
</button>
<button
onClick={onConfirm}
className="px-4 py-2 bg-red-600 text-white rounded-md text-sm font-medium hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
>
{confirmText}
</button>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,14 +1,56 @@
import { useState } from "react";
import { databases, ID, databaseId, membersCollectionId } from "../lib/appwrite";
'use client';
import { useState, useEffect } from "react";
import { databases, ID, databaseId, membersCollectionId, Query } from "../lib/appwrite";
import { getCurrentUserWithRole } from "../utils/auth";
export default function MemberForm() {
const [currentUser, setCurrentUser] = useState(null);
const [loading, setLoading] = useState(true);
const [form, setForm] = useState({
name: "",
email: "",
phone: "",
role: "",
joinDate: "",
role: "member",
joinDate: new Date().toISOString().split('T')[0],
});
const [error, setError] = useState("");
useEffect(() => {
const fetchCurrentUser = async () => {
try {
const user = await getCurrentUserWithRole();
setCurrentUser(user);
setForm(prev => ({
...prev,
name: user.name || "",
email: user.email || ""
}));
} catch (err) {
console.error("Failed to fetch current user:", err);
setError("Failed to load user data");
} finally {
setLoading(false);
}
};
fetchCurrentUser();
}, []);
const checkDuplicateEmail = async (email) => {
try {
const response = await databases.listDocuments(
databaseId,
membersCollectionId,
[Query.equal("email", email)]
);
return response.documents.length > 0;
} catch (err) {
console.error("Error checking duplicate email:", err);
return false;
}
};
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
@ -16,6 +58,21 @@ export default function MemberForm() {
const handleSubmit = async (e) => {
e.preventDefault();
setError("");
// Validate email matches current user
if (form.email !== currentUser?.email) {
setError("You must use your registered email address");
return;
}
// Check for duplicate entry
const isDuplicate = await checkDuplicateEmail(form.email);
if (isDuplicate) {
setError("This email is already registered as a member");
return;
}
try {
await databases.createDocument(
databaseId,
@ -23,20 +80,119 @@ export default function MemberForm() {
ID.unique(),
form
);
alert("Member added!");
alert("Member added successfully!");
setForm(prev => ({
...prev,
phone: "",
role: "member",
joinDate: new Date().toISOString().split('T')[0]
}));
} catch (err) {
console.error("Failed to add member:", err);
setError("Failed to add member. Please try again.");
}
};
if (loading) {
return <div className="text-center p-4">Loading form...</div>;
}
return (
<form onSubmit={handleSubmit}>
<input name="name" onChange={handleChange} placeholder="Name" />
<input name="email" onChange={handleChange} placeholder="Email" />
<input name="phone" onChange={handleChange} placeholder="Phone" />
<input name="role" onChange={handleChange} placeholder="Role" />
<input type="date" name="joinDate" onChange={handleChange} />
<button type="submit">Add Member</button>
</form>
<div className="max-w-2xl mx-auto p-6 bg-white rounded-lg shadow-md">
<h2 className="text-xl font-semibold mb-4">Add New Member</h2>
{error && (
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded-md">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
{/* First Row - Name and Email */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Name Field */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Name</label>
<div className="relative">
<input
name="name"
value={form.name}
className="w-full px-3 py-1.5 border rounded-md bg-gray-100 text-sm"
readOnly
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<span className="text-gray-500 text-xs">(your account name)</span>
</div>
</div>
</div>
{/* Email Field */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Email</label>
<div className="relative">
<input
type="email"
name="email"
value={form.email}
className="w-full px-3 py-1.5 border rounded-md bg-gray-100 text-sm"
readOnly
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<span className="text-gray-500 text-xs">(your login email)</span>
</div>
</div>
</div>
</div>
{/* Second Row - Phone and Role */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Phone Field */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Phone</label>
<input
name="phone"
value={form.phone}
onChange={handleChange}
placeholder="Enter phone number"
className="w-full px-3 py-1.5 border rounded-md text-sm"
/>
</div>
{/* Role Field */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Role</label>
<select
name="role"
value={form.role}
onChange={handleChange}
className="w-full px-3 py-1.5 border rounded-md text-sm"
>
<option value="member">Member</option>
<option value="admin">Admin</option>
</select>
</div>
</div>
{/* Join Date Field */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Join Date</label>
<input
type="date"
name="joinDate"
value={form.joinDate}
onChange={handleChange}
className="w-full px-3 py-1.5 border rounded-md text-sm"
/>
</div>
<button
type="submit"
className="w-full bg-blue-600 text-white py-1.5 px-4 rounded-md hover:bg-blue-700 transition text-sm"
>
Add Member
</button>
</form>
</div>
);
}
}

View File

@ -6,24 +6,87 @@ import { databaseId, membersCollectionId } from "../lib/appwrite";
import { getCurrentUserWithRole } from "../utils/auth";
import { Query } from "appwrite";
// Import icons
const EditIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
</svg>
);
const DeleteIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
);
const SaveIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
);
const CancelIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
);
// Confirmation Modal Component
const ConfirmationModal = ({ isOpen, onClose, onConfirm, title, message }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg shadow-xl max-w-md w-full">
<div className="p-6">
<h3 className="text-lg font-medium text-gray-900 mb-2">{title}</h3>
<p className="text-gray-600 mb-6">{message}</p>
<div className="flex justify-end space-x-3">
<button
onClick={onClose}
className="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Cancel
</button>
<button
onClick={onConfirm}
className="px-4 py-2 bg-red-600 text-white rounded-md text-sm font-medium hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
>
Delete
</button>
</div>
</div>
</div>
</div>
);
};
export default function MemberList() {
const [members, setMembers] = useState([]);
const [currentUser, setCurrentUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [editingId, setEditingId] = useState(null);
const [editFormData, setEditFormData] = useState({
name: '',
email: '',
phone: '',
role: ''
});
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [memberToDelete, setMemberToDelete] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
// Get current user with role first
const user = await getCurrentUserWithRole();
setCurrentUser(user);
// Then fetch members with proper error handling
const res = await databases.listDocuments(
databaseId,
membersCollectionId,
[Query.orderDesc("$createdAt")] // Optional: sort by creation date
[Query.orderDesc("$createdAt")]
);
setMembers(res.documents);
@ -38,6 +101,76 @@ export default function MemberList() {
fetchData();
}, []);
const handleEditClick = (member) => {
setEditingId(member.$id);
setEditFormData({
name: member.name,
email: member.email,
phone: member.phone,
role: member.role
});
};
const handleEditFormChange = (e) => {
const { name, value } = e.target;
setEditFormData({
...editFormData,
[name]: value
});
};
const handleUpdate = async (memberId) => {
try {
await databases.updateDocument(
databaseId,
membersCollectionId,
memberId,
editFormData
);
const res = await databases.listDocuments(
databaseId,
membersCollectionId,
[Query.orderDesc("$createdAt")]
);
setMembers(res.documents);
setEditingId(null);
} catch (err) {
console.error("Error updating member:", err);
setError("Failed to update member");
}
};
const handleDeleteClick = (memberId) => {
setMemberToDelete(memberId);
setShowDeleteModal(true);
};
const handleDeleteConfirm = async () => {
if (!memberToDelete) return;
try {
await databases.deleteDocument(
databaseId,
membersCollectionId,
memberToDelete
);
const res = await databases.listDocuments(
databaseId,
membersCollectionId,
[Query.orderDesc("$createdAt")]
);
setMembers(res.documents);
} catch (err) {
console.error("Error deleting member:", err);
setError("Failed to delete member");
} finally {
setShowDeleteModal(false);
setMemberToDelete(null);
}
};
if (loading) {
return <div className="p-4">Loading members...</div>;
}
@ -50,7 +183,6 @@ export default function MemberList() {
<div className="mt-8 p-4">
<h2 className="text-xl font-semibold mb-4">All Members</h2>
{/* Current user info */}
{currentUser && (
<div className="mb-6 p-4 bg-blue-50 rounded-lg">
<p className="font-medium">You are logged in as: {currentUser.name}</p>
@ -58,7 +190,6 @@ export default function MemberList() {
</div>
)}
{/* Members table */}
<div className="overflow-x-auto">
<table className="w-full border">
<thead>
@ -68,32 +199,115 @@ export default function MemberList() {
<th className="p-3">Phone</th>
<th className="p-3">Join Date</th>
<th className="p-3">Role</th>
{currentUser?.role === 'admin' && <th className="p-3">Actions</th>}
</tr>
</thead>
<tbody>
{members.length > 0 ? (
members.map((member) => (
<tr key={member.$id} className="border-t hover:bg-gray-50">
<td className="p-3">{member.name || "N/A"}</td>
<td className="p-3">{member.email || "N/A"}</td>
<td className="p-3">{member.phone || "N/A"}</td>
<td className="p-3">
{member.joinDate ? new Date(member.joinDate).toLocaleDateString() : "N/A"}
</td>
<td className="p-3 capitalize">
<span className={`px-2 py-1 rounded-full text-xs ${
member.role === "admin"
? "bg-purple-100 text-purple-800"
: "bg-blue-100 text-blue-800"
}`}>
{member.role || "unknown"}
</span>
</td>
{editingId === member.$id ? (
<>
<td className="p-3">
<input
type="text"
name="name"
value={editFormData.name}
onChange={handleEditFormChange}
className="border p-1 w-full"
/>
</td>
<td className="p-3">
<input
type="email"
name="email"
value={editFormData.email}
onChange={handleEditFormChange}
className="border p-1 w-full"
/>
</td>
<td className="p-3">
<input
type="text"
name="phone"
value={editFormData.phone}
onChange={handleEditFormChange}
className="border p-1 w-full"
/>
</td>
<td className="p-3">
{member.joinDate ? new Date(member.joinDate).toLocaleDateString() : "N/A"}
</td>
<td className="p-3">
<select
name="role"
value={editFormData.role}
onChange={handleEditFormChange}
className="border p-1 w-full"
>
<option value="admin">Admin</option>
<option value="member">Member</option>
</select>
</td>
<td className="p-3 flex space-x-2">
<button
onClick={() => handleUpdate(member.$id)}
className="bg-green-500 text-white p-1.5 rounded hover:bg-green-600 transition"
title="Save"
>
<SaveIcon />
</button>
<button
onClick={() => setEditingId(null)}
className="bg-gray-500 text-white p-1.5 rounded hover:bg-gray-600 transition"
title="Cancel"
>
<CancelIcon />
</button>
</td>
</>
) : (
<>
<td className="p-3">{member.name || "N/A"}</td>
<td className="p-3">{member.email || "N/A"}</td>
<td className="p-3">{member.phone || "N/A"}</td>
<td className="p-3">
{member.joinDate ? new Date(member.joinDate).toLocaleDateString() : "N/A"}
</td>
<td className="p-3 capitalize">
<span className={`px-2 py-1 rounded-full text-xs ${
member.role === "admin"
? "bg-purple-100 text-purple-800"
: "bg-blue-100 text-blue-800"
}`}>
{member.role || "unknown"}
</span>
</td>
{currentUser?.role === 'admin' && (
<td className="p-3 flex space-x-2">
<button
onClick={() => handleEditClick(member)}
className="text-blue-500 hover:text-blue-700 p-1.5 rounded hover:bg-blue-50 transition"
title="Edit"
>
<EditIcon />
</button>
<button
onClick={() => handleDeleteClick(member.$id)}
className="text-red-500 hover:text-red-700 p-1.5 rounded hover:bg-red-50 transition"
title="Delete"
>
<DeleteIcon />
</button>
</td>
)}
</>
)}
</tr>
))
) : (
<tr>
<td colSpan="5" className="p-4 text-center text-gray-500">
<td colSpan={currentUser?.role === 'admin' ? 6 : 5} className="p-4 text-center text-gray-500">
No members found
</td>
</tr>
@ -101,6 +315,14 @@ export default function MemberList() {
</tbody>
</table>
</div>
<ConfirmationModal
isOpen={showDeleteModal}
onClose={() => setShowDeleteModal(false)}
onConfirm={handleDeleteConfirm}
title="Delete Member"
message="Are you sure you want to delete this member? This action cannot be undone."
/>
</div>
);
}

View File

@ -62,7 +62,7 @@ export default function Navbar({ toggleSidebar }) {
};
return (
<nav className="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-4 py-3 sm:px-6 lg:px-8 relative">
<nav className="bg-white border-b border-gray-200 dark:border-gray-700 px-4 py-3 sm:px-6 lg:px-8 relative">
<div className="flex justify-between items-center">
<div className="flex items-center space-x-4">
{/* Sidebar Toggle Button - Hidden on mobile */}

View File

@ -1,5 +1,5 @@
'use client';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { account, ID } from "../lib/appwrite";
@ -9,60 +9,129 @@ export default function AuthPage() {
const [password, setPassword] = useState('');
const [err, setErr] = useState('');
const [isLogin, setIsLogin] = useState(true);
const [isLoading, setIsLoading] = useState(true);
// Check for existing session on component mount
useEffect(() => {
const checkSession = async () => {
try {
const session = await account.getSession('current');
if (session) {
router.push('/pages/dashboard');
}
} catch (error) {
// No active session
} finally {
setIsLoading(false);
}
};
checkSession();
}, [router]);
const handleAuth = async (e) => {
e.preventDefault();
setErr('');
setIsLoading(true);
try {
if (isLogin) {
await account.createEmailPasswordSession(email, password);
router.push('/pages/dashboard');
} else {
await account.create(ID.unique(), email, password);
// Automatically log in after sign up
await account.createEmailPasswordSession(email, password);
}
// Verify session was created successfully
const session = await account.getSession('current');
if (session) {
router.push('/pages/dashboard');
} else {
setErr('Authentication failed. Please try again.');
}
} catch (error) {
console.error('Auth error:', error);
setErr(error.message || 'Something went wrong');
} finally {
setIsLoading(false);
}
};
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-center">
<p>Checking authentication status...</p>
</div>
</div>
);
}
return (
<div className="flex items-center justify-center min-h-screen">
<form onSubmit={handleAuth} className="bg-white p-6 rounded shadow-md w-full max-w-sm">
<h2 className="text-xl font-semibold mb-4">{isLogin ? 'Login' : 'Sign Up'}</h2>
{err && <p className="text-red-500 mb-4">{err}</p>}
<input
type="email"
placeholder="Email"
className="w-full mb-2 p-2 border rounded"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<input
type="password"
placeholder="Password"
className="w-full mb-4 p-2 border rounded"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength="8"
/>
<button type="submit" className="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded w-full mb-4">
{isLogin ? 'Login' : 'Sign Up'}
</button>
<button
type="button"
onClick={() => {
setIsLogin(!isLogin);
setErr('');
}}
className="text-blue-500 hover:text-blue-700 text-sm"
<div className="flex items-center justify-center min-h-screen bg-gray-50">
<form onSubmit={handleAuth} className="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h2 className="text-2xl font-bold text-center mb-6 text-gray-800">
{isLogin ? 'Login' : 'Create Account'}
</h2>
{err && (
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded-md text-sm">
{err}
</div>
)}
<div className="mb-4">
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
Email Address
</label>
<input
id="email"
type="email"
placeholder="your@email.com"
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
autoComplete="email"
/>
</div>
<div className="mb-6">
<label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-1">
Password
</label>
<input
id="password"
type="password"
placeholder="••••••••"
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength="8"
autoComplete={isLogin ? "current-password" : "new-password"}
/>
</div>
<button
type="submit"
disabled={isLoading}
className={`w-full py-2 px-4 rounded-md text-white font-medium ${isLoading ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'}`}
>
{isLogin ? 'Need an account? Sign Up' : 'Already have an account? Login'}
{isLoading ? 'Processing...' : (isLogin ? 'Login' : 'Sign Up')}
</button>
<div className="mt-4 text-center text-sm text-gray-600">
<button
type="button"
onClick={() => {
setIsLogin(!isLogin);
setErr('');
}}
className="text-blue-600 hover:text-blue-800 focus:outline-none"
>
{isLogin ? 'Need an account? Sign up' : 'Already have an account? Log in'}
</button>
</div>
</form>
</div>
);

View File

@ -9,14 +9,25 @@ export default function Home() {
useEffect(() => {
const checkSession = async () => {
try {
await account.get(); // Check if session exists
router.replace('/pages/dashboard'); // Redirect if logged in
} catch {
router.replace('/login'); // Redirect to login if no session
const session = await account.getSession('current');
if (session) {
router.replace('/pages/dashboard');
} else {
router.replace('/login');
}
} catch (error) {
console.error('Session check error:', error);
router.replace('/login');
}
};
checkSession();
}, []);
}, [router]);
return null; // No content, just redirection
}
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-center">
<p>Checking authentication status...</p>
</div>
</div>
);
}