Admin.tsx - Role-based access control (admin/staff), no owner-email check
cgen-13ccc66c52474a43b12c685c6c070339
This commit is contained in:
parent
a3d4a1fa88
commit
5e280b6030
1 changed files with 16 additions and 39 deletions
|
|
@ -16,7 +16,6 @@ import {
|
||||||
CardTitle,
|
CardTitle,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import AdminStatCard from "@/components/admin/AdminStatCard";
|
import AdminStatCard from "@/components/admin/AdminStatCard";
|
||||||
|
|
@ -39,26 +38,13 @@ import {
|
||||||
PenTool,
|
PenTool,
|
||||||
Command,
|
Command,
|
||||||
Activity,
|
Activity,
|
||||||
UserCog,
|
|
||||||
Settings,
|
Settings,
|
||||||
ExternalLink,
|
|
||||||
ClipboardList,
|
ClipboardList,
|
||||||
Loader2,
|
Loader2,
|
||||||
RefreshCw,
|
|
||||||
CheckCircle,
|
|
||||||
AlertTriangle,
|
|
||||||
XCircle,
|
|
||||||
Server,
|
|
||||||
Database,
|
|
||||||
Wifi,
|
|
||||||
Zap,
|
|
||||||
Heart,
|
|
||||||
BarChart3,
|
BarChart3,
|
||||||
Grid3x3,
|
Grid3x3,
|
||||||
Gauge,
|
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
Lock,
|
Gauge,
|
||||||
Globe,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
type Studio = {
|
type Studio = {
|
||||||
|
|
@ -97,12 +83,11 @@ type OpportunityApplication = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Admin() {
|
export default function Admin() {
|
||||||
const { user, loading } = useAuth();
|
const { user, roles, loading } = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const normalizedEmail = user?.email?.toLowerCase() ?? "";
|
// Role-based access: allow "admin" and "staff" roles
|
||||||
const ownerEmail = "admin@aethex.tech";
|
const hasAdminAccess = roles.includes("admin") || roles.includes("staff");
|
||||||
const isOwner = normalizedEmail === ownerEmail.toLowerCase();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && !user) {
|
if (!loading && !user) {
|
||||||
|
|
@ -213,7 +198,7 @@ export default function Admin() {
|
||||||
aethexToast.error({
|
aethexToast.error({
|
||||||
title: "Access denied",
|
title: "Access denied",
|
||||||
description:
|
description:
|
||||||
"You must be signed in as the owner to view opportunity applications.",
|
"You must be signed in as an admin or staff member to view opportunity applications.",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.warn("Opportunity applications request failed:", message);
|
console.warn("Opportunity applications request failed:", message);
|
||||||
|
|
@ -241,19 +226,19 @@ export default function Admin() {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<LoadingScreen
|
<LoadingScreen
|
||||||
message="Verifying admin access..."
|
message="Verifying access..."
|
||||||
showProgress
|
showProgress
|
||||||
duration={1000}
|
duration={1000}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user || !isOwner) {
|
if (!user || !hasAdminAccess) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO
|
<SEO
|
||||||
pageTitle="Admin"
|
pageTitle="Admin Control"
|
||||||
description="Administrative controls for AeThex."
|
description="Administrative controls for AeThex platform management."
|
||||||
canonical={
|
canonical={
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
? window.location.href
|
? window.location.href
|
||||||
|
|
@ -267,8 +252,8 @@ export default function Admin() {
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-red-400">Access denied</CardTitle>
|
<CardTitle className="text-red-400">Access denied</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
This panel is restricted to {ownerEmail}. If you need
|
This panel requires admin or staff access. Your current
|
||||||
access, contact the site owner.
|
roles: {roles.length ? roles.join(", ") : "none"}.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex gap-2">
|
<CardContent className="flex gap-2">
|
||||||
|
|
@ -308,17 +293,6 @@ export default function Admin() {
|
||||||
);
|
);
|
||||||
}).length;
|
}).length;
|
||||||
|
|
||||||
const blogHighlights = useMemo(
|
|
||||||
() =>
|
|
||||||
resolvedBlogPosts.slice(0, 4).map((post) => ({
|
|
||||||
slug: post.slug || String(post.id || "post"),
|
|
||||||
title: post.title || "Untitled",
|
|
||||||
category: post.category || "General",
|
|
||||||
date: post.date || post.published_at || null,
|
|
||||||
})),
|
|
||||||
[resolvedBlogPosts]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -353,7 +327,10 @@ export default function Admin() {
|
||||||
Control Center
|
Control Center
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
Manage platform, users, content, and integrations
|
Manage platform, users, content, and integrations · Roles:{" "}
|
||||||
|
<span className="text-aethex-300 font-medium">
|
||||||
|
{roles.join(", ") || "none"}
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -589,7 +566,7 @@ export default function Admin() {
|
||||||
<AdminMemberManager
|
<AdminMemberManager
|
||||||
onSelectedIdChange={(id) => setSelectedMemberId(id)}
|
onSelectedIdChange={(id) => setSelectedMemberId(id)}
|
||||||
onRefresh={loadProfiles}
|
onRefresh={loadProfiles}
|
||||||
ownerEmail={ownerEmail}
|
ownerEmail="admin@aethex.tech"
|
||||||
/>
|
/>
|
||||||
<AdminAchievementManager targetUser={selectedMember} />
|
<AdminAchievementManager targetUser={selectedMember} />
|
||||||
<AdminSpotlightManager profiles={managedProfiles} />
|
<AdminSpotlightManager profiles={managedProfiles} />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue