feat: add architecture, api routes and components
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user