81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import Link from "next/link";
|
||
|
|
import { useEffect } from "react";
|
||
|
|
import { useRouter } from "next/navigation";
|
||
|
|
|
||
|
|
export default function AdminLayout({
|
||
|
|
children,
|
||
|
|
}: {
|
||
|
|
children: React.ReactNode;
|
||
|
|
}) {
|
||
|
|
const router = useRouter();
|
||
|
|
|
||
|
|
const handleLogout = async () => {
|
||
|
|
try {
|
||
|
|
await fetch("/api/auth/logout", { method: "POST" });
|
||
|
|
router.push("/login");
|
||
|
|
router.refresh();
|
||
|
|
} catch (e) {
|
||
|
|
console.error("Logout failed", e);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const closeAdminSidebar = () => {
|
||
|
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||
|
|
const offcanvasEl = document.getElementById('adminSidebar');
|
||
|
|
if (offcanvasEl && (window as any).bootstrap) {
|
||
|
|
try {
|
||
|
|
const bsOffcanvas = (window as any).bootstrap.Offcanvas.getInstance(offcanvasEl) || new (window as any).bootstrap.Offcanvas(offcanvasEl);
|
||
|
|
if (bsOffcanvas) {
|
||
|
|
bsOffcanvas.hide();
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('Error closing admin offcanvas:', e);
|
||
|
|
offcanvasEl.classList.remove('show', 'showing');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
return (
|
||
|
|
<div className="d-flex h-100" style={{ minHeight: "100vh" }}>
|
||
|
|
{/* Mobile Header with Toggle Button */}
|
||
|
|
<div className="d-md-none bg-dark text-white p-3 d-flex justify-content-between align-items-center w-100 position-fixed top-0 z-3" style={{ height: "60px" }}>
|
||
|
|
<span className="fs-5">Admin Panel</span>
|
||
|
|
<button className="btn btn-outline-light" type="button" data-bs-toggle="offcanvas" data-bs-target="#adminSidebar" aria-controls="adminSidebar">
|
||
|
|
☰
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Sidebar (Offcanvas on mobile, visible on desktop) */}
|
||
|
|
<div className="offcanvas-md offcanvas-start bg-dark text-white border-end border-secondary d-flex flex-column flex-shrink-0 p-3" tabIndex={-1} id="adminSidebar" style={{ width: "280px" }}>
|
||
|
|
<div className="offcanvas-header d-md-none border-bottom border-secondary mb-3 p-0 pb-3">
|
||
|
|
<h5 className="offcanvas-title">Admin Panel</h5>
|
||
|
|
<button type="button" className="btn-close btn-close-white" onClick={closeAdminSidebar} aria-label="Close"></button>
|
||
|
|
</div>
|
||
|
|
<Link href="/admin" className="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none d-none d-md-flex">
|
||
|
|
<span className="fs-4">Admin Panel</span>
|
||
|
|
</Link>
|
||
|
|
<hr className="d-none d-md-block" />
|
||
|
|
<ul className="nav nav-pills flex-column mb-auto">
|
||
|
|
<li>
|
||
|
|
<Link href="/" className="nav-link text-white" onClick={closeAdminSidebar}>
|
||
|
|
Go to Site
|
||
|
|
</Link>
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<button onClick={handleLogout} className="nav-link text-white text-start w-100 bg-transparent border-0">
|
||
|
|
Log out
|
||
|
|
</button>
|
||
|
|
</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Main Content Area */}
|
||
|
|
<div className="w-100 overflow-auto bg-dark text-white pt-5 pt-md-0" data-bs-theme="dark">
|
||
|
|
<div className="container mt-4 p-4">{children}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|