diff --git a/src/hooks/use-auth.ts b/src/hooks/use-auth.ts deleted file mode 100644 index 9afd271..0000000 --- a/src/hooks/use-auth.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { useEffect, useState } from "react"; -import type { User } from "@supabase/supabase-js"; -import { supabase } from "@/integrations/supabase/client"; - -// Mirrors the public.app_role enum. "student" has no enum member but is kept -// because existing screens branch on it. -export type Role = - | "super_admin" - | "org_admin" - | "admin" - | "campus_admin" - | "management" - | "billing_admin" - | "teacher" - | "staff" - | "parent" - | "auditor" - | "student"; - -export interface AuthState { - user: User | null; - roles: Role[]; - loading: boolean; -} - -export function useAuth(): AuthState { - const [user, setUser] = useState(null); - const [roles, setRoles] = useState([]); - const [loading, setLoading] = useState(true); - - useEffect(() => { - let mounted = true; - - const loadRoles = async (uid: string) => { - const { data } = await supabase.from("user_roles").select("role").eq("user_id", uid); - if (mounted) setRoles((data ?? []).map((r) => r.role as Role)); - }; - - supabase.auth.getSession().then(({ data }) => { - if (!mounted) return; - setUser(data.session?.user ?? null); - if (data.session?.user) - loadRoles(data.session.user.id).finally(() => mounted && setLoading(false)); - else setLoading(false); - }); - - const { data: sub } = supabase.auth.onAuthStateChange((_e, session) => { - setUser(session?.user ?? null); - if (session?.user) { - setTimeout(() => loadRoles(session.user.id), 0); - } else { - setRoles([]); - } - }); - - return () => { - mounted = false; - sub.subscription.unsubscribe(); - }; - }, []); - - return { user, roles, loading }; -} - -const ROLE_SENIORITY: Role[] = [ - "super_admin", - "org_admin", - "admin", - "campus_admin", - "management", - "billing_admin", - "teacher", - "staff", - "parent", - "auditor", - "student", -]; - -export function highestRole(roles: Role[]): Role | null { - return ROLE_SENIORITY.find((r) => roles.includes(r)) ?? null; -} - -/** - * Organization-wide administrative reach. Mirrors public.is_org_admin() — - * keep the two in step, or the UI will offer actions that RLS then refuses. - */ -export function isOrgAdmin(roles: Role[]): boolean { - return roles.some((r) => r === "admin" || r === "org_admin" || r === "super_admin"); -} - -/** Mirrors public.is_billing_admin(). */ -export function canBill(roles: Role[]): boolean { - return isOrgAdmin(roles) || roles.includes("billing_admin"); -}