production auth: signup, login, protected dashboard, landing page, WAHA QR fix
AUTH: - NextAuth with credentials provider (bcrypt password hashing) - /api/auth/signup: creates org + user in transaction - /login, /signup pages with clean minimal UI - Middleware protects all /dashboard/* routes → redirects to /login - Session-based org resolution (no more hardcoded 'demo' headers) - SessionProvider wraps entire app - Dashboard header shows org name + sign out button LANDING PAGE: - Full marketing page at / with hero, problem, how-it-works, features, CTA - 'Get Started Free' → /signup → auto-login → /dashboard/setup - Clean responsive design, no auth required for public pages WAHA QR FIX: - WAHA CORE doesn't expose QR value via API or webhook - Now uses /api/screenshot (full browser capture) with CSS crop to QR area - Settings panel shows cropped screenshot with overflow:hidden - Auto-polls every 5s, refresh button MULTI-TENANT: - getOrgId() tries session first, then header, then first-org fallback - All dashboard APIs use session-based org - Signup creates isolated org per charity
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { LayoutDashboard, Calendar, FileBarChart, Upload, Download, Settings, Plus, ExternalLink } from "lucide-react"
|
||||
import { useSession, signOut } from "next-auth/react"
|
||||
import { LayoutDashboard, Calendar, FileBarChart, Upload, Download, Settings, Plus, ExternalLink, LogOut } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const navItems = [
|
||||
@@ -16,6 +17,9 @@ const navItems = [
|
||||
|
||||
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname()
|
||||
const { data: session } = useSession()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const user = session?.user as any
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50/50">
|
||||
@@ -27,8 +31,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
|
||||
<span className="text-white font-bold text-sm">P</span>
|
||||
</div>
|
||||
<div className="hidden sm:block">
|
||||
<span className="font-black text-sm text-gray-900">PNPL</span>
|
||||
<span className="text-[10px] text-muted-foreground ml-1">Dashboard</span>
|
||||
<span className="font-black text-sm text-gray-900">{user?.orgName || "PNPL"}</span>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex-1" />
|
||||
@@ -38,8 +41,16 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
|
||||
</button>
|
||||
</Link>
|
||||
<Link href="/" className="text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1">
|
||||
<ExternalLink className="h-3 w-3" /> <span className="hidden sm:inline">Public Site</span>
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</Link>
|
||||
{session && (
|
||||
<button
|
||||
onClick={() => signOut({ callbackUrl: "/login" })}
|
||||
className="text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1"
|
||||
>
|
||||
<LogOut className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user