Remove Staff.tsx - consolidating into Admin

cgen-d4b4630792bd4ad7845f599a7eedbd34
This commit is contained in:
Builder.io 2025-11-11 01:51:44 +00:00
parent a4d66c919d
commit e690205c62
8 changed files with 0 additions and 1890 deletions

View file

@ -1,263 +0,0 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { useAuth } from "@/contexts/AuthContext";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Lock, Users, FileText, Zap, Award, MessageSquare } from "lucide-react";
export default function Staff() {
const { user, loading } = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loading && user) {
navigate("/admin", { replace: true });
}
}, [user, loading, navigate]);
return (
<Layout>
<SEO
title="AeThex Staff"
description="Internal platform for AeThex employees and authorized contractors"
/>
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-purple-950 to-slate-950 relative overflow-hidden">
{/* Animated background */}
<div className="absolute inset-0 opacity-30">
<div className="absolute top-20 left-10 w-96 h-96 bg-purple-600 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
<div className="absolute bottom-20 right-10 w-96 h-96 bg-blue-600 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
<div className="absolute top-1/2 left-1/2 w-96 h-96 bg-indigo-600 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
</div>
<div className="relative">
{/* Hero Section */}
<div className="container mx-auto px-4 py-20 text-center">
<Badge className="mb-4 inline-block bg-purple-500/20 text-purple-300 border-purple-500/50">
Internal Platform
</Badge>
<h1 className="text-5xl md:text-6xl font-bold mb-6 bg-gradient-to-r from-purple-400 to-blue-400 bg-clip-text text-transparent">
AeThex Staff
</h1>
<p className="text-xl text-purple-200/80 max-w-2xl mx-auto mb-12">
The internal hub for AeThex employees and authorized contractors.
Unified access to dashboards, tools, documentation, and
collaboration features.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button
size="lg"
onClick={() => navigate("/admin")}
className="bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700"
>
<Lock className="mr-2 h-5 w-5" />
Admin Dashboard
</Button>
<Button
size="lg"
variant="outline"
onClick={() => navigate("/dashboard")}
className="border-purple-500/50 text-purple-300 hover:bg-purple-500/10"
>
Back to AeThex
</Button>
</div>
</div>
{/* Features Grid */}
<div className="container mx-auto px-4 py-20">
<h2 className="text-3xl font-bold text-center mb-12 text-purple-100">
Staff Tools & Features
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Dashboard */}
<Card className="border-purple-500/30 bg-purple-950/30 backdrop-blur hover:border-purple-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-purple-500/20">
<Zap className="h-5 w-5 text-purple-400" />
</div>
<CardTitle className="text-purple-100">Dashboard</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-purple-200/70">
Real-time operations metrics, service status, and quick
access to common tools.
</CardDescription>
</CardContent>
</Card>
{/* Directory */}
<Card className="border-blue-500/30 bg-blue-950/30 backdrop-blur hover:border-blue-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-blue-500/20">
<Users className="h-5 w-5 text-blue-400" />
</div>
<CardTitle className="text-blue-100">Directory</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-blue-200/70">
Browse team members, view profiles, and find contact
information.
</CardDescription>
</CardContent>
</Card>
{/* Admin Tools */}
<Card className="border-indigo-500/30 bg-indigo-950/30 backdrop-blur hover:border-indigo-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-indigo-500/20">
<Lock className="h-5 w-5 text-indigo-400" />
</div>
<CardTitle className="text-indigo-100">
Admin Tools
</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-indigo-200/70">
Manage users, roles, permissions, and platform
configuration.
</CardDescription>
</CardContent>
</Card>
{/* Docs */}
<Card className="border-cyan-500/30 bg-cyan-950/30 backdrop-blur hover:border-cyan-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-cyan-500/20">
<FileText className="h-5 w-5 text-cyan-400" />
</div>
<CardTitle className="text-cyan-100">Docs & API</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-cyan-200/70">
Internal documentation, API keys, credentials, and setup
guides.
</CardDescription>
</CardContent>
</Card>
{/* Achievements */}
<Card className="border-amber-500/30 bg-amber-950/30 backdrop-blur hover:border-amber-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-amber-500/20">
<Award className="h-5 w-5 text-amber-400" />
</div>
<CardTitle className="text-amber-100">
Achievements
</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-amber-200/70">
Track team accomplishments, milestones, and performance
metrics.
</CardDescription>
</CardContent>
</Card>
{/* Collaboration */}
<Card className="border-rose-500/30 bg-rose-950/30 backdrop-blur hover:border-rose-400/50 transition-colors">
<CardHeader>
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded bg-rose-500/20">
<MessageSquare className="h-5 w-5 text-rose-400" />
</div>
<CardTitle className="text-rose-100">
Collaboration
</CardTitle>
</div>
</CardHeader>
<CardContent>
<CardDescription className="text-rose-200/70">
Internal chat, team discussions, and project coordination.
</CardDescription>
</CardContent>
</Card>
</div>
</div>
{/* Info Section */}
<div className="container mx-auto px-4 py-20 border-t border-purple-500/20">
<div className="grid md:grid-cols-2 gap-12">
<div>
<h3 className="text-2xl font-bold mb-4 text-purple-100">
Who Can Access?
</h3>
<ul className="space-y-3 text-purple-200/80">
<li className="flex gap-2">
<span className="text-purple-400"></span>
<span>AeThex employees (@aethex.dev)</span>
</li>
<li className="flex gap-2">
<span className="text-purple-400"></span>
<span>Authorized contractors (invited)</span>
</li>
<li className="flex gap-2">
<span className="text-purple-400"></span>
<span>Partners with special access</span>
</li>
</ul>
</div>
<div>
<h3 className="text-2xl font-bold mb-4 text-purple-100">
Getting Started
</h3>
<ol className="space-y-3 text-purple-200/80">
<li className="flex gap-2">
<span className="text-purple-400">1.</span>
<span>Click "Staff Login" to sign in with Google</span>
</li>
<li className="flex gap-2">
<span className="text-purple-400">2.</span>
<span>Use your @aethex.dev email address</span>
</li>
<li className="flex gap-2">
<span className="text-purple-400">3.</span>
<span>Access your personalized dashboard</span>
</li>
</ol>
</div>
</div>
</div>
{/* Footer CTA */}
<div className="container mx-auto px-4 py-12 text-center border-t border-purple-500/20">
<p className="text-purple-300 mb-6">
Not a staff member? Visit the public platform.
</p>
<Button
variant="outline"
onClick={() => navigate("/")}
className="border-purple-500/50 text-purple-300 hover:bg-purple-500/10"
>
Back to Main Site
</Button>
</div>
</div>
</div>
</Layout>
);
}

View file

@ -1,411 +0,0 @@
import React, { useEffect, useMemo, useState } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import { aethexToast } from "@/lib/aethex-toast";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
function useHasStaffAccess(roles: string[]) {
return useMemo(
() =>
roles.some((r) =>
["owner", "admin", "founder", "staff", "employee"].includes(
r.toLowerCase(),
),
),
[roles],
);
}
export default function StaffDashboard() {
const { user, roles, loading } = useAuth();
const navigate = useNavigate();
const hasAccess = useHasStaffAccess(roles);
useEffect(() => {
if (loading) return;
if (!user) {
aethexToast.info({
title: "Sign in required",
description: "Staff area requires authentication",
});
navigate("/admin");
return;
}
if (!hasAccess) {
aethexToast.error({
title: "Access denied",
description: "You don't have staff permissions",
});
navigate("/dashboard");
}
}, [user, roles, hasAccess, loading, navigate]);
const [activeTab, setActiveTab] = useState("overview");
const [openReports, setOpenReports] = useState<any[]>([]);
const [mentorshipAll, setMentorshipAll] = useState<any[]>([]);
const [loadingData, setLoadingData] = useState(false);
const [searchQ, setSearchQ] = useState("");
const [users, setUsers] = useState<any[]>([]);
const refresh = async () => {
setLoadingData(true);
try {
const [r1, r2] = await Promise.all([
fetch("/api/moderation/reports?status=open&limit=100"),
fetch("/api/mentorship/requests/all?limit=50&status=pending"),
]);
const reports = r1.ok ? await r1.json() : [];
const m = r2.ok ? await r2.json() : [];
setOpenReports(Array.isArray(reports) ? reports : []);
setMentorshipAll(Array.isArray(m) ? m : []);
} catch (e) {
/* ignore */
} finally {
setLoadingData(false);
}
};
useEffect(() => {
if (user && hasAccess) refresh();
}, [user, hasAccess]);
const loadUsers = async () => {
try {
const params = new URLSearchParams();
if (searchQ.trim()) params.set("q", searchQ.trim());
params.set("limit", "25");
const resp = await fetch(`/api/staff/users?${params.toString()}`);
const data = resp.ok ? await resp.json() : [];
setUsers(Array.isArray(data) ? data : []);
} catch {
setUsers([]);
}
};
const updateReportStatus = async (
id: string,
status: "resolved" | "ignored" | "open",
) => {
try {
const resp = await fetch(
`/api/moderation/reports/${encodeURIComponent(id)}/status`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status }),
},
);
if (resp.ok) {
aethexToast.success({
title: "Updated",
description: `Report marked ${status}`,
});
refresh();
}
} catch {}
};
return (
<Layout>
<div className="container mx-auto px-4 py-10">
<div className="mb-6">
<Badge variant="outline" className="mb-2">
Internal
</Badge>
<h1 className="text-3xl font-bold">Operations Command</h1>
<p className="text-muted-foreground">
Staff dashboards, moderation, and internal tools.
</p>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="moderation">Moderation</TabsTrigger>
<TabsTrigger value="mentorship">Mentorship</TabsTrigger>
<TabsTrigger value="users">Users</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="mt-6">
<div className="grid gap-4 md:grid-cols-3">
<Card>
<CardHeader>
<CardTitle>Community Health</CardTitle>
<CardDescription>
Quick pulse across posts and reports
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between">
<div className="text-sm text-muted-foreground">
Open reports
</div>
<div className="text-xl font-semibold">
{openReports.length}
</div>
</div>
<div className="flex items-center justify-between mt-3">
<div className="text-sm text-muted-foreground">
Mentorship requests
</div>
<div className="text-xl font-semibold">
{mentorshipAll.length}
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Service Status</CardTitle>
<CardDescription>APIs and queues</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between">
<div className="text-sm text-muted-foreground">
Admin API
</div>
<Badge className="bg-emerald-600">OK</Badge>
</div>
<div className="flex items-center justify-between mt-3">
<div className="text-sm text-muted-foreground">
Notifications
</div>
<Badge className="bg-emerald-600">OK</Badge>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Staff Resources</CardTitle>
<CardDescription>Knowledge & HR tools</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/knowledge-base">Knowledge Base</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/team-handbook">Team Handbook</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/announcements">Announcements</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/learning-portal">Learning Portal</a>
</Button>
</CardContent>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-2 mt-6">
<Card>
<CardHeader>
<CardTitle>Operations</CardTitle>
<CardDescription>Tracking and management</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/project-tracking">Project Tracking</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/announcements">Announcements</a>
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Employee Services</CardTitle>
<CardDescription>HR and financial tools</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/performance-reviews">
Performance Reviews
</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/expenses">Expense Reports</a>
</Button>
<Button asChild variant="outline" className="w-full">
<a href="/admin/staff/marketplace">Internal Marketplace</a>
</Button>
</CardContent>
</Card>
</div>
</TabsContent>
<TabsContent value="moderation" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Moderation Queue</CardTitle>
<CardDescription>Flagged content and actions</CardDescription>
</CardHeader>
<CardContent>
{loadingData && (
<p className="text-sm text-muted-foreground">Loading</p>
)}
{!loadingData && openReports.length === 0 && (
<p className="text-sm text-muted-foreground">
No items in queue.
</p>
)}
<div className="space-y-3">
{openReports.map((r) => (
<div
key={r.id}
className="rounded border border-border/50 p-3"
>
<div className="flex items-center justify-between">
<div>
<div className="text-sm font-medium">{r.reason}</div>
<div className="text-xs text-muted-foreground">
{r.details}
</div>
</div>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => updateReportStatus(r.id, "ignored")}
>
Ignore
</Button>
<Button
size="sm"
onClick={() => updateReportStatus(r.id, "resolved")}
>
Resolve
</Button>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="mentorship" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Mentorship Requests</CardTitle>
<CardDescription>
Review recent mentor/mentee activity
</CardDescription>
</CardHeader>
<CardContent>
{loadingData && (
<p className="text-sm text-muted-foreground">Loading</p>
)}
{!loadingData && mentorshipAll.length === 0 && (
<p className="text-sm text-muted-foreground">
No requests to review.
</p>
)}
<div className="space-y-3">
{mentorshipAll.map((req) => (
<div
key={req.id}
className="rounded border border-border/50 p-3"
>
<div className="flex items-center justify-between">
<div>
<div className="text-sm font-medium">
{req.mentee?.full_name || req.mentee?.username} {" "}
{req.mentor?.full_name || req.mentor?.username}
</div>
<div className="text-xs text-muted-foreground">
{req.message || "No message"}
</div>
</div>
<div className="flex gap-2">
<Badge
variant="outline"
className="text-xs capitalize"
>
{req.status}
</Badge>
</div>
</div>
</div>
))}
</div>
<Separator className="my-4" />
<div className="flex gap-2">
<Button asChild>
<a href="/community/mentorship">Open requests</a>
</Button>
<Button asChild variant="outline">
<a href="/community/mentorship/apply">Mentor directory</a>
</Button>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="users" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Users</CardTitle>
<CardDescription>
Search, roles, and quick actions
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex gap-2">
<input
className="w-full rounded border border-border/50 bg-background px-3 py-2 text-sm"
placeholder="Search by name or username"
value={searchQ}
onChange={(e) => setSearchQ(e.target.value)}
/>
<Button onClick={loadUsers} variant="outline">
Search
</Button>
</div>
<div className="rounded border border-border/50">
{users.length === 0 ? (
<p className="p-3 text-sm text-muted-foreground">
No users found.
</p>
) : (
<div className="divide-y divide-border/50">
{users.map((u) => (
<div
key={u.id}
className="flex items-center justify-between p-3"
>
<div>
<div className="text-sm font-medium">
{u.full_name || u.username || u.id}
</div>
<div className="text-xs text-muted-foreground">
{u.username}
</div>
</div>
<Badge variant="outline" className="capitalize">
{u.user_type || "unknown"}
</Badge>
</div>
))}
</div>
)}
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</div>
</Layout>
);
}

View file

@ -1,205 +0,0 @@
import { useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { useAuth } from "@/contexts/AuthContext";
import { useAethexToast } from "@/hooks/use-aethex-toast";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import LoadingScreen from "@/components/LoadingScreen";
import { LogIn, Lock, Users } from "lucide-react";
const GoogleIcon = () => (
<svg
className="h-4 w-4"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="currentColor"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="currentColor"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="currentColor"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
);
export default function StaffLogin() {
const [isLoading, setIsLoading] = useState(false);
const [errorFromUrl, setErrorFromUrl] = useState<string | null>(null);
const navigate = useNavigate();
const location = useLocation();
const { signInWithOAuth, user, loading, profileComplete } = useAuth();
const { error: toastError, info: toastInfo } = useAethexToast();
// Check for error messages from URL (e.g., from OAuth callbacks)
useEffect(() => {
const params = new URLSearchParams(location.search);
const errorType = params.get("error");
const errorMessage = params.get("message");
if (errorType && errorMessage) {
setErrorFromUrl(decodeURIComponent(errorMessage));
if (errorType === "domain_not_allowed") {
toastError({
title: "Access Denied",
description: errorMessage,
});
}
}
}, [location.search, toastError]);
// Redirect if already authenticated (with @aethex.dev email validation)
useEffect(() => {
if (!loading && user) {
const userEmail = user.email || "";
const isAethexDev = userEmail.endsWith("@aethex.dev");
if (!isAethexDev) {
// Email is not @aethex.dev - show error
setErrorFromUrl(
"Only @aethex.dev email addresses can access the Staff Portal. If you're an authorized contractor, please use your assigned contractor email.",
);
toastError({
title: "Access Denied",
description: "This email domain is not authorized for staff access.",
});
return;
}
// Valid staff email - redirect to admin dashboard
const params = new URLSearchParams(location.search);
const next = params.get("next");
const safeNext = next && next.startsWith("/admin") ? next : null;
navigate(safeNext || "/admin", { replace: true });
}
}, [user, loading, navigate, location.search, toastError]);
const handleGoogleSignIn = async () => {
setIsLoading(true);
try {
// Pass the admin dashboard as the intended destination after OAuth completes
await signInWithOAuth("google", "/admin");
} catch (error: any) {
console.error("Google sign-in error:", error);
toastError({
title: "Sign-in failed",
description:
error?.message || "Failed to sign in with Google. Please try again.",
});
} finally {
setIsLoading(false);
}
};
if (loading) {
return <LoadingScreen />;
}
return (
<Layout>
<SEO title="Staff Login" description="AeThex staff and employees only" />
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 flex items-center justify-center p-4">
<div className="absolute inset-0 opacity-10">
<div className="absolute top-20 left-10 w-72 h-72 bg-purple-500 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
<div className="absolute bottom-20 right-10 w-72 h-72 bg-blue-500 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
</div>
<div className="relative w-full max-w-md">
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardHeader className="space-y-2 text-center">
<div className="flex justify-center mb-4">
<div className="p-3 rounded-lg bg-purple-500/20 border border-purple-500/30">
<Lock className="h-6 w-6 text-purple-400" />
</div>
</div>
<CardTitle className="text-2xl font-bold">Staff Portal</CardTitle>
<CardDescription>
AeThex employees and authorized contractors only
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
{errorFromUrl && (
<Alert className="border-red-400/30 bg-red-500/10 text-foreground">
<AlertTitle>Access Denied</AlertTitle>
<AlertDescription>{errorFromUrl}</AlertDescription>
</Alert>
)}
<div className="space-y-3">
<p className="text-sm text-slate-400 text-center">
Sign in with your @aethex.dev Google Workspace account
</p>
<Button
onClick={handleGoogleSignIn}
disabled={isLoading}
size="lg"
className="w-full bg-white hover:bg-slate-100 text-slate-900 font-semibold"
>
<GoogleIcon />
<span>
{isLoading ? "Signing in..." : "Sign in with Google"}
</span>
</Button>
</div>
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-slate-700" />
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-slate-900 text-slate-400">
For team members only
</span>
</div>
</div>
<div className="grid gap-3 text-sm text-slate-400">
<div className="flex gap-2">
<Users className="h-4 w-4 text-purple-400 flex-shrink-0 mt-0.5" />
<span>Full access to internal tools and dashboards</span>
</div>
<div className="flex gap-2">
<Lock className="h-4 w-4 text-purple-400 flex-shrink-0 mt-0.5" />
<span>Secured with Google Workspace authentication</span>
</div>
</div>
<div className="pt-4 border-t border-slate-700">
<p className="text-xs text-slate-500 text-center">
Public login available at{" "}
<a
href="/login"
className="text-purple-400 hover:text-purple-300"
>
aethex.dev/login
</a>
</p>
</div>
</CardContent>
</Card>
</div>
</div>
</Layout>
);
}

View file

@ -1,204 +0,0 @@
import { useEffect, useState } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
import { Trophy, Zap, Users, Target } from "lucide-react";
interface Achievement {
id: string;
title: string;
description: string;
icon: string;
earned: boolean;
earnedDate?: string;
progress?: number;
}
export default function StaffAchievements() {
const { user, loading } = useAuth();
const navigate = useNavigate();
const [achievements, setAchievements] = useState<Achievement[]>([
{
id: "1",
title: "Team Contributor",
description: "Contribute to 5 team projects",
icon: "Users",
earned: true,
earnedDate: "2025-01-15",
},
{
id: "2",
title: "Code Master",
description: "100+ commits to main repository",
icon: "Zap",
earned: false,
progress: 67,
},
{
id: "3",
title: "Documentation Champion",
description: "Complete internal documentation setup",
icon: "Target",
earned: true,
earnedDate: "2025-01-10",
},
{
id: "4",
title: "Mentor",
description: "Mentor 3 team members",
icon: "Trophy",
earned: false,
progress: 33,
},
]);
useEffect(() => {
if (!loading && !user) {
navigate("/admin");
}
}, [user, loading, navigate]);
if (loading)
return (
<Layout>
<div className="container py-20">Loading...</div>
</Layout>
);
return (
<Layout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
<div className="container mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">Achievements</h1>
<p className="text-slate-400">
Track team accomplishments and milestones
</p>
</div>
{/* Stats */}
<div className="grid md:grid-cols-4 gap-6 mb-12">
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="text-sm text-slate-400 mb-2">
Total Achievements
</div>
<div className="text-3xl font-bold text-white">4</div>
</CardContent>
</Card>
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="text-sm text-slate-400 mb-2">Earned</div>
<div className="text-3xl font-bold text-green-400">2</div>
</CardContent>
</Card>
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="text-sm text-slate-400 mb-2">In Progress</div>
<div className="text-3xl font-bold text-blue-400">2</div>
</CardContent>
</Card>
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="text-sm text-slate-400 mb-2">
Completion Rate
</div>
<div className="text-3xl font-bold text-purple-400">50%</div>
</CardContent>
</Card>
</div>
{/* Achievements Grid */}
<div className="grid md:grid-cols-2 gap-6">
{achievements.map((achievement) => (
<Card
key={achievement.id}
className={`border-slate-700/50 backdrop-blur transition-colors ${
achievement.earned
? "bg-green-500/5 border-green-500/30"
: "bg-slate-900/50 border-slate-700/50"
} hover:border-slate-600/50`}
>
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex items-start gap-3">
<div
className={`p-3 rounded-lg ${
achievement.earned
? "bg-green-500/20"
: "bg-slate-700/50"
}`}
>
<Trophy
className={`h-6 w-6 ${
achievement.earned
? "text-green-400"
: "text-slate-400"
}`}
/>
</div>
<div>
<CardTitle
className={
achievement.earned ? "text-green-300" : "text-white"
}
>
{achievement.title}
</CardTitle>
<CardDescription className="text-slate-400 mt-1">
{achievement.description}
</CardDescription>
</div>
</div>
{achievement.earned && (
<Badge className="bg-green-500/30 text-green-300 border-green-500/50">
Earned
</Badge>
)}
</div>
</CardHeader>
<CardContent className="space-y-4">
{!achievement.earned &&
achievement.progress !== undefined && (
<div>
<div className="flex justify-between items-center mb-2">
<span className="text-xs text-slate-400">
Progress
</span>
<span className="text-xs text-slate-300 font-medium">
{achievement.progress}%
</span>
</div>
<Progress
value={achievement.progress}
className="h-2"
/>
</div>
)}
{achievement.earnedDate && (
<p className="text-xs text-slate-500">
Earned on{" "}
{new Date(achievement.earnedDate).toLocaleDateString()}
</p>
)}
</CardContent>
</Card>
))}
</div>
</div>
</div>
</Layout>
);
}

View file

@ -1,195 +0,0 @@
import { useEffect } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Users,
Shield,
Settings,
GitBranch,
Eye,
RefreshCw,
} from "lucide-react";
export default function StaffAdmin() {
const { user, roles, loading } = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loading && !user) {
navigate("/admin");
return;
}
const isAdmin = roles?.some((r) =>
["owner", "admin", "founder"].includes(r.toLowerCase()),
);
if (!isAdmin) {
navigate("/admin");
}
}, [user, roles, loading, navigate]);
if (loading)
return (
<Layout>
<div className="container py-20">Loading...</div>
</Layout>
);
return (
<Layout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
<div className="container mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">Admin Tools</h1>
<p className="text-slate-400">
Manage users, roles, and platform configuration
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* User Management */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<Users className="h-5 w-5 text-blue-400" />
Users
</CardTitle>
<CardDescription className="text-slate-400">
Manage team members and roles
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-blue-600 hover:bg-blue-700">
Manage Users
</Button>
</CardContent>
</Card>
{/* Permissions */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<Shield className="h-5 w-5 text-purple-400" />
Permissions
</CardTitle>
<CardDescription className="text-slate-400">
Configure role-based access
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-purple-600 hover:bg-purple-700">
Manage Roles
</Button>
</CardContent>
</Card>
{/* Settings */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<Settings className="h-5 w-5 text-indigo-400" />
Settings
</CardTitle>
<CardDescription className="text-slate-400">
Platform configuration
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-indigo-600 hover:bg-indigo-700">
Edit Settings
</Button>
</CardContent>
</Card>
{/* API Keys */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<GitBranch className="h-5 w-5 text-green-400" />
API Keys
</CardTitle>
<CardDescription className="text-slate-400">
Manage authentication tokens
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-green-600 hover:bg-green-700">
View API Keys
</Button>
</CardContent>
</Card>
{/* Audit Log */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<Eye className="h-5 w-5 text-yellow-400" />
Audit Log
</CardTitle>
<CardDescription className="text-slate-400">
Platform activity history
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-yellow-600 hover:bg-yellow-700">
View Logs
</Button>
</CardContent>
</Card>
{/* Maintenance */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<RefreshCw className="h-5 w-5 text-red-400" />
Maintenance
</CardTitle>
<CardDescription className="text-slate-400">
System operations
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<Button className="w-full bg-red-600 hover:bg-red-700">
System Maintenance
</Button>
</CardContent>
</Card>
</div>
</div>
</div>
</Layout>
);
}

View file

@ -1,237 +0,0 @@
import { useEffect } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { MessageSquare, Users, Hash, Lock, Plus } from "lucide-react";
const channels = [
{
name: "announcements",
description: "Company announcements and updates",
type: "public",
members: 45,
},
{
name: "engineering",
description: "Engineering team discussions",
type: "private",
members: 12,
},
{
name: "product",
description: "Product and feature discussions",
type: "public",
members: 28,
},
{
name: "design",
description: "Design and UX team",
type: "private",
members: 8,
},
{
name: "random",
description: "Off-topic and casual chat",
type: "public",
members: 42,
},
];
const directMessages = [
{ name: "Sarah Johnson", role: "CEO", status: "online" },
{ name: "Mike Chen", role: "CTO", status: "online" },
{ name: "Emma Davis", role: "Product Lead", status: "away" },
{ name: "Alex Kim", role: "Designer", status: "offline" },
];
export default function StaffChat() {
const { user, loading } = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loading && !user) {
navigate("/admin");
}
}, [user, loading, navigate]);
if (loading)
return (
<Layout>
<div className="container py-20">Loading...</div>
</Layout>
);
return (
<Layout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
<div className="container mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">Team Chat</h1>
<p className="text-slate-400">
Internal collaboration and team discussions
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{/* Sidebar */}
<div className="space-y-6">
{/* Channels */}
<div>
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-white flex items-center gap-2">
<Hash className="h-5 w-5 text-slate-400" />
Channels
</h2>
<Button
variant="ghost"
size="sm"
className="text-slate-400 hover:text-white p-0"
>
<Plus className="h-4 w-4" />
</Button>
</div>
<div className="space-y-2">
{channels.map((channel) => (
<Button
key={channel.name}
variant="ghost"
className="w-full justify-start text-slate-300 hover:text-white hover:bg-slate-700/50"
>
<Hash className="h-4 w-4 mr-2" />
{channel.name}
</Button>
))}
</div>
</div>
{/* DMs */}
<div>
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-white flex items-center gap-2">
<MessageSquare className="h-5 w-5 text-slate-400" />
Direct Messages
</h2>
<Button
variant="ghost"
size="sm"
className="text-slate-400 hover:text-white p-0"
>
<Plus className="h-4 w-4" />
</Button>
</div>
<div className="space-y-2">
{directMessages.map((dm) => (
<Button
key={dm.name}
variant="ghost"
className="w-full justify-start text-slate-300 hover:text-white hover:bg-slate-700/50"
>
<div className="flex items-center gap-2 w-full">
<div className="w-2 h-2 rounded-full bg-slate-400" />
<span className="truncate">{dm.name}</span>
</div>
</Button>
))}
</div>
</div>
</div>
{/* Main Chat Area */}
<div className="md:col-span-2 space-y-6">
{/* Channel Info */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2 text-white">
<Hash className="h-5 w-5" />
announcements
</CardTitle>
<CardDescription className="text-slate-400">
Company announcements and updates
</CardDescription>
</div>
<Badge className="bg-green-500/20 text-green-300 border-green-500/50">
45 members
</Badge>
</div>
</CardHeader>
</Card>
{/* Messages Area */}
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur h-96 flex flex-col">
<CardContent className="flex-1 overflow-y-auto p-6 space-y-4">
<div className="flex gap-3">
<div className="w-10 h-10 rounded-full bg-blue-500/20 flex-shrink-0" />
<div>
<p className="text-sm text-white font-medium">
Sarah Johnson
</p>
<p className="text-slate-300 text-sm mt-1">
Welcome to the internal team chat! This is where we
collaborate and share updates.
</p>
<p className="text-xs text-slate-500 mt-2">10:30 AM</p>
</div>
</div>
<div className="flex gap-3">
<div className="w-10 h-10 rounded-full bg-purple-500/20 flex-shrink-0" />
<div>
<p className="text-sm text-white font-medium">
Mike Chen
</p>
<p className="text-slate-300 text-sm mt-1">
Great! Looking forward to building amazing things
together.
</p>
<p className="text-xs text-slate-500 mt-2">10:35 AM</p>
</div>
</div>
</CardContent>
<div className="border-t border-slate-700/50 p-4">
<div className="flex gap-2">
<input
type="text"
placeholder="Type a message..."
className="flex-1 px-4 py-2 rounded bg-slate-800 border border-slate-700 text-white placeholder-slate-500 focus:outline-none focus:border-purple-500"
/>
<Button className="bg-purple-600 hover:bg-purple-700">
Send
</Button>
</div>
</div>
</Card>
{/* Info */}
<Card className="border-blue-500/30 bg-blue-500/10 backdrop-blur">
<CardHeader>
<CardTitle className="text-blue-300 flex items-center gap-2">
<Users className="h-5 w-5" />
Team Chat Coming Soon
</CardTitle>
</CardHeader>
<CardContent className="text-blue-200/80 space-y-2">
<p> Full-featured internal messaging platform</p>
<p> Channels for teams and projects</p>
<p> Direct messages and group chats</p>
<p> File sharing and integrations</p>
</CardContent>
</Card>
</div>
</div>
</div>
</div>
</Layout>
);
}

View file

@ -1,192 +0,0 @@
import { useEffect, useState } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import { aethexToast } from "@/lib/aethex-toast";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Search, Mail, Phone, Briefcase } from "lucide-react";
interface StaffMember {
id: string;
full_name: string;
email: string;
role: string;
department?: string;
position?: string;
avatar_url?: string;
phone?: string;
}
export default function StaffDirectory() {
const { user, loading } = useAuth();
const navigate = useNavigate();
const [staffMembers, setStaffMembers] = useState<StaffMember[]>([]);
const [filteredMembers, setFilteredMembers] = useState<StaffMember[]>([]);
const [searchQuery, setSearchQuery] = useState("");
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (!loading && !user) {
navigate("/admin");
}
}, [user, loading, navigate]);
useEffect(() => {
const fetchMembers = async () => {
try {
const response = await fetch("/api/staff/members");
if (response.ok) {
const data = await response.json();
setStaffMembers(Array.isArray(data) ? data : []);
setFilteredMembers(Array.isArray(data) ? data : []);
} else {
aethexToast.error({
title: "Failed to load directory",
description: "Could not fetch staff members",
});
}
} catch (error) {
console.error("Error fetching staff members:", error);
aethexToast.error({
title: "Error",
description: "Failed to load staff directory",
});
} finally {
setIsLoading(false);
}
};
if (user) fetchMembers();
}, [user]);
useEffect(() => {
if (searchQuery.trim() === "") {
setFilteredMembers(staffMembers);
} else {
const query = searchQuery.toLowerCase();
const filtered = staffMembers.filter(
(member) =>
member.full_name.toLowerCase().includes(query) ||
member.email.toLowerCase().includes(query) ||
member.department?.toLowerCase().includes(query),
);
setFilteredMembers(filtered);
}
}, [searchQuery, staffMembers]);
if (loading)
return (
<Layout>
<div className="container py-20">Loading...</div>
</Layout>
);
return (
<Layout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
<div className="container mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">
Team Directory
</h1>
<p className="text-slate-400">
Find and connect with AeThex team members
</p>
</div>
{/* Search Bar */}
<Card className="mb-8 border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="relative">
<Search className="absolute left-3 top-3 h-5 w-5 text-slate-400" />
<Input
placeholder="Search by name, email, or department..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 bg-slate-800 border-slate-700 text-white placeholder-slate-500"
/>
</div>
</CardContent>
</Card>
{/* Results */}
{isLoading ? (
<div className="text-center py-12 text-slate-400">
Loading team members...
</div>
) : filteredMembers.length === 0 ? (
<div className="text-center py-12 text-slate-400">
No staff members found matching your search
</div>
) : (
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredMembers.map((member) => (
<Card
key={member.id}
className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors"
>
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex-1">
<CardTitle className="text-white">
{member.full_name}
</CardTitle>
<p className="text-sm text-slate-400 mt-1">
{member.position || "Team Member"}
</p>
</div>
{member.role && (
<Badge className="bg-purple-500/30 text-purple-300 border-purple-500/50 capitalize">
{member.role}
</Badge>
)}
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex items-center gap-2 text-slate-400 text-sm">
<Mail className="h-4 w-4 text-slate-500" />
<a
href={`mailto:${member.email}`}
className="hover:text-purple-400"
>
{member.email}
</a>
</div>
{member.phone && (
<div className="flex items-center gap-2 text-slate-400 text-sm">
<Phone className="h-4 w-4 text-slate-500" />
<a
href={`tel:${member.phone}`}
className="hover:text-purple-400"
>
{member.phone}
</a>
</div>
)}
{member.department && (
<div className="flex items-center gap-2 text-slate-400 text-sm">
<Briefcase className="h-4 w-4 text-slate-500" />
<span>{member.department}</span>
</div>
)}
</CardContent>
</Card>
))}
</div>
)}
{/* Stats */}
<div className="mt-12 pt-8 border-t border-slate-700/50">
<p className="text-center text-slate-400">
Showing {filteredMembers.length} of {staffMembers.length} team
members
</p>
</div>
</div>
</div>
</Layout>
);
}

View file

@ -1,183 +0,0 @@
import { useEffect } from "react";
import Layout from "@/components/Layout";
import { useAuth } from "@/contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { FileText, Key, Database, Code2, ExternalLink } from "lucide-react";
export default function StaffDocs() {
const { user, loading } = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loading && !user) {
navigate("/admin");
}
}, [user, loading, navigate]);
if (loading)
return (
<Layout>
<div className="container py-20">Loading...</div>
</Layout>
);
const docs = [
{
icon: FileText,
title: "Getting Started",
description: "Onboarding guide and platform overview",
link: "#",
},
{
icon: Code2,
title: "API Reference",
description: "Complete API documentation and endpoints",
link: "#",
},
{
icon: Database,
title: "Database Schema",
description: "Database structure and relationships",
link: "#",
},
{
icon: Key,
title: "Authentication",
description: "OAuth, tokens, and security guidelines",
link: "#",
},
];
const apiKeys = [
{ name: "Public API Key", key: "pk_aethex_...", status: "active" },
{ name: "Secret API Key", key: "sk_aethex_...", status: "active" },
{ name: "Webhook Secret", key: "whk_aethex_...", status: "active" },
];
return (
<Layout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
<div className="container mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">
Documentation & API
</h1>
<p className="text-slate-400">
Internal docs, API keys, and credentials
</p>
</div>
{/* Documentation */}
<div className="mb-12">
<h2 className="text-2xl font-bold text-white mb-6">
Documentation
</h2>
<div className="grid md:grid-cols-2 gap-6">
{docs.map((doc, idx) => {
const IconComponent = doc.icon;
return (
<Card
key={idx}
className="border-slate-700/50 bg-slate-900/50 backdrop-blur hover:border-slate-600/50 transition-colors cursor-pointer"
>
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex items-start gap-3">
<div className="p-2 rounded bg-blue-500/20">
<IconComponent className="h-5 w-5 text-blue-400" />
</div>
<div>
<CardTitle className="text-white">
{doc.title}
</CardTitle>
<CardDescription className="text-slate-400">
{doc.description}
</CardDescription>
</div>
</div>
</div>
</CardHeader>
<CardContent>
<Button
variant="ghost"
className="text-blue-400 hover:text-blue-300 p-0"
>
Read Docs <ExternalLink className="ml-2 h-4 w-4" />
</Button>
</CardContent>
</Card>
);
})}
</div>
</div>
{/* API Keys */}
<div className="mb-12">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold text-white">API Keys</h2>
<Badge className="bg-yellow-500/20 text-yellow-300 border-yellow-500/50">
Keep secure
</Badge>
</div>
<Card className="border-slate-700/50 bg-slate-900/50 backdrop-blur">
<CardContent className="p-6">
<div className="space-y-4">
{apiKeys.map((key, idx) => (
<div
key={idx}
className="flex items-center justify-between p-4 rounded border border-slate-700/50 bg-slate-800/30"
>
<div>
<p className="text-white font-medium">{key.name}</p>
<p className="text-slate-400 text-sm font-mono">
{key.key}
</p>
</div>
<div className="flex items-center gap-3">
<Badge className="bg-green-500/20 text-green-300 border-green-500/50 capitalize">
{key.status}
</Badge>
<Button
variant="ghost"
size="sm"
className="text-blue-400 hover:text-blue-300"
>
Copy
</Button>
</div>
</div>
))}
</div>
<Button className="w-full mt-6 bg-blue-600 hover:bg-blue-700">
Generate New Key
</Button>
</CardContent>
</Card>
</div>
{/* Security Notice */}
<Card className="border-red-500/30 bg-red-500/10 backdrop-blur">
<CardHeader>
<CardTitle className="text-red-300">🔐 Security Notice</CardTitle>
</CardHeader>
<CardContent className="text-red-200/80 space-y-2">
<p> Never share API keys in public channels or repositories</p>
<p> Rotate keys regularly for security</p>
<p> Use secrets management for production deployments</p>
<p> Report compromised keys immediately</p>
</CardContent>
</Card>
</div>
</div>
</Layout>
);
}