Merge branch 'feature/drizzle-rls-real-auth'

# Conflicts:
#	CLAUDE.md
#	package.json
#	src/app/api/auth/[...nextauth]/route.ts
#	src/app/login/LoginClient.tsx
#	src/auth.config.ts
#	src/components/admin/AdminSidebar.tsx
#	src/lib/admin-permissions-types.ts
#	src/lib/admin-permissions.ts
#	src/lib/auth.ts
#	src/middleware.ts
This commit is contained in:
2026-06-07 01:55:06 +00:00
84 changed files with 4165 additions and 2881 deletions
+2 -5
View File
@@ -9,7 +9,7 @@ import Link from "next/link";
import { useRouter } from "next/navigation";
import { usePathname } from "next/navigation";
import { useState, useEffect, useRef } from "react";
import { supabase } from "@/lib/supabase";
import { signOutAction } from "@/actions/auth-actions";
type AdminHeaderProps = {
userRole?: string | null;
@@ -89,10 +89,7 @@ export default function AdminHeader({ userRole, canManageUsers, routeTraceEnable
const homeLabel = isStoreEmployee ? "Pickup" : "Admin";
async function handleLogout() {
document.cookie = "dev_session=;path=/;max-age=0";
await supabase.auth.signOut();
router.push("/login");
router.refresh();
await signOutAction();
}
const roleLabel = userRole === "platform_admin" ? "Platform Admin"
+9 -32
View File
@@ -4,8 +4,7 @@ import { useState, useEffect, useRef, useCallback, KeyboardEvent } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useRouter } from "next/navigation";
import { supabase } from "@/lib/supabase";
import BrandSelector from "./BrandSelector";
import { signOutAction } from "@/actions/auth-actions";
// Elegant warm sidebar design
// Colors: parchment 100 bg, soft linen text, powder petal accent
@@ -220,10 +219,15 @@ type SidebarProps = {
userRole?: string | null;
brandIds?: string[];
activeBrandId?: string | null;
brands?: Array<{ id: string; name: string; slug: string; logo_url: string | null }>;
brands?: { id: string; name: string; slug: string; logo_url: string | null }[];
};
export default function AdminSidebar({ userRole, brandIds, activeBrandId, brands }: SidebarProps) {
export default function AdminSidebar({
userRole,
brandIds,
activeBrandId,
brands,
}: SidebarProps) {
const pathname = usePathname();
const router = useRouter();
const [mobileOpen, setMobileOpen] = useState(false);
@@ -234,15 +238,9 @@ export default function AdminSidebar({ userRole, brandIds, activeBrandId, brands
const roleLabel = userRole === "platform_admin" ? "Platform Admin"
: userRole === "brand_admin" ? "Brand Admin"
: userRole === "multi_brand_admin" ? "Multi-Brand Manager"
: userRole === "store_employee" ? "Store Employee"
: null;
const isMultiBrandAdmin = userRole === "multi_brand_admin";
const showAllBrandsOption = userRole === "platform_admin";
const showBrandSelector =
brands && (showAllBrandsOption || (brandIds && brandIds.length >= 2));
const isActive = useCallback((href: string) => {
if (href === "/admin") return pathname === "/admin";
return pathname.startsWith(href);
@@ -306,10 +304,7 @@ export default function AdminSidebar({ userRole, brandIds, activeBrandId, brands
}, [router, mobileOpen, closeMobileMenu]);
async function handleLogout() {
document.cookie = "dev_session=;path=/;max-age=0";
await supabase.auth.signOut();
router.push("/login");
router.refresh();
await signOutAction();
}
return (
@@ -404,24 +399,6 @@ export default function AdminSidebar({ userRole, brandIds, activeBrandId, brands
</Link>
</div>
{/* Brand selector (multi-brand admins + platform_admin) */}
{showBrandSelector && (
<div className="px-4 py-3 border-b flex-shrink-0" style={{ borderColor: "rgba(208, 203, 180, 0.2)" }}>
<p
className="text-[10px] font-semibold uppercase tracking-widest mb-1.5 px-1"
style={{ color: "rgba(195, 195, 193, 0.6)" }}
>
Active Brand
</p>
<BrandSelector
brands={brands!}
activeBrandId={activeBrandId ?? null}
showAllBrandsOption={showAllBrandsOption}
isMultiBrandAdmin={isMultiBrandAdmin}
/>
</div>
)}
{/* Nav links with keyboard navigation */}
<nav className="flex-1 overflow-y-auto overflow-x-hidden px-3 py-4 scrollbar-thin">
<ul className="space-y-1" role="list">
@@ -22,7 +22,7 @@ type StopProductAssignmentProps = {
stopId: string;
allProducts: Product[];
assignedProducts: AssignedProduct[];
callerUid: string;
callerUid: string | null;
};
type Filter = "all" | "available" | "assigned";