wacrm/src/app/(dashboard)/layout.tsx
Arnas Donauskas 186c9f0e1e
fix: share auth via React Context to prevent getSession() timeouts
Fixes the cascading warnings:
  [useAuth] getSession() timed out after 3s, clearing loading state
  [useAuth] getSession() timed out after 3s, clearing loading state
  [useAuth] getSession() timed out after 3s, clearing loading state

The warning appeared 3x per page load because 3 components each called
useAuth() independently (DashboardLayout, Sidebar, Header), each firing
their own supabase.auth.getSession() call. The Supabase client has
internal mutex locks around session reads, so concurrent calls from
multiple components queue up and timeout.

Fix: introduce an AuthProvider React Context that calls getSession()
ONCE for the whole subtree. useAuth() now reads from context instead
of making its own call.

Also fixes the Settings page stuck on loading: WhatsAppConfig,
TemplateManager, and TagManager were making their own getSession()
calls in fetch functions. They now read the user from useAuth()
context — no redundant session calls.

Changes:
- src/hooks/use-auth.ts -> use-auth.tsx (JSX for the Provider)
  Added AuthProvider component and converted useAuth() to a
  context consumer. Renamed because the file now exports JSX.
- src/app/(dashboard)/layout.tsx — wraps children in <AuthProvider>
  with a DashboardShell inner component that consumes the context.
- src/components/settings/whatsapp-config.tsx — uses useAuth() for
  user instead of calling getSession() itself.
- src/components/settings/template-manager.tsx — same.
- src/components/settings/tag-manager.tsx — same.
- Profile fetch is now fire-and-forget (doesn't block setLoading),
  so the UI renders as soon as the session is known.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:26:09 +03:00

54 lines
1.4 KiB
TypeScript

"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { AuthProvider, useAuth } from "@/hooks/use-auth";
import { Sidebar } from "@/components/layout/sidebar";
import { Header } from "@/components/layout/header";
function DashboardShell({ children }: { children: React.ReactNode }) {
const { user, loading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!loading && !user) {
router.push("/login");
}
}, [user, loading, router]);
if (loading) {
return (
<div className="flex h-screen items-center justify-center bg-slate-950">
<div className="flex flex-col items-center gap-3">
<div className="h-8 w-8 animate-spin rounded-full border-2 border-emerald-500 border-t-transparent" />
<p className="text-sm text-slate-400">Loading...</p>
</div>
</div>
);
}
if (!user) return null;
return (
<div className="flex h-screen overflow-hidden bg-slate-950">
<Sidebar />
<div className="flex flex-1 flex-col overflow-hidden">
<Header />
<main className="flex-1 overflow-y-auto p-6">{children}</main>
</div>
</div>
);
}
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<AuthProvider>
<DashboardShell>{children}</DashboardShell>
</AuthProvider>
);
}