Enhanced Labs Dashboard with strategic widgets and soft-gating

cgen-00352ad013cc47fdaaea59ed9bc32518
This commit is contained in:
Builder.io 2025-11-17 07:45:30 +00:00
parent 497fcd8203
commit df48783a2b

View file

@ -24,99 +24,159 @@ import {
ArrowRight, ArrowRight,
AlertCircle, AlertCircle,
Send, Send,
Briefcase,
TrendingUp,
Code2,
} from "lucide-react"; } from "lucide-react";
import { ResearchWidget } from "@/components/ResearchWidget";
const API_BASE = import.meta.env.VITE_API_BASE || ""; const API_BASE = import.meta.env.VITE_API_BASE || "";
interface ResearchTrack {
id: string;
title: string;
description: string;
status: "scoping" | "research" | "in-development" | "testing" | "released";
progress: number;
lead_name: string;
team_size: number;
}
interface IPPortfolioItem {
id: string;
name: string;
type: "patent" | "trademark" | "trade-secret" | "copyright";
status: "filed" | "pending" | "secured" | "expired";
filing_date: string;
licensed_to: string;
}
interface Publication {
id: string;
title: string;
description: string;
status: "drafting" | "review" | "published";
author: string;
published_date: string;
url?: string;
}
interface ResearchBounty {
id: string;
title: string;
description: string;
reward: number;
difficulty: "intermediate" | "advanced" | "expert";
applicants_count: number;
}
export default function LabsDashboard() { export default function LabsDashboard() {
const navigate = useNavigate(); const navigate = useNavigate();
const { user, loading: authLoading } = useAuth(); const { user, loading: authLoading } = useAuth();
const { theme } = useArmTheme(); const { theme } = useArmTheme();
const [activeTab, setActiveTab] = useState("overview"); const [activeTab, setActiveTab] = useState("overview");
const [researchTracks, setResearchTracks] = useState<any[]>([]); const [isAccessible, setIsAccessible] = useState(false);
const [bounties, setBounties] = useState<any[]>([]); const [researchTracks, setResearchTracks] = useState<ResearchTrack[]>([]);
const [publications, setPublications] = useState<any[]>([]); const [ipPortfolio, setIpPortfolio] = useState<IPPortfolioItem[]>([]);
const [ipPortfolio, setIpPortfolio] = useState<any>(null); const [publications, setPublications] = useState<Publication[]>([]);
const [bounties, setBounties] = useState<ResearchBounty[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [isAdmin, setIsAdmin] = useState(false);
useEffect(() => { useEffect(() => {
if (!authLoading && user) { if (!authLoading && user) {
loadDashboardData(); checkAccessAndLoadData();
} else if (!authLoading && !user) {
setLoading(false);
} }
}, [user, authLoading]); }, [user, authLoading]);
const loadDashboardData = async () => { const checkAccessAndLoadData = async () => {
try { try {
setLoading(true); setLoading(true);
// Check if user has labs affiliation
const { const {
data: { session }, data: { session },
} = await supabase.auth.getSession(); } = await supabase.auth.getSession();
const token = session?.access_token; const token = session?.access_token;
if (!token) throw new Error("No auth token"); if (!token) throw new Error("No auth token");
try { // Check arm affiliations
const tracksRes = await fetch(`${API_BASE}/api/labs/research-tracks`, { const affiliationRes = await fetch(
`${API_BASE}/api/user/arm-affiliations`,
{
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}); },
if ( );
tracksRes.ok &&
tracksRes.headers.get("content-type")?.includes("application/json") let hasLabsAccess = false;
) { if (affiliationRes.ok) {
const data = await affiliationRes.json();
hasLabsAccess =
data.arms?.includes("labs") ||
data.role === "admin" ||
data.verified;
}
setIsAccessible(hasLabsAccess);
if (hasLabsAccess) {
// Load research tracks
try {
const tracksRes = await fetch(
`${API_BASE}/api/labs/research-tracks`,
{
headers: { Authorization: `Bearer ${token}` },
},
);
if (tracksRes.ok) {
const data = await tracksRes.json(); const data = await tracksRes.json();
setResearchTracks(Array.isArray(data) ? data : []); setResearchTracks(Array.isArray(data) ? data : []);
} }
} catch (err) { } catch {
// Silently ignore API errors // Silently ignore
}
try {
const bountiesRes = await fetch(`${API_BASE}/api/labs/bounties`, {
headers: { Authorization: `Bearer ${token}` },
});
if (
bountiesRes.ok &&
bountiesRes.headers.get("content-type")?.includes("application/json")
) {
const data = await bountiesRes.json();
setBounties(Array.isArray(data) ? data : []);
}
} catch (err) {
// Silently ignore API errors
}
try {
const pubRes = await fetch(`${API_BASE}/api/labs/publications`, {
headers: { Authorization: `Bearer ${token}` },
});
if (
pubRes.ok &&
pubRes.headers.get("content-type")?.includes("application/json")
) {
const data = await pubRes.json();
setPublications(Array.isArray(data) ? data : []);
}
} catch (err) {
// Silently ignore API errors
} }
// Load IP portfolio
try { try {
const ipRes = await fetch(`${API_BASE}/api/labs/ip-portfolio`, { const ipRes = await fetch(`${API_BASE}/api/labs/ip-portfolio`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}); });
if ( if (ipRes.ok) {
ipRes.ok &&
ipRes.headers.get("content-type")?.includes("application/json")
) {
const data = await ipRes.json(); const data = await ipRes.json();
setIpPortfolio(data); setIpPortfolio(Array.isArray(data) ? data : []);
setIsAdmin(data?.is_admin || false);
} }
} catch (err) { } catch {
// Silently ignore API errors // Silently ignore
} }
} catch (error) {
// Load publications (all)
try {
const pubRes = await fetch(`${API_BASE}/api/labs/publications`, {
headers: { Authorization: `Bearer ${token}` },
});
if (pubRes.ok) {
const data = await pubRes.json();
setPublications(Array.isArray(data) ? data : []);
}
} catch {
// Silently ignore
}
// Load bounties
try {
const bountiesRes = await fetch(`${API_BASE}/api/labs/bounties`, {
headers: { Authorization: `Bearer ${token}` },
});
if (bountiesRes.ok) {
const data = await bountiesRes.json();
setBounties(Array.isArray(data) ? data : []);
}
} catch {
// Silently ignore
}
}
} catch {
// Silently ignore errors // Silently ignore errors
} finally { } finally {
setLoading(false); setLoading(false);
@ -132,15 +192,23 @@ export default function LabsDashboard() {
<Layout> <Layout>
<div className="min-h-screen bg-gradient-to-b from-black via-amber-950/30 to-black flex items-center justify-center px-4"> <div className="min-h-screen bg-gradient-to-b from-black via-amber-950/30 to-black flex items-center justify-center px-4">
<div className="max-w-md text-center space-y-6"> <div className="max-w-md text-center space-y-6">
<h1 className="text-4xl font-bold bg-gradient-to-r from-amber-300 to-yellow-300 bg-clip-text text-transparent"> <div className="space-y-2">
Research LABS <Code2 className="h-16 w-16 mx-auto text-amber-400" />
<h1 className="text-4xl font-bold bg-gradient-to-r from-amber-300 to-yellow-300 bg-clip-text text-transparent font-mono">
AeThex LABS
</h1> </h1>
<p className="text-gray-400">Discover cutting-edge R&D</p> </div>
<p className="text-gray-400 text-lg">
Our proprietary R&D skunkworks
</p>
<p className="text-sm text-gray-500">
Access our cutting-edge research, IP portfolio, and publications
</p>
<Button <Button
onClick={() => navigate("/login")} onClick={() => navigate("/login")}
className="w-full bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700 text-lg py-6" className="w-full bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700 text-lg py-6"
> >
Sign In Sign In to Continue
</Button> </Button>
</div> </div>
</div> </div>
@ -148,6 +216,69 @@ export default function LabsDashboard() {
); );
} }
if (!isAccessible) {
return (
<Layout>
<div className="min-h-screen bg-gradient-to-b from-black via-amber-950/30 to-black py-8">
<div className="container mx-auto px-4 max-w-2xl">
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/30">
<CardContent className="p-12 text-center space-y-6">
<div className="space-y-3">
<Lock className="h-16 w-16 mx-auto text-amber-400" />
<h2 className="text-3xl font-bold text-white font-mono">
Join LABS?
</h2>
<p className="text-gray-400 text-lg">
LABS is our internal R&D department for A-Corp employees
</p>
</div>
<div className="space-y-4 text-left bg-black/30 p-6 rounded-lg border border-amber-500/20">
<h3 className="font-semibold text-white text-sm uppercase tracking-wider">
What is LABS?
</h3>
<p className="text-sm text-gray-400">
LABS is our proprietary, for-profit R&D department that takes
the open-source Axiom Protocol and builds competitive,
closed-source "secret weapons" on top of it.
</p>
<p className="text-sm text-gray-400">
We house active research tracks, manage our IP portfolio,
publish technical whitepapers, and post high-difficulty
research bounties to our elite architect community.
</p>
</div>
<div className="space-y-3">
<Button
onClick={() => navigate("/labs")}
className="w-full bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700 h-12"
>
<ArrowRight className="h-4 w-4 mr-2" />
Explore Published Research
</Button>
<Button
onClick={() => navigate("/labs/join-request")}
variant="outline"
className="w-full border-amber-500/30 text-amber-300 hover:bg-amber-500/10 h-12"
>
Request LABS Access
</Button>
</div>
<p className="text-xs text-gray-500 max-w-sm mx-auto">
To join LABS, you must be a verified A-Corp employee or
architect with proven expertise
</p>
</CardContent>
</Card>
</div>
</div>
</Layout>
);
}
// Main dashboard - user has access
return ( return (
<Layout> <Layout>
<div <div
@ -157,13 +288,16 @@ export default function LabsDashboard() {
<div className="container mx-auto px-4 max-w-7xl space-y-8"> <div className="container mx-auto px-4 max-w-7xl space-y-8">
{/* Header */} {/* Header */}
<div className="space-y-4 animate-slide-down"> <div className="space-y-4 animate-slide-down">
<div className="flex items-center gap-3">
<Code2 className="h-8 w-8 text-amber-400" />
<h1 <h1
className={`text-5xl md:text-6xl font-bold bg-gradient-to-r ${theme.accentColor} bg-clip-text text-transparent`} className={`text-5xl md:text-6xl font-bold bg-gradient-to-r ${theme.accentColor} bg-clip-text text-transparent font-mono`}
> >
Research LABS LABS
</h1> </h1>
<p className="text-gray-400 text-lg"> </div>
R&D Workshop | Blueprint Technical <p className="text-gray-400 text-lg max-w-2xl">
R&D Workshop | Proprietary Research & IP Management
</p> </p>
</div> </div>
@ -175,71 +309,183 @@ export default function LabsDashboard() {
> >
<TabsList <TabsList
className="grid w-full grid-cols-4 bg-amber-950/30 border border-amber-500/20 p-1" className="grid w-full grid-cols-4 bg-amber-950/30 border border-amber-500/20 p-1"
style={{ fontFamily: theme.fontFamily }} style={{ fontFamily: "Monaco, Courier New, monospace" }}
> >
<TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="tracks">Tracks</TabsTrigger> <TabsTrigger value="tracks">Research Tracks</TabsTrigger>
<TabsTrigger value="publications">Publications</TabsTrigger>
<TabsTrigger value="bounties">Bounties</TabsTrigger> <TabsTrigger value="bounties">Bounties</TabsTrigger>
<TabsTrigger value="pubs">Publications</TabsTrigger>
</TabsList> </TabsList>
{/* Overview Tab */} {/* Overview Tab */}
<TabsContent value="overview" className="space-y-6 animate-fade-in"> <TabsContent value="overview" className="space-y-6 animate-fade-in">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> {/* Quick Stats */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20"> <Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardContent className="p-6 space-y-2"> <CardContent className="p-6 space-y-2">
<p className="text-sm text-gray-400">Active Tracks</p> <div className="flex items-center justify-between">
<p className="text-3xl font-bold text-white"> <p className="text-xs text-gray-400 uppercase tracking-wider">
Active Tracks
</p>
<Lightbulb className="h-5 w-5 text-amber-400" />
</div>
<p className="text-3xl font-bold text-white font-mono">
{researchTracks.length} {researchTracks.length}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="bg-gradient-to-br from-yellow-950/40 to-yellow-900/20 border-yellow-500/20"> <Card className="bg-gradient-to-br from-yellow-950/40 to-yellow-900/20 border-yellow-500/20">
<CardContent className="p-6 space-y-2"> <CardContent className="p-6 space-y-2">
<p className="text-sm text-gray-400">Available Bounties</p> <div className="flex items-center justify-between">
<p className="text-3xl font-bold text-white"> <p className="text-xs text-gray-400 uppercase tracking-wider">
{bounties.length} IP Assets
</p>
<Lock className="h-5 w-5 text-yellow-400" />
</div>
<p className="text-3xl font-bold text-white font-mono">
{ipPortfolio.length}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="bg-gradient-to-br from-orange-950/40 to-orange-900/20 border-orange-500/20"> <Card className="bg-gradient-to-br from-orange-950/40 to-orange-900/20 border-orange-500/20">
<CardContent className="p-6 space-y-2"> <CardContent className="p-6 space-y-2">
<p className="text-sm text-gray-400">Publications</p> <div className="flex items-center justify-between">
<p className="text-3xl font-bold text-white"> <p className="text-xs text-gray-400 uppercase tracking-wider">
Publications
</p>
<FileText className="h-5 w-5 text-orange-400" />
</div>
<p className="text-3xl font-bold text-white font-mono">
{publications.length} {publications.length}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardContent className="p-6 space-y-2">
<div className="flex items-center justify-between">
<p className="text-xs text-gray-400 uppercase tracking-wider">
Bounties
</p>
<Zap className="h-5 w-5 text-amber-400" />
</div>
<p className="text-3xl font-bold text-white font-mono">
{bounties.length}
</p>
</CardContent>
</Card>
</div> </div>
{/* Recent Publications */} {/* Featured Research Track */}
{publications.length > 0 && ( {researchTracks.length > 0 && (
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20"> <Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardHeader>
<CardTitle>Featured Research Track</CardTitle>
<CardDescription>
Our current flagship R&D initiative
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{(() => {
const featured = researchTracks[0];
return (
<div className="space-y-4">
<div>
<h3 className="text-lg font-semibold text-white mb-1">
{featured.title}
</h3>
<p className="text-sm text-gray-400">
{featured.description}
</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
<div className="space-y-1">
<p className="text-xs text-gray-500 uppercase">
Lead
</p>
<p className="text-sm font-mono text-white">
{featured.lead_name}
</p>
</div>
<div className="space-y-1">
<p className="text-xs text-gray-500 uppercase">
Team Size
</p>
<p className="text-sm font-mono text-white">
{featured.team_size} members
</p>
</div>
<div className="space-y-1">
<p className="text-xs text-gray-500 uppercase">
Progress
</p>
<p className="text-sm font-mono text-white">
{featured.progress}%
</p>
</div>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between text-xs">
<span className="text-gray-400">Overall Progress</span>
<span className="font-mono text-amber-400">
{featured.progress}%
</span>
</div>
<div className="w-full bg-black/30 rounded h-2 border border-amber-500/20 overflow-hidden">
<div
className="h-full bg-gradient-to-r from-amber-500 to-yellow-500"
style={{ width: `${featured.progress}%` }}
/>
</div>
</div>
<Badge className="bg-amber-600/50 text-amber-100 capitalize w-fit">
{featured.status.replace("-", " ")}
</Badge>
</div>
);
})()}
</CardContent>
</Card>
)}
{/* Recent Publications */}
{publications.filter((p) => p.status === "published").length > 0 && (
<Card className="bg-gradient-to-br from-orange-950/40 to-orange-900/20 border-orange-500/20">
<CardHeader> <CardHeader>
<CardTitle>Recent Publications</CardTitle> <CardTitle>Recent Publications</CardTitle>
<CardDescription>
Latest technical whitepapers and blog posts
</CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-3"> <CardContent className="space-y-3">
{publications.slice(0, 3).map((pub: any) => ( {publications
.filter((p) => p.status === "published")
.slice(0, 3)
.map((pub) => (
<a <a
key={pub.id} key={pub.id}
href={pub.url} href={pub.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="p-4 bg-black/30 rounded-lg border border-amber-500/10 hover:border-amber-500/30 transition block" className="p-4 bg-black/30 rounded-lg border border-orange-500/10 hover:border-orange-500/30 transition block group"
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<FileText className="h-5 w-5 text-amber-500 flex-shrink-0 mt-1" /> <FileText className="h-5 w-5 text-orange-400 flex-shrink-0 mt-1" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="font-semibold text-white truncate"> <p className="font-semibold text-white group-hover:text-orange-300 transition truncate">
{pub.title} {pub.title}
</p> </p>
<p className="text-xs text-gray-400 mt-1"> <p className="text-xs text-gray-400 mt-1">
{new Date( By {pub.author} {" "}
pub.published_date, {new Date(pub.published_date).toLocaleDateString()}
).toLocaleDateString()}
</p> </p>
</div> </div>
<ExternalLink className="h-4 w-4 text-gray-500 flex-shrink-0" /> <ExternalLink className="h-4 w-4 text-gray-500 flex-shrink-0 group-hover:text-orange-400 transition" />
</div> </div>
</a> </a>
))} ))}
@ -247,192 +493,329 @@ export default function LabsDashboard() {
</Card> </Card>
)} )}
{/* Submit Research Proposal CTA */} {/* CTA Section */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="bg-gradient-to-br from-amber-600/20 to-yellow-600/20 border-amber-500/40"> <Card className="bg-gradient-to-br from-amber-600/20 to-yellow-600/20 border-amber-500/40">
<CardContent className="p-8 text-center space-y-4"> <CardContent className="p-8 flex flex-col justify-center h-full space-y-4">
<h3 <h3
className="text-2xl font-bold text-white" className="text-xl font-bold text-white font-mono"
style={{ fontFamily: theme.fontFamily }} style={{ fontFamily: "Monaco, Courier New, monospace" }}
> >
Have a Research Idea? Submit Research Proposal
</h3> </h3>
<p className="text-gray-300"> <p className="text-sm text-gray-300">
Submit your research proposal for the LABS pipeline Propose a new R&D initiative for LABS
</p> </p>
<Button <Button
onClick={() => navigate("/labs/submit-proposal")} onClick={() => navigate("/labs/submit-proposal")}
className="bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700" className="w-full bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700 justify-center"
style={{ fontFamily: theme.fontFamily }}
> >
<Send className="h-4 w-4 mr-2" /> <Send className="h-4 w-4 mr-2" />
Submit Research Proposal Submit Proposal
</Button> </Button>
</CardContent> </CardContent>
</Card> </Card>
<Card className="bg-gradient-to-br from-yellow-600/20 to-amber-600/20 border-yellow-500/40">
<CardContent className="p-8 flex flex-col justify-center h-full space-y-4">
<h3
className="text-xl font-bold text-white font-mono"
style={{ fontFamily: "Monaco, Courier New, monospace" }}
>
Browse LABS Bounties
</h3>
<p className="text-sm text-gray-300">
High-difficulty research opportunities from NEXUS
</p>
<Button
onClick={() => navigate("/nexus?category=research")}
className="w-full bg-gradient-to-r from-yellow-600 to-amber-600 hover:from-yellow-700 hover:to-amber-700 justify-center"
>
<ArrowRight className="h-4 w-4 mr-2" />
Browse Bounties
</Button>
</CardContent>
</Card>
</div>
</TabsContent> </TabsContent>
{/* Research Tracks Tab */} {/* Research Tracks Tab */}
<TabsContent value="tracks" className="space-y-4 animate-fade-in"> <TabsContent value="tracks" className="space-y-4 animate-fade-in">
<ResearchWidget {researchTracks.length === 0 ? (
tracks={researchTracks.map((t: any) => ({
id: t.id,
title: t.title,
description: t.description,
status: t.status,
progress: t.progress || 0,
publications: t.publications || [],
whitepaper_url: t.whitepaper_url,
lead: t.lead?.full_name,
}))}
title="Active Research Tracks"
description="Internal R&D projects"
accentColor="amber"
/>
</TabsContent>
{/* Bounties Tab */}
<TabsContent value="bounties" className="space-y-4 animate-fade-in">
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20"> <Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardHeader> <CardContent className="p-12 text-center space-y-4">
<CardTitle>Research Bounties</CardTitle> <Lightbulb className="h-12 w-12 mx-auto text-amber-500 opacity-50" />
<CardDescription> <p className="text-gray-400">No active research tracks</p>
High-difficulty opportunities from NEXUS </CardContent>
</CardDescription> </Card>
</CardHeader>
<CardContent>
{bounties.length === 0 ? (
<div className="text-center py-12">
<Zap className="h-12 w-12 mx-auto text-gray-500 opacity-50 mb-4" />
<p className="text-gray-400">No bounties available</p>
</div>
) : ( ) : (
<div className="space-y-3"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{bounties.map((bounty: any) => ( {researchTracks.map((track) => (
<div <Card
key={bounty.id} key={track.id}
className="p-4 bg-black/30 rounded-lg border border-amber-500/10 hover:border-amber-500/30 transition" className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20 hover:border-amber-500/40 transition"
> >
<div className="flex items-start justify-between gap-4 mb-2"> <CardHeader>
<h4 className="font-semibold text-white"> <div className="flex items-start justify-between gap-2">
{bounty.title} <div className="flex-1 min-w-0">
</h4> <CardTitle className="text-base truncate">
<p className="text-lg font-bold text-amber-400"> {track.title}
${bounty.reward?.toLocaleString()} </CardTitle>
</div>
<Badge className="capitalize shrink-0">
{track.status.replace("-", " ")}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-4">
<p className="text-sm text-gray-400">
{track.description}
</p>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<p className="text-xs text-gray-500 uppercase">
Lead
</p>
<p className="text-sm font-mono text-white">
{track.lead_name}
</p> </p>
</div> </div>
<p className="text-sm text-gray-400"> <div className="space-y-1">
{bounty.description} <p className="text-xs text-gray-500 uppercase">
Team
</p> </p>
<p className="text-sm font-mono text-white">
{track.team_size} members
</p>
</div>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between text-xs">
<span className="text-gray-400">Progress</span>
<span className="font-mono text-amber-400">
{track.progress}%
</span>
</div>
<div className="w-full bg-black/30 rounded h-2 border border-amber-500/20 overflow-hidden">
<div
className="h-full bg-gradient-to-r from-amber-500 to-yellow-500"
style={{ width: `${track.progress}%` }}
/>
</div>
</div>
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
className="mt-3 border-amber-500/30 text-amber-300 hover:bg-amber-500/10" className="w-full border-amber-500/30 text-amber-300 hover:bg-amber-500/10"
> >
View Details <ArrowRight className="h-3 w-3 ml-2" /> View Details <ArrowRight className="h-3 w-3 ml-2" />
</Button> </Button>
</div> </CardContent>
</Card>
))} ))}
</div> </div>
)} )}
</CardContent>
</Card>
</TabsContent> </TabsContent>
{/* Publications Tab */} {/* Publications Tab */}
<TabsContent value="pubs" className="space-y-4 animate-fade-in"> <TabsContent value="publications" className="space-y-4 animate-fade-in">
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardHeader>
<CardTitle>Publication Pipeline</CardTitle>
<CardDescription>
Upcoming whitepapers and technical blog posts
</CardDescription>
</CardHeader>
<CardContent>
{publications.length === 0 ? ( {publications.length === 0 ? (
<div className="text-center py-12"> <Card className="bg-gradient-to-br from-orange-950/40 to-orange-900/20 border-orange-500/20">
<FileText className="h-12 w-12 mx-auto text-gray-500 opacity-50 mb-4" /> <CardContent className="p-12 text-center space-y-4">
<p className="text-gray-400">No publications</p> <FileText className="h-12 w-12 mx-auto text-orange-500 opacity-50" />
</div> <p className="text-gray-400">No publications yet</p>
</CardContent>
</Card>
) : ( ) : (
<div className="space-y-3"> <div className="space-y-3">
{publications.map((pub: any) => ( {publications.map((pub) => (
<a <a
key={pub.id} key={pub.id}
href={pub.url} href={pub.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="p-4 bg-black/30 rounded-lg border border-amber-500/10 hover:border-amber-500/30 transition block" className="p-4 bg-gradient-to-r from-orange-950/40 to-orange-900/20 rounded-lg border border-orange-500/20 hover:border-orange-500/40 transition block group"
> >
<div className="flex items-start justify-between gap-4 mb-2"> <div className="flex items-start justify-between gap-4 mb-2">
<h4 className="font-semibold text-white"> <div className="flex-1 min-w-0">
<h4 className="font-semibold text-white group-hover:text-orange-300 transition truncate">
{pub.title} {pub.title}
</h4> </h4>
</div>
<Badge <Badge
className={ className={
pub.status === "published" pub.status === "published"
? "bg-green-600/50 text-green-100" ? "bg-green-600/50 text-green-100 capitalize shrink-0"
: "bg-blue-600/50 text-blue-100" : "bg-blue-600/50 text-blue-100 capitalize shrink-0"
} }
> >
{pub.status} {pub.status}
</Badge> </Badge>
</div> </div>
<p className="text-sm text-gray-400"> <p className="text-sm text-gray-400 mb-2">
{pub.description} {pub.description}
</p> </p>
<p className="text-xs text-gray-500 mt-2"> <div className="flex items-center justify-between">
<p className="text-xs text-gray-500">
By {pub.author} {" "}
{new Date(pub.published_date).toLocaleDateString()} {new Date(pub.published_date).toLocaleDateString()}
</p> </p>
{pub.url && (
<ExternalLink className="h-4 w-4 text-orange-400 group-hover:translate-x-0.5 transition" />
)}
</div>
</a> </a>
))} ))}
</div> </div>
)} )}
</CardContent>
</Card>
</TabsContent> </TabsContent>
{/* IP Dashboard - Admin Only */} {/* Bounties Tab */}
{isAdmin && ( <TabsContent value="bounties" className="space-y-4 animate-fade-in">
{bounties.length === 0 ? (
<Card className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20">
<CardContent className="p-12 text-center space-y-4">
<Zap className="h-12 w-12 mx-auto text-amber-500 opacity-50" />
<p className="text-gray-400">
No active research bounties at this time
</p>
<Button
onClick={() => navigate("/nexus")}
variant="outline"
className="border-amber-500/30 text-amber-300 hover:bg-amber-500/10"
>
Browse All NEXUS Bounties
</Button>
</CardContent>
</Card>
) : (
<div className="space-y-3">
{bounties.map((bounty) => (
<Card
key={bounty.id}
className="bg-gradient-to-br from-amber-950/40 to-amber-900/20 border-amber-500/20 hover:border-amber-500/40 transition"
>
<CardContent className="p-4">
<div className="flex items-start justify-between gap-4 mb-3">
<div className="flex-1 min-w-0">
<h4 className="font-semibold text-white truncate">
{bounty.title}
</h4>
</div>
<div className="text-right shrink-0">
<p className="text-lg font-bold text-amber-400 font-mono">
${bounty.reward.toLocaleString()}
</p>
</div>
</div>
<p className="text-sm text-gray-400 mb-3">
{bounty.description}
</p>
<div className="flex items-center justify-between mb-3">
<Badge
variant="outline"
className={
bounty.difficulty === "expert"
? "border-red-500/50 text-red-300"
: bounty.difficulty === "advanced"
? "border-orange-500/50 text-orange-300"
: "border-yellow-500/50 text-yellow-300"
}
>
{bounty.difficulty}
</Badge>
<span className="text-xs text-gray-500">
{bounty.applicants_count} applicants
</span>
</div>
<Button
size="sm"
className="w-full bg-gradient-to-r from-amber-600 to-yellow-600 hover:from-amber-700 hover:to-yellow-700"
>
View & Apply <ArrowRight className="h-3 w-3 ml-2" />
</Button>
</CardContent>
</Card>
))}
</div>
)}
</TabsContent>
{/* IP Portfolio - Admin Only */}
{ipPortfolio.length > 0 && (
<Card className="bg-gradient-to-br from-red-950/40 to-red-900/20 border-red-500/20 mt-6"> <Card className="bg-gradient-to-br from-red-950/40 to-red-900/20 border-red-500/20 mt-6">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Lock className="h-5 w-5 text-red-500" /> <Lock className="h-5 w-5 text-red-500" />
IP Dashboard (Admin Only) IP Portfolio
</CardTitle> </CardTitle>
<CardDescription>
Proprietary intellectual property assets
</CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent>
{ipPortfolio ? ( <div className="overflow-x-auto">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <table className="w-full text-sm">
<div className="p-4 bg-black/30 rounded-lg border border-red-500/20"> <thead>
<p className="text-sm text-gray-400">Patents Filed</p> <tr className="border-b border-red-500/20">
<p className="text-3xl font-bold text-white"> <th className="text-left py-3 px-3 font-semibold text-gray-400 uppercase text-xs">
{ipPortfolio.patents_count || 0} IP Name
</p> </th>
<th className="text-left py-3 px-3 font-semibold text-gray-400 uppercase text-xs">
Type
</th>
<th className="text-left py-3 px-3 font-semibold text-gray-400 uppercase text-xs">
Status
</th>
<th className="text-left py-3 px-3 font-semibold text-gray-400 uppercase text-xs">
Licensed To
</th>
</tr>
</thead>
<tbody>
{ipPortfolio.map((item) => (
<tr
key={item.id}
className="border-b border-red-500/10 hover:bg-red-500/5 transition"
>
<td className="py-3 px-3 text-white font-mono text-xs">
{item.name}
</td>
<td className="py-3 px-3">
<Badge
variant="outline"
className="capitalize text-xs"
>
{item.type.replace("-", " ")}
</Badge>
</td>
<td className="py-3 px-3">
<Badge
className={
item.status === "secured"
? "bg-green-600/50 text-green-100"
: item.status === "filed"
? "bg-blue-600/50 text-blue-100"
: "bg-yellow-600/50 text-yellow-100"
}
>
{item.status}
</Badge>
</td>
<td className="py-3 px-3 text-gray-400 text-xs">
{item.licensed_to}
</td>
</tr>
))}
</tbody>
</table>
</div> </div>
<div className="p-4 bg-black/30 rounded-lg border border-red-500/20">
<p className="text-sm text-gray-400">Trademarks</p>
<p className="text-3xl font-bold text-white">
{ipPortfolio.trademarks_count || 0}
</p>
</div>
<div className="p-4 bg-black/30 rounded-lg border border-red-500/20">
<p className="text-sm text-gray-400">Trade Secrets</p>
<p className="text-3xl font-bold text-white">
{ipPortfolio.trade_secrets_count || 0}
</p>
</div>
<div className="p-4 bg-black/30 rounded-lg border border-red-500/20">
<p className="text-sm text-gray-400">Copyrights</p>
<p className="text-3xl font-bold text-white">
{ipPortfolio.copyrights_count || 0}
</p>
</div>
</div>
) : (
<p className="text-gray-400 text-center py-8">
IP portfolio data not available
</p>
)}
</CardContent> </CardContent>
</Card> </Card>
)} )}