Initial project upload

This commit is contained in:
Mohamed Mathar Irfan
2026-07-28 17:57:02 +05:30
commit ed6610d5d8
23919 changed files with 3003316 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Bell, HelpCircle, Search, Menu } from "lucide-react";
import Sidebar from "@/components/Sidebar";
import { api, clearToken } from "@/lib/api";
import { useRef } from "react";
import { LogOut } from "lucide-react";
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
const router = useRouter();
const [me, setMe] = useState<any>(null);
const [org, setOrg] = useState<any>(null);
const [ready, setReady] = useState(false);
const [navOpen, setNavOpen] = useState(false);
const [profileOpen, setProfileOpen] = useState(false);
const profileRef = useRef<HTMLDivElement>(null);
function logout() {
clearToken();
router.replace("/login");
}
useEffect(() => {
function handleClick(e: MouseEvent) {
if (
profileRef.current &&
!profileRef.current.contains(e.target as Node)
) {
setProfileOpen(false);
}
}
document.addEventListener("mousedown", handleClick);
return () =>
document.removeEventListener("mousedown", handleClick);
}, []);
useEffect(() => {
api("/me")
.then((m) => {
setMe(m);
// Product Admins don't belong here — send them to the Super Admin Panel.
if (m.is_product_admin) {
router.replace("/admin");
return;
}
if (!m.has_org) {
router.replace("/onboarding");
return;
}
api("/organization").then(setOrg).catch(() => {});
setReady(true);
})
.catch((e) => {
clearToken();
router.replace("/login");
});
}, [router]);
if (!ready)
return <div className="min-h-screen grid place-items-center text-slate-400">Loading</div>;
const initial = (me?.name?.[0] ?? "U").toUpperCase();
return (
<div className="flex min-h-screen bg-slate-50">
<Sidebar org={org} open={navOpen} onClose={() => setNavOpen(false)} />
<div className="flex-1 min-w-0">
<header className="sticky top-0 z-10 bg-slate-50/80 backdrop-blur px-4 md:px-8 py-4 flex items-center gap-4">
<button onClick={() => setNavOpen(true)} className="md:hidden h-10 w-10 grid place-items-center rounded-full bg-white border border-slate-200">
<Menu className="h-4 w-4 text-slate-600" />
</button>
<div className="flex-1">
<h1 className="text-lg font-bold text-slate-900">
Welcome back, {me?.name ?? "there"}! 👋
</h1>
<p className="text-sm text-slate-500">
Here&apos;s what&apos;s happening with your products today.
</p>
</div>
<div className="relative hidden md:block">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-slate-400" />
<input placeholder="Search anything..."
className="pl-9 pr-4 py-2 w-64 rounded-full border border-slate-200 bg-white text-sm
focus:outline-none focus:ring-2 focus:ring-brand-500/30" />
</div>
<button className="relative h-10 w-10 grid place-items-center rounded-full bg-white border border-slate-200">
<Bell className="h-4 w-4 text-slate-600" />
</button>
<button className="h-10 w-10 grid place-items-center rounded-full bg-white border border-slate-200">
<HelpCircle className="h-4 w-4 text-slate-600" />
</button>
<div className="relative" ref={profileRef}>
<button
onClick={() => setProfileOpen(!profileOpen)}
className="flex items-center gap-2 pl-2 rounded-lg hover:bg-slate-100 px-2 py-1"
>
<div className="h-9 w-9 rounded-full bg-brand-500 text-white grid place-items-center font-semibold text-sm">
{initial}
</div>
<div className="text-sm leading-tight hidden sm:block text-left">
<div className="font-semibold text-slate-800">
{me?.name}
</div>
<div className="text-[11px] text-slate-400 capitalize">
{me?.client_role}
</div>
</div>
</button>
{profileOpen && (
<div className="absolute right-0 mt-2 w-72 bg-white rounded-xl shadow-lg border border-slate-200 overflow-hidden z-50">
<div className="px-4 py-4">
<div className="font-semibold text-slate-900">
{me?.name}
</div>
<div className="text-sm text-slate-500 mt-1">
{me?.email}
</div>
</div>
<div className="border-t" />
<button
onClick={logout}
className="w-full flex items-center gap-2 px-4 py-3 hover:bg-red-50 text-red-600 font-medium transition-colors"
>
<LogOut className="h-4 w-4" />
Logout
</button>
</div>
)}
</div>
</header>
<main className="px-4 md:px-8 pb-10">{children}</main>
</div>
</div>
);
}