feat: scaffold initial dashboard layout and base pages for all modules
This commit is contained in:
+152
-114
@@ -1,21 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowUpRight, Brain, TrendingUp, Zap, Target, ArrowDownRight, BarChart3, Filter } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Radar,
|
||||
RadarChart,
|
||||
PolarGrid,
|
||||
PolarAngleAxis,
|
||||
ArrowUpRight, Brain, TrendingUp, Zap, Target, ArrowDownRight,
|
||||
BarChart3, Filter, Download, Info, CheckCircle2, AlertCircle
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer,
|
||||
Tooltip, XAxis, YAxis, Radar, RadarChart, PolarGrid, PolarAngleAxis, Cell
|
||||
} from "recharts";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const productivityTrend = [
|
||||
@@ -29,10 +23,10 @@ const productivityTrend = [
|
||||
];
|
||||
|
||||
const habitCompletion = [
|
||||
{ name: "Reading", completed: 85, missed: 15 },
|
||||
{ name: "Workout", completed: 60, missed: 40 },
|
||||
{ name: "Meditation", completed: 90, missed: 10 },
|
||||
{ name: "Coding", completed: 75, missed: 25 },
|
||||
{ name: "Reading", completed: 85, missed: 15, color: "#6C5BB0" },
|
||||
{ name: "Workout", completed: 60, missed: 40, color: "#a798e8" },
|
||||
{ name: "Meditation", completed: 90, missed: 10, color: "#10b981" },
|
||||
{ name: "Coding", completed: 75, missed: 25, color: "#3b82f6" },
|
||||
];
|
||||
|
||||
const focusRadarData = [
|
||||
@@ -44,8 +38,16 @@ const focusRadarData = [
|
||||
];
|
||||
|
||||
export default function AnalyticsPage() {
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
const [activeInsight, setActiveInsight] = useState<string | null>(null);
|
||||
|
||||
const handleExport = () => {
|
||||
setIsExporting(true);
|
||||
setTimeout(() => setIsExporting(false), 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
@@ -61,95 +63,116 @@ export default function AnalyticsPage() {
|
||||
<option className="bg-[#0A0710]">This Year</option>
|
||||
</select>
|
||||
</div>
|
||||
<button className="bg-white/5 hover:bg-white/10 text-foreground border border-white/10 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button
|
||||
onClick={handleExport}
|
||||
disabled={isExporting}
|
||||
className={`min-w-[140px] px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center justify-center gap-2 transition-all ${isExporting ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-white/5 hover:bg-white/10 text-foreground border border-white/10'}`}
|
||||
>
|
||||
{isExporting ? (
|
||||
<>
|
||||
<motion.div animate={{ rotate: 360 }} transition={{ repeat: Infinity, duration: 1, ease: "linear" }}>
|
||||
<Download className="h-4 w-4" />
|
||||
</motion.div>
|
||||
GENERATING...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BarChart3 className="h-4 w-4" />
|
||||
EXPORT REPORT
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* KPI Row */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
<KpiCard title="Total Focus Hours" value="124.5" change="+12%" icon={Zap} trend="up" />
|
||||
<KpiCard title="Goal Completion" value="82%" change="+4%" icon={Target} trend="up" color="emerald" />
|
||||
<KpiCard title="Productivity Score" value="9.2" change="-2%" icon={TrendingUp} trend="down" color="blue" />
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<Zap className="h-16 w-16 text-primary" />
|
||||
{/* Dynamic AI Score Ring */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 relative overflow-hidden group flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-primary mb-2">Strategic Readiness</h3>
|
||||
<div className="text-3xl font-black text-foreground">94<span className="text-sm font-normal opacity-60 ml-1">%</span></div>
|
||||
<p className="text-[10px] text-muted-foreground mt-2 font-medium">Optimal alignment with goals.</p>
|
||||
</div>
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4">Total Focus Hours</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-4xl font-bold text-foreground">124.5</span>
|
||||
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
|
||||
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 12%
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">vs previous 30 days</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<Target className="h-16 w-16 text-emerald-500" />
|
||||
</div>
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4">Goal Completion</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-4xl font-bold text-foreground">82%</span>
|
||||
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
|
||||
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 4%
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">vs previous 30 days</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<TrendingUp className="h-16 w-16 text-blue-500" />
|
||||
</div>
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4">Productivity Score</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-4xl font-bold text-foreground">9.2</span>
|
||||
<span className="text-xs text-rose-500 flex items-center font-medium mb-1">
|
||||
<ArrowDownRight className="h-3 w-3 mr-0.5" /> 2%
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">Out of 10.0 max</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 relative overflow-hidden group flex flex-col justify-between">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="relative w-16 h-16">
|
||||
<svg className="w-full h-full" viewBox="0 0 36 36">
|
||||
<path className="text-white/5" stroke="currentColor" strokeWidth="3" fill="none" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
|
||||
<motion.path
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 0.94 }}
|
||||
transition={{ duration: 1.5, ease: "easeOut" }}
|
||||
className="text-primary"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeDasharray="100, 100"
|
||||
fill="none"
|
||||
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"
|
||||
/>
|
||||
</svg>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Brain className="h-4 w-4 text-primary" />
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-primary">AI Insight</h3>
|
||||
</div>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed font-medium">
|
||||
Your energy peaks consistently around <span className="text-primary font-bold">10:00 AM</span>. Consider scheduling complex tasks during this block to maximize output.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Charts Grid */}
|
||||
{/* Main Analysis Area */}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6 flex-1 min-h-[400px]">
|
||||
|
||||
{/* Main Area Chart */}
|
||||
<div className="xl:col-span-2 rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col">
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
{/* Productivity Chart with Hotspots */}
|
||||
<div className="xl:col-span-2 rounded-sm border border-white/5 bg-[#0A0710] p-8 flex flex-col relative">
|
||||
<div className="flex justify-between items-start mb-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold mb-1">Productivity vs Energy Correlation</h3>
|
||||
<p className="text-xs text-muted-foreground">How your physical energy levels impact deep work output.</p>
|
||||
<h3 className="text-lg font-bold mb-1">Correlation: Focus vs Energy</h3>
|
||||
<p className="text-sm text-muted-foreground">Detailed visual mapping of biological energy impact on focus output.</p>
|
||||
</div>
|
||||
<div className="flex gap-4 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-[#6C5BB0]"></div> Focus Score</div>
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-emerald-500"></div> Energy Level</div>
|
||||
<div className="flex gap-4 text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-full bg-[#6C5BB0]"></div> Focus</div>
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-full bg-emerald-500"></div> Energy</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Chart Interaction Layer */}
|
||||
<div className="absolute top-24 left-1/2 -translate-x-1/2 z-10 flex gap-4">
|
||||
<button
|
||||
onMouseEnter={() => setActiveInsight("Your energy and focus peaked together on May 20. This suggests your evening rest was highly effective.")}
|
||||
onMouseLeave={() => setActiveInsight(null)}
|
||||
className="p-2 bg-primary/20 border border-primary/40 rounded-full text-primary hover:scale-110 transition-transform animate-pulse"
|
||||
>
|
||||
<Info className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AnimatePresence>
|
||||
{activeInsight && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
className="absolute top-36 left-1/2 -translate-x-1/2 z-20 w-64 p-3 bg-[#1F172B] border border-primary/30 rounded-sm shadow-2xl text-[11px] leading-relaxed text-foreground"
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-1 text-primary font-bold uppercase tracking-widest">
|
||||
<Brain className="h-3 w-3" /> AI Observation
|
||||
</div>
|
||||
{activeInsight}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="flex-1 w-full min-h-[300px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={productivityTrend}>
|
||||
<defs>
|
||||
<linearGradient id="colorFocus" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#6C5BB0" stopOpacity={0.3}/>
|
||||
<stop offset="5%" stopColor="#6C5BB0" stopOpacity={0.4}/>
|
||||
<stop offset="95%" stopColor="#6C5BB0" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
<linearGradient id="colorEnergy" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#10b981" stopOpacity={0.3}/>
|
||||
<stop offset="5%" stopColor="#10b981" stopOpacity={0.4}/>
|
||||
<stop offset="95%" stopColor="#10b981" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
@@ -157,61 +180,76 @@ export default function AnalyticsPage() {
|
||||
<XAxis dataKey="date" axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dy={10} />
|
||||
<YAxis axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dx={-10} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE", borderRadius: "4px" }}
|
||||
itemStyle={{ color: "#FBF9FE" }}
|
||||
cursor={{ stroke: '#6C5BB0', strokeWidth: 1 }}
|
||||
contentStyle={{ backgroundColor: "#150F1D", border: "1px solid rgba(255,255,255,0.05)", fontSize: "12px", color: "#FBF9FE", borderRadius: "4px" }}
|
||||
/>
|
||||
<Area type="monotone" dataKey="focus" stroke="#6C5BB0" strokeWidth={2} fillOpacity={1} fill="url(#colorFocus)" />
|
||||
<Area type="monotone" dataKey="energy" stroke="#10b981" strokeWidth={2} fillOpacity={1} fill="url(#colorEnergy)" />
|
||||
<Area type="monotone" dataKey="focus" stroke="#6C5BB0" strokeWidth={3} fillOpacity={1} fill="url(#colorFocus)" />
|
||||
<Area type="monotone" dataKey="energy" stroke="#10b981" strokeWidth={3} fillOpacity={1} fill="url(#colorEnergy)" />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Side Charts Stack */}
|
||||
{/* Sidebar Insights */}
|
||||
<div className="flex flex-col gap-6">
|
||||
|
||||
{/* Radar Chart */}
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex-1 flex flex-col">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4">Effort Distribution</h3>
|
||||
<div className="flex-1 w-full min-h-[200px] flex items-center justify-center">
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-6">Effort Distribution</h3>
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<RadarChart cx="50%" cy="50%" outerRadius="70%" data={focusRadarData}>
|
||||
<PolarGrid stroke="#ffffff10" />
|
||||
<PolarAngleAxis dataKey="subject" tick={{ fill: '#8F89A5', fontSize: 10 }} />
|
||||
<Radar name="Effort" dataKey="A" stroke="#6C5BB0" fill="#6C5BB0" fillOpacity={0.3} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE" }}
|
||||
itemStyle={{ color: "#FBF9FE" }}
|
||||
/>
|
||||
<RadarChart cx="50%" cy="50%" outerRadius="80%" data={focusRadarData}>
|
||||
<PolarGrid stroke="#ffffff05" />
|
||||
<PolarAngleAxis dataKey="subject" tick={{ fill: '#8F89A5', fontSize: 10, fontWeight: 600 }} />
|
||||
<Radar name="Effort" dataKey="A" stroke="#6C5BB0" strokeWidth={2} fill="#6C5BB0" fillOpacity={0.4} />
|
||||
<Tooltip contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px" }} />
|
||||
</RadarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bar Chart */}
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex-1 flex flex-col">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4">Habit Consistency</h3>
|
||||
<div className="flex-1 w-full min-h-[150px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data={habitCompletion} layout="vertical" margin={{ left: 0, right: 0, top: 0, bottom: 0 }}>
|
||||
<XAxis type="number" hide />
|
||||
<YAxis dataKey="name" type="category" axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#8F89A5' }} width={70} />
|
||||
<Tooltip
|
||||
cursor={{ fill: '#ffffff05' }}
|
||||
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE" }}
|
||||
itemStyle={{ color: "#FBF9FE" }}
|
||||
/>
|
||||
<Bar dataKey="completed" stackId="a" fill="#6C5BB0" radius={[2, 0, 0, 2]} barSize={12} />
|
||||
<Bar dataKey="missed" stackId="a" fill="#2B2538" radius={[0, 2, 2, 0]} barSize={12} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex-1">
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-6">Strategic Alerts</h3>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-start gap-3 p-3 rounded-sm bg-emerald-500/5 border border-emerald-500/10">
|
||||
<CheckCircle2 className="h-4 w-4 text-emerald-500 mt-0.5" />
|
||||
<div>
|
||||
<div className="text-xs font-bold text-emerald-400">Habit Streak Maintained</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1">Reading streak is now at 12 days. Energy levels are correlating positively.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-3 p-3 rounded-sm bg-orange-500/5 border border-orange-500/10">
|
||||
<AlertCircle className="h-4 w-4 text-orange-500 mt-0.5" />
|
||||
<div>
|
||||
<div className="text-xs font-bold text-orange-400">Admin Overload</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1">Admin tasks have increased by 15%. Consider automating these via Cognis AI.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function KpiCard({ title, value, change, icon: Icon, trend, color = "primary" }: any) {
|
||||
const isUp = trend === "up";
|
||||
const trendColor = isUp ? "text-emerald-500" : "text-rose-500";
|
||||
|
||||
return (
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 relative overflow-hidden group">
|
||||
<div className={`absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity ${color === 'primary' ? 'text-primary' : color === 'emerald' ? 'text-emerald-500' : 'text-blue-500'}`}>
|
||||
<Icon className="h-16 w-16" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-4">{title}</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-4xl font-black text-foreground tracking-tight">{value}</span>
|
||||
<span className={`text-[10px] flex items-center font-bold mb-1.5 px-1.5 py-0.5 rounded-sm bg-white/5 ${trendColor}`}>
|
||||
{isUp ? <ArrowUpRight className="h-3 w-3 mr-0.5" /> : <ArrowDownRight className="h-3 w-3 mr-0.5" />} {change}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">vs previous 30 days</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { ChevronLeft, ChevronRight, Plus, Search, Calendar as CalendarIcon, Clock, Filter, MoreHorizontal, Brain } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
ChevronLeft, ChevronRight, Plus, Search, Calendar as CalendarIcon,
|
||||
Clock, Filter, MoreHorizontal, Brain, X, Check, ArrowRight
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const categories = [
|
||||
@@ -25,16 +30,13 @@ const mockEvents = [
|
||||
|
||||
const daysOfWeek = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
|
||||
// Generates a mock calendar grid for a 30-day month starting on a Tuesday
|
||||
const generateCalendarDays = () => {
|
||||
const days = [];
|
||||
// 1 empty slot for Monday before the 1st
|
||||
days.push({ empty: true, key: "empty-0" });
|
||||
for (let i = 1; i <= 30; i++) {
|
||||
const events = mockEvents.filter((e) => e.day === i);
|
||||
days.push({ empty: false, day: i, events, isToday: i === 15 });
|
||||
}
|
||||
// Fill the rest of the grid (35 total cells for a 5-week view)
|
||||
const remaining = 35 - days.length;
|
||||
for (let i = 1; i <= remaining; i++) {
|
||||
days.push({ empty: true, key: `empty-end-${i}` });
|
||||
@@ -43,13 +45,53 @@ const generateCalendarDays = () => {
|
||||
};
|
||||
|
||||
export default function CalendarPage() {
|
||||
const [selectedDay, setSelectedDay] = useState<any>(null);
|
||||
const [isOptimizing, setIsOptimizing] = useState(false);
|
||||
const calendarDays = generateCalendarDays();
|
||||
|
||||
const handleOptimize = () => {
|
||||
setIsOptimizing(true);
|
||||
setTimeout(() => setIsOptimizing(false), 2500);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans relative">
|
||||
|
||||
{/* Optimization Overlay */}
|
||||
<AnimatePresence>
|
||||
{isOptimizing && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute inset-0 z-50 bg-[#0A0710]/80 backdrop-blur-md flex flex-col items-center justify-center"
|
||||
>
|
||||
<motion.div
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 10, -10, 0]
|
||||
}}
|
||||
transition={{ repeat: Infinity, duration: 1.5 }}
|
||||
className="mb-6"
|
||||
>
|
||||
<Brain className="h-16 w-16 text-primary" />
|
||||
</motion.div>
|
||||
<h2 className="text-xl font-bold mb-2">AI Schedule Optimization</h2>
|
||||
<p className="text-muted-foreground text-sm">Analyzing energy trends and focus blocks...</p>
|
||||
<div className="w-48 h-1 bg-white/10 rounded-full mt-6 overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ x: "-100%" }}
|
||||
animate={{ x: "100%" }}
|
||||
transition={{ repeat: Infinity, duration: 1, ease: "linear" }}
|
||||
className="w-full h-full bg-primary"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mb-6">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mb-6 mt-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Calendar</span> / Monthly View
|
||||
</h1>
|
||||
@@ -62,7 +104,10 @@ export default function CalendarPage() {
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button
|
||||
onClick={() => setSelectedDay({ day: 15, events: mockEvents.filter(e => e.day === 15) })}
|
||||
className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-all active:scale-95 shadow-lg shadow-primary/20"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW EVENT
|
||||
</button>
|
||||
@@ -92,15 +137,11 @@ export default function CalendarPage() {
|
||||
{[...Array(30)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`py-1 rounded-sm cursor-pointer hover:bg-white/5 ${i + 1 === 15 ? 'bg-primary/20 text-primary font-bold' : ''}`}
|
||||
className={`py-1 rounded-sm cursor-pointer hover:bg-white/5 transition-colors ${i + 1 === 15 ? 'bg-primary/20 text-primary font-bold' : ''}`}
|
||||
>
|
||||
{i + 1}
|
||||
</div>
|
||||
))}
|
||||
<div className="text-muted-foreground/30 py-1">1</div>
|
||||
<div className="text-muted-foreground/30 py-1">2</div>
|
||||
<div className="text-muted-foreground/30 py-1">3</div>
|
||||
<div className="text-muted-foreground/30 py-1">4</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -113,40 +154,35 @@ export default function CalendarPage() {
|
||||
<div className="space-y-3">
|
||||
{categories.map((cat, idx) => (
|
||||
<label key={idx} className="flex items-center gap-3 cursor-pointer group">
|
||||
<div className={`w-3 h-3 rounded-sm ${cat.color} ring-2 ring-transparent group-hover:ring-white/10 transition-all`}></div>
|
||||
<div className={`w-3 h-3 rounded-sm ${cat.color} ring-2 ring-transparent group-hover:ring-white/10 transition-all shadow-[0_0_8px_rgba(108,91,176,0.3)]`}></div>
|
||||
<span className="text-sm text-muted-foreground group-hover:text-foreground transition-colors">{cat.name}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-8 mb-5 border-t border-white/5 pt-5">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Shared Context</h3>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<label className="flex items-center gap-3 cursor-pointer group">
|
||||
<div className="w-3 h-3 rounded-sm border border-muted-foreground/40 group-hover:border-muted-foreground transition-all"></div>
|
||||
<span className="text-sm text-muted-foreground group-hover:text-foreground transition-colors">Team Holidays</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-3 cursor-pointer group">
|
||||
<div className="w-3 h-3 rounded-sm bg-muted-foreground/40 group-hover:bg-muted-foreground transition-all"></div>
|
||||
<span className="text-sm text-muted-foreground group-hover:text-foreground transition-colors">Company Events</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Features */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-5 flex flex-col gap-3">
|
||||
{/* AI Optimizer Card */}
|
||||
<motion.div
|
||||
whileHover={{ y: -4 }}
|
||||
className="rounded-sm border border-primary/20 bg-primary/5 p-5 flex flex-col gap-3 relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute -right-4 -bottom-4 opacity-5 rotate-12">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<Brain className="h-4 w-4 text-primary" />
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-primary">AI Assistant</h3>
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-primary">AI Optimizer</h3>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground leading-relaxed">
|
||||
Based on your energy trends, I suggest moving the <strong>UI Review</strong> to Thursday afternoon.
|
||||
Detected focus peak at 10 AM on Thursdays. Suggest moving **UI Review** to maximize alignment.
|
||||
</p>
|
||||
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-3 py-1.5 rounded-sm text-xs font-semibold transition-colors mt-2 text-center flex justify-center w-full">
|
||||
Auto-Optimize Schedule
|
||||
<button
|
||||
onClick={handleOptimize}
|
||||
className="bg-primary/10 text-primary hover:bg-primary/20 border border-primary/20 px-3 py-1.5 rounded-sm text-[10px] font-bold uppercase tracking-widest transition-all mt-2 text-center flex justify-center w-full"
|
||||
>
|
||||
Run AI Optimization
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -170,7 +206,7 @@ export default function CalendarPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Calendar Header (Days) */}
|
||||
{/* Calendar Header */}
|
||||
<div className="grid grid-cols-7 border-b border-white/5 bg-[#0F0B15]/50">
|
||||
{daysOfWeek.map((day) => (
|
||||
<div key={day} className="py-3 text-center text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
@@ -182,34 +218,122 @@ export default function CalendarPage() {
|
||||
{/* Calendar Grid */}
|
||||
<div className="flex-1 grid grid-cols-7 grid-rows-5 overflow-hidden bg-white/[0.02] gap-[1px]">
|
||||
{calendarDays.map((cell, idx) => (
|
||||
<div
|
||||
<motion.div
|
||||
key={cell.key || cell.day}
|
||||
className={`bg-[#0A0710] p-2 flex flex-col gap-1 transition-colors hover:bg-[#0F0B15] relative group ${cell.empty ? 'opacity-30' : ''}`}
|
||||
whileHover={{ backgroundColor: "rgba(15, 11, 21, 0.8)" }}
|
||||
onClick={() => !cell.empty && setSelectedDay(cell)}
|
||||
className={`bg-[#0A0710] p-2 flex flex-col gap-1 transition-all cursor-pointer relative group ${cell.empty ? 'opacity-30 pointer-events-none' : ''}`}
|
||||
>
|
||||
{!cell.empty && (
|
||||
<div className={`text-xs font-medium mb-1 w-6 h-6 flex items-center justify-center rounded-sm ${cell.isToday ? 'bg-primary text-primary-foreground' : 'text-muted-foreground group-hover:text-foreground'}`}>
|
||||
<div className={`text-xs font-medium mb-1 w-6 h-6 flex items-center justify-center rounded-sm transition-colors ${cell.isToday ? 'bg-primary text-primary-foreground shadow-[0_0_12px_rgba(108,91,176,0.5)]' : 'text-muted-foreground group-hover:text-foreground'}`}>
|
||||
{cell.day}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Events */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar flex flex-col gap-1 pr-1">
|
||||
{cell.events?.map((event, eIdx) => (
|
||||
<div
|
||||
<motion.div
|
||||
key={eIdx}
|
||||
className={`text-[10px] px-2 py-1 rounded-sm border truncate font-medium cursor-pointer transition-all hover:brightness-125 ${event.colorClass}`}
|
||||
title={`${event.time} - ${event.title}`}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: idx * 0.01 + eIdx * 0.05 }}
|
||||
className={`text-[9px] px-1.5 py-1 rounded-sm border truncate font-bold tracking-tight transition-all hover:scale-[1.02] active:scale-95 ${event.colorClass}`}
|
||||
>
|
||||
{event.time} • {event.title}
|
||||
{event.title}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Quick Entry Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedDay && (
|
||||
<>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={() => setSelectedDay(null)}
|
||||
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100]"
|
||||
/>
|
||||
<motion.div
|
||||
initial={{ x: "100%" }}
|
||||
animate={{ x: 0 }}
|
||||
exit={{ x: "100%" }}
|
||||
transition={{ type: "spring", damping: 25, stiffness: 200 }}
|
||||
className="fixed top-0 right-0 h-full w-full max-w-md bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col"
|
||||
>
|
||||
<div className="p-6 border-b border-white/5 flex items-center justify-between bg-[#0F0B15]/50">
|
||||
<div>
|
||||
<h2 className="text-xl font-bold">May {selectedDay.day}, 2026</h2>
|
||||
<p className="text-xs text-muted-foreground uppercase tracking-widest mt-1">Daily Schedule Overview</p>
|
||||
</div>
|
||||
<button onClick={() => setSelectedDay(null)} className="p-2 hover:bg-white/5 rounded-sm transition-colors text-muted-foreground hover:text-foreground">
|
||||
<X className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-6 space-y-8">
|
||||
<div>
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-primary mb-4 flex items-center gap-2">
|
||||
<Clock className="h-3.5 w-3.5" /> Scheduled Events
|
||||
</h3>
|
||||
<div className="space-y-3">
|
||||
{selectedDay.events?.length > 0 ? (
|
||||
selectedDay.events.map((event: any, idx: number) => (
|
||||
<div key={idx} className="p-4 rounded-sm border border-white/5 bg-[#150F1D] flex items-center justify-between group">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`w-1 h-8 rounded-full ${event.colorClass.split(' ')[0]}`} />
|
||||
<div>
|
||||
<div className="text-sm font-bold">{event.title}</div>
|
||||
<div className="text-[10px] text-muted-foreground">{event.time} • {event.type}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button className="opacity-0 group-hover:opacity-100 p-1.5 hover:bg-white/5 rounded-sm transition-opacity">
|
||||
<MoreHorizontal className="h-4 w-4 text-muted-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground italic px-2">No events scheduled for this day.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 border-t border-white/5">
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-widest text-primary mb-4">Quick Add Event</h3>
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<label className="text-[10px] font-bold text-muted-foreground">TIME</label>
|
||||
<input type="time" className="w-full bg-[#150F1D] border border-white/10 rounded-sm px-3 py-2 text-xs outline-none focus:border-primary/50" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-[10px] font-bold text-muted-foreground">CATEGORY</label>
|
||||
<select className="w-full bg-[#150F1D] border border-white/10 rounded-sm px-3 py-2 text-xs outline-none focus:border-primary/50">
|
||||
{categories.map(c => <option key={c.name}>{c.name}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-[10px] font-bold text-muted-foreground">EVENT TITLE</label>
|
||||
<input type="text" placeholder="e.g., Team Sync" className="w-full bg-[#150F1D] border border-white/10 rounded-sm px-3 py-2 text-xs outline-none focus:border-primary/50" />
|
||||
</div>
|
||||
<button className="w-full bg-primary hover:bg-primary/90 text-primary-foreground py-3 rounded-sm text-xs font-bold tracking-widest shadow-lg shadow-primary/20 transition-all active:scale-[0.98]">
|
||||
ADD TO CALENDAR
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, User, Mail, Phone, Globe,
|
||||
MoreHorizontal, MessageSquare, Briefcase,
|
||||
TrendingUp, Star, Clock, X, ChevronRight,
|
||||
ArrowUpRight, DollarSign, Brain, Shield,
|
||||
Activity, CheckCircle2, AlertCircle
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const clients = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Acme Corp",
|
||||
contact: "John Doe",
|
||||
email: "john@acme.com",
|
||||
status: "Active",
|
||||
value: "$12,400",
|
||||
projects: 2,
|
||||
health: "Stable",
|
||||
lastContact: "2 days ago",
|
||||
aiInsight: "Excellent relationship. High potential for upsell into the Q3 Marketing Package.",
|
||||
history: [
|
||||
{ type: "Meeting", date: "May 12", note: "Q3 Strategy Review" },
|
||||
{ type: "Payment", date: "May 08", note: "$4,200 received" },
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Global Tech",
|
||||
contact: "Jane Smith",
|
||||
email: "jane@global.io",
|
||||
status: "Onboarding",
|
||||
value: "$8,500",
|
||||
projects: 1,
|
||||
health: "Critical",
|
||||
lastContact: "1 week ago",
|
||||
aiInsight: "Risk of churn detected. Last communication was 7 days ago. Immediate outreach suggested.",
|
||||
history: [
|
||||
{ type: "Proposal", date: "May 01", note: "Infrastructure Scale" },
|
||||
]
|
||||
},
|
||||
{ id: 3, name: "Nexus Design", contact: "Mike Ross", email: "mike@nexus.com", status: "Active", value: "$42,000", projects: 4, health: "Growth", lastContact: "Today", aiInsight: "Client is expanding rapidly. Consider offering a dedicated project manager role.", history: [] },
|
||||
{ id: 4, name: "Stark Ind.", contact: "Pepper P.", email: "pepper@stark.com", status: "Lead", value: "$0", projects: 0, health: "Neutral", lastContact: "May 14", aiInsight: "Warm lead from the Webflow conference. Interested in AI integration.", history: [] },
|
||||
];
|
||||
|
||||
export default function ClientsPage() {
|
||||
const [selectedClient, setSelectedClient] = useState<any>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Network</span> / Strategic Clients
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-primary bg-primary/5 px-3 py-1 rounded-sm border border-primary/10">
|
||||
<Users className="h-3 w-3" /> 12 ACTIVE PARTNERSHIPS
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search clients..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95">
|
||||
<Plus className="h-4 w-4" />
|
||||
ADD CLIENT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CRM Stats */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 shrink-0">
|
||||
<ClientStatCard label="Pipeline Value" value="$128.5k" subtext="+12% this month" icon={DollarSign} />
|
||||
<ClientStatCard label="Avg. Health" value="Stable" subtext="92% Retention" icon={Activity} />
|
||||
<ClientStatCard label="New Leads" value="15" subtext="8 Qualified" icon={TrendingUp} />
|
||||
<div className="bg-primary/5 border border-primary/20 rounded-sm p-6 flex flex-col justify-center relative overflow-hidden group">
|
||||
<div className="absolute -right-4 -top-4 opacity-5 rotate-12 transition-transform group-hover:scale-110"><Brain className="h-20 w-20 text-primary" /></div>
|
||||
<div className="flex items-center gap-2 text-primary font-black uppercase tracking-widest text-[10px] mb-2">
|
||||
<Brain className="h-3.5 w-3.5" /> AI Insight
|
||||
</div>
|
||||
<p className="text-[11px] font-bold text-foreground/80 leading-relaxed italic">
|
||||
"High churn risk for Global Tech. Immediate outreach suggested."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Clients List */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar pr-1">
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm overflow-hidden shadow-2xl">
|
||||
<div className="grid grid-cols-12 gap-4 p-5 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground">
|
||||
<div className="col-span-4 px-2">Partner Entity</div>
|
||||
<div className="col-span-2">Relationship</div>
|
||||
<div className="col-span-2">Strategic Value</div>
|
||||
<div className="col-span-2">Engagement</div>
|
||||
<div className="col-span-2 text-right">Actions</div>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-white/5">
|
||||
{clients.map((client) => (
|
||||
<motion.div
|
||||
key={client.id}
|
||||
onClick={() => setSelectedClient(client)}
|
||||
className="grid grid-cols-12 gap-4 p-6 items-center hover:bg-white/[0.02] transition-all group cursor-pointer border-l-2 border-transparent hover:border-primary"
|
||||
>
|
||||
<div className="col-span-4 flex items-center gap-4">
|
||||
<div className="h-10 w-10 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-center font-black text-primary text-xs uppercase tracking-tighter shadow-inner">
|
||||
{client.name.split(' ').map(n => n[0]).join('')}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-black group-hover:text-primary transition-colors truncate">{client.name}</div>
|
||||
<div className="text-[10px] text-muted-foreground font-bold tracking-widest mt-0.5">{client.contact}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2">
|
||||
<span className={`text-[9px] font-black uppercase tracking-[0.2em] px-2.5 py-1 rounded-sm border ${
|
||||
client.health === 'Growth' ? 'text-emerald-400 border-emerald-500/20 bg-emerald-500/5' :
|
||||
client.health === 'Stable' ? 'text-blue-400 border-blue-500/20 bg-blue-500/5' :
|
||||
client.health === 'Critical' ? 'text-rose-400 border-rose-500/20 bg-rose-500/5' : 'text-muted-foreground border-white/10'
|
||||
}`}>
|
||||
{client.health}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex flex-col">
|
||||
<span className="text-sm font-black text-foreground">{client.value}</span>
|
||||
<span className="text-[9px] text-muted-foreground font-bold uppercase tracking-widest">{client.projects} Active Projects</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex flex-col">
|
||||
<span className="text-xs font-bold text-foreground">{client.lastContact}</span>
|
||||
<span className="text-[9px] text-muted-foreground font-bold uppercase tracking-widest mt-0.5">Last Touchpoint</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex justify-end gap-1 opacity-0 group-hover:opacity-100 transition-all">
|
||||
<button className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><MessageSquare className="h-4 w-4" /></button>
|
||||
<button className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Client Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedClient && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedClient(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-2xl bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col">
|
||||
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/5">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="h-16 w-16 rounded-sm bg-primary/10 border border-primary/20 flex items-center justify-center font-black text-primary text-xl uppercase shadow-xl">
|
||||
{selectedClient.name.split(' ').map((n: string) => n[0]).join('')}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-3xl font-black tracking-tighter text-foreground">{selectedClient.name}</h2>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[10px] font-black text-primary uppercase tracking-widest">{selectedClient.contact}</span>
|
||||
<div className="w-1 h-1 rounded-full bg-white/20" />
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{selectedClient.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setSelectedClient(null)} className="p-3 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-6 w-6" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-10 space-y-12 tiny-scrollbar">
|
||||
|
||||
{/* AI Client Pulse */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-8 space-y-4 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 opacity-5">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> Client Health Pulse
|
||||
</h3>
|
||||
<p className="text-sm font-medium text-foreground/90 leading-relaxed italic">
|
||||
"{selectedClient.aiInsight}"
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Key Financials */}
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm p-6 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">LIFETIME VALUE</div>
|
||||
<div className="text-2xl font-black text-primary">{selectedClient.value}</div>
|
||||
</div>
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm p-6 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">ACTIVE DELIVERABLES</div>
|
||||
<div className="text-2xl font-black text-foreground">{selectedClient.projects}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Relationship History */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Relationship Log</h3>
|
||||
<div className="relative space-y-6 pl-6 before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-px before:bg-white/10">
|
||||
{selectedClient.history?.length > 0 ? selectedClient.history.map((log: any, i: number) => (
|
||||
<div key={i} className="relative group">
|
||||
<div className="absolute -left-[23px] top-1 h-3 w-3 rounded-full border-2 border-[#0A0710] bg-primary z-10" />
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="text-sm font-bold group-hover:text-primary transition-colors">{log.note}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1 uppercase font-medium">{log.date} • {log.type}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)) : <p className="text-xs text-muted-foreground italic">No historical log entries found for this partner.</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="space-y-6 pt-6 border-t border-white/5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Strategic Actions</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<ActionButton icon={Briefcase} label="Launch New Project" />
|
||||
<ActionButton icon={DollarSign} label="Generate Invoice" />
|
||||
<ActionButton icon={MessageSquare} label="Relationship Review" />
|
||||
<ActionButton icon={Shield} label="Update Contract" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 bg-[#0F0B15]/50 flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-widest shadow-2xl shadow-primary/30 transition-all active:scale-[0.98]">
|
||||
OPEN PARTNER PORTAL
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionButton({ icon: Icon, label }: { icon: any, label: string }) {
|
||||
return (
|
||||
<button className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center gap-3 group hover:border-primary/20 transition-all text-left">
|
||||
<div className="p-2 bg-white/5 rounded-sm group-hover:bg-primary/10 transition-colors">
|
||||
<Icon className="h-4 w-4 text-muted-foreground group-hover:text-primary" />
|
||||
</div>
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-widest leading-tight group-hover:text-foreground">{label}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function ClientStatCard({ label, value, subtext, icon: Icon }: any) {
|
||||
return (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex items-center gap-6 group relative overflow-hidden shadow-xl">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity">
|
||||
<Icon className="h-20 w-20 text-foreground" />
|
||||
</div>
|
||||
<div className="p-4 bg-white/5 rounded-sm group-hover:bg-primary/10 transition-colors relative z-10">
|
||||
<Icon className="h-6 w-6 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
<div className="relative z-10">
|
||||
<div className="text-[10px] font-black uppercase tracking-[0.2em] text-muted-foreground mb-1">{label}</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-black text-foreground tracking-tighter leading-none">{value}</span>
|
||||
<span className="text-[10px] text-emerald-500 font-bold uppercase tracking-widest">{subtext}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+340
-113
@@ -1,154 +1,381 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Search, Filter, Brain, FileText, Download, MoreHorizontal, FileSpreadsheet, FileIcon, MessageSquare } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, FileText, File, Image, Music, Video,
|
||||
MoreHorizontal, Download, Share2, Trash2, Eye,
|
||||
Layout, List, Brain, Clock, ChevronRight, X,
|
||||
Folder, HardDrive, Shield, Cloud, Tag, Info,
|
||||
Star, Filter, Zap, Globe, ExternalLink, Activity
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const documents = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Q3 Strategy Planning.docx",
|
||||
type: "word",
|
||||
name: "Marketing Strategy 2026.pdf",
|
||||
type: "PDF",
|
||||
size: "2.4 MB",
|
||||
updated: "2 hours ago",
|
||||
aiStatus: "Summarized",
|
||||
aiSummary: "Focuses on user acquisition and shifting marketing budget to TikTok ads. AI extracted 4 key action items."
|
||||
date: "May 10, 2026",
|
||||
category: "Strategy",
|
||||
starred: true,
|
||||
summary: "Comprehensive roadmap for Q3 marketing funnels and ad spend allocation.",
|
||||
owner: "Sarah J.",
|
||||
tags: ["Marketing", "Strategy", "Q3"],
|
||||
aiAnalysis: "This document outlines a 15% increase in digital spend. Key focus is on video-first content."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Financial_Report_May.xlsx",
|
||||
type: "excel",
|
||||
size: "5.1 MB",
|
||||
updated: "Yesterday",
|
||||
aiStatus: "Analyzing",
|
||||
aiSummary: "AI is currently detecting anomalies in the Q2 vs Q3 expense margins."
|
||||
name: "Project Brand Identity.fig",
|
||||
type: "FIG",
|
||||
size: "15.8 MB",
|
||||
date: "May 08, 2026",
|
||||
category: "Design",
|
||||
starred: false,
|
||||
summary: "Core design tokens, typography, and color palette for the Cognis rebrand.",
|
||||
owner: "Alex R.",
|
||||
tags: ["Design", "UI", "Branding"],
|
||||
aiAnalysis: "Identifies 'Cyber-Lavender' as the primary action color. Typography is set to Geist Sans."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Design_System_Guidelines.pdf",
|
||||
type: "pdf",
|
||||
size: "12 MB",
|
||||
updated: "May 04, 2026",
|
||||
aiStatus: "Summarized",
|
||||
aiSummary: "Details the new dark mode color tokens (#0A0710). AI created a searchable index for developers."
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Client_Feedback_Transcript.txt",
|
||||
type: "text",
|
||||
size: "145 KB",
|
||||
updated: "May 01, 2026",
|
||||
aiStatus: "Action Required",
|
||||
aiSummary: "Sentiment analysis is extremely negative regarding the login flow. AI flagged this for urgent review."
|
||||
}
|
||||
{ id: 3, name: "Client Contracts Bundle.zip", type: "ZIP", size: "4.2 MB", date: "May 05, 2026", category: "Legal", starred: true, summary: "Collection of signed service agreements for the top 5 enterprise clients.", owner: "Emma W.", tags: ["Legal", "Enterprise"] },
|
||||
{ id: 4, name: "Revenue Forecast Q3.xlsx", type: "XLSX", size: "1.1 MB", date: "May 01, 2026", category: "Finance", starred: false, summary: "Predicted revenue growth based on current subscription trends and churn rates.", owner: "Sarah J.", tags: ["Finance", "Data"] },
|
||||
{ id: 5, name: "User Research Session 01.mp4", type: "MP4", size: "142 MB", date: "Apr 28, 2026", category: "Research", starred: false, summary: "Interview with primary persona 'Executive Alex' regarding workflow pain points.", owner: "Mike C.", tags: ["Research", "User-Test"] },
|
||||
];
|
||||
|
||||
const storageStats = [
|
||||
{ label: "Documents", size: "1.2 GB", color: "bg-primary", percentage: 65 },
|
||||
{ label: "Media", size: "800 MB", color: "bg-blue-500", percentage: 25 },
|
||||
{ label: "Others", size: "400 MB", color: "bg-white/20", percentage: 10 },
|
||||
];
|
||||
|
||||
export default function DocumentsPage() {
|
||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
||||
const [selectedDoc, setSelectedDoc] = useState<any>(null);
|
||||
const [activeFolder, setActiveFolder] = useState("All Files");
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Management</span> / Documents
|
||||
<span className="text-foreground">Resources</span> / Documents & Drive
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10 hidden md:block" />
|
||||
<div className="hidden md:flex items-center gap-3">
|
||||
<div className="flex -space-x-2">
|
||||
{[1, 2, 3].map(i => <div key={i} className="h-6 w-6 rounded-full border-2 border-[#0A0710] bg-[#1F172B] flex items-center justify-center text-[8px] font-bold">U{i}</div>)}
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">Shared with team</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search documents or ask AI..."
|
||||
className="bg-transparent border-none outline-none text-xs w-64 placeholder:text-muted-foreground/50 text-foreground"
|
||||
placeholder="Search files..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground font-medium"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95">
|
||||
<Plus className="h-4 w-4" />
|
||||
UPLOAD
|
||||
UPLOAD FILE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Semantic Search Banner */}
|
||||
<div className="rounded-sm border border-primary/20 bg-[linear-gradient(90deg,rgba(108,91,176,0.1)_0%,rgba(10,7,16,0)_100%)] p-6 flex flex-col gap-4">
|
||||
<div className="flex-1 flex gap-8 min-h-0">
|
||||
|
||||
{/* Left Sidebar: Navigation & Storage */}
|
||||
<div className="hidden xl:flex w-72 flex-col gap-8 shrink-0">
|
||||
|
||||
<div className="space-y-1">
|
||||
{["All Files", "Recent", "Starred", "Shared", "Trash"].map(folder => (
|
||||
<button
|
||||
key={folder}
|
||||
onClick={() => setActiveFolder(folder)}
|
||||
className={`w-full flex items-center justify-between px-4 py-3 rounded-sm text-sm font-bold transition-all border ${activeFolder === folder ? 'bg-primary/5 text-primary border-primary/20 shadow-lg shadow-primary/5' : 'text-muted-foreground hover:bg-white/5 hover:text-foreground border-transparent'}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Folder className={`h-4 w-4 ${activeFolder === folder ? 'text-primary' : 'text-muted-foreground'}`} />
|
||||
{folder}
|
||||
</div>
|
||||
{folder === "Starred" && <Star className="h-3 w-3 fill-primary text-primary" />}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground px-4">Storage Usage</h3>
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-5 space-y-4 shadow-xl">
|
||||
<div className="flex justify-between items-end mb-2">
|
||||
<span className="text-[10px] font-black text-foreground uppercase tracking-widest">2.4 GB / 10 GB</span>
|
||||
<span className="text-[10px] font-black text-primary uppercase tracking-widest">24%</span>
|
||||
</div>
|
||||
<div className="h-1.5 w-full bg-white/5 rounded-full overflow-hidden flex">
|
||||
{storageStats.map(stat => (
|
||||
<div key={stat.label} className={`h-full ${stat.color}`} style={{ width: `${stat.percentage}%` }} />
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-3 pt-2">
|
||||
{storageStats.map(stat => (
|
||||
<div key={stat.label} className="flex justify-between items-center text-[9px] font-bold uppercase tracking-widest">
|
||||
<div className="flex items-center gap-2">
|
||||
<Brain className="h-5 w-5 text-primary" />
|
||||
<h2 className="text-sm font-semibold">Talk to your Workspace</h2>
|
||||
<div className={`w-1.5 h-1.5 rounded-full ${stat.color}`} />
|
||||
<span className="text-muted-foreground">{stat.label}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground w-1/2 leading-relaxed">
|
||||
The AI has indexed 1,240 documents. Instead of searching by keywords, ask a direct question like <em>"What were the key takeaways from the Q3 Strategy?"</em>
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Ask anything about your files..."
|
||||
className="flex-1 bg-[#0A0710] border border-white/10 rounded-sm px-4 py-2 text-sm outline-none focus:border-primary/50 transition-colors"
|
||||
/>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground px-6 py-2 rounded-sm text-sm font-semibold transition-colors">
|
||||
Ask AI
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Document List */}
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{documents.map((doc) => (
|
||||
<div key={doc.id} className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex flex-col md:flex-row md:items-center gap-6 group hover:border-white/10 transition-colors">
|
||||
|
||||
{/* File Info */}
|
||||
<div className="flex items-center gap-4 min-w-[300px]">
|
||||
<div className={`p-3 rounded-sm flex items-center justify-center shrink-0 ${
|
||||
doc.type === 'word' ? 'bg-blue-500/10 text-blue-400' :
|
||||
doc.type === 'excel' ? 'bg-emerald-500/10 text-emerald-400' :
|
||||
doc.type === 'pdf' ? 'bg-red-500/10 text-red-400' :
|
||||
'bg-white/10 text-foreground'
|
||||
}`}>
|
||||
{doc.type === 'word' ? <FileText className="h-6 w-6" /> :
|
||||
doc.type === 'excel' ? <FileSpreadsheet className="h-6 w-6" /> :
|
||||
<FileIcon className="h-6 w-6" />}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h3 className="text-sm font-semibold truncate hover:text-primary cursor-pointer transition-colors mb-1">{doc.name}</h3>
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<span>{doc.size}</span>
|
||||
<span className="w-1 h-1 rounded-full bg-white/20"></span>
|
||||
<span>{doc.updated}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Insight */}
|
||||
<div className="flex-1 flex flex-col bg-[#150F1D]/50 border border-white/5 p-3 rounded-sm relative overflow-hidden">
|
||||
<div className="absolute left-0 top-0 bottom-0 w-0.5 bg-primary/50"></div>
|
||||
<div className="flex items-center gap-2 mb-1.5">
|
||||
<Brain className="h-3 w-3 text-primary" />
|
||||
<span className={`text-[10px] font-bold uppercase tracking-wider ${
|
||||
doc.aiStatus === 'Action Required' ? 'text-red-400' :
|
||||
doc.aiStatus === 'Analyzing' ? 'text-orange-400 animate-pulse' :
|
||||
'text-primary'
|
||||
}`}>{doc.aiStatus}</span>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground leading-snug">
|
||||
{doc.aiSummary}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex items-center gap-2">
|
||||
<button className="bg-primary/10 hover:bg-primary/20 text-primary border border-primary/20 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<MessageSquare className="h-3.5 w-3.5" />
|
||||
Chat
|
||||
</button>
|
||||
<button className="p-2 hover:bg-white/5 rounded-sm text-muted-foreground transition-colors">
|
||||
<Download className="h-4 w-4" />
|
||||
</button>
|
||||
<button className="p-2 hover:bg-white/5 rounded-sm text-muted-foreground transition-colors">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span>{stat.size}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="w-full bg-white/5 hover:bg-white/10 text-[9px] font-black uppercase tracking-widest py-2 rounded-sm border border-white/5 transition-all mt-2">
|
||||
UPGRADE STORAGE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 space-y-4 relative overflow-hidden group shadow-2xl">
|
||||
<div className="absolute -right-4 -top-4 opacity-5 rotate-12 transition-transform group-hover:scale-110">
|
||||
<Brain className="h-20 w-20 text-primary" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Brain className="h-4 w-4 text-primary" />
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">AI Librarian</h3>
|
||||
</div>
|
||||
<p className="text-[11px] font-bold text-foreground/80 leading-relaxed italic">
|
||||
"Your 'Legal' folder is 80% redundant. Should I suggest an automated cleanup strategy?"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<div className="flex-1 flex flex-col gap-6 overflow-hidden">
|
||||
|
||||
<div className="flex items-center justify-between shrink-0">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2 bg-[#150F1D] border border-white/5 rounded-sm p-0.5 shadow-inner">
|
||||
<button onClick={() => setViewMode("grid")} className={`px-4 py-2 text-[10px] font-black uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'grid' ? 'bg-[#2B2538] text-foreground shadow-lg' : 'text-muted-foreground hover:text-foreground'}`}><Layout className="h-3.5 w-3.5" /> Grid</button>
|
||||
<button onClick={() => setViewMode("list")} className={`px-4 py-2 text-[10px] font-black uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'list' ? 'bg-[#2B2538] text-foreground shadow-lg' : 'text-muted-foreground hover:text-foreground'}`}><List className="h-3.5 w-3.5" /> List</button>
|
||||
</div>
|
||||
<div className="h-6 w-px bg-white/5" />
|
||||
<div className="flex items-center gap-4">
|
||||
{["All", "PDF", "Design", "Media"].map(f => (
|
||||
<button key={f} className="text-[10px] font-black uppercase tracking-widest text-muted-foreground hover:text-primary transition-colors">{f}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<button className="p-2.5 bg-[#150F1D] border border-white/5 rounded-sm text-muted-foreground hover:text-foreground transition-all">
|
||||
<Filter className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar pr-1">
|
||||
{viewMode === "grid" ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8 pb-8">
|
||||
{documents.map((doc) => (
|
||||
<motion.div
|
||||
key={doc.id}
|
||||
whileHover={{ y: -6, scale: 1.02 }}
|
||||
onClick={() => setSelectedDoc(doc)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-6 flex flex-col group relative overflow-hidden shadow-2xl transition-all hover:border-primary/40 cursor-pointer"
|
||||
>
|
||||
<div className="absolute top-3 right-3 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-all">
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm transition-colors text-muted-foreground"><Star className={`h-3.5 w-3.5 ${doc.starred ? 'fill-primary text-primary' : ''}`} /></button>
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm transition-colors text-muted-foreground"><MoreHorizontal className="h-3.5 w-3.5" /></button>
|
||||
</div>
|
||||
|
||||
<div className="aspect-[4/3] bg-[#150F1D] border border-white/5 rounded-sm mb-6 flex items-center justify-center relative overflow-hidden group/thumb shadow-inner">
|
||||
<DocIcon type={doc.type} />
|
||||
<div className="absolute inset-0 bg-primary/5 opacity-0 group-hover/thumb:opacity-100 transition-opacity" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<div className="text-[13px] font-black truncate group-hover:text-primary transition-colors tracking-tight">{doc.name}</div>
|
||||
<div className="flex items-center justify-between text-[9px] text-muted-foreground font-black uppercase tracking-[0.2em]">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<div className="w-1 h-1 rounded-full bg-white/20" />
|
||||
{doc.type} • {doc.size}
|
||||
</span>
|
||||
<span>{doc.date.split(',')[0]}</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm overflow-hidden shadow-2xl mb-8">
|
||||
<div className="grid grid-cols-12 gap-4 p-5 border-b border-white/5 bg-[#0F0B15]/50 text-[9px] font-black uppercase tracking-[0.3em] text-muted-foreground">
|
||||
<div className="col-span-6 px-2">Document Name</div>
|
||||
<div className="col-span-2">File Weight</div>
|
||||
<div className="col-span-2">Ownership</div>
|
||||
<div className="col-span-2 text-right">Strategic Date</div>
|
||||
</div>
|
||||
<div className="divide-y divide-white/5">
|
||||
{documents.map(doc => (
|
||||
<div key={doc.id} onClick={() => setSelectedDoc(doc)} className="grid grid-cols-12 gap-4 p-6 items-center hover:bg-white/[0.02] transition-all group cursor-pointer border-l-2 border-transparent hover:border-primary">
|
||||
<div className="col-span-6 flex items-center gap-5">
|
||||
<DocIcon type={doc.type} small />
|
||||
<div className="min-w-0">
|
||||
<div className="text-[13px] font-black group-hover:text-primary transition-colors truncate tracking-tight">{doc.name}</div>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<span className="text-[9px] text-muted-foreground uppercase font-black tracking-[0.2em]">{doc.category}</span>
|
||||
{doc.starred && <Star className="h-2.5 w-2.5 fill-primary text-primary" />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 text-[11px] text-muted-foreground font-black uppercase tracking-tighter">{doc.size}</div>
|
||||
<div className="col-span-2 text-[11px] text-muted-foreground font-black uppercase tracking-widest">{doc.owner}</div>
|
||||
<div className="col-span-2 text-right text-[11px] text-muted-foreground font-black uppercase tracking-tighter">{doc.date.split(',')[0]}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Document Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedDoc && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedDoc(null)} className="fixed inset-0 bg-black/90 backdrop-blur-xl z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-xl bg-[#0A0710] border-l border-white/10 z-[101] shadow-2xl flex flex-col">
|
||||
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/10 relative overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_-20%,rgba(108,91,176,0.15),transparent)] pointer-events-none" />
|
||||
<div className="flex items-center gap-6 relative z-10">
|
||||
<div className="p-4 bg-[#150F1D] border border-white/10 rounded-sm shadow-xl">
|
||||
<DocIcon type={selectedDoc.type} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-2xl font-black tracking-tighter text-foreground truncate max-w-sm uppercase">{selectedDoc.name}</h2>
|
||||
<div className="flex items-center gap-4 mt-2">
|
||||
<span className="text-[10px] font-black uppercase tracking-[0.2em] bg-primary/20 text-primary px-3 py-1 rounded-sm border border-primary/20 shadow-sm">{selectedDoc.type}</span>
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">{selectedDoc.size}</span>
|
||||
{selectedDoc.starred && <Star className="h-3.5 w-3.5 fill-primary text-primary" />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setSelectedDoc(null)} className="p-2.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors relative z-10"><X className="h-8 w-8" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-10 space-y-12 tiny-scrollbar relative">
|
||||
|
||||
{/* AI Summary Section */}
|
||||
<div className="rounded-sm border border-primary/30 bg-primary/5 p-8 space-y-5 relative overflow-hidden shadow-2xl">
|
||||
<div className="absolute -right-6 -top-6 opacity-10 rotate-12">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> Strategic Content Intelligence
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
<p className="text-sm font-bold text-foreground/90 leading-[1.6] italic tracking-tight">
|
||||
"{selectedDoc.summary}"
|
||||
</p>
|
||||
{selectedDoc.aiAnalysis && (
|
||||
<div className="pt-5 border-t border-primary/20 mt-5">
|
||||
<div className="text-[10px] font-black text-primary uppercase tracking-[0.3em] mb-3 flex items-center gap-2">
|
||||
<Zap className="h-3.5 w-3.5" /> High-Level Insight
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground leading-relaxed font-medium uppercase tracking-wider">{selectedDoc.aiAnalysis}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Metadata & Actions */}
|
||||
<div className="grid grid-cols-2 gap-12">
|
||||
<div className="space-y-5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-primary">File Properties</h3>
|
||||
<div className="space-y-5">
|
||||
<MetaItem label="AUTHOR" value={selectedDoc.owner} />
|
||||
<MetaItem label="TIMELINE" value={selectedDoc.date} />
|
||||
<MetaItem label="CLASSIF." value={selectedDoc.category} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-primary">Strategic Tags</h3>
|
||||
<div className="flex flex-wrap gap-2.5">
|
||||
{selectedDoc.tags?.map((tag: string) => (
|
||||
<span key={tag} className="text-[9px] font-black uppercase tracking-[0.2em] px-3 py-1.5 rounded-sm bg-white/5 border border-white/10 text-muted-foreground hover:border-primary hover:text-primary transition-all cursor-pointer">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
<button className="text-[9px] font-black uppercase tracking-[0.2em] px-3 py-1.5 rounded-sm border border-dashed border-white/20 text-muted-foreground hover:border-white/40 transition-colors">
|
||||
+ NEW TAG
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Connected Ecosystem */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-primary">Strategic Ecosystem</h3>
|
||||
<span className="text-[9px] font-black text-muted-foreground uppercase tracking-widest">Linked by AI</span>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="p-5 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/40 transition-all shadow-xl">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm shadow-inner"><Globe className="h-5 w-5 text-primary" /></div>
|
||||
<div>
|
||||
<div className="text-[11px] font-black uppercase tracking-widest text-foreground">Project: Q3 Expansion</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1 font-bold">Referenced in Section 4.2</div>
|
||||
</div>
|
||||
</div>
|
||||
<ExternalLink className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
<div className="p-5 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/40 transition-all shadow-xl">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-3 bg-emerald-500/10 rounded-sm shadow-inner"><Activity className="h-5 w-5 text-emerald-500" /></div>
|
||||
<div>
|
||||
<div className="text-[11px] font-black uppercase tracking-widest text-foreground">Goal: Market Dominance</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1 font-bold">Foundational Resource</div>
|
||||
</div>
|
||||
</div>
|
||||
<ExternalLink className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/10 bg-[#0F0B15]/60 flex gap-6">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-[0.3em] shadow-2xl shadow-primary/40 transition-all active:scale-[0.98] flex items-center justify-center gap-3">
|
||||
<Download className="h-5 w-5" /> DOWNLOAD FILE
|
||||
</button>
|
||||
<button className="p-5 border border-white/10 rounded-sm text-muted-foreground hover:bg-white/10 transition-all shadow-xl">
|
||||
<Share2 className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DocIcon({ type, small = false }: { type: string, small?: boolean }) {
|
||||
const sizeClass = small ? "h-6 w-6" : "h-14 w-14";
|
||||
if (["PDF", "XLSX"].includes(type)) return <FileText className={`${sizeClass} text-rose-500`} />;
|
||||
if (["FIG"].includes(type)) return <File className={`${sizeClass} text-purple-500`} />;
|
||||
if (["MP4"].includes(type)) return <Video className={`${sizeClass} text-blue-500`} />;
|
||||
if (["ZIP"].includes(type)) return <File className={`${sizeClass} text-orange-500`} />;
|
||||
return <File className={`${sizeClass} text-muted-foreground`} />;
|
||||
}
|
||||
|
||||
function MetaItem({ label, value }: { label: string, value: string }) {
|
||||
return (
|
||||
<div className="flex items-center justify-between border-b border-white/5 pb-3">
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">{label}</span>
|
||||
<span className="text-[11px] font-black text-foreground uppercase tracking-tight">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+329
-180
@@ -1,255 +1,404 @@
|
||||
"use client";
|
||||
|
||||
import { Search, Filter, Brain, ArrowUpRight, ArrowDownRight, DollarSign, Activity, PieChart, Download, Wallet, Plus } from "lucide-react";
|
||||
import { useState, useMemo } from "react";
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Area,
|
||||
AreaChart,
|
||||
Pie,
|
||||
PieChart as RechartsPieChart,
|
||||
Cell
|
||||
Plus, Search, TrendingUp, TrendingDown, DollarSign,
|
||||
CreditCard, ArrowUpRight, ArrowDownRight, MoreHorizontal,
|
||||
Calendar, FileText, Download, PieChart as PieChartIcon,
|
||||
Wallet, Brain, ArrowRight, X, Check, Activity,
|
||||
Briefcase, Landmark, Receipt, Percent, Target
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Area, AreaChart, Bar, BarChart, CartesianGrid,
|
||||
ResponsiveContainer, Tooltip, XAxis, YAxis, Cell,
|
||||
Pie, PieChart
|
||||
} from "recharts";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const cashFlowData = [
|
||||
{ month: "Jan", in: 45000, out: 28000 },
|
||||
{ month: "Feb", in: 52000, out: 31000 },
|
||||
{ month: "Mar", in: 48000, out: 29000 },
|
||||
{ month: "Apr", in: 61000, out: 34000 },
|
||||
{ month: "May", in: 59000, out: 42000 },
|
||||
{ month: "Jun", in: 75000, out: 38000 },
|
||||
const cashflowData = [
|
||||
{ month: "Jan", income: 12500, expense: 8400, predicted: 13000 },
|
||||
{ month: "Feb", income: 14200, expense: 9100, predicted: 14500 },
|
||||
{ month: "Mar", income: 13800, expense: 8800, predicted: 14000 },
|
||||
{ month: "Apr", income: 15600, expense: 10200, predicted: 16000 },
|
||||
{ month: "May", income: 18400, expense: 11500, predicted: 19500 },
|
||||
{ month: "Jun", income: 21000, expense: 12000, predicted: 22000 },
|
||||
];
|
||||
|
||||
const expensesData = [
|
||||
{ name: "Payroll", value: 45000, color: "#6C5BB0" },
|
||||
{ name: "Software/SaaS", value: 12000, color: "#54468B" },
|
||||
{ name: "Marketing", value: 18000, color: "#3B3161" },
|
||||
{ name: "Office/Rent", value: 8000, color: "#221C38" },
|
||||
const expensesByCategory = [
|
||||
{ name: "Software", value: 3400, color: "#6C5BB0" },
|
||||
{ name: "Rent", value: 2500, color: "#a798e8" },
|
||||
{ name: "Marketing", value: 1800, color: "#10b981" },
|
||||
{ name: "Taxes", value: 4200, color: "#3b82f6" },
|
||||
{ name: "Travel", value: 1200, color: "#f59e0b" },
|
||||
];
|
||||
|
||||
const recentTransactions = [
|
||||
{ id: 1, desc: "Stripe Payout", category: "Revenue", amount: "+$12,450.00", date: "Today", status: "Completed" },
|
||||
{ id: 2, desc: "Amazon Web Services", category: "Software", amount: "-$3,240.50", date: "Yesterday", status: "Completed" },
|
||||
{ id: 3, desc: "Google Ads", category: "Marketing", amount: "-$4,500.00", date: "May 15", status: "Pending" },
|
||||
{ id: 4, desc: "WeWork Remote", category: "Office", amount: "-$1,200.00", date: "May 12", status: "Completed" },
|
||||
const transactions = [
|
||||
{ id: 1, name: "Stripe Subscription", date: "May 15", amount: "+$4,200", status: "Success", type: "Income", category: "Direct Sales", project: "Cognis Mobile" },
|
||||
{ id: 2, name: "Amazon Web Services", date: "May 12", amount: "-$840", status: "Pending", type: "Expense", category: "Cloud Infra", project: "Infrastructure" },
|
||||
{ id: 3, name: "Office Rent Q3", date: "May 10", amount: "-$2,500", status: "Success", type: "Expense", category: "Overhead", project: "General" },
|
||||
{ id: 4, name: "Client: Marketing Site", date: "May 08", amount: "+$2,800", status: "Success", type: "Income", category: "Freelance", project: "Marketing Site" },
|
||||
{ id: 5, name: "GitHub Enterprise", date: "May 05", amount: "-$120", status: "Success", type: "Expense", category: "Software", project: "Infrastructure" },
|
||||
];
|
||||
|
||||
export default function FinancePage() {
|
||||
const [showInvoiceModal, setShowInvoiceModal] = useState(false);
|
||||
const [selectedTransaction, setSelectedTransaction] = useState<any>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Management</span> / Finance
|
||||
<span className="text-foreground">Business</span> / Financials
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-emerald-500 bg-emerald-500/5 px-3 py-1 rounded-sm border border-emerald-500/10">
|
||||
<Check className="h-3 w-3" /> ALL SYSTEMS HEALTHY
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button className="bg-white/5 hover:bg-white/10 text-foreground border border-white/10 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Download className="h-4 w-4" />
|
||||
STATEMENT
|
||||
</button>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW INVOICE
|
||||
<button
|
||||
onClick={() => setShowInvoiceModal(true)}
|
||||
className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95"
|
||||
>
|
||||
<Receipt className="h-4 w-4" />
|
||||
CREATE INVOICE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Financial Analyst */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Financial Analyst
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
|
||||
I detected an anomaly: <strong>Software/SaaS expenses</strong> increased by 22% compared to last month. Specifically, AWS costs spiked. AI recommends auditing idle EC2 instances to save approximately $850/mo.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
|
||||
Run Cloud Audit
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* KPI Row */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
|
||||
<DollarSign className="h-3.5 w-3.5" /> Total Revenue (MTD)
|
||||
</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-3xl font-bold text-foreground">$124,500</span>
|
||||
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
|
||||
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 8.4%
|
||||
</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 shrink-0">
|
||||
<FinanceKpiCard label="Total Revenue" value="$42,850" change="+18%" trend="up" icon={DollarSign} />
|
||||
<FinanceKpiCard label="Tax Provision" value="$8,400" change="+12%" trend="up" icon={Landmark} />
|
||||
<FinanceKpiCard label="Operating Costs" value="$12,400" change="-5%" trend="down" icon={TrendingDown} />
|
||||
<FinanceKpiCard label="Projected Net" value="$30,450" change="+24%" trend="up" icon={Wallet} color="primary" />
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
|
||||
<Activity className="h-3.5 w-3.5" /> Monthly Burn Rate
|
||||
</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-3xl font-bold text-foreground">$42,300</span>
|
||||
<span className="text-xs text-red-500 flex items-center font-medium mb-1">
|
||||
<ArrowUpRight className="h-3 w-3 mr-0.5" /> 2.1%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
|
||||
<Wallet className="h-3.5 w-3.5" /> Cash Runway
|
||||
</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-3xl font-bold text-foreground">14.2</span>
|
||||
<span className="text-xs text-muted-foreground flex items-center font-medium mb-1">
|
||||
Months
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-4 flex items-center gap-2">
|
||||
<Brain className="h-3.5 w-3.5 text-primary" /> AI Profitability Score
|
||||
</h3>
|
||||
<div className="flex items-end gap-3 mb-1">
|
||||
<span className="text-3xl font-bold text-primary">94/100</span>
|
||||
<span className="text-xs text-emerald-500 flex items-center font-medium mb-1">
|
||||
Optimal
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Charts & Tables */}
|
||||
{/* Main Analysis Area */}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6 flex-1 min-h-[400px]">
|
||||
|
||||
{/* Cash Flow Chart */}
|
||||
<div className="xl:col-span-2 rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col">
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
{/* Cashflow Chart */}
|
||||
<div className="xl:col-span-2 bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col relative overflow-hidden group shadow-2xl">
|
||||
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-opacity">
|
||||
<TrendingUp className="h-48 w-48 text-primary" />
|
||||
</div>
|
||||
<div className="flex justify-between items-start mb-10 relative z-10">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold mb-1">Cash Flow Overview</h3>
|
||||
<p className="text-xs text-muted-foreground">Revenue vs Expenses over the last 6 months.</p>
|
||||
<h3 className="text-xl font-black mb-1 flex items-center gap-3">
|
||||
Intelligent Cashflow
|
||||
<span className="text-[10px] font-black bg-primary/20 text-primary px-3 py-1 rounded-sm uppercase tracking-[0.2em] animate-pulse">AI Forecasting</span>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-md">Real-time revenue monitoring compared with deep-learning projections for the next quarter.</p>
|
||||
</div>
|
||||
<div className="flex gap-4 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-emerald-500"></div> Inflow</div>
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-sm bg-red-500"></div> Outflow</div>
|
||||
<div className="flex gap-6 text-[10px] font-black uppercase tracking-widest text-muted-foreground">
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-full bg-primary" /> Income</div>
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-full bg-rose-500" /> Expense</div>
|
||||
<div className="flex items-center gap-2"><div className="w-2 h-2 rounded-full border-2 border-dashed border-primary" /> Forecast</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 w-full min-h-[250px]">
|
||||
<div className="flex-1 w-full min-h-[300px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data={cashFlowData}>
|
||||
<AreaChart data={cashflowData}>
|
||||
<defs>
|
||||
<linearGradient id="colorIncome" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#6C5BB0" stopOpacity={0.4}/>
|
||||
<stop offset="95%" stopColor="#6C5BB0" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#ffffff05" />
|
||||
<XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dy={10} />
|
||||
<YAxis axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5' }} dx={-10} tickFormatter={(val) => `$${val/1000}k`} />
|
||||
<XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5', fontWeight: 600 }} dy={10} />
|
||||
<YAxis axisLine={false} tickLine={false} tick={{ fontSize: 11, fill: '#8F89A5', fontWeight: 600 }} dx={-10} />
|
||||
<Tooltip
|
||||
cursor={{ fill: '#ffffff05' }}
|
||||
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE", borderRadius: "4px" }}
|
||||
itemStyle={{ color: "#FBF9FE" }}
|
||||
cursor={{ stroke: '#6C5BB0', strokeWidth: 1 }}
|
||||
contentStyle={{ backgroundColor: "#150F1D", border: "1px solid rgba(255,255,255,0.05)", borderRadius: "4px", fontSize: "12px" }}
|
||||
/>
|
||||
<Bar dataKey="in" fill="#10b981" radius={[2, 2, 0, 0]} barSize={16} />
|
||||
<Bar dataKey="out" fill="#ef4444" radius={[2, 2, 0, 0]} barSize={16} />
|
||||
</BarChart>
|
||||
<Area type="monotone" dataKey="income" stroke="#6C5BB0" strokeWidth={4} fillOpacity={1} fill="url(#colorIncome)" />
|
||||
<Area type="monotone" dataKey="expense" stroke="#f43f5e" strokeWidth={2} fill="transparent" strokeDasharray="4 4" />
|
||||
<Area type="monotone" dataKey="predicted" stroke="#6C5BB0" strokeWidth={1} fill="transparent" strokeDasharray="10 10" opacity={0.5} />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expenses Pie & Recent Transactions */}
|
||||
{/* Expense Breakdown & AI Insights */}
|
||||
<div className="flex flex-col gap-6">
|
||||
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex-1 flex flex-col">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2">Expenses Breakdown</h3>
|
||||
<div className="flex-1 w-full flex items-center justify-center relative min-h-[160px]">
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col shadow-2xl">
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.2em] text-muted-foreground mb-8">Category Allocation</h3>
|
||||
<div className="flex-1 w-full min-h-[180px] flex items-center justify-center">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<RechartsPieChart>
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={expensesData}
|
||||
data={expensesByCategory}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
innerRadius={50}
|
||||
outerRadius={70}
|
||||
paddingAngle={2}
|
||||
innerRadius={55}
|
||||
outerRadius={80}
|
||||
paddingAngle={4}
|
||||
dataKey="value"
|
||||
stroke="none"
|
||||
>
|
||||
{expensesData.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
||||
{expensesByCategory.map((entry, index) => (
|
||||
<Cell key={index} fill={entry.color} />
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px" }} />
|
||||
</RechartsPieChart>
|
||||
<Tooltip contentStyle={{ backgroundColor: "#150F1D", border: "none" }} />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
<div className="absolute inset-0 flex items-center justify-center pointer-events-none flex-col">
|
||||
<span className="text-[10px] text-muted-foreground uppercase font-bold tracking-widest">Total</span>
|
||||
<span className="text-sm font-bold">$83k</span>
|
||||
</div>
|
||||
<div className="mt-8 space-y-3">
|
||||
{expensesByCategory.slice(0, 3).map(ex => (
|
||||
<div key={ex.name} className="flex justify-between items-center text-[10px] font-black uppercase tracking-widest">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: ex.color }} />
|
||||
<span className="text-muted-foreground">{ex.name}</span>
|
||||
</div>
|
||||
<div className="space-y-2 mt-4">
|
||||
{expensesData.map((item, idx) => (
|
||||
<div key={idx} className="flex justify-between items-center text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-sm" style={{ backgroundColor: item.color }}></div>
|
||||
<span className="text-muted-foreground">{item.name}</span>
|
||||
</div>
|
||||
<span className="font-semibold">${(item.value / 1000).toFixed(1)}k</span>
|
||||
<span>${ex.value.toLocaleString()}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-primary/5 border border-primary/20 rounded-sm p-8 flex-1 flex flex-col justify-between relative overflow-hidden group">
|
||||
<div className="absolute -right-4 -top-4 opacity-5 rotate-12 transition-transform group-hover:scale-110">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-primary/20 rounded-sm">
|
||||
<Percent className="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.2em] text-primary">Strategic Advantage</h3>
|
||||
</div>
|
||||
<p className="text-sm font-bold leading-relaxed text-foreground/90 italic">
|
||||
"Your project-specific ROI is 18% higher when tasks are completed in the morning focus block. Strategic reinvestment of $5k suggested for Q4."
|
||||
</p>
|
||||
</div>
|
||||
<button className="text-[10px] font-black text-primary uppercase tracking-[0.2em] flex items-center gap-2 group/btn border-b border-primary/20 pb-1 self-start hover:border-primary transition-all">
|
||||
OPTIMIZE SPENDING <ArrowRight className="h-3 w-3 group-hover/btn:translate-x-1 transition-transform" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Transactions Ledger */}
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm overflow-hidden flex flex-col h-[450px] shadow-2xl">
|
||||
<div className="flex justify-between items-center p-8 border-b border-white/5 bg-[#0F0B15]/40 backdrop-blur-sm">
|
||||
<div>
|
||||
<h3 className="text-xs font-black uppercase tracking-[0.3em] text-muted-foreground">Strategic Ledger</h3>
|
||||
<p className="text-[10px] text-muted-foreground mt-1 uppercase font-bold tracking-widest">Showing last 24 transactions across 5 projects</p>
|
||||
</div>
|
||||
|
||||
{/* AI Categorized Transactions */}
|
||||
<div className="bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden">
|
||||
<div className="p-4 border-b border-white/5 flex justify-between items-center">
|
||||
<h3 className="text-sm font-semibold">Recent Transactions</h3>
|
||||
<span className="text-[10px] font-bold uppercase tracking-wider text-primary flex items-center gap-1"><Brain className="h-3 w-3" /> Auto-Categorized by AI</span>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Filter className="h-3 w-3 text-muted-foreground" />
|
||||
<span className="text-[10px] font-bold text-muted-foreground">FILTER</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="col-span-5">Description</div>
|
||||
<div className="col-span-2">Category</div>
|
||||
<div className="col-span-2">Date</div>
|
||||
<div className="col-span-2">Amount</div>
|
||||
<div className="col-span-1 text-right">Status</div>
|
||||
<button className="text-[10px] font-black text-primary uppercase tracking-[0.2em] bg-primary/10 px-4 py-2 rounded-sm hover:bg-primary/20 transition-all">Full Report</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar">
|
||||
<div className="divide-y divide-white/5">
|
||||
{recentTransactions.map((tx) => (
|
||||
<div key={tx.id} className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors">
|
||||
<div className="col-span-5 text-sm font-medium">{tx.desc}</div>
|
||||
<div className="col-span-2 text-xs text-muted-foreground">{tx.category}</div>
|
||||
<div className="col-span-2 text-xs text-muted-foreground">{tx.date}</div>
|
||||
<div className={`col-span-2 text-sm font-bold ${tx.amount.startsWith('+') ? 'text-emerald-400' : 'text-foreground'}`}>
|
||||
{tx.amount}
|
||||
{transactions.map(t => (
|
||||
<div key={t.id} onClick={() => setSelectedTransaction(t)} className="grid grid-cols-12 gap-4 p-6 items-center hover:bg-white/[0.02] transition-all group cursor-pointer border-l-2 border-transparent hover:border-primary">
|
||||
<div className="col-span-1 flex justify-center">
|
||||
<div className={`p-3 rounded-sm ${t.type === 'Income' ? 'bg-emerald-500/10 text-emerald-500 shadow-[0_0_10px_rgba(16,185,129,0.1)]' : 'bg-rose-500/10 text-rose-500 shadow-[0_0_10px_rgba(244,63,94,0.1)]'}`}>
|
||||
{t.type === 'Income' ? <ArrowUpRight className="h-5 w-5" /> : <ArrowDownRight className="h-5 w-5" />}
|
||||
</div>
|
||||
<div className="col-span-1 text-right">
|
||||
<span className={`text-[10px] uppercase font-bold px-2 py-1 rounded-sm border inline-block ${
|
||||
tx.status === 'Completed' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
|
||||
'bg-orange-500/10 text-orange-400 border-orange-500/20'
|
||||
}`}>
|
||||
{tx.status}
|
||||
</div>
|
||||
<div className="col-span-5">
|
||||
<div className="text-sm font-black group-hover:text-primary transition-colors">{t.name}</div>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<span className="text-[10px] text-muted-foreground uppercase font-black tracking-widest">{t.category}</span>
|
||||
<span className="text-[10px] text-primary font-bold bg-primary/5 px-2 py-0.5 rounded-sm">{t.project}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 text-xs text-muted-foreground font-black uppercase tracking-tighter">{t.date}</div>
|
||||
<div className="col-span-2">
|
||||
<span className={`text-sm font-black tracking-tighter ${t.type === 'Income' ? 'text-emerald-400' : 'text-rose-400'}`}>
|
||||
{t.amount}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-end gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Invoice Editor Modal */}
|
||||
<AnimatePresence>
|
||||
{showInvoiceModal && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setShowInvoiceModal(false)} className="fixed inset-0 bg-black/90 backdrop-blur-xl z-[100]" />
|
||||
<motion.div initial={{ scale: 0.9, opacity: 0, y: 20 }} animate={{ scale: 1, opacity: 1, y: 0 }} exit={{ scale: 0.9, opacity: 0, y: 20 }} className="fixed inset-0 m-auto w-full max-w-3xl h-fit max-h-[90vh] bg-[#0A0710] border border-white/10 z-[101] shadow-2xl flex flex-col rounded-sm overflow-hidden">
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/10 relative overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_-20%,rgba(108,91,176,0.15),transparent)] pointer-events-none" />
|
||||
<div className="flex items-center gap-4 relative z-10">
|
||||
<div className="p-3 bg-primary rounded-sm shadow-xl shadow-primary/20"><Receipt className="h-6 w-6 text-primary-foreground" /></div>
|
||||
<div>
|
||||
<h2 className="text-2xl font-black uppercase tracking-tighter">Strategic Invoice</h2>
|
||||
<p className="text-[10px] font-black text-primary tracking-[0.3em] uppercase">AI-Optimized Billing Engine</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setShowInvoiceModal(false)} className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors relative z-10"><X className="h-7 w-7" /></button>
|
||||
</div>
|
||||
|
||||
<div className="p-10 space-y-8 overflow-y-auto tiny-scrollbar">
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">Select Client</label>
|
||||
<div className="relative">
|
||||
<input type="text" placeholder="Start typing client name..." className="w-full bg-[#150F1D] border border-white/10 rounded-sm px-5 py-4 text-sm font-bold outline-none focus:border-primary/50 transition-all" />
|
||||
<Search className="absolute right-4 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">Project Association</label>
|
||||
<select className="w-full bg-[#150F1D] border border-white/10 rounded-sm px-5 py-4 text-sm font-bold outline-none focus:border-primary/50 transition-all appearance-none">
|
||||
<option className="bg-[#0A0710]">Marketing Site Redesign</option>
|
||||
<option className="bg-[#0A0710]">Infrastructure Scale</option>
|
||||
<option className="bg-[#0A0710]">Cognis Mobile Dev</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6 pt-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-primary">Billable Items</h3>
|
||||
<button className="text-[10px] font-black text-muted-foreground hover:text-primary transition-colors flex items-center gap-2">
|
||||
<Plus className="h-3 w-3" /> ADD CUSTOM LINE
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<InvoiceLineItem title="Phase 1: Design Strategy" rate="$120/hr" hours="24h" total="$2,880" />
|
||||
<InvoiceLineItem title="Phase 2: Core Development" rate="$150/hr" hours="12h" total="$1,800" />
|
||||
<div className="p-4 rounded-sm border border-dashed border-white/10 flex items-center justify-center text-[10px] font-bold text-muted-foreground hover:bg-white/5 transition-all cursor-pointer">
|
||||
AI SUGGESTION: ADD "QA & TESTING" (8H)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-8 border-t border-white/10 flex flex-col items-end gap-3">
|
||||
<div className="flex gap-16 text-sm">
|
||||
<span className="text-muted-foreground font-black uppercase tracking-widest text-[10px] mt-1">Subtotal</span>
|
||||
<span className="font-black text-lg">$4,680.00</span>
|
||||
</div>
|
||||
<div className="flex gap-16 text-sm">
|
||||
<span className="text-muted-foreground font-black uppercase tracking-widest text-[10px] mt-1">Tax (18%)</span>
|
||||
<span className="font-black text-lg">$842.40</span>
|
||||
</div>
|
||||
<div className="flex gap-16 text-2xl font-black mt-4 pt-4 border-t border-primary/20 w-full justify-end">
|
||||
<span className="text-primary uppercase tracking-[0.4em] text-[10px] mt-3">Grand Total</span>
|
||||
<span className="text-primary text-4xl tracking-tighter">$5,522.40</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 flex gap-6 bg-[#0F0B15]/60">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-[0.3em] shadow-2xl shadow-primary/40 transition-all active:scale-[0.98] flex items-center justify-center gap-3">
|
||||
<Download className="h-5 w-5" /> GENERATE & SEND
|
||||
</button>
|
||||
<button className="px-10 border border-white/10 rounded-sm text-[11px] font-black uppercase tracking-[0.2em] text-muted-foreground hover:bg-white/5 transition-all">
|
||||
SAVE AS DRAFT
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Transaction Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedTransaction && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedTransaction(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-lg bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col p-10 space-y-12">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className={`p-4 rounded-sm ${selectedTransaction.type === 'Income' ? 'bg-emerald-500/10 text-emerald-500' : 'bg-rose-500/10 text-rose-500'}`}>
|
||||
{selectedTransaction.type === 'Income' ? <ArrowUpRight className="h-8 w-8" /> : <ArrowDownRight className="h-8 w-8" />}
|
||||
</div>
|
||||
<button onClick={() => setSelectedTransaction(null)} className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-7 w-7" /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-3xl font-black tracking-tighter">{selectedTransaction.name}</h2>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className={`text-xl font-black ${selectedTransaction.type === 'Income' ? 'text-emerald-400' : 'text-rose-400'}`}>{selectedTransaction.amount}</span>
|
||||
<span className="text-[10px] font-black uppercase tracking-widest bg-white/5 px-2 py-1 rounded-sm text-muted-foreground border border-white/5">{selectedTransaction.status}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6 pt-6 border-t border-white/5">
|
||||
<DetailMeta label="TRANSACTION DATE" value={selectedTransaction.date} />
|
||||
<DetailMeta label="STRATEGIC CATEGORY" value={selectedTransaction.category} />
|
||||
<DetailMeta label="PROJECT LINK" value={selectedTransaction.project} isPrimary />
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 space-y-4">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-widest text-primary flex items-center gap-2">
|
||||
<Brain className="h-3.5 w-3.5" /> Financial Insight
|
||||
</h3>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed italic">
|
||||
This {selectedTransaction.type.toLowerCase()} was processed via Stripe and linked to your **{selectedTransaction.project}** deliverables. Tax obligations have been pre-calculated.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button className="w-full bg-white/5 hover:bg-white/10 border border-white/10 py-4 rounded-sm text-[10px] font-black uppercase tracking-[0.2em] transition-all flex items-center justify-center gap-3 mt-auto">
|
||||
<Download className="h-4 w-4" /> DOWNLOAD RECEIPT
|
||||
</button>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function InvoiceLineItem({ title, rate, hours, total }: any) {
|
||||
return (
|
||||
<div className="grid grid-cols-12 gap-4 p-5 rounded-sm bg-[#150F1D] border border-white/5 items-center group hover:border-primary/30 transition-all">
|
||||
<div className="col-span-7 flex flex-col">
|
||||
<span className="text-xs font-black group-hover:text-primary transition-colors uppercase tracking-widest">{title}</span>
|
||||
<span className="text-[9px] text-muted-foreground font-bold uppercase tracking-widest mt-1">Strategic Development Block</span>
|
||||
</div>
|
||||
<div className="col-span-2 text-center text-xs font-black text-muted-foreground">{rate}</div>
|
||||
<div className="col-span-1 text-center text-xs font-black text-muted-foreground">{hours}</div>
|
||||
<div className="col-span-2 text-right text-sm font-black text-primary">{total}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DetailMeta({ label, value, isPrimary = false }: any) {
|
||||
return (
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">{label}</span>
|
||||
<span className={`text-sm font-black ${isPrimary ? 'text-primary' : 'text-foreground'}`}>{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FinanceKpiCard({ label, value, change, trend, icon: Icon, color = "default" }: any) {
|
||||
const isUp = trend === "up";
|
||||
const trendColor = isUp ? "text-emerald-500" : "text-rose-500";
|
||||
|
||||
return (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 group relative overflow-hidden shadow-2xl transition-all hover:border-white/10">
|
||||
<div className={`absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity ${color === 'primary' ? 'text-primary' : 'text-foreground'}`}>
|
||||
<Icon className="h-20 w-20" />
|
||||
</div>
|
||||
<div className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground mb-4">{label}</div>
|
||||
<div className="flex items-baseline gap-3 relative z-10">
|
||||
<span className="text-3xl font-black text-foreground tracking-tighter leading-none">{value}</span>
|
||||
<div className={`flex items-center text-[10px] font-black px-2 py-0.5 rounded-sm bg-white/5 ${trendColor}`}>
|
||||
{isUp ? <ArrowUpRight className="h-3.5 w-3.5 mr-0.5" /> : <ArrowDownRight className="h-3.5 w-3.5 mr-0.5" />} {change}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+251
-122
@@ -1,165 +1,294 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Brain, Target, Compass, Award, MoreHorizontal, CircleDashed, CheckCircle2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, Target, Flag, TrendingUp, Zap,
|
||||
CheckCircle2, Clock, Brain, MoreHorizontal, X,
|
||||
ChevronRight, ArrowRight, BarChart3, Star,
|
||||
Shield, Globe, Briefcase, Award
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const goals = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Launch SaaS Product MVP",
|
||||
category: "Career & Business",
|
||||
progress: 75,
|
||||
dueDate: "Q3 2026",
|
||||
status: "On Track",
|
||||
color: "#6C5BB0", // Primary
|
||||
title: "100k Monthly Recurring Revenue",
|
||||
category: "Financial",
|
||||
progress: 42,
|
||||
deadline: "Dec 2026",
|
||||
status: "Active",
|
||||
priority: "Critical",
|
||||
milestones: [
|
||||
{ name: "Finalize Designs", done: true },
|
||||
{ name: "Backend Architecture", done: true },
|
||||
{ name: "Frontend Development", done: true },
|
||||
{ name: "Beta Testing", done: false },
|
||||
{ name: "Public Launch", done: false },
|
||||
]
|
||||
{ name: "Reach 50k MRR", status: "Done", date: "Aug 2026" },
|
||||
{ name: "Scale Sales Team", status: "In Progress", date: "Sep 2026" },
|
||||
{ name: "Launch Enterprise Tier", status: "Upcoming", date: "Nov 2026" },
|
||||
],
|
||||
aiInsight: "Currently 12% ahead of target. Strategic focus should remain on enterprise lead generation."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Run a Half-Marathon",
|
||||
category: "Health & Fitness",
|
||||
progress: 40,
|
||||
dueDate: "Oct 12, 2026",
|
||||
status: "Behind",
|
||||
color: "#10b981", // Emerald
|
||||
title: "Launch Cognis AI Mobile App",
|
||||
category: "Product",
|
||||
progress: 85,
|
||||
deadline: "May 25, 2026",
|
||||
status: "Active",
|
||||
priority: "High",
|
||||
milestones: [
|
||||
{ name: "Run 5K Without Stopping", done: true },
|
||||
{ name: "Run 10K", done: true },
|
||||
{ name: "Maintain 15K weekly volume", done: false },
|
||||
{ name: "Complete 18K long run", done: false },
|
||||
]
|
||||
{ name: "Beta Testing", status: "Done", date: "Apr 15" },
|
||||
{ name: "App Store Review", status: "In Progress", date: "May 10" },
|
||||
{ name: "Global Launch", status: "Upcoming", date: "May 25" },
|
||||
],
|
||||
aiInsight: "85% complete. Recommendation: Finalize push notification logic to ensure day-1 retention."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Read 24 Books",
|
||||
category: "Personal Growth",
|
||||
progress: 50,
|
||||
dueDate: "Dec 31, 2026",
|
||||
status: "Ahead",
|
||||
color: "#f97316", // Orange
|
||||
milestones: [
|
||||
{ name: "Read 6 Books (Q1)", done: true },
|
||||
{ name: "Read 12 Books (Q2)", done: true },
|
||||
{ name: "Read 18 Books (Q3)", done: false },
|
||||
]
|
||||
}
|
||||
{ id: 3, title: "Achieve Peak Physical Fitness", category: "Personal", progress: 60, deadline: "Ongoing", status: "Active", priority: "Medium", milestones: [], aiInsight: "" },
|
||||
{ id: 4, title: "Acquire 500 Enterprise Leads", category: "Marketing", progress: 25, deadline: "Jun 2026", status: "Delayed", priority: "High", milestones: [], aiInsight: "" },
|
||||
];
|
||||
|
||||
export default function GoalsPage() {
|
||||
const [selectedGoal, setSelectedGoal] = useState<any>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Personal</span> / Strategic Goals
|
||||
<span className="text-foreground">Vision</span> / Strategic Goals
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-primary bg-primary/5 px-3 py-1 rounded-sm border border-primary/10">
|
||||
<Target className="h-3 w-3" /> 4 ACTIVE OBJECTIVES
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search goals..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW GOAL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Goal Strategist */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
{/* Goal Matrix Categories */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 shrink-0">
|
||||
<GoalCategoryCard label="Critical" count={1} color="text-rose-500" icon={Zap} />
|
||||
<GoalCategoryCard label="High Priority" count={2} color="text-orange-500" icon={Star} />
|
||||
<GoalCategoryCard label="Medium" count={1} color="text-blue-500" icon={TrendingUp} />
|
||||
<GoalCategoryCard label="Completed" count={12} color="text-emerald-500" icon={CheckCircle2} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Goal Strategist
|
||||
|
||||
{/* Main Goals Grid */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar pr-1">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 pb-6">
|
||||
{goals.map((goal) => (
|
||||
<motion.div
|
||||
key={goal.id}
|
||||
whileHover={{ y: -4 }}
|
||||
onClick={() => setSelectedGoal(goal)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col gap-8 relative group overflow-hidden shadow-2xl cursor-pointer hover:border-primary/30 transition-all"
|
||||
>
|
||||
<div className={`absolute top-0 right-0 w-32 h-32 translate-x-16 -translate-y-16 opacity-10 blur-3xl rounded-full ${goal.priority === 'Critical' ? 'bg-rose-500' : 'bg-primary'}`} />
|
||||
|
||||
<div className="flex justify-between items-start relative z-10">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={`text-[10px] font-black uppercase tracking-widest px-2 py-0.5 rounded-sm border ${
|
||||
goal.priority === 'Critical' ? 'text-rose-400 border-rose-500/20 bg-rose-500/5' :
|
||||
goal.priority === 'High' ? 'text-orange-400 border-orange-500/20 bg-orange-500/5' : 'text-blue-400 border-blue-500/20 bg-blue-500/5'
|
||||
}`}>
|
||||
{goal.priority}
|
||||
</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{goal.category}</span>
|
||||
</div>
|
||||
<h3 className="text-2xl font-black tracking-tighter group-hover:text-primary transition-colors">{goal.title}</h3>
|
||||
</div>
|
||||
<button className="p-2 hover:bg-white/5 rounded-sm transition-colors text-muted-foreground"><MoreHorizontal className="h-5 w-5" /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 relative z-10">
|
||||
<div className="flex justify-between items-end">
|
||||
<div className="space-y-1">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">Strategic Progress</div>
|
||||
<div className="text-3xl font-black text-foreground">{goal.progress}%</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-1">Target Date</div>
|
||||
<div className="text-xs font-bold text-foreground">{goal.deadline}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-1.5 w-full bg-white/5 rounded-full overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${goal.progress}%` }}
|
||||
transition={{ duration: 1, ease: "easeOut" }}
|
||||
className={`h-full rounded-full ${goal.progress === 100 ? 'bg-emerald-500' : goal.status === 'Delayed' ? 'bg-rose-500' : 'bg-primary shadow-[0_0_15px_rgba(108,91,176,0.5)]'}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t border-white/5 flex items-center justify-between relative z-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex -space-x-2">
|
||||
{[1, 2, 3].map(i => <div key={i} className="h-6 w-6 rounded-full border border-[#0A0710] bg-[#1F172B] flex items-center justify-center text-[8px] font-bold">U{i}</div>)}
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{goal.milestones?.length || 0} Milestones</span>
|
||||
</div>
|
||||
<button className="text-[10px] font-black uppercase tracking-widest text-primary flex items-center gap-2 group/btn">
|
||||
VIEW STRATEGY <ArrowRight className="h-3 w-3 group-hover/btn:translate-x-1 transition-transform" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Goal Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedGoal && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedGoal(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-2xl bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col">
|
||||
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={`text-[10px] font-black uppercase tracking-widest px-2 py-1 rounded-sm border ${
|
||||
selectedGoal.priority === 'Critical' ? 'text-rose-400 border-rose-500/20' : 'text-primary border-primary/20'
|
||||
}`}>
|
||||
{selectedGoal.priority} Priority
|
||||
</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">Category: {selectedGoal.category}</span>
|
||||
</div>
|
||||
<h2 className="text-3xl font-black tracking-tighter text-foreground">{selectedGoal.title}</h2>
|
||||
</div>
|
||||
<button onClick={() => setSelectedGoal(null)} className="p-3 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-6 w-6" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-10 space-y-12 tiny-scrollbar">
|
||||
|
||||
{/* Progress Visual */}
|
||||
<div className="grid grid-cols-3 gap-8">
|
||||
<div className="col-span-2 bg-[#150F1D] border border-white/5 rounded-sm p-8 flex flex-col justify-center">
|
||||
<div className="flex justify-between items-end mb-4">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-primary">Strategic Completion</div>
|
||||
<div className="text-4xl font-black">{selectedGoal.progress}%</div>
|
||||
</div>
|
||||
<div className="h-2 w-full bg-white/5 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-primary" style={{ width: `${selectedGoal.progress}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 border border-white/5 rounded-sm p-6 flex flex-col items-center justify-center text-center">
|
||||
<Clock className="h-6 w-6 text-muted-foreground mb-2" />
|
||||
<div className="text-lg font-black">{selectedGoal.deadline}</div>
|
||||
<div className="text-[9px] font-bold text-muted-foreground uppercase tracking-widest">Target Date</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Goal Intelligence */}
|
||||
{selectedGoal.aiInsight && (
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-8 space-y-4 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 opacity-5">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> Goal Intelligence Report
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
|
||||
You are falling behind on your <strong>Half-Marathon</strong> goal. Your running habit completion has dropped to 30% this month. AI suggests breaking the next milestone ("Maintain 15K weekly volume") into smaller, manageable 3K chunks to rebuild momentum.
|
||||
<p className="text-sm font-medium text-foreground/90 leading-relaxed italic">
|
||||
"{selectedGoal.aiInsight}"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0 shadow-lg shadow-primary/20">
|
||||
Refactor Milestones
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Goals List */}
|
||||
<div className="space-y-6 pb-6">
|
||||
{goals.map((goal) => (
|
||||
<div key={goal.id} className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col lg:flex-row gap-8 relative overflow-hidden group">
|
||||
|
||||
{/* Left Side: Overview & Progress */}
|
||||
<div className="flex-1 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<h2 className="text-xl font-bold text-foreground">{goal.title}</h2>
|
||||
<span className={`text-[10px] uppercase font-bold px-2 py-0.5 rounded-sm border ${
|
||||
goal.status === 'Ahead' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
|
||||
goal.status === 'Behind' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' :
|
||||
'bg-blue-500/10 text-blue-400 border-blue-500/20'
|
||||
}`}>
|
||||
{goal.status}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-xs text-muted-foreground mb-6">
|
||||
<span className="flex items-center gap-1.5"><Compass className="h-3.5 w-3.5" /> {goal.category}</span>
|
||||
<span className="flex items-center gap-1.5"><Target className="h-3.5 w-3.5" /> Due: {goal.dueDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Big Progress Bar */}
|
||||
<div>
|
||||
<div className="flex justify-between items-end mb-2">
|
||||
<span className="text-sm font-semibold">Overall Progress</span>
|
||||
<span className="text-2xl font-bold" style={{ color: goal.color }}>{goal.progress}%</span>
|
||||
</div>
|
||||
<div className="h-3 w-full bg-white/5 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full transition-all duration-1000 relative"
|
||||
style={{ width: `${goal.progress}%`, backgroundColor: goal.color }}
|
||||
>
|
||||
{/* Inner highlight for 3D effect */}
|
||||
<div className="absolute top-0 left-0 right-0 h-1/2 bg-white/20"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side: Milestones */}
|
||||
<div className="w-full lg:w-96 rounded-sm bg-[#150F1D] border border-white/5 p-4 flex flex-col">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Milestones</h3>
|
||||
<button className="text-muted-foreground hover:text-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
<div className="space-y-3 flex-1 overflow-y-auto tiny-scrollbar">
|
||||
{goal.milestones.map((ms, idx) => (
|
||||
<div key={idx} className="flex items-start gap-3">
|
||||
{ms.done ? (
|
||||
<CheckCircle2 className="h-4 w-4 shrink-0 mt-0.5" style={{ color: goal.color }} />
|
||||
) : (
|
||||
<CircleDashed className="h-4 w-4 text-muted-foreground shrink-0 mt-0.5" />
|
||||
)}
|
||||
<span className={`text-sm ${ms.done ? 'text-muted-foreground line-through' : 'text-foreground font-medium'}`}>
|
||||
{ms.name}
|
||||
</span>
|
||||
|
||||
{/* Milestone Roadmap */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Milestone Roadmap</h3>
|
||||
<div className="relative space-y-8 pl-6 before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-px before:bg-white/10">
|
||||
{selectedGoal.milestones?.map((ms: any, i: number) => (
|
||||
<div key={i} className="relative group">
|
||||
<div className={`absolute -left-[23px] top-1 h-3 w-3 rounded-full border-2 border-[#0A0710] z-10 ${
|
||||
ms.status === 'Done' ? 'bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]' :
|
||||
ms.status === 'In Progress' ? 'bg-primary shadow-[0_0_8px_rgba(108,91,176,0.5)]' : 'bg-white/10'
|
||||
}`} />
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="text-sm font-bold group-hover:text-primary transition-colors">{ms.name}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1 uppercase font-medium">{ms.date} • {ms.status}</div>
|
||||
</div>
|
||||
{ms.status === 'Done' && <CheckCircle2 className="h-4 w-4 text-emerald-500" />}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button className="mt-4 w-full border border-dashed border-white/10 hover:border-white/30 text-muted-foreground hover:text-foreground py-2 rounded-sm text-xs font-semibold transition-colors flex items-center justify-center gap-2">
|
||||
<Plus className="h-3 w-3" /> Add Milestone
|
||||
{/* Connect Resources */}
|
||||
<div className="space-y-6 pt-6 border-t border-white/5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Linked Deliverables</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/20 transition-all">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-blue-500/10 rounded-sm"><Briefcase className="h-4 w-4 text-blue-400" /></div>
|
||||
<div>
|
||||
<div className="text-xs font-bold">Project: Cognis App</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1">Core Requirement</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
<div className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/20 transition-all">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-emerald-500/10 rounded-sm"><Award className="h-4 w-4 text-emerald-500" /></div>
|
||||
<div>
|
||||
<div className="text-xs font-bold">Achievement: Series A</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1">Strategic Outcome</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 bg-[#0F0B15]/50 flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-widest shadow-2xl shadow-primary/30 transition-all active:scale-[0.98]">
|
||||
UPDATE STRATEGIC PROGRESS
|
||||
</button>
|
||||
<button className="p-5 border border-white/10 rounded-sm text-muted-foreground hover:bg-white/5 transition-colors">
|
||||
<BarChart3 className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GoalCategoryCard({ label, count, color, icon: Icon }: any) {
|
||||
return (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-6 flex items-center justify-between group hover:border-white/10 transition-all shadow-xl">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`p-3 bg-white/5 rounded-sm ${color} transition-colors group-hover:bg-white/10`}>
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-0.5">{label}</div>
|
||||
<div className="text-xl font-black">{count}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground/30" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+235
-147
@@ -1,187 +1,275 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Filter, Brain, Check, X, Flame, Target, Trophy, TrendingUp } from "lucide-react";
|
||||
import { Area, AreaChart, ResponsiveContainer, XAxis, Tooltip } from "recharts";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, Zap, Flame, Calendar, CheckCircle2,
|
||||
Trophy, TrendingUp, Brain, Info, X, MoreHorizontal,
|
||||
ChevronRight, Activity, Clock, BarChart3, Target
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const habits = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Morning Meditation",
|
||||
category: "Mindfulness",
|
||||
streak: 12,
|
||||
goal: "Daily",
|
||||
color: "#6C5BB0", // Primary
|
||||
status: [true, true, true, false, true, true, false],
|
||||
trend: [40, 45, 30, 60, 50, 70, 85]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Read 20 Pages",
|
||||
category: "Learning",
|
||||
streak: 4,
|
||||
goal: "Daily",
|
||||
color: "#10b981", // Emerald
|
||||
status: [false, true, true, true, true, false, false],
|
||||
trend: [20, 40, 50, 40, 60, 80, 75]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Gym Workout",
|
||||
category: "Health",
|
||||
streak: 2,
|
||||
goal: "4x Week",
|
||||
color: "#f97316", // Orange
|
||||
status: [true, false, true, false, true, false, false],
|
||||
trend: [50, 55, 45, 65, 60, 75, 90]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "No Sugar",
|
||||
category: "Diet",
|
||||
streak: 0,
|
||||
goal: "Daily",
|
||||
color: "#ef4444", // Red
|
||||
status: [true, true, false, false, false, false, false],
|
||||
trend: [80, 70, 60, 40, 30, 20, 10]
|
||||
}
|
||||
{ id: 1, name: "Deep Work Block", frequency: "Daily", streak: 12, bestStreak: 24, progress: 85, color: "bg-[#6C5BB0]", icon: Brain, completedDays: [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15] },
|
||||
{ id: 2, name: "7AM Gym Session", frequency: "Mon, Wed, Fri", streak: 4, bestStreak: 8, progress: 60, color: "bg-emerald-500", icon: Activity, completedDays: [1, 3, 5, 8, 10, 12, 15] },
|
||||
{ id: 3, name: "Strategic Reading", frequency: "Daily", streak: 0, bestStreak: 15, progress: 30, color: "bg-blue-500", icon: Zap, completedDays: [1, 2, 3, 4, 10, 11] },
|
||||
{ id: 4, name: "Journaling", frequency: "Daily", streak: 18, bestStreak: 18, progress: 100, color: "bg-orange-500", icon: Target, completedDays: Array.from({length: 15}, (_, i) => i + 1) },
|
||||
];
|
||||
|
||||
const days = ["M", "T", "W", "T", "F", "S", "S"];
|
||||
|
||||
export default function HabitsPage() {
|
||||
const [selectedHabit, setSelectedHabit] = useState<any>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Personal</span> / Habits Tracker
|
||||
<span className="text-foreground">Mindset</span> / Habits & Performance
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-orange-500 bg-orange-500/5 px-3 py-1 rounded-sm border border-orange-500/10">
|
||||
<Flame className="h-3 w-3" /> 18 DAY OVERALL STREAK
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Filter className="h-4 w-4" />
|
||||
</button>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search habits..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW HABIT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Habit Optimizer */}
|
||||
<div className="rounded-sm border border-primary/20 bg-[linear-gradient(90deg,rgba(108,91,176,0.1)_0%,rgba(10,7,16,0)_100%)] p-6 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
{/* Top Stats Overview */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 shrink-0">
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex items-center gap-6 group relative overflow-hidden shadow-2xl">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity"><Flame className="h-20 w-20 text-orange-500" /></div>
|
||||
<div className="p-4 bg-orange-500/10 rounded-sm"><Flame className="h-6 w-6 text-orange-500" /></div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Habit Optimizer
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
|
||||
I noticed a pattern: You often break your <strong>"No Sugar"</strong> streak on Thursdays. This correlates with high-stress days marked in your Journal. AI suggests scheduling a stress-relief activity (like a walk) around 3 PM on Thursdays to curb cravings.
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-1">Consistency Score</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-black text-foreground tracking-tighter">92%</span>
|
||||
<span className="text-[10px] text-emerald-500 font-bold">+4% vs last week</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex items-center gap-6 group relative overflow-hidden shadow-2xl">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity"><Trophy className="h-20 w-20 text-primary" /></div>
|
||||
<div className="p-4 bg-primary/10 rounded-sm"><Trophy className="h-6 w-6 text-primary" /></div>
|
||||
<div>
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-1">Weekly Goals Hit</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-black text-foreground tracking-tighter">14/18</span>
|
||||
<span className="text-[10px] text-muted-foreground font-bold tracking-widest uppercase">Target: 16</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-primary/5 border border-primary/20 rounded-sm p-8 flex flex-col justify-center relative overflow-hidden group">
|
||||
<div className="absolute -right-4 -top-4 opacity-5 rotate-12"><Brain className="h-24 w-24 text-primary" /></div>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Brain className="h-4 w-4 text-primary" />
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">AI Coach</h3>
|
||||
</div>
|
||||
<p className="text-xs font-bold leading-relaxed text-foreground/80 italic">
|
||||
"Your 'Strategic Reading' is slipping. Consider linking it to your 'Morning Coffee' habit to increase completion by ~40%."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
|
||||
Add Routine Intervention
|
||||
</button>
|
||||
|
||||
{/* Main Habits Container */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-2 gap-8 pb-6">
|
||||
|
||||
{/* Habits Cards */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-muted-foreground">Active Disciplines</h3>
|
||||
<button className="text-[10px] font-bold text-muted-foreground hover:text-foreground flex items-center gap-2 uppercase tracking-widest"><Calendar className="h-3.5 w-3.5" /> Monthly View</button>
|
||||
</div>
|
||||
|
||||
{/* KPI Row */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Perfect Days This Month</h4>
|
||||
<div className="text-3xl font-bold text-foreground">8</div>
|
||||
</div>
|
||||
<Trophy className="h-10 w-10 text-emerald-500 opacity-20" />
|
||||
</div>
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Longest Active Streak</h4>
|
||||
<div className="text-3xl font-bold text-foreground">12 <span className="text-sm text-muted-foreground font-normal">days</span></div>
|
||||
</div>
|
||||
<Flame className="h-10 w-10 text-orange-500 opacity-20" />
|
||||
</div>
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5 flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Overall Completion Rate</h4>
|
||||
<div className="text-3xl font-bold text-foreground">68%</div>
|
||||
</div>
|
||||
<Target className="h-10 w-10 text-blue-500 opacity-20" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Habit Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 pb-6">
|
||||
{habits.map((habit) => (
|
||||
<div key={habit.id} className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col group hover:border-white/10 transition-colors relative overflow-hidden">
|
||||
|
||||
{/* Top Info */}
|
||||
<div className="flex justify-between items-start mb-6 z-10">
|
||||
<div>
|
||||
<h3 className="text-lg font-bold text-foreground mb-1">{habit.name}</h3>
|
||||
<div className="flex gap-2 items-center">
|
||||
<span className="text-[10px] uppercase tracking-wider font-bold px-2 py-0.5 rounded-sm bg-white/5 text-muted-foreground border border-white/5">{habit.category}</span>
|
||||
<span className="text-xs text-muted-foreground flex items-center gap-1">
|
||||
<Target className="h-3 w-3" /> {habit.goal}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-end">
|
||||
<span className="text-xs text-muted-foreground mb-0.5">Current Streak</span>
|
||||
<div className="flex items-center gap-1.5 font-bold" style={{ color: habit.streak > 0 ? habit.color : '#8F89A5' }}>
|
||||
<Flame className="h-4 w-4" /> {habit.streak}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Weekly Checkboxes */}
|
||||
<div className="flex justify-between items-center mb-6 z-10">
|
||||
{days.map((day, idx) => (
|
||||
<div key={idx} className="flex flex-col items-center gap-2">
|
||||
<span className="text-[10px] font-bold text-muted-foreground">{day}</span>
|
||||
<button
|
||||
className="w-8 h-8 rounded-sm flex items-center justify-center transition-all border"
|
||||
style={{
|
||||
backgroundColor: habit.status[idx] ? `${habit.color}20` : '#150F1D',
|
||||
borderColor: habit.status[idx] ? `${habit.color}50` : '#ffffff10',
|
||||
color: habit.status[idx] ? habit.color : '#ffffff20'
|
||||
}}
|
||||
<div className="space-y-4">
|
||||
{habits.map(habit => (
|
||||
<motion.div
|
||||
key={habit.id}
|
||||
whileHover={{ x: 4 }}
|
||||
onClick={() => setSelectedHabit(habit)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-6 flex flex-col gap-6 relative group overflow-hidden shadow-xl cursor-pointer hover:border-primary/30 transition-all"
|
||||
>
|
||||
{habit.status[idx] ? <Check className="h-4 w-4" /> : <X className="h-3 w-3" />}
|
||||
<div className="flex justify-between items-start relative z-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`p-3 rounded-sm ${habit.color}/10 text-foreground`}>
|
||||
<habit.icon className="h-6 w-6 text-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-black group-hover:text-primary transition-colors">{habit.name}</h3>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">{habit.frequency}</span>
|
||||
<div className="w-1 h-1 rounded-full bg-white/20" />
|
||||
<div className="flex items-center gap-1 text-[10px] font-black text-orange-500 uppercase tracking-widest">
|
||||
<Flame className="h-3 w-3" /> {habit.streak} DAY STREAK
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="text-right">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest mb-1">Completion</div>
|
||||
<div className="text-xl font-black">{habit.progress}%</div>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground p-3 rounded-sm shadow-xl shadow-primary/20 transition-all active:scale-90">
|
||||
<CheckCircle2 className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Micro Chart (Background styling) */}
|
||||
<div className="h-16 w-full mt-auto relative z-0 opacity-50 group-hover:opacity-100 transition-opacity">
|
||||
<div className="absolute top-0 left-0 text-[10px] text-muted-foreground uppercase tracking-widest font-bold flex items-center gap-1">
|
||||
<TrendingUp className="h-3 w-3" /> 30-Day Trend
|
||||
</div>
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={habit.trend.map((val, i) => ({ name: i, value: val }))}>
|
||||
<defs>
|
||||
<linearGradient id={`grad-${habit.id}`} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor={habit.color} stopOpacity={0.3}/>
|
||||
<stop offset="95%" stopColor={habit.color} stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Tooltip
|
||||
cursor={false}
|
||||
contentStyle={{ display: 'none' }}
|
||||
{/* Mini Heatmap Visualization */}
|
||||
<div className="grid grid-cols-15 gap-1.5 h-3">
|
||||
{Array.from({length: 15}).map((_, i) => {
|
||||
const isCompleted = habit.completedDays.includes(i + 1);
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`rounded-[2px] transition-all ${isCompleted ? habit.color + ' opacity-100 shadow-[0_0_8px_rgba(108,91,176,0.3)]' : 'bg-white/5 opacity-30 hover:opacity-50'}`}
|
||||
/>
|
||||
<Area type="monotone" dataKey="value" stroke={habit.color} strokeWidth={2} fillOpacity={1} fill={`url(#grad-${habit.id})`} />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Detailed Performance Analytics */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-muted-foreground">Strategic Insight</h3>
|
||||
<button className="text-[10px] font-bold text-muted-foreground hover:text-foreground uppercase tracking-widest">Full Reports</button>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col gap-8 h-fit shadow-2xl">
|
||||
<div>
|
||||
<h4 className="text-xs font-black uppercase tracking-widest text-primary mb-4">Weekly Success Rate</h4>
|
||||
<div className="flex items-end justify-between h-40 gap-4">
|
||||
{[45, 65, 30, 85, 95, 70, 80].map((h, i) => (
|
||||
<div key={i} className="flex-1 flex flex-col items-center gap-3 group/bar">
|
||||
<div className="w-full relative">
|
||||
<motion.div
|
||||
initial={{ height: 0 }}
|
||||
animate={{ height: `${h}%` }}
|
||||
transition={{ duration: 1, delay: i * 0.1 }}
|
||||
className={`w-full rounded-sm bg-primary/20 border-t-2 border-primary group-hover/bar:bg-primary/40 transition-all cursor-pointer`}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[8px] font-black text-muted-foreground uppercase tracking-widest">{["M", "T", "W", "T", "F", "S", "S"][i]}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-8 border-t border-white/5 space-y-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<TrendingUp className="h-5 w-5 text-emerald-500" />
|
||||
<div>
|
||||
<div className="text-xs font-black uppercase tracking-widest">Momentum Building</div>
|
||||
<p className="text-[10px] text-muted-foreground leading-relaxed mt-1">You've maintained a 90%+ completion rate for 4 consecutive days. This is a 12% improvement over last week's performance.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Activity className="h-5 w-5 text-primary" />
|
||||
<div>
|
||||
<div className="text-xs font-black uppercase tracking-widest">Peak Performance Hub</div>
|
||||
<p className="text-[10px] text-muted-foreground leading-relaxed mt-1">Deep Work completion correlates 85% with 7AM Gym sessions. Physical discipline is driving your strategic output.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Habit Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedHabit && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedHabit(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-xl bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col p-10 space-y-12">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className={`p-5 rounded-sm ${selectedHabit.color}/20 text-foreground`}>
|
||||
<selectedHabit.icon className="h-10 w-10" />
|
||||
</div>
|
||||
<button onClick={() => setSelectedHabit(null)} className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-7 w-7" /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-4xl font-black tracking-tighter">{selectedHabit.name}</h2>
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex items-center gap-2">
|
||||
<Flame className="h-4 w-4 text-orange-500" />
|
||||
<span className="text-lg font-black text-orange-500">{selectedHabit.streak} DAY STREAK</span>
|
||||
</div>
|
||||
<div className="text-xs font-black text-muted-foreground uppercase tracking-widest border-l border-white/10 pl-5">BEST STREAK: {selectedHabit.bestStreak} DAYS</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-8 pt-8 border-t border-white/5">
|
||||
<div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary mb-6">30-Day Activity Heatmap</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
{Array.from({length: 30}).map((_, i) => {
|
||||
const isCompleted = selectedHabit.completedDays.includes(i + 1);
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`aspect-square rounded-sm border ${isCompleted ? selectedHabit.color + ' border-transparent shadow-[0_0_12px_rgba(108,91,176,0.2)]' : 'bg-white/5 border-white/5 opacity-20'}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="p-6 rounded-sm bg-[#150F1D] border border-white/5 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">FREQUENCY</div>
|
||||
<div className="text-sm font-black text-foreground">{selectedHabit.frequency}</div>
|
||||
</div>
|
||||
<div className="p-6 rounded-sm bg-[#150F1D] border border-white/5 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">MONTHLY SUCCESS</div>
|
||||
<div className="text-sm font-black text-emerald-400">{selectedHabit.progress}%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 space-y-4">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-widest text-primary flex items-center gap-2">
|
||||
<Zap className="h-3.5 w-3.5" /> Performance Context
|
||||
</h3>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed italic">
|
||||
You've hit this habit {selectedHabit.completedDays.length} times this month. Strategic data suggests that completing this before 10 AM increases your daily task throughput by 12%.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-auto flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-4 rounded-sm text-[11px] font-black uppercase tracking-widest shadow-2xl shadow-primary/30 transition-all active:scale-[0.98]">
|
||||
MARK AS COMPLETED TODAY
|
||||
</button>
|
||||
<button className="p-4 border border-white/10 rounded-sm text-muted-foreground hover:bg-white/5 transition-colors">
|
||||
<BarChart3 className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,152 +1,294 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Search, Filter, Brain, PenTool, Calendar, AlignLeft, Tag, Lock, Sparkles, Image as ImageIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, Calendar, Clock, Brain, MessageSquare,
|
||||
Smile, Frown, Meh, Star, MoreHorizontal, X,
|
||||
Zap, Save, Trash2, Edit3, Image as ImageIcon, Link as LinkIcon,
|
||||
ChevronLeft, ChevronRight, Activity, Filter, AlignLeft, Hash
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const journalEntries = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Breakthrough in System Design",
|
||||
preview: "Today we finally cracked the database architecture. By moving to a distributed model...",
|
||||
date: "Today, 10:45 AM",
|
||||
tags: ["Work", "Idea", "Win"],
|
||||
sentiment: "Positive"
|
||||
date: "May 15, 2026",
|
||||
title: "Deep Work Breakthrough",
|
||||
excerpt: "Today I finally cracked the multi-tenant architecture logic for the Cognis core. Energy was high after the morning focus block.",
|
||||
sentiment: "Great",
|
||||
moodScore: 92,
|
||||
tags: ["Productivity", "Coding"],
|
||||
content: "The morning started with a 4-hour deep work block. I avoided all notifications and focused purely on the database schema. The multi-tenant logic is now solid. I feel a huge weight off my shoulders. Physical energy was 9/10 thanks to the 7am gym session."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Feeling a bit overwhelmed",
|
||||
preview: "The Q3 deadlines are approaching fast. I need to make sure I'm prioritizing...",
|
||||
date: "Yesterday",
|
||||
tags: ["Mental Health", "Vent"],
|
||||
sentiment: "Anxious"
|
||||
date: "May 14, 2026",
|
||||
title: "Project Risk Discussion",
|
||||
excerpt: "Met with Alex regarding the Infrastructure delays. Felt a bit anxious about the timeline but the AI risk report helped us focus.",
|
||||
sentiment: "Neutral",
|
||||
moodScore: 65,
|
||||
tags: ["Meeting", "Stress"],
|
||||
content: "Alex and I went through the infrastructure roadmap. We are indeed behind on the database migration. The stress is real, but we have a plan now. AI suggests prioritizing the migration scripts. Note for tomorrow: focus on script optimization."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Morning Routine Reflection",
|
||||
preview: "Woke up at 6 AM. Did 20 minutes of meditation. It really sets the tone for...",
|
||||
date: "May 06, 2026",
|
||||
tags: ["Habits", "Morning"],
|
||||
sentiment: "Calm"
|
||||
}
|
||||
{ id: 3, date: "May 12, 2026", title: "Creative Flow", excerpt: "Spent the afternoon in Figma. The new 'Cyber-Lavender' palette is looking stunning in the dark mode previews.", sentiment: "Great", moodScore: 88, tags: ["Design", "Creative"] },
|
||||
];
|
||||
|
||||
export default function JournalPage() {
|
||||
const [selectedEntry, setSelectedEntry] = useState<any>(null);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Personal</span> / Daily Journal
|
||||
<span className="text-foreground">Mindset</span> / Strategic Journal
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-primary">
|
||||
<Edit3 className="h-3 w-3" /> 128 ENTRIES RECORDED
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search memories..."
|
||||
placeholder="Search thoughts..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button
|
||||
onClick={() => setIsCreating(true)}
|
||||
className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW ENTRY
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Layout */}
|
||||
<div className="flex flex-col lg:flex-row gap-6 flex-1 min-h-0">
|
||||
<div className="flex-1 flex gap-8 min-h-0">
|
||||
|
||||
{/* Left Panel: Entry List & AI */}
|
||||
<div className="w-full lg:w-80 flex flex-col gap-6 shrink-0">
|
||||
|
||||
{/* AI Sentiment Analysis */}
|
||||
<div className="rounded-sm border border-primary/20 bg-[linear-gradient(135deg,rgba(108,91,176,0.1)_0%,rgba(10,7,16,0)_100%)] p-5">
|
||||
<h3 className="text-sm font-semibold text-primary mb-2 flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> AI Reflection Insight
|
||||
</h3>
|
||||
<p className="text-[11px] text-foreground/80 leading-relaxed mb-3">
|
||||
Over the last 14 days, your entries tagged with <strong>"Work"</strong> show a 30% increase in stress vocabulary. However, entries after <strong>Morning Meditation</strong> are consistently highly positive.
|
||||
</p>
|
||||
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-3 py-1.5 rounded-sm text-[10px] font-bold uppercase tracking-wider transition-colors w-full">
|
||||
Generate Weekly Summary
|
||||
{/* Left Sidebar: Entries List */}
|
||||
<div className="w-full max-w-sm flex flex-col gap-4 overflow-y-auto tiny-scrollbar pr-2">
|
||||
<div className="flex items-center justify-between px-2 mb-2">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground">Recent Reflections</h3>
|
||||
<button className="text-[10px] font-bold text-muted-foreground hover:text-foreground flex items-center gap-1">
|
||||
<Filter className="h-3 w-3" /> FILTER
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Entries List */}
|
||||
<div className="flex-1 rounded-sm border border-white/5 bg-[#0A0710] flex flex-col overflow-hidden">
|
||||
<div className="p-4 border-b border-white/5 flex justify-between items-center">
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Recent Entries</span>
|
||||
<Filter className="h-4 w-4 text-muted-foreground hover:text-foreground cursor-pointer" />
|
||||
<div className="space-y-4">
|
||||
{journalEntries.map(entry => (
|
||||
<motion.div
|
||||
key={entry.id}
|
||||
whileHover={{ x: 4 }}
|
||||
onClick={() => setSelectedEntry(entry)}
|
||||
className={`p-5 rounded-sm border cursor-pointer transition-all ${selectedEntry?.id === entry.id ? 'bg-[#1F172B] border-primary/40 shadow-xl' : 'bg-[#0A0710] border-white/5 hover:border-white/10'}`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">{entry.date}</span>
|
||||
<SentimentIcon sentiment={entry.sentiment} />
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar p-2 space-y-1">
|
||||
{journalEntries.map((entry, idx) => (
|
||||
<div key={entry.id} className={`p-3 rounded-sm cursor-pointer transition-colors ${idx === 0 ? 'bg-[#1F172B] border border-primary/30' : 'hover:bg-white/5 border border-transparent'}`}>
|
||||
<h4 className="text-sm font-semibold text-foreground mb-1 truncate">{entry.title}</h4>
|
||||
<p className="text-[11px] text-muted-foreground line-clamp-2 leading-relaxed mb-2">
|
||||
{entry.preview}
|
||||
</p>
|
||||
<div className="flex justify-between items-center text-[10px]">
|
||||
<span className="text-primary font-medium">{entry.date}</span>
|
||||
<span className="flex gap-1">
|
||||
<h3 className={`text-sm font-black mb-2 transition-colors ${selectedEntry?.id === entry.id ? 'text-primary' : 'text-foreground'}`}>{entry.title}</h3>
|
||||
<p className="text-[11px] text-muted-foreground leading-relaxed line-clamp-2 italic">"{entry.excerpt}"</p>
|
||||
<div className="flex gap-2 mt-4">
|
||||
{entry.tags.map(tag => (
|
||||
<span key={tag} className="bg-white/10 px-1.5 py-0.5 rounded-sm">{tag}</span>
|
||||
<span key={tag} className="text-[8px] font-black uppercase tracking-widest px-2 py-0.5 rounded-sm bg-white/5 text-muted-foreground">#{tag}</span>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Main Content: Entry Viewer/Editor */}
|
||||
<div className="flex-1 bg-[#0A0710] border border-white/5 rounded-sm flex flex-col relative overflow-hidden shadow-2xl">
|
||||
<AnimatePresence mode="wait">
|
||||
{selectedEntry ? (
|
||||
<motion.div
|
||||
key={selectedEntry.id}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
className="flex-1 flex flex-col"
|
||||
>
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/5">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">{selectedEntry.date}</span>
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-white/20" />
|
||||
<div className="flex items-center gap-1.5 text-[10px] font-black text-emerald-400">
|
||||
<Activity className="h-3 w-3" /> MOOD SCORE: {selectedEntry.moodScore}%
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="text-3xl font-black tracking-tighter text-foreground">{selectedEntry.title}</h2>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="p-2.5 hover:bg-white/5 rounded-sm text-muted-foreground transition-colors"><Edit3 className="h-5 w-5" /></button>
|
||||
<button className="p-2.5 hover:bg-white/5 rounded-sm text-rose-500 transition-colors"><Trash2 className="h-5 w-5" /></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 p-10 overflow-y-auto tiny-scrollbar space-y-12">
|
||||
|
||||
{/* AI Psychological Insight */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-8 space-y-4 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 opacity-5">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> Cognitive Analysis
|
||||
</h3>
|
||||
<p className="text-sm font-medium text-foreground/90 leading-relaxed italic">
|
||||
"I've noticed that your mood scores peak when you mention 'Deep Work' blocks in the morning. However, meeting-heavy days seem to correlate with anxious sentiment. Consider restructuring 'Infrastructure' discussions for early PM."
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Body Content */}
|
||||
<div className="space-y-6">
|
||||
<p className="text-lg text-foreground/90 leading-[1.8] font-medium tracking-tight">
|
||||
{selectedEntry.content || "No detailed content available for this entry."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Strategic Connections */}
|
||||
<div className="pt-10 border-t border-white/5 space-y-6">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Connected Strategics</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/30 transition-all">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-primary/10 rounded-sm"><Zap className="h-4 w-4 text-primary" /></div>
|
||||
<div>
|
||||
<div className="text-xs font-bold text-foreground">Goal: Scaling Backend</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1">Directly Referenced</div>
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground group-hover:text-primary transition-all" />
|
||||
</div>
|
||||
<div className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center justify-between group cursor-pointer hover:border-primary/30 transition-all">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-emerald-500/10 rounded-sm"><Clock className="h-4 w-4 text-emerald-500" /></div>
|
||||
<div>
|
||||
<div className="text-xs font-bold text-foreground">Habit: 7AM Gym</div>
|
||||
<div className="text-[9px] text-muted-foreground uppercase mt-1">Impact Observed</div>
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground group-hover:text-primary transition-all" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Panel: Editor Mock */}
|
||||
<div className="flex-1 rounded-sm border border-white/5 bg-[#0A0710] flex flex-col relative overflow-hidden group">
|
||||
|
||||
{/* Editor Header */}
|
||||
<div className="p-4 border-b border-white/5 flex justify-between items-center bg-[#0F0B15]/50">
|
||||
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5"><Calendar className="h-4 w-4" /> Today, 10:45 AM</span>
|
||||
<span className="flex items-center gap-1.5"><Tag className="h-4 w-4" /> 3 Tags</span>
|
||||
<span className="flex items-center gap-1.5"><Lock className="h-4 w-4" /> Private</span>
|
||||
<div className="p-8 border-t border-white/5 bg-[#0F0B15]/40 flex justify-between items-center">
|
||||
<div className="flex -space-x-2">
|
||||
{[1, 2, 3].map(i => <div key={i} className="h-8 w-8 rounded-full border-2 border-[#0A0710] bg-[#1F172B] flex items-center justify-center text-[10px] font-bold">A{i}</div>)}
|
||||
<div className="h-8 w-8 rounded-full border-2 border-[#0A0710] bg-primary/20 flex items-center justify-center text-[10px] font-bold text-primary">+2</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><AlignLeft className="h-4 w-4" /></button>
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><ImageIcon className="h-4 w-4" /></button>
|
||||
<button className="p-1.5 hover:bg-primary/20 bg-primary/10 rounded-sm text-primary transition-colors flex items-center gap-1">
|
||||
<Sparkles className="h-4 w-4" /> <span className="text-[10px] font-bold">Ask AI</span>
|
||||
<button className="text-[10px] font-black text-primary uppercase tracking-widest flex items-center gap-2 hover:bg-primary/10 px-4 py-2 rounded-sm transition-all">
|
||||
<MessageSquare className="h-4 w-4" /> 12 COMMENTS
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<div className="flex-1 flex flex-col items-center justify-center p-20 text-center space-y-6">
|
||||
<div className="p-6 bg-white/5 rounded-full">
|
||||
<AlignLeft className="h-12 w-12 text-muted-foreground/30" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-black uppercase tracking-widest text-muted-foreground">No Entry Selected</h2>
|
||||
<p className="text-sm text-muted-foreground mt-2 max-w-xs mx-auto italic">Select a reflection from the sidebar or create a new strategic entry to begin.</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsCreating(true)}
|
||||
className="bg-primary/10 text-primary border border-primary/20 px-6 py-2.5 rounded-sm text-xs font-black tracking-widest uppercase hover:bg-primary/20 transition-all"
|
||||
>
|
||||
Create Your First Entry
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Editor Body */}
|
||||
<div className="flex-1 p-8 md:px-12 md:py-10 overflow-y-auto tiny-scrollbar">
|
||||
<input
|
||||
type="text"
|
||||
value="Breakthrough in System Design"
|
||||
readOnly
|
||||
className="w-full bg-transparent border-none outline-none text-3xl font-bold text-foreground mb-6"
|
||||
{/* New Entry Modal */}
|
||||
<AnimatePresence>
|
||||
{isCreating && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setIsCreating(false)} className="fixed inset-0 bg-black/90 backdrop-blur-xl z-[100]" />
|
||||
<motion.div initial={{ scale: 0.95, opacity: 0, y: 20 }} animate={{ scale: 1, opacity: 1, y: 0 }} exit={{ scale: 0.95, opacity: 0, y: 20 }} className="fixed inset-0 m-auto w-full max-w-4xl h-[85vh] bg-[#0A0710] border border-white/10 z-[101] shadow-2xl flex flex-col rounded-sm overflow-hidden">
|
||||
<div className="p-8 border-b border-white/5 flex items-center justify-between bg-primary/10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-2.5 bg-primary rounded-sm shadow-xl shadow-primary/20"><Edit3 className="h-5 w-5 text-primary-foreground" /></div>
|
||||
<div>
|
||||
<h2 className="text-xl font-black uppercase tracking-tight">New Reflection</h2>
|
||||
<p className="text-[10px] font-black text-primary tracking-[0.3em] uppercase">Documenting Strategic Growth</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setIsCreating(false)} className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-7 w-7" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex flex-col p-10 space-y-8 overflow-y-auto tiny-scrollbar">
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em]">Title of Reflection</label>
|
||||
<input type="text" placeholder="e.g., Q3 Breakthrough or Team Alignment thoughts..." className="w-full bg-transparent border-none text-3xl font-black placeholder:text-muted-foreground/20 outline-none" />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-6 pb-6 border-b border-white/5">
|
||||
<div className="flex items-center gap-3 bg-white/5 px-4 py-2 rounded-sm border border-white/5">
|
||||
<Calendar className="h-4 w-4 text-primary" />
|
||||
<span className="text-xs font-bold">May 15, 2026</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">Sentiment:</span>
|
||||
<div className="flex gap-2">
|
||||
<button className="p-2 rounded-sm bg-white/5 hover:bg-emerald-500/20 hover:text-emerald-500 transition-all"><Smile className="h-5 w-5" /></button>
|
||||
<button className="p-2 rounded-sm bg-white/5 hover:bg-primary/20 hover:text-primary transition-all"><Meh className="h-5 w-5" /></button>
|
||||
<button className="p-2 rounded-sm bg-white/5 hover:bg-rose-500/20 hover:text-rose-500 transition-all"><Frown className="h-5 w-5" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-h-[300px]">
|
||||
<textarea
|
||||
placeholder="Write your strategic reflections here... Use # to link goals or tasks."
|
||||
className="w-full h-full bg-transparent border-none outline-none text-lg leading-relaxed text-foreground/80 resize-none placeholder:text-muted-foreground/10 font-medium"
|
||||
/>
|
||||
<div className="text-foreground/80 leading-loose space-y-6 text-sm">
|
||||
<p>
|
||||
Today we finally cracked the database architecture. By moving to a distributed model, we've essentially solved the latency issues we were seeing during peak load. It feels incredibly satisfying to see weeks of research finally click into place.
|
||||
</p>
|
||||
<p>
|
||||
I was discussing this with Alex earlier, and he pointed out that this structure directly mirrors the microservices split we planned for Q4. This means we are actually ahead of schedule!
|
||||
</p>
|
||||
<div className="pl-4 border-l-2 border-primary text-primary italic">
|
||||
AI Note: You've mentioned "latency issues" in 3 previous entries. Consider documenting this final solution in the Engineering Wiki for future reference.
|
||||
</div>
|
||||
<p>
|
||||
Gonna take the rest of the evening off to recharge. Need to keep this momentum going without burning out.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-4 pt-6 border-t border-white/5">
|
||||
<button className="p-2 text-muted-foreground hover:text-primary transition-colors"><ImageIcon className="h-5 w-5" /></button>
|
||||
<button className="p-2 text-muted-foreground hover:text-primary transition-colors"><LinkIcon className="h-5 w-5" /></button>
|
||||
<button className="p-2 text-muted-foreground hover:text-primary transition-colors"><Hash className="h-5 w-5" /></button>
|
||||
<div className="ml-auto flex items-center gap-2 text-[10px] font-black text-muted-foreground/50 uppercase tracking-widest">
|
||||
<Clock className="h-3 w-3" /> Auto-saving to Cloud...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 flex gap-6 bg-[#0F0B15]/60">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-[0.3em] shadow-2xl shadow-primary/40 transition-all active:scale-[0.98] flex items-center justify-center gap-3">
|
||||
<Save className="h-5 w-5" /> PUBLISH REFLECTION
|
||||
</button>
|
||||
<button onClick={() => setIsCreating(false)} className="px-10 border border-white/10 rounded-sm text-[11px] font-black uppercase tracking-[0.2em] text-muted-foreground hover:bg-white/5 transition-all">
|
||||
DISCARD
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SentimentIcon({ sentiment }: { sentiment: string }) {
|
||||
if (sentiment === "Great") return <Smile className="h-4 w-4 text-emerald-500" />;
|
||||
if (sentiment === "Neutral") return <Meh className="h-4 w-4 text-primary" />;
|
||||
return <Frown className="h-4 w-4 text-rose-500" />;
|
||||
}
|
||||
|
||||
+283
-112
@@ -1,57 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Search, Filter, Brain, AlertCircle, Clock, CheckCircle2, MoreHorizontal, Users, BarChart } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, MoreHorizontal, MessageSquare, Clock,
|
||||
CheckCircle2, AlertCircle, Layout, List, ArrowRight,
|
||||
TrendingUp, Users, Calendar, Activity, X, ChevronRight,
|
||||
Zap, Shield, Globe, Briefcase, Brain
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const projects = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Cognis Mobile App",
|
||||
status: "In Progress",
|
||||
progress: 65,
|
||||
dueDate: "May 28, 2026",
|
||||
team: ["JD", "AK", "LM"],
|
||||
aiRisk: "Low",
|
||||
aiSuggestion: "On track. Consistent velocity detected."
|
||||
name: "Marketing Site",
|
||||
description: "Main landing page and marketing funnel optimizations for the Q3 campaign.",
|
||||
progress: 75,
|
||||
members: 4,
|
||||
tasks: 24,
|
||||
deadline: "May 25",
|
||||
status: "Active",
|
||||
health: "Good",
|
||||
phases: [
|
||||
{ name: "Design", status: "Done", date: "Apr 15" },
|
||||
{ name: "Development", status: "In Progress", date: "May 10" },
|
||||
{ name: "QA", status: "Upcoming", date: "May 20" },
|
||||
],
|
||||
aiRisk: "Low risk. Team velocity is 12% higher than average. Content approval is the only potential bottleneck."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Q3 Marketing Site",
|
||||
status: "At Risk",
|
||||
progress: 32,
|
||||
dueDate: "Jun 15, 2026",
|
||||
team: ["RK", "ST"],
|
||||
aiRisk: "High",
|
||||
aiSuggestion: "Bottleneck detected in Design phase. Suggest assigning 1 more designer."
|
||||
name: "Infrastructure",
|
||||
description: "Database and cloud server optimizations to support scaling to 100k users.",
|
||||
progress: 45,
|
||||
members: 2,
|
||||
tasks: 12,
|
||||
deadline: "Jun 10",
|
||||
status: "Delayed",
|
||||
health: "At Risk",
|
||||
phases: [
|
||||
{ name: "Migration", status: "In Progress", date: "May 12" },
|
||||
{ name: "Load Testing", status: "Upcoming", date: "May 25" },
|
||||
{ name: "Live Deploy", status: "Upcoming", date: "Jun 05" },
|
||||
],
|
||||
aiRisk: "High risk. Lead developer is over-allocated. Database migration scripts need optimization for the large dataset."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Database Migration",
|
||||
status: "Review",
|
||||
progress: 90,
|
||||
dueDate: "May 20, 2026",
|
||||
team: ["JS", "AL", "BQ", "MK"],
|
||||
aiRisk: "Medium",
|
||||
aiSuggestion: "QA testing is taking 20% longer than historical average."
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "User Authentication V2",
|
||||
status: "To Do",
|
||||
progress: 0,
|
||||
dueDate: "Jul 01, 2026",
|
||||
team: ["AK", "LM"],
|
||||
aiRisk: "Low",
|
||||
aiSuggestion: "Dependencies cleared. Ready to start."
|
||||
}
|
||||
{ id: 3, name: "Cognis Mobile", description: "React Native application for iOS/Android including push notifications.", progress: 92, members: 6, tasks: 48, deadline: "May 18", status: "Active", health: "Excell.", phases: [], aiRisk: "" },
|
||||
{ id: 4, name: "Research", description: "User interview synthesis and competitor analysis for market expansion.", progress: 100, members: 3, tasks: 8, deadline: "May 05", status: "Completed", health: "Stable", phases: [], aiRisk: "" },
|
||||
{ id: 5, name: "API v2", description: "Restructuring the core API for scale and performance improvements.", progress: 30, members: 5, tasks: 32, deadline: "Jul 15", status: "Active", health: "Good", phases: [], aiRisk: "" },
|
||||
];
|
||||
|
||||
export default function ProjectsPage() {
|
||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
||||
const [selectedProject, setSelectedProject] = useState<any>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Management</span> / Projects
|
||||
</h1>
|
||||
@@ -64,103 +71,267 @@ export default function ProjectsPage() {
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Filter className="h-4 w-4" />
|
||||
</button>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-bold tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/20">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW PROJECT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Project Manager Insight */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex items-start gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Project Assistant
|
||||
<span className="bg-primary/20 text-primary text-[9px] uppercase px-1.5 py-0.5 rounded-sm">Active</span>
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed mb-3">
|
||||
I have analyzed your active projects. <strong>Q3 Marketing Site</strong> is showing a high risk of delay based on current commit velocity.
|
||||
I recommend redistributing tasks or extending the deadline by 4 days.
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground px-4 py-1.5 rounded-sm text-xs font-semibold transition-colors">
|
||||
Apply AI Reallocation
|
||||
</button>
|
||||
<button className="bg-transparent hover:bg-white/5 text-foreground border border-white/10 px-4 py-1.5 rounded-sm text-xs font-semibold transition-colors">
|
||||
View Detailed Analysis
|
||||
</button>
|
||||
{/* Analytics Overview Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 shrink-0">
|
||||
<ProjectStatCard label="Active Projects" value="4" subtext="+1 from last month" icon={Activity} />
|
||||
<ProjectStatCard label="Average Progress" value="68%" subtext="12% ahead of schedule" icon={TrendingUp} />
|
||||
<ProjectStatCard label="Total Members" value="15" subtext="Across 5 project teams" icon={Users} />
|
||||
</div>
|
||||
|
||||
{/* View Toggle */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 bg-[#150F1D] border border-white/5 rounded-sm p-0.5">
|
||||
<button onClick={() => setViewMode("grid")} className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'grid' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}><Layout className="h-3 w-3" /> Grid</button>
|
||||
<button onClick={() => setViewMode("list")} className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'list' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}><List className="h-3 w-3" /> List</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Project Cards Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{/* Projects Container */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar">
|
||||
{viewMode === "grid" ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
{projects.map((project) => (
|
||||
<div key={project.id} className="rounded-sm border border-white/5 bg-[#0A0710] flex flex-col group">
|
||||
{/* Card Header */}
|
||||
<div className="p-6 border-b border-white/5 flex justify-between items-start">
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<h2 className="text-base font-semibold">{project.name}</h2>
|
||||
<span className={`text-[10px] uppercase font-bold px-2 py-0.5 rounded-sm border ${
|
||||
project.status === 'In Progress' ? 'bg-blue-500/10 text-blue-400 border-blue-500/20' :
|
||||
project.status === 'At Risk' ? 'bg-red-500/10 text-red-400 border-red-500/20' :
|
||||
project.status === 'Review' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' :
|
||||
'bg-white/5 text-muted-foreground border-white/10'
|
||||
<motion.div
|
||||
key={project.id}
|
||||
whileHover={{ y: -4 }}
|
||||
onClick={() => setSelectedProject(project)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-6 flex flex-col gap-6 relative group overflow-hidden shadow-2xl cursor-pointer hover:border-primary/30 transition-all"
|
||||
>
|
||||
<div className={`absolute top-0 right-0 w-32 h-32 translate-x-16 -translate-y-16 opacity-10 blur-3xl rounded-full ${project.status === 'Delayed' ? 'bg-rose-500' : 'bg-primary'}`} />
|
||||
|
||||
<div className="flex justify-between items-start relative z-10">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-lg font-black truncate group-hover:text-primary transition-colors">{project.name}</h3>
|
||||
<p className="text-xs text-muted-foreground mt-1 line-clamp-1">{project.description}</p>
|
||||
</div>
|
||||
<button className="p-1.5 hover:bg-white/5 rounded-sm transition-colors text-muted-foreground"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between text-[10px] font-bold">
|
||||
<span className="text-muted-foreground uppercase tracking-widest">Global Progress</span>
|
||||
<span>{project.progress}%</span>
|
||||
</div>
|
||||
<div className="h-1 w-full bg-white/5 rounded-full overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${project.progress}%` }}
|
||||
transition={{ duration: 1, ease: "easeOut" }}
|
||||
className={`h-full rounded-full ${project.progress === 100 ? 'bg-emerald-500' : project.status === 'Delayed' ? 'bg-rose-500' : 'bg-primary shadow-[0_0_12px_rgba(108,91,176,0.6)]'}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="p-1.5 bg-white/5 rounded-sm">
|
||||
<Calendar className="h-3 w-3 text-muted-foreground" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-muted-foreground">{project.deadline}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<div className="flex -space-x-2">
|
||||
{[1, 2, 3].map(i => (
|
||||
<div key={i} className="h-5 w-5 rounded-full border border-[#0A0710] bg-[#1F172B] flex items-center justify-center text-[8px] font-bold">U{i}</div>
|
||||
))}
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-muted-foreground ml-1">{project.members} Team</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 border-t border-white/5 flex items-center justify-between">
|
||||
<span className={`text-[9px] font-black uppercase tracking-[0.2em] px-2 py-1 rounded-sm border ${
|
||||
project.health === 'Good' ? 'text-blue-400 border-blue-500/20 bg-blue-500/5' :
|
||||
project.health === 'Excell.' ? 'text-emerald-400 border-emerald-500/20 bg-emerald-500/5' :
|
||||
project.health === 'At Risk' ? 'text-rose-400 border-rose-500/20 bg-rose-500/5' : 'text-muted-foreground border-white/10'
|
||||
}`}>
|
||||
{project.status}
|
||||
{project.health}
|
||||
</span>
|
||||
<button className="text-[9px] font-black uppercase tracking-widest flex items-center gap-1 text-primary group/btn">
|
||||
VIEW DETAILS <ArrowRight className="h-3 w-3 group-hover/btn:translate-x-1 transition-transform" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm overflow-hidden">
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
|
||||
<div className="col-span-4">Project Name</div>
|
||||
<div className="col-span-2">Health Status</div>
|
||||
<div className="col-span-3">Progress Metrics</div>
|
||||
<div className="col-span-2">Final Deadline</div>
|
||||
<div className="col-span-1"></div>
|
||||
</div>
|
||||
<div className="divide-y divide-white/5">
|
||||
{projects.map(project => (
|
||||
<div key={project.id} onClick={() => setSelectedProject(project)} className="grid grid-cols-12 gap-4 p-5 items-center hover:bg-white/[0.02] transition-colors group cursor-pointer">
|
||||
<div className="col-span-4">
|
||||
<div className="text-sm font-black group-hover:text-primary transition-colors">{project.name}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-0.5 tracking-wider">{project.tasks} Active Deliverables</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<span className={`text-[9px] font-black uppercase tracking-widest px-2 py-1 rounded-sm border ${
|
||||
project.health === 'Good' ? 'text-blue-400 border-blue-500/20 bg-blue-500/5' :
|
||||
project.health === 'Excell.' ? 'text-emerald-400 border-emerald-500/20 bg-emerald-500/5' : 'text-rose-400 border-rose-500/20 bg-rose-500/5'
|
||||
}`}>
|
||||
{project.health}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||
<div className="flex items-center gap-1.5"><Clock className="h-3.5 w-3.5" /> Due {project.dueDate}</div>
|
||||
<div className="flex items-center gap-1.5"><Users className="h-3.5 w-3.5" /> {project.team.length} Members</div>
|
||||
</div>
|
||||
</div>
|
||||
<button className="text-muted-foreground hover:text-foreground opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<MoreHorizontal className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* AI Risk & Suggestion */}
|
||||
<div className="p-4 bg-[#150F1D]/50 border-b border-white/5 flex gap-3 items-start">
|
||||
{project.aiRisk === "High" ? <AlertCircle className="h-4 w-4 text-red-400 mt-0.5 shrink-0" /> :
|
||||
project.aiRisk === "Medium" ? <BarChart className="h-4 w-4 text-orange-400 mt-0.5 shrink-0" /> :
|
||||
<CheckCircle2 className="h-4 w-4 text-emerald-400 mt-0.5 shrink-0" />}
|
||||
<div>
|
||||
<div className="text-[10px] font-bold uppercase tracking-wider mb-0.5 flex items-center gap-1.5">
|
||||
<Brain className="h-3 w-3" />
|
||||
AI Risk: <span className={
|
||||
project.aiRisk === 'High' ? 'text-red-400' :
|
||||
project.aiRisk === 'Medium' ? 'text-orange-400' : 'text-emerald-400'
|
||||
}>{project.aiRisk}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">{project.aiSuggestion}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress & Actions */}
|
||||
<div className="p-6 mt-auto">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-xs font-medium">Progress</span>
|
||||
<span className="text-xs font-bold text-primary">{project.progress}%</span>
|
||||
<div className="col-span-3 pr-12">
|
||||
<div className="flex justify-between text-[10px] font-bold mb-2">
|
||||
<span className="text-muted-foreground">{project.progress}% Complete</span>
|
||||
</div>
|
||||
<div className="h-1.5 w-full bg-white/5 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-primary rounded-full transition-all duration-1000"
|
||||
style={{ width: `${project.progress}%` }}
|
||||
></div>
|
||||
<div className={`h-full rounded-full ${project.progress === 100 ? 'bg-emerald-500' : 'bg-primary'}`} style={{ width: `${project.progress}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 text-xs font-bold text-muted-foreground uppercase">{project.deadline}</div>
|
||||
<div className="col-span-1 flex justify-end">
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Project Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedProject && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedProject(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-2xl bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col">
|
||||
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={`text-[10px] font-black uppercase tracking-widest px-2 py-1 rounded-sm border ${
|
||||
selectedProject.health === 'Good' ? 'text-blue-400 border-blue-500/20' :
|
||||
selectedProject.health === 'Excell.' ? 'text-emerald-400 border-emerald-500/20' : 'text-rose-400 border-rose-500/20'
|
||||
}`}>
|
||||
{selectedProject.health} Health
|
||||
</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">Due: {selectedProject.deadline}</span>
|
||||
</div>
|
||||
<h2 className="text-3xl font-black tracking-tighter text-foreground">{selectedProject.name}</h2>
|
||||
</div>
|
||||
<button onClick={() => setSelectedProject(null)} className="p-3 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-6 w-6" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-10 space-y-12 tiny-scrollbar">
|
||||
|
||||
{/* Description & KPI */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div className="md:col-span-2 space-y-4">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Overview</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">{selectedProject.description}</p>
|
||||
</div>
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm p-6 flex flex-col items-center justify-center text-center">
|
||||
<div className="text-4xl font-black text-primary mb-1">{selectedProject.progress}%</div>
|
||||
<div className="text-[9px] font-bold text-muted-foreground uppercase tracking-widest">Global Progress</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Risk Intelligence */}
|
||||
{selectedProject.aiRisk && (
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 space-y-3 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 opacity-5">
|
||||
<Brain className="h-20 w-20 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-3.5 w-3.5" /> AI Risk Assessment
|
||||
</h3>
|
||||
<p className="text-xs font-medium text-foreground/90 leading-relaxed italic">
|
||||
"{selectedProject.aiRisk}"
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Timeline / Phases */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Project Roadmap</h3>
|
||||
<div className="relative space-y-8 pl-6 before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-px before:bg-white/10">
|
||||
{selectedProject.phases?.map((phase: any, i: number) => (
|
||||
<div key={i} className="relative group">
|
||||
<div className={`absolute -left-[23px] top-1 h-3 w-3 rounded-full border-2 border-[#0A0710] z-10 ${
|
||||
phase.status === 'Done' ? 'bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]' :
|
||||
phase.status === 'In Progress' ? 'bg-primary shadow-[0_0_8px_rgba(108,91,176,0.5)]' : 'bg-white/10'
|
||||
}`} />
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="text-sm font-bold group-hover:text-primary transition-colors">{phase.name}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1 uppercase font-medium">{phase.date} • {phase.status}</div>
|
||||
</div>
|
||||
{phase.status === 'Done' && <CheckCircle2 className="h-4 w-4 text-emerald-500" />}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Team & Resources */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Team Allocation</h3>
|
||||
<button className="text-[10px] font-bold text-muted-foreground hover:text-foreground">MANAGE TEAM</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{[1, 2, 3, 4].slice(0, selectedProject.members).map(i => (
|
||||
<div key={i} className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center gap-3">
|
||||
<div className="h-10 w-10 rounded-sm bg-primary/10 border border-primary/20 flex items-center justify-center font-black text-primary text-xs">U{i}</div>
|
||||
<div>
|
||||
<div className="text-xs font-bold text-foreground">Project Member {i}</div>
|
||||
<div className="text-[10px] text-muted-foreground uppercase tracking-widest mt-1">Strategic Lead</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 bg-[#0F0B15]/50 flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-4 rounded-sm text-[11px] font-black uppercase tracking-widest shadow-xl shadow-primary/30 transition-all active:scale-[0.98]">
|
||||
LAUNCH PROJECT CONSOLE
|
||||
</button>
|
||||
<button className="p-4 border border-white/10 rounded-sm text-muted-foreground hover:bg-white/5 transition-colors">
|
||||
<Activity className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ProjectStatCard({ label, value, subtext, icon: Icon }: any) {
|
||||
return (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex items-center gap-6 group relative overflow-hidden shadow-xl">
|
||||
<div className="absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity">
|
||||
<Icon className="h-20 w-20 text-foreground" />
|
||||
</div>
|
||||
<div className="p-4 bg-white/5 rounded-sm group-hover:bg-primary/10 transition-colors relative z-10">
|
||||
<Icon className="h-6 w-6 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
</div>
|
||||
<div className="relative z-10">
|
||||
<div className="text-[10px] font-black uppercase tracking-[0.2em] text-muted-foreground mb-1">{label}</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-black text-foreground tracking-tighter">{value}</span>
|
||||
<span className="text-[10px] text-emerald-500 font-bold uppercase tracking-widest">{subtext}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, FileText, FileCheck, Clock, Shield,
|
||||
MoreHorizontal, Download, Share2, Eye, Brain,
|
||||
ChevronRight, ArrowRight, X, CheckCircle2,
|
||||
AlertCircle, DollarSign, PenTool, Send, Layout, List
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const proposals = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Enterprise AI Integration",
|
||||
client: "Acme Corp",
|
||||
value: "$42,000",
|
||||
status: "Sent",
|
||||
date: "May 15",
|
||||
health: "Warm",
|
||||
aiInsight: "92% probability of closing based on recent meeting sentiment analysis.",
|
||||
details: "Full stack AI integration including LLM deployment and custom data pipelines."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Cloud Infrastructure Audit",
|
||||
client: "Global Tech",
|
||||
value: "$12,500",
|
||||
status: "Negotiation",
|
||||
date: "May 12",
|
||||
health: "Critical",
|
||||
aiInsight: "Client is questioning the pricing on Clause 4.2. Suggesting a 5% bundle discount.",
|
||||
details: "Security audit and scalability roadmap for the AWS infrastructure."
|
||||
},
|
||||
{ id: 3, title: "Design System Revamp", client: "Nexus Design", value: "$8,200", status: "Signed", date: "May 08", health: "Secure", aiInsight: "", details: "" },
|
||||
{ id: 4, title: "Mobile App Retainer", client: "Stark Ind.", value: "$5,000/mo", status: "Draft", date: "May 20", health: "Lead", aiInsight: "", details: "" },
|
||||
];
|
||||
|
||||
export default function ProposalsPage() {
|
||||
const [selectedProposal, setSelectedProposal] = useState<any>(null);
|
||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Business</span> / Proposals & Contracts
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-primary bg-primary/5 px-3 py-1 rounded-sm border border-primary/10">
|
||||
<FileCheck className="h-3 w-3" /> 8 SIGNED CONTRACTS
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm px-3 py-1.5 flex items-center gap-2">
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search proposals..."
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-5 py-2 rounded-sm text-xs font-black tracking-widest flex items-center gap-2 transition-all shadow-lg shadow-primary/30 active:scale-95">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW PROPOSAL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lifecycle Status Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 shrink-0">
|
||||
<StatusCard label="Drafts" count={2} color="text-muted-foreground" icon={PenTool} />
|
||||
<StatusCard label="Out for Review" count={3} color="text-blue-500" icon={Send} />
|
||||
<StatusCard label="Negotiation" count={1} color="text-orange-500" icon={Clock} />
|
||||
<StatusCard label="Active Contracts" count={8} color="text-emerald-500" icon={Shield} />
|
||||
</div>
|
||||
|
||||
{/* Main Container */}
|
||||
<div className="flex-1 flex flex-col gap-6 overflow-hidden">
|
||||
|
||||
<div className="flex items-center justify-between shrink-0">
|
||||
<div className="flex items-center gap-2 bg-[#150F1D] border border-white/5 rounded-sm p-0.5">
|
||||
<button onClick={() => setViewMode("grid")} className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'grid' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}><Layout className="h-3 w-3" /> Grid</button>
|
||||
<button onClick={() => setViewMode("list")} className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'list' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}><List className="h-3 w-3" /> List</button>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-[10px] font-black uppercase tracking-widest text-muted-foreground">
|
||||
<span>Sort by: Latest</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar pr-1">
|
||||
{viewMode === "grid" ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8 pb-6">
|
||||
{proposals.map((prop) => (
|
||||
<motion.div
|
||||
key={prop.id}
|
||||
whileHover={{ y: -4 }}
|
||||
onClick={() => setSelectedProposal(prop)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col gap-8 relative group overflow-hidden shadow-2xl cursor-pointer hover:border-primary/30 transition-all"
|
||||
>
|
||||
<div className={`absolute top-0 right-0 w-32 h-32 translate-x-16 -translate-y-16 opacity-5 blur-3xl rounded-full ${prop.status === 'Signed' ? 'bg-emerald-500' : 'bg-primary'}`} />
|
||||
|
||||
<div className="flex justify-between items-start relative z-10">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={`text-[9px] font-black uppercase tracking-widest px-2 py-0.5 rounded-sm border ${
|
||||
prop.status === 'Signed' ? 'text-emerald-400 border-emerald-500/20 bg-emerald-500/5' :
|
||||
prop.status === 'Negotiation' ? 'text-orange-400 border-orange-500/20 bg-orange-500/5' : 'text-blue-400 border-blue-500/20 bg-blue-500/5'
|
||||
}`}>
|
||||
{prop.status}
|
||||
</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{prop.client}</span>
|
||||
</div>
|
||||
<h3 className="text-xl font-black tracking-tighter group-hover:text-primary transition-colors">{prop.title}</h3>
|
||||
</div>
|
||||
<FileText className="h-6 w-6 text-muted-foreground/30 group-hover:text-primary/50 transition-colors" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 relative z-10">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">Contract Value</div>
|
||||
<div className="text-2xl font-black text-foreground">{prop.value}</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t border-white/5 flex items-center justify-between relative z-10">
|
||||
<div className="flex items-center gap-2">
|
||||
<Clock className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">Updated {prop.date}</span>
|
||||
</div>
|
||||
<div className={`text-[9px] font-black uppercase tracking-widest flex items-center gap-1 ${
|
||||
prop.health === 'Secure' ? 'text-emerald-400' : prop.health === 'Critical' ? 'text-rose-400' : 'text-primary'
|
||||
}`}>
|
||||
{prop.health} PULSE
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm overflow-hidden shadow-2xl">
|
||||
<div className="grid grid-cols-12 gap-4 p-5 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground">
|
||||
<div className="col-span-4 px-2">Document Title</div>
|
||||
<div className="col-span-2">Client</div>
|
||||
<div className="col-span-2">Lifecycle</div>
|
||||
<div className="col-span-2">Value</div>
|
||||
<div className="col-span-2 text-right">Actions</div>
|
||||
</div>
|
||||
<div className="divide-y divide-white/5">
|
||||
{proposals.map(prop => (
|
||||
<div key={prop.id} onClick={() => setSelectedProposal(prop)} className="grid grid-cols-12 gap-4 p-6 items-center hover:bg-white/[0.02] transition-all group cursor-pointer">
|
||||
<div className="col-span-4 flex items-center gap-4">
|
||||
<div className="h-8 w-8 rounded-sm bg-white/5 flex items-center justify-center"><FileText className="h-4 w-4 text-muted-foreground" /></div>
|
||||
<span className="text-sm font-black group-hover:text-primary transition-colors">{prop.title}</span>
|
||||
</div>
|
||||
<div className="col-span-2 text-xs font-bold text-muted-foreground uppercase">{prop.client}</div>
|
||||
<div className="col-span-2">
|
||||
<span className={`text-[9px] font-black uppercase tracking-widest px-2 py-0.5 rounded-sm border ${prop.status === 'Signed' ? 'text-emerald-400 border-emerald-500/20' : 'text-primary border-primary/20'}`}>
|
||||
{prop.status}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-2 text-sm font-black text-foreground">{prop.value}</div>
|
||||
<div className="col-span-2 flex justify-end opacity-0 group-hover:opacity-100 transition-all">
|
||||
<button className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Proposal Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedProposal && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedProposal(null)} className="fixed inset-0 bg-black/80 backdrop-blur-md z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-2xl bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col">
|
||||
|
||||
<div className="p-10 border-b border-white/5 flex items-center justify-between bg-primary/5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-primary border border-primary/20 px-2 py-0.5 rounded-sm">{selectedProposal.status}</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{selectedProposal.client}</span>
|
||||
</div>
|
||||
<h2 className="text-3xl font-black tracking-tighter text-foreground">{selectedProposal.title}</h2>
|
||||
</div>
|
||||
<button onClick={() => setSelectedProposal(null)} className="p-3 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><X className="h-6 w-6" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-10 space-y-12 tiny-scrollbar">
|
||||
|
||||
{/* AI Closing Probability */}
|
||||
{selectedProposal.aiInsight && (
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-8 space-y-4 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 opacity-5">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary flex items-center gap-2">
|
||||
<Brain className="h-4 w-4" /> AI Strategic Analysis
|
||||
</h3>
|
||||
<p className="text-sm font-medium text-foreground/90 leading-relaxed italic">
|
||||
"{selectedProposal.aiInsight}"
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Key Details */}
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm p-6 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">CONTRACT VALUE</div>
|
||||
<div className="text-2xl font-black text-primary">{selectedProposal.value}</div>
|
||||
</div>
|
||||
<div className="bg-[#150F1D] border border-white/5 rounded-sm p-6 space-y-2">
|
||||
<div className="text-[10px] font-black text-muted-foreground uppercase tracking-widest">RELATIONSHIP HEALTH</div>
|
||||
<div className="text-2xl font-black text-foreground">{selectedProposal.health}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lifecycle Roadmap */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Engagement History</h3>
|
||||
<div className="relative space-y-8 pl-6 before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-px before:bg-white/10">
|
||||
<HistoryItem title="Proposal Draft Created" date="May 10" status="Done" />
|
||||
<HistoryItem title="Initial Review with Client" date="May 12" status="Done" />
|
||||
<HistoryItem title="Current State: Negotiation" date="Now" status="Active" />
|
||||
<HistoryItem title="Pending: Final Approval" date="TBD" status="Upcoming" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="space-y-6 pt-6 border-t border-white/5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Contractual Controls</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<ControlBtn icon={Download} label="Export PDF" />
|
||||
<ControlBtn icon={Share2} label="Secure Share" />
|
||||
<ControlBtn icon={Eye} label="Client Preview" />
|
||||
<ControlBtn icon={Shield} label="Verify Sig." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="p-10 border-t border-white/5 bg-[#0F0B15]/50 flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-5 rounded-sm text-[11px] font-black uppercase tracking-widest shadow-2xl shadow-primary/30 transition-all active:scale-[0.98] flex items-center justify-center gap-3">
|
||||
<Send className="h-5 w-5" /> SEND REVISED PROPOSAL
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function HistoryItem({ title, date, status }: any) {
|
||||
return (
|
||||
<div className="relative group">
|
||||
<div className={`absolute -left-[23px] top-1 h-3 w-3 rounded-full border-2 border-[#0A0710] z-10 ${
|
||||
status === 'Done' ? 'bg-emerald-500' : status === 'Active' ? 'bg-primary' : 'bg-white/10'
|
||||
}`} />
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="text-sm font-bold group-hover:text-primary transition-colors">{title}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-1 uppercase font-medium">{date}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ControlBtn({ icon: Icon, label }: any) {
|
||||
return (
|
||||
<button className="p-4 rounded-sm bg-[#150F1D] border border-white/5 flex items-center gap-3 group hover:border-primary/20 transition-all">
|
||||
<Icon className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||
<span className="text-[10px] font-black text-muted-foreground uppercase tracking-widest group-hover:text-foreground">{label}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function StatusCard({ label, count, color, icon: Icon }: any) {
|
||||
return (
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-6 flex items-center justify-between group hover:border-white/10 transition-all shadow-xl">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`p-3 bg-white/5 rounded-sm ${color} transition-colors group-hover:bg-white/10`}>
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-0.5">{label}</div>
|
||||
<div className="text-xl font-black">{count}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground/30" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+198
-119
@@ -1,67 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Search, Filter, Brain, CheckSquare2, Clock, AlertCircle, MoreHorizontal, MessageSquare, ArrowUpRight, CheckCircle2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Plus, Search, Filter, Brain, CheckSquare2, Clock, AlertCircle,
|
||||
MoreHorizontal, MessageSquare, ArrowUpRight, CheckCircle2,
|
||||
GripVertical, List, Layout, X, Calendar, User, Tag
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence, Reorder } from "framer-motion";
|
||||
|
||||
// Mock Data
|
||||
const tasks = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Finalize Q3 Marketing Assets",
|
||||
project: "Marketing Site",
|
||||
priority: "High",
|
||||
status: "In Progress",
|
||||
assignee: "Sarah J.",
|
||||
aiPredict: "2 days",
|
||||
dueDate: "May 15"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Database Migration Script",
|
||||
project: "Infrastructure",
|
||||
priority: "Critical",
|
||||
status: "Review",
|
||||
assignee: "Alex R.",
|
||||
aiPredict: "4 hours",
|
||||
dueDate: "May 12"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Design System Tokens",
|
||||
project: "Cognis Mobile",
|
||||
priority: "Medium",
|
||||
status: "To Do",
|
||||
assignee: "Mike C.",
|
||||
aiPredict: "3 days",
|
||||
dueDate: "May 20"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Client Interview Synthesis",
|
||||
project: "Research",
|
||||
priority: "Low",
|
||||
status: "Done",
|
||||
assignee: "Emma W.",
|
||||
aiPredict: "Completed",
|
||||
dueDate: "May 08"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Optimize Webpack Config",
|
||||
project: "Infrastructure",
|
||||
priority: "Medium",
|
||||
status: "To Do",
|
||||
assignee: "Alex R.",
|
||||
aiPredict: "1 day",
|
||||
dueDate: "May 18"
|
||||
}
|
||||
const initialTasks = [
|
||||
{ id: "1", title: "Finalize Q3 Marketing Assets", project: "Marketing Site", priority: "High", status: "In Progress", assignee: "Sarah J.", aiPredict: "2 days", dueDate: "May 15" },
|
||||
{ id: "2", title: "Database Migration Script", project: "Infrastructure", priority: "Critical", status: "Review", assignee: "Alex R.", aiPredict: "4 hours", dueDate: "May 12" },
|
||||
{ id: "3", title: "Design System Tokens", project: "Cognis Mobile", priority: "Medium", status: "To Do", assignee: "Mike C.", aiPredict: "3 days", dueDate: "May 20" },
|
||||
{ id: "4", title: "Client Interview Synthesis", project: "Research", priority: "Low", status: "Done", assignee: "Emma W.", aiPredict: "Completed", dueDate: "May 08" },
|
||||
{ id: "5", title: "Optimize Webpack Config", project: "Infrastructure", priority: "Medium", status: "To Do", assignee: "Alex R.", aiPredict: "1 day", dueDate: "May 18" }
|
||||
];
|
||||
|
||||
const columns = ["To Do", "In Progress", "Review", "Done"];
|
||||
|
||||
export default function TasksPage() {
|
||||
const [viewMode, setViewMode] = useState<"list" | "kanban">("list");
|
||||
const [tasks, setTasks] = useState(initialTasks);
|
||||
const [isSorting, setIsSorting] = useState(false);
|
||||
const [selectedTask, setSelectedTask] = useState<any>(null);
|
||||
|
||||
const handleAutoSort = () => {
|
||||
setIsSorting(true);
|
||||
setTimeout(() => {
|
||||
const sorted = [...tasks].sort((a, b) => {
|
||||
const priorityOrder: any = { Critical: 0, High: 1, Medium: 2, Low: 3 };
|
||||
return priorityOrder[a.priority] - priorityOrder[b.priority];
|
||||
});
|
||||
setTasks(sorted);
|
||||
setIsSorting(false);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6">
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Management</span> / Tasks
|
||||
</h1>
|
||||
@@ -74,128 +54,227 @@ export default function TasksPage() {
|
||||
className="bg-transparent border-none outline-none text-xs w-48 placeholder:text-muted-foreground/50 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-3 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Filter className="h-4 w-4" />
|
||||
FILTER
|
||||
</button>
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<button className="bg-primary hover:bg-primary/90 text-primary-foreground border border-primary/20 px-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-all active:scale-95 shadow-lg shadow-primary/20">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW TASK
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Task Prioritization */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-6">
|
||||
{/* AI Task Prioritization Card */}
|
||||
<div className="rounded-sm border border-primary/20 bg-primary/5 p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-6 relative overflow-hidden group">
|
||||
<div className="absolute -right-4 -bottom-4 opacity-5 rotate-12 transition-transform group-hover:scale-110">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-3 bg-primary/10 rounded-sm shrink-0">
|
||||
<Brain className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Task Prioritization
|
||||
AI Priority Engine
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-2xl">
|
||||
Based on the upcoming <strong>Infrastructure</strong> deadlines and <strong>Alex R.</strong>'s historical velocity, AI strongly suggests starting the <em>Database Migration Script</em> immediately. It has a high risk of cascading delays.
|
||||
Based on deadlines and team velocity, I've identified 3 tasks that need immediate focus. Auto-sort will reorder your backlog for maximum strategic impact.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="bg-primary/20 text-primary hover:bg-primary/30 border border-primary/30 px-4 py-2 rounded-sm text-xs font-semibold transition-colors shrink-0">
|
||||
Auto-Sort Backlog
|
||||
<button
|
||||
onClick={handleAutoSort}
|
||||
disabled={isSorting}
|
||||
className={`min-w-[140px] px-4 py-2 rounded-sm text-xs font-bold uppercase tracking-widest transition-all shadow-lg ${isSorting ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-primary/10 text-primary border border-primary/30 hover:bg-primary/20'}`}
|
||||
>
|
||||
{isSorting ? "SORTING..." : "AUTO-SORT BACKLOG"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Task List Header */}
|
||||
<div className="flex items-center justify-between mt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<button className="px-3 py-1.5 text-xs font-medium rounded-sm bg-[#2B2538] text-foreground shadow-sm">List View</button>
|
||||
<button className="px-3 py-1.5 text-xs font-medium rounded-sm text-muted-foreground hover:text-foreground transition-colors">Kanban Board</button>
|
||||
{/* View Toggle */}
|
||||
<div className="flex items-center justify-between shrink-0">
|
||||
<div className="flex items-center gap-2 bg-[#150F1D] border border-white/5 rounded-sm p-0.5">
|
||||
<button
|
||||
onClick={() => setViewMode("list")}
|
||||
className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'list' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
<List className="h-3 w-3" /> List View
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setViewMode("kanban")}
|
||||
className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-widest rounded-sm transition-all flex items-center gap-2 ${viewMode === 'kanban' ? 'bg-[#2B2538] text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
<Layout className="h-3 w-3" /> Kanban Board
|
||||
</button>
|
||||
</div>
|
||||
<div className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
|
||||
{tasks.length} Active Tasks
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground font-medium">12 Active Tasks</div>
|
||||
</div>
|
||||
|
||||
{/* Tasks Table */}
|
||||
<div className="bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden flex-1">
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex-1 min-h-0 overflow-hidden">
|
||||
{viewMode === "list" ? (
|
||||
<div className="bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden flex flex-col h-full">
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-white/5 bg-[#0F0B15]/50 text-[10px] font-bold uppercase tracking-widest text-muted-foreground shrink-0">
|
||||
<div className="col-span-5">Task Details</div>
|
||||
<div className="col-span-2">Status</div>
|
||||
<div className="col-span-2">Assignee</div>
|
||||
<div className="col-span-2">AI Time Estimate</div>
|
||||
<div className="col-span-2">AI Time Est.</div>
|
||||
<div className="col-span-1 text-right">Actions</div>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-white/5">
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar">
|
||||
<Reorder.Group axis="y" values={tasks} onReorder={setTasks} className="divide-y divide-white/5">
|
||||
{tasks.map((task) => (
|
||||
<div key={task.id} className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors group">
|
||||
|
||||
{/* Task Details */}
|
||||
<Reorder.Item
|
||||
key={task.id}
|
||||
value={task}
|
||||
onClick={() => setSelectedTask(task)}
|
||||
className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors group cursor-pointer"
|
||||
>
|
||||
<div className="col-span-5 flex items-start gap-3">
|
||||
<button className="mt-0.5 text-muted-foreground hover:text-primary transition-colors">
|
||||
{task.status === "Done" ? <CheckCircle2 className="h-4 w-4 text-emerald-400" /> : <CheckSquare2 className="h-4 w-4" />}
|
||||
</button>
|
||||
<div>
|
||||
<div className={`text-sm font-medium mb-1 ${task.status === 'Done' ? 'text-muted-foreground line-through' : 'text-foreground'}`}>
|
||||
<GripVertical className="h-4 w-4 text-muted-foreground/30 mt-1 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className={`text-sm font-medium mb-1 truncate ${task.status === 'Done' ? 'text-muted-foreground line-through' : 'text-foreground'}`}>
|
||||
{task.title}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[10px] text-muted-foreground font-medium bg-[#150F1D] px-2 py-0.5 rounded-sm border border-white/5">
|
||||
{task.project}
|
||||
</span>
|
||||
<span className={`text-[10px] uppercase font-bold tracking-wider flex items-center gap-1 ${
|
||||
task.priority === 'Critical' ? 'text-red-400' :
|
||||
task.priority === 'High' ? 'text-orange-400' :
|
||||
task.priority === 'Medium' ? 'text-blue-400' : 'text-muted-foreground'
|
||||
}`}>
|
||||
{task.priority === 'Critical' && <AlertCircle className="h-3 w-3" />}
|
||||
<span className="text-[10px] text-muted-foreground font-bold bg-[#150F1D] px-2 py-0.5 rounded-sm border border-white/5">{task.project}</span>
|
||||
<span className={`text-[10px] uppercase font-black tracking-widest flex items-center gap-1 ${task.priority === 'Critical' ? 'text-red-400' : task.priority === 'High' ? 'text-orange-400' : 'text-blue-400'}`}>
|
||||
{task.priority}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status */}
|
||||
<div className="col-span-2">
|
||||
<span className={`text-[10px] uppercase font-bold px-2 py-1 rounded-sm border inline-block ${
|
||||
task.status === 'In Progress' ? 'bg-blue-500/10 text-blue-400 border-blue-500/20' :
|
||||
task.status === 'Review' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' :
|
||||
task.status === 'Done' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' :
|
||||
'bg-white/5 text-muted-foreground border-white/10'
|
||||
}`}>
|
||||
<span className={`text-[9px] uppercase font-black px-2 py-1 rounded-sm border inline-block tracking-widest ${task.status === 'In Progress' ? 'bg-blue-500/10 text-blue-400 border-blue-500/20' : task.status === 'Review' ? 'bg-orange-500/10 text-orange-400 border-orange-500/20' : task.status === 'Done' ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20' : 'bg-white/5 text-muted-foreground border-white/10'}`}>
|
||||
{task.status}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Assignee */}
|
||||
<div className="col-span-2 flex items-center gap-2">
|
||||
<div className="h-6 w-6 rounded-sm bg-[#1F172B] border border-white/10 flex items-center justify-center text-[10px] font-bold text-primary">
|
||||
{task.assignee.split(' ')[0][0]}{task.assignee.split(' ')[1][0]}
|
||||
<div className="h-6 w-6 rounded-sm bg-[#1F172B] border border-primary/20 flex items-center justify-center text-[10px] font-black text-primary uppercase">
|
||||
{task.assignee.split(' ').map(n => n[0]).join('')}
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground">{task.assignee}</span>
|
||||
<span className="text-xs text-muted-foreground truncate">{task.assignee}</span>
|
||||
</div>
|
||||
|
||||
{/* AI Estimate */}
|
||||
<div className="col-span-2 flex items-center gap-2">
|
||||
{task.status !== 'Done' && <Clock className="h-3.5 w-3.5 text-primary" />}
|
||||
<span className={`text-xs ${task.status === 'Done' ? 'text-emerald-400 font-medium' : 'text-muted-foreground'}`}>
|
||||
{task.aiPredict}
|
||||
<Clock className="h-3.5 w-3.5 text-primary opacity-50" />
|
||||
<span className="text-xs text-muted-foreground">{task.aiPredict}</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex justify-end gap-1">
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground transition-colors"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</Reorder.Item>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-4 gap-6 h-full overflow-x-auto pb-4 tiny-scrollbar">
|
||||
{columns.map((col) => (
|
||||
<div key={col} className="flex flex-col gap-4 min-w-[280px]">
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-muted-foreground">{col}</h3>
|
||||
<span className="text-[10px] font-bold bg-white/5 px-2 py-0.5 rounded-sm">{tasks.filter(t => t.status === col).length}</span>
|
||||
</div>
|
||||
<div className="flex-1 bg-white/[0.02] border border-white/5 rounded-sm p-3 space-y-3 overflow-y-auto tiny-scrollbar">
|
||||
{tasks.filter(t => t.status === col).map(task => (
|
||||
<motion.div
|
||||
key={task.id}
|
||||
layoutId={task.id}
|
||||
onClick={() => setSelectedTask(task)}
|
||||
className="bg-[#0A0710] border border-white/5 rounded-sm p-4 hover:border-primary/30 transition-all cursor-pointer group shadow-xl"
|
||||
>
|
||||
<div className="text-xs font-bold mb-3 group-hover:text-primary transition-colors leading-relaxed">{task.title}</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={`text-[8px] font-black uppercase tracking-widest px-1.5 py-0.5 rounded-sm border ${task.priority === 'Critical' ? 'bg-red-500/10 text-red-400 border-red-500/20' : 'bg-white/5 text-muted-foreground border-white/10'}`}>
|
||||
{task.priority}
|
||||
</span>
|
||||
<div className="h-5 w-5 rounded-sm bg-[#1F172B] border border-white/10 flex items-center justify-center text-[8px] font-black text-primary">
|
||||
{task.assignee.split(' ').map(n => n[0]).join('')}
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="col-span-1 flex justify-end gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground hover:text-foreground transition-colors">
|
||||
<MessageSquare className="h-4 w-4" />
|
||||
</button>
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground hover:text-foreground transition-colors">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
<button className="w-full py-2 border border-dashed border-white/10 rounded-sm text-[10px] font-bold text-muted-foreground hover:bg-white/5 hover:border-white/20 transition-all">
|
||||
+ ADD TASK
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Task Detail Sheet */}
|
||||
<AnimatePresence>
|
||||
{selectedTask && (
|
||||
<>
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={() => setSelectedTask(null)} className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100]" />
|
||||
<motion.div initial={{ x: "100%" }} animate={{ x: 0 }} exit={{ x: "100%" }} transition={{ type: "spring", damping: 25, stiffness: 200 }} className="fixed top-0 right-0 h-full w-full max-w-lg bg-[#0A0710] border-l border-white/5 z-[101] shadow-2xl flex flex-col">
|
||||
<div className="p-8 border-b border-white/5 flex items-center justify-between bg-[#0F0B15]/50">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest bg-primary/20 text-primary px-2 py-0.5 rounded-sm">{selectedTask.project}</span>
|
||||
<span className="text-[10px] font-bold text-muted-foreground">ID: #TSK-{selectedTask.id}</span>
|
||||
</div>
|
||||
<h2 className="text-xl font-black tracking-tight">{selectedTask.title}</h2>
|
||||
</div>
|
||||
<button onClick={() => setSelectedTask(null)} className="p-2 hover:bg-white/5 rounded-sm text-muted-foreground transition-colors"><X className="h-5 w-5" /></button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-8 space-y-10 tiny-scrollbar">
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<DetailItem label="ASSIGNEE" icon={User} value={selectedTask.assignee} />
|
||||
<DetailItem label="DUE DATE" icon={Calendar} value={selectedTask.dueDate} />
|
||||
<DetailItem label="PRIORITY" icon={AlertCircle} value={selectedTask.priority} />
|
||||
<DetailItem label="AI ESTIMATE" icon={Brain} value={selectedTask.aiPredict} color="text-primary" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Description</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
This task is part of the strategic {selectedTask.project} roadmap. Please ensure all design tokens are verified against the core Cognis design system before final review.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 pt-8 border-t border-white/5">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Subtasks</h3>
|
||||
<div className="space-y-2">
|
||||
{[1, 2, 3].map(i => (
|
||||
<div key={i} className="flex items-center gap-3 p-3 rounded-sm bg-[#150F1D] border border-white/5 hover:border-white/10 transition-colors">
|
||||
<div className="w-4 h-4 rounded-sm border border-white/20 flex items-center justify-center cursor-pointer hover:border-primary transition-colors">
|
||||
<CheckSquare2 className="h-3 w-3 text-transparent hover:text-muted-foreground transition-colors" />
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground">Verification step {i} for the migration script.</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-8 border-t border-white/5 bg-[#0F0B15]/50 flex gap-4">
|
||||
<button className="flex-1 bg-primary hover:bg-primary/90 text-primary-foreground py-3 rounded-sm text-[10px] font-black uppercase tracking-widest shadow-lg shadow-primary/20 transition-all active:scale-[0.98]">
|
||||
MARK AS DONE
|
||||
</button>
|
||||
<button className="p-3 border border-white/10 rounded-sm text-muted-foreground hover:bg-white/5 transition-colors">
|
||||
<MessageSquare className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DetailItem({ label, icon: Icon, value, color = "text-muted-foreground" }: any) {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground/50">{label}</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon className={`h-4 w-4 ${color}`} />
|
||||
<span className={`text-sm font-bold ${color === 'text-primary' ? 'text-primary' : 'text-foreground'}`}>{value}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Play, Pause, Square, Plus, Search, Clock,
|
||||
BarChart3, Calendar, MoreHorizontal, X,
|
||||
CheckCircle2, AlertCircle, Brain, Zap,
|
||||
TrendingUp, Activity, Briefcase, User
|
||||
} from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import {
|
||||
ResponsiveContainer, PieChart, Pie, Cell, Tooltip,
|
||||
BarChart, Bar, XAxis, YAxis, CartesianGrid
|
||||
} from "recharts";
|
||||
|
||||
// Mock Data
|
||||
const todayTimeData = [
|
||||
{ name: "Deep Work", value: 240, color: "#6C5BB0" },
|
||||
{ name: "Meetings", value: 90, color: "#a798e8" },
|
||||
{ name: "Learning", value: 45, color: "#10b981" },
|
||||
{ name: "Admin", value: 30, color: "#3b82f6" },
|
||||
];
|
||||
|
||||
const weeklyTimeData = [
|
||||
{ day: "Mon", hours: 8.5 },
|
||||
{ day: "Tue", hours: 7.2 },
|
||||
{ day: "Wed", hours: 9.0 },
|
||||
{ day: "Thu", hours: 6.5 },
|
||||
{ day: "Fri", hours: 8.0 },
|
||||
{ day: "Sat", hours: 2.5 },
|
||||
{ day: "Sun", hours: 0 },
|
||||
];
|
||||
|
||||
const recentLogs = [
|
||||
{ id: 1, task: "Database Migration Script", project: "Infrastructure", duration: "2h 15m", date: "Today, 10:30 AM", type: "Deep Work" },
|
||||
{ id: 2, task: "UI Review & Polish", project: "Marketing Site", duration: "1h 45m", date: "Today, 02:00 PM", type: "Creative" },
|
||||
{ id: 3, task: "Client Strategy Sync", project: "Acme Corp", duration: "1h 00m", date: "Yesterday", type: "Meeting" },
|
||||
{ id: 4, task: "Security Audit", project: "Infrastructure", duration: "3h 30m", date: "Yesterday", type: "Deep Work" },
|
||||
];
|
||||
|
||||
export default function TimeTrackingPage() {
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const [seconds, setSeconds] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let interval: any = null;
|
||||
if (isActive) {
|
||||
interval = setInterval(() => {
|
||||
setSeconds((seconds) => seconds + 1);
|
||||
}, 1000);
|
||||
} else if (!isActive && seconds !== 0) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
return () => clearInterval(interval);
|
||||
}, [isActive, seconds]);
|
||||
|
||||
const formatTime = (totalSeconds: number) => {
|
||||
const h = Math.floor(totalSeconds / 3600);
|
||||
const m = Math.floor((totalSeconds % 3600) / 60);
|
||||
const s = totalSeconds % 60;
|
||||
return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl animate-in fade-in slide-in-from-bottom-4 duration-500 h-full flex flex-col text-foreground font-sans space-y-6 pb-12 relative">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4 shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Performance</span> / Time Intelligence
|
||||
</h1>
|
||||
<div className="h-4 w-px bg-white/10" />
|
||||
<div className="flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-primary bg-primary/5 px-3 py-1 rounded-sm border border-primary/10">
|
||||
<Clock className="h-3 w-3" /> 38.5 HOURS LOGGED THIS WEEK
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<button className="bg-[#150F1D] hover:bg-white/5 text-foreground border border-white/10 px-4 py-1.5 rounded-sm text-xs font-bold tracking-widest flex items-center gap-2 transition-all">
|
||||
<Plus className="h-4 w-4" />
|
||||
MANUAL LOG
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content Grid */}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-8 flex-1 min-h-0">
|
||||
|
||||
{/* Left: Active Timer & Recent Logs */}
|
||||
<div className="xl:col-span-2 flex flex-col gap-8 overflow-hidden">
|
||||
|
||||
{/* Active Timer Attraction */}
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-10 flex flex-col items-center justify-center relative overflow-hidden shadow-2xl group">
|
||||
<div className={`absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(108,91,176,0.05),transparent)] transition-opacity ${isActive ? 'opacity-100' : 'opacity-0'}`} />
|
||||
|
||||
<div className="flex flex-col items-center gap-8 relative z-10 w-full max-w-md">
|
||||
<div className="text-center space-y-2">
|
||||
<div className="text-[10px] font-black uppercase tracking-[0.4em] text-primary animate-pulse">Current Focus Block</div>
|
||||
<h2 className="text-6xl font-black tracking-tighter tabular-nums text-foreground">{formatTime(seconds)}</h2>
|
||||
</div>
|
||||
|
||||
<div className="w-full space-y-4">
|
||||
<div className="flex items-center gap-4 bg-[#150F1D] border border-white/10 rounded-sm px-6 py-4">
|
||||
<div className="p-2 bg-primary/10 rounded-sm"><Briefcase className="h-4 w-4 text-primary" /></div>
|
||||
<div className="flex-1">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">Project</div>
|
||||
<div className="text-sm font-bold">Marketing Site Redesign</div>
|
||||
</div>
|
||||
<div className="h-8 w-px bg-white/5" />
|
||||
<div className="flex-1 text-right">
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground">Task</div>
|
||||
<div className="text-sm font-bold truncate">UI Audit & Review</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
onClick={() => setIsActive(!isActive)}
|
||||
className={`flex-1 flex items-center justify-center gap-3 py-4 rounded-sm text-sm font-black uppercase tracking-widest transition-all shadow-xl ${isActive ? 'bg-orange-500/10 text-orange-500 border border-orange-500/20' : 'bg-primary text-primary-foreground shadow-primary/20'}`}
|
||||
>
|
||||
{isActive ? <><Pause className="h-5 w-5" /> PAUSE TIMER</> : <><Play className="h-5 w-5" /> START FOCUS</>}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {setIsActive(false); setSeconds(0);}}
|
||||
className="px-8 bg-white/5 border border-white/10 text-muted-foreground hover:bg-white/10 transition-all rounded-sm"
|
||||
>
|
||||
<Square className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Recent Logs Table */}
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm flex-1 flex flex-col overflow-hidden shadow-2xl">
|
||||
<div className="p-6 border-b border-white/5 bg-[#0F0B15]/40 flex justify-between items-center">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground">Today's Activity Ledger</h3>
|
||||
<button className="text-[10px] font-bold text-primary uppercase tracking-widest">Full History</button>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar">
|
||||
<div className="divide-y divide-white/5">
|
||||
{recentLogs.map(log => (
|
||||
<div key={log.id} className="grid grid-cols-12 gap-4 p-5 items-center hover:bg-white/[0.02] transition-all group">
|
||||
<div className="col-span-5 flex items-center gap-4">
|
||||
<div className="h-10 w-10 rounded-sm bg-white/5 flex items-center justify-center"><Clock className="h-5 w-5 text-muted-foreground group-hover:text-primary transition-colors" /></div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-black truncate">{log.task}</div>
|
||||
<div className="text-[9px] text-muted-foreground font-bold uppercase tracking-widest mt-1">{log.project} • {log.type}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-3 text-xs font-black text-muted-foreground uppercase">{log.date}</div>
|
||||
<div className="col-span-2 text-sm font-black text-foreground">{log.duration}</div>
|
||||
<div className="col-span-2 flex justify-end gap-1 opacity-0 group-hover:opacity-100 transition-all">
|
||||
<button className="p-2 hover:bg-white/10 rounded-sm text-muted-foreground"><MoreHorizontal className="h-4 w-4" /></button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: Analytics & AI */}
|
||||
<div className="flex flex-col gap-8">
|
||||
|
||||
{/* Daily Distribution Chart */}
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col shadow-2xl">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground mb-8">Daily Distribution</h3>
|
||||
<div className="h-48 w-full flex items-center justify-center">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={todayTimeData}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
innerRadius={50}
|
||||
outerRadius={80}
|
||||
paddingAngle={4}
|
||||
dataKey="value"
|
||||
stroke="none"
|
||||
>
|
||||
{todayTimeData.map((entry, index) => (
|
||||
<Cell key={index} fill={entry.color} />
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip contentStyle={{ backgroundColor: "#150F1D", border: "none" }} />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<div className="mt-8 space-y-3">
|
||||
{todayTimeData.map(item => (
|
||||
<div key={item.name} className="flex justify-between items-center text-[10px] font-black uppercase tracking-widest">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
<span className="text-muted-foreground">{item.name}</span>
|
||||
</div>
|
||||
<span>{Math.floor(item.value / 60)}h {item.value % 60}m</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Productivity Pulse */}
|
||||
<div className="bg-primary/5 border border-primary/20 rounded-sm p-8 flex flex-col gap-6 relative overflow-hidden group">
|
||||
<div className="absolute -right-4 -top-4 opacity-5 rotate-12 transition-transform group-hover:scale-110">
|
||||
<Brain className="h-24 w-24 text-primary" />
|
||||
</div>
|
||||
<div className="space-y-4 relative z-10">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-primary/20 rounded-sm shadow-inner"><Brain className="h-4 w-4 text-primary" /></div>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">Focus Analysis</h3>
|
||||
</div>
|
||||
<p className="text-sm font-bold leading-relaxed text-foreground/90 italic">
|
||||
"Your deep work output is highest between 9:00 AM and 11:30 AM. Weekly burnout risk is Low (12%). Strategic momentum is positive."
|
||||
</p>
|
||||
</div>
|
||||
<button className="text-[10px] font-black text-primary uppercase tracking-widest flex items-center gap-2 group/btn border-b border-primary/20 pb-1 self-start hover:border-primary transition-all">
|
||||
VIEW BURN RATE <ArrowRight className="h-3 w-3 group-hover/btn:translate-x-1 transition-transform" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Weekly Summary Stat */}
|
||||
<div className="bg-[#0A0710] border border-white/5 rounded-sm p-8 flex flex-col gap-6 shadow-2xl">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-muted-foreground">Weekly Performance</h3>
|
||||
<div className="h-32 w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data={weeklyTimeData}>
|
||||
<Bar dataKey="hours" fill="#6C5BB0" radius={[2, 2, 0, 0]} />
|
||||
<Tooltip cursor={{ fill: '#ffffff05' }} contentStyle={{ backgroundColor: "#150F1D", border: "none" }} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<div className="flex justify-between items-end">
|
||||
<div>
|
||||
<div className="text-[10px] font-black uppercase tracking-widest text-muted-foreground mb-1">Average / Day</div>
|
||||
<div className="text-2xl font-black">7.4h</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-emerald-500 flex items-center gap-1 text-[10px] font-black uppercase tracking-widest">
|
||||
<TrendingUp className="h-3 w-3" /> +12% VS LAST WEEK
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user