mirror of
https://github.com/arkorty/B.Tech-Project-III.git
synced 2026-04-19 12:41:48 +00:00
319 lines
10 KiB
TypeScript
319 lines
10 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { fetchAllPatterns, fetchAllSignals, Pattern, Signal } from "../lib/api";
|
|
|
|
type CardMetric = {
|
|
type: string;
|
|
label: string;
|
|
value: string;
|
|
width?: string;
|
|
valueDim?: boolean;
|
|
};
|
|
|
|
type CardData = {
|
|
icon: string;
|
|
iconBg: string;
|
|
iconBorder: string;
|
|
iconColor: string;
|
|
title: string;
|
|
pulse?: boolean;
|
|
time: string;
|
|
description: string;
|
|
metrics?: CardMetric[];
|
|
recommendation?: string;
|
|
footerLabel: string;
|
|
footerIcon: string;
|
|
footerDim: boolean;
|
|
};
|
|
|
|
const STATIC_CARDS = [
|
|
{
|
|
icon: "subject",
|
|
iconBg: "rgba(167,139,250,0.1)",
|
|
iconBorder: "rgba(167,139,250,0.2)",
|
|
iconColor: "#A78BFA",
|
|
title: "SEMANTIC_PROCESSOR",
|
|
},
|
|
{
|
|
icon: "mood",
|
|
iconBg: "rgba(167,139,250,0.1)",
|
|
iconBorder: "rgba(167,139,250,0.2)",
|
|
iconColor: "#A78BFA",
|
|
title: "SENTIMENT_MINER",
|
|
},
|
|
{
|
|
icon: "schema",
|
|
iconBg: "rgba(249,245,248,0.05)",
|
|
iconBorder: "rgba(255,255,255,0.1)",
|
|
iconColor: "rgba(249,245,248,0.4)",
|
|
title: "PATTERN_DETECTOR",
|
|
},
|
|
];
|
|
|
|
export default function IntelligenceCards() {
|
|
const [patterns, setPatterns] = useState<Pattern[]>([]);
|
|
const [signals, setSignals] = useState<Signal[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
async function load() {
|
|
try {
|
|
const [ptns, allGroups] = await Promise.all([
|
|
fetchAllPatterns(),
|
|
fetchAllSignals(),
|
|
]);
|
|
setPatterns(ptns);
|
|
setSignals(allGroups.flatMap((g) => g.signals));
|
|
} catch {
|
|
// ignore
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
load();
|
|
}, []);
|
|
|
|
const totalSignals = signals.length;
|
|
const sentimentSignals = signals.filter(
|
|
(s) =>
|
|
s.metadata.type.includes("sentiment") ||
|
|
s.metadata.sentiment !== "neutral"
|
|
);
|
|
const avgSentiment =
|
|
sentimentSignals.length > 0
|
|
? `${Math.round((sentimentSignals.length / Math.max(totalSignals, 1)) * 100)}%`
|
|
: "—";
|
|
|
|
const activePatterns = patterns.filter((p) => p.is_active);
|
|
const criticalPatterns = patterns.filter((p) => p.severity === "critical");
|
|
|
|
const cardData: CardData[] = [
|
|
{
|
|
...STATIC_CARDS[0],
|
|
time: loading ? "LOADING..." : `${totalSignals} SIGNALS`,
|
|
description: loading
|
|
? "Loading signal data..."
|
|
: `Processing deep contextual inference across ${totalSignals} signals. Semantic alignment analysis running across all active node clusters.`,
|
|
metrics: [
|
|
{
|
|
type: "bar",
|
|
label: "Coverage",
|
|
value: totalSignals > 0 ? "active" : "0%",
|
|
width: totalSignals > 0 ? "88%" : "0%",
|
|
},
|
|
{
|
|
type: "row",
|
|
label: "Signals Indexed",
|
|
value: String(totalSignals),
|
|
},
|
|
],
|
|
footerLabel: "Inference Details",
|
|
footerIcon: "arrow_forward",
|
|
footerDim: false,
|
|
},
|
|
{
|
|
...STATIC_CARDS[1],
|
|
pulse: true,
|
|
time: loading ? "LOADING..." : `${sentimentSignals.length} SAMPLES`,
|
|
description: loading
|
|
? "Loading sentiment data..."
|
|
: `Identifying emotional flux patterns within communications. Analyzed ${sentimentSignals.length} sentiment-bearing signals out of ${totalSignals} total.`,
|
|
recommendation:
|
|
sentimentSignals.length > 0
|
|
? `${avgSentiment} of signals carry sentiment signals. Monitor channels with high emotional flux.`
|
|
: undefined,
|
|
footerLabel: "Refine Analysis",
|
|
footerIcon: "arrow_forward",
|
|
footerDim: false,
|
|
},
|
|
{
|
|
...STATIC_CARDS[2],
|
|
time: loading ? "LOADING..." : `${activePatterns.length} ACTIVE`,
|
|
description: loading
|
|
? "Loading pattern data..."
|
|
: activePatterns.length > 0
|
|
? `${activePatterns.length} active patterns detected across all groups. ${criticalPatterns.length} require immediate attention.`
|
|
: "No patterns detected yet. Patterns emerge as more signals are processed.",
|
|
metrics:
|
|
activePatterns.length > 0
|
|
? [
|
|
{
|
|
type: "row",
|
|
label: "Active Patterns",
|
|
value: String(activePatterns.length),
|
|
valueDim: false,
|
|
},
|
|
{
|
|
type: "row",
|
|
label: "Critical",
|
|
value: criticalPatterns.length > 0 ? `${criticalPatterns.length} CRITICAL` : "NONE",
|
|
valueDim: criticalPatterns.length > 0,
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
type: "row",
|
|
label: "Status",
|
|
value: "Accumulating data",
|
|
valueDim: true,
|
|
},
|
|
],
|
|
footerLabel: activePatterns.length > 0 ? "View Patterns" : "System Initializing",
|
|
footerIcon: activePatterns.length > 0 ? "arrow_forward" : "hourglass_empty",
|
|
footerDim: activePatterns.length === 0,
|
|
},
|
|
];
|
|
|
|
type CardMetric = {
|
|
type: string;
|
|
label: string;
|
|
value: string;
|
|
width?: string;
|
|
valueDim?: boolean;
|
|
};
|
|
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
{cardData.map((card, idx) => (
|
|
<div
|
|
key={card.title}
|
|
className="glass p-6 rounded-2xl border neon-border flex flex-col relative overflow-hidden group card-interactive animate-fade-in-up"
|
|
style={{ animationDelay: `${idx * 100}ms` }}
|
|
>
|
|
{/* Background Glow */}
|
|
<div className="absolute inset-0 rounded-2xl -z-10 bg-gradient-to-br from-violet-500/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
|
|
|
{/* Card Header */}
|
|
<div className="flex justify-between items-start">
|
|
<div
|
|
className="p-2.5 rounded-xl"
|
|
style={{ backgroundColor: card.iconBg, border: `1px solid ${card.iconBorder}` }}
|
|
>
|
|
<span
|
|
className={`material-symbols-outlined${card.pulse ? " active-pulse" : ""}`}
|
|
style={{ color: card.iconColor, fontSize: "24px" }}
|
|
>
|
|
{card.icon}
|
|
</span>
|
|
</div>
|
|
<span
|
|
className="text-[10px] font-mono-data uppercase tracking-widest"
|
|
style={{ color: "rgba(249,245,248,0.4)" }}
|
|
>
|
|
{card.time}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Card Body */}
|
|
<div className="flex-1 mt-4">
|
|
<h3 className="text-lg font-bold tracking-tight text-white mb-2 uppercase">
|
|
{card.title}
|
|
</h3>
|
|
<p className="text-sm leading-relaxed mb-6" style={{ color: "rgba(249,245,248,0.7)" }}>
|
|
{card.description}
|
|
</p>
|
|
|
|
{card.recommendation && (
|
|
<div
|
|
className="p-4 rounded-xl mb-6"
|
|
style={{
|
|
backgroundColor: "rgba(167,139,250,0.05)",
|
|
border: "1px solid rgba(167,139,250,0.1)",
|
|
}}
|
|
>
|
|
<div className="text-[10px] uppercase font-bold mb-1" style={{ color: "#A78BFA" }}>
|
|
Recommended Action
|
|
</div>
|
|
<p className="text-[11px] leading-relaxed" style={{ color: "rgba(249,245,248,0.8)" }}>
|
|
{card.recommendation}
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{card.metrics && (
|
|
<div className="space-y-4 mb-6">
|
|
{(card.metrics as CardMetric[]).map((m) =>
|
|
m.type === "bar" ? (
|
|
<div key={m.label} className="flex flex-col">
|
|
<div className="flex justify-between items-end mb-1.5">
|
|
<span
|
|
className="text-[10px] uppercase tracking-widest"
|
|
style={{ color: "rgba(249,245,248,0.4)" }}
|
|
>
|
|
{m.label}
|
|
</span>
|
|
<span
|
|
className="text-[10px] font-mono-data"
|
|
style={{ color: "#A78BFA" }}
|
|
>
|
|
{m.value}
|
|
</span>
|
|
</div>
|
|
<div
|
|
className="w-full h-1 rounded-full overflow-hidden"
|
|
style={{ backgroundColor: "rgba(255,255,255,0.05)" }}
|
|
>
|
|
<div
|
|
className="h-full"
|
|
style={{
|
|
width: m.width,
|
|
background: "linear-gradient(to right, #A78BFA, #b79fff)",
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div
|
|
key={m.label}
|
|
className="flex justify-between items-center py-2"
|
|
style={{ borderBottom: "1px solid rgba(255,255,255,0.05)" }}
|
|
>
|
|
<span
|
|
className="text-[10px] uppercase"
|
|
style={{ color: "rgba(249,245,248,0.4)" }}
|
|
>
|
|
{m.label}
|
|
</span>
|
|
<span
|
|
className="text-xs font-mono-data"
|
|
style={{
|
|
color: m.valueDim ? "#A78BFA" : "rgba(249,245,248,1)",
|
|
}}
|
|
>
|
|
{m.value}
|
|
</span>
|
|
</div>
|
|
)
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Card Footer */}
|
|
<div
|
|
className="px-6 py-4 flex justify-between items-center cursor-pointer group/footer btn-interactive"
|
|
style={{ borderTop: "1px solid rgba(255,255,255,0.05)" }}
|
|
>
|
|
<span
|
|
className="text-[10px] font-bold uppercase tracking-[0.2em] group-hover/footer:translate-x-1 transition-transform"
|
|
style={{ color: card.footerDim ? "rgba(249,245,248,0.4)" : "#A78BFA" }}
|
|
>
|
|
{card.footerLabel}
|
|
</span>
|
|
<span
|
|
className="material-symbols-outlined text-sm group-hover/footer:translate-x-1 transition-transform"
|
|
style={{
|
|
fontSize: "18px",
|
|
color: card.footerDim ? "rgba(249,245,248,0.4)" : "#A78BFA",
|
|
}}
|
|
>
|
|
{card.footerIcon}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|