feat(public_page): allow unauthenticated browsing with auth-gated interactivity

- Add get_optional_user dependency; dashboard returns guest-safe payload
- AuthGuard only redirects /following and /notifications for guests
- Sidebar hides auth-required nav items and shows Sign In/Register for guests
- Dashboard shows trending bills as "Most Popular" for unauthenticated visitors
- FollowButton opens AuthModal instead of acting when not signed in
- Members page pins followed members at the top for quick unfollowing
- useFollows skips API call and invalidates dashboard on follow/unfollow

Authored-By: Jack Levy
This commit is contained in:
Jack Levy
2026-03-01 15:54:54 -05:00
parent 73881b2404
commit ddd74a02d5
9 changed files with 314 additions and 128 deletions

View File

@@ -6,7 +6,8 @@ import { useAuthStore } from "@/stores/authStore";
import { Sidebar } from "./Sidebar";
import { MobileHeader } from "./MobileHeader";
const PUBLIC_PATHS = ["/login", "/register"];
const NO_SHELL_PATHS = ["/login", "/register"];
const AUTH_REQUIRED = ["/following", "/notifications"];
export function AuthGuard({ children }: { children: React.ReactNode }) {
const router = useRouter();
@@ -22,22 +23,24 @@ export function AuthGuard({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (!hydrated) return;
if (!token && !PUBLIC_PATHS.includes(pathname)) {
const needsAuth = AUTH_REQUIRED.some((p) => pathname.startsWith(p));
if (!token && needsAuth) {
router.replace("/login");
}
}, [hydrated, token, pathname, router]);
if (!hydrated) return null;
// Public pages (login/register) render without the app shell
if (PUBLIC_PATHS.includes(pathname)) {
// Login/register pages render without the app shell
if (NO_SHELL_PATHS.includes(pathname)) {
return <>{children}</>;
}
// Not logged in yet — blank while redirecting
if (!token) return null;
// Auth-required pages: blank while redirecting
const needsAuth = AUTH_REQUIRED.some((p) => pathname.startsWith(p));
if (!token && needsAuth) return null;
// Authenticated: render the full app shell
// Authenticated or guest browsing: render the full app shell
return (
<div className="flex h-screen bg-background">
{/* Desktop sidebar — hidden on mobile */}