feat: portal redesign — shadcn/ui, React Query, Zod, isolated portals

Foundation:
- CLAUDE.md with full coding rules (tech stack, patterns, redirect rules)
- Install @tanstack/react-query, zod, react-hook-form, shadcn/ui deps
- CSS variables design system (Tailwind v4 + tw-animate-css)
- Shared components: Button, Input, Label, Card, Badge, Separator, Form
- PortalLoginShell: two-column login layout (branding left, form right)
- PortalNav: shared sidebar nav used by all portals
- ReactQueryProvider in root layout
- api-client.ts: typed fetch wrapper (no raw fetch in components)

Portal isolation:
- Sidebar now returns null for all non-chapter routes; portals own their layout
- Admin layout: auth guard + PortalNav (slate accent)
- Org layout: auth guard + PortalNav (violet accent)
- Member layout: server-side cookie check → MemberNav client component
- Chapter admin sidebar: PortalNav (blue accent)

Login pages (all use react-hook-form + Zod + PortalLoginShell):
- /login → defaults next to /search (was /) — fixes redirect bug
- /admin/login → replaces /admin
- /org/login → replaces /org
- /member-login → two-step phone+OTP with proper form validation

Portal selector (/) redesigned with accent border-left cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:01:27 +05:30
parent f8b7afcc38
commit d7b5988858
27 changed files with 2306 additions and 521 deletions
+13 -11
View File
@@ -1,28 +1,30 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import './globals.css';
import { ReactQueryProvider } from './_lib/query-client';
import { AuthProvider } from './_lib/auth-context';
import { SuperAdminProvider } from './_lib/super-admin-context';
import { OrgAdminProvider } from './_lib/org-admin-context';
import { Sidebar } from './_lib/sidebar';
export const metadata: Metadata = {
title: 'Insignia TOWER',
title: 'TOWER',
description: 'Community Knowledge Infrastructure Platform',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="flex min-h-screen bg-gray-50 text-gray-900 antialiased">
<AuthProvider>
<SuperAdminProvider>
<OrgAdminProvider>
<Sidebar />
<main className="flex-1 overflow-auto p-6">{children}</main>
</OrgAdminProvider>
</SuperAdminProvider>
</AuthProvider>
<body className="flex min-h-screen bg-background text-foreground antialiased">
<ReactQueryProvider>
<AuthProvider>
<SuperAdminProvider>
<OrgAdminProvider>
<Sidebar />
<main className="flex-1 overflow-auto p-6">{children}</main>
</OrgAdminProvider>
</SuperAdminProvider>
</AuthProvider>
</ReactQueryProvider>
</body>
</html>
);