Enhanced Labs Dashboard with strategic widgets and soft-gating
cgen-00352ad013cc47fdaaea59ed9bc32518
This commit is contained in:
parent
497fcd8203
commit
df48783a2b
1 changed files with 661 additions and 278 deletions
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue