feat: implement freelance dashboard pages for time tracking, client CRM, and proposals
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Search, Filter, Brain, Building2, Mail, Phone, MoreHorizontal, ShieldCheck, AlertCircle, ArrowUpRight } from "lucide-react";
|
||||
|
||||
// Mock Data
|
||||
const clients = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Acme Corp",
|
||||
contact: "Alice Johnson",
|
||||
email: "alice@acme.co",
|
||||
status: "Active",
|
||||
ltv: "$45,000",
|
||||
activeProjects: 2,
|
||||
aiSentiment: "Excellent",
|
||||
aiInsight: "Client engagement is at an all-time high. AI suggests pitching the Q4 Marketing Retainer this week."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Globex Industries",
|
||||
contact: "Mark Smith",
|
||||
email: "msmith@globex.com",
|
||||
status: "At Risk",
|
||||
ltv: "$12,500",
|
||||
activeProjects: 1,
|
||||
aiSentiment: "Frustrated",
|
||||
aiInsight: "Sentiment analysis on recent emails indicates frustration with turnaround times. Schedule a sync ASAP."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Soylent Corp",
|
||||
contact: "John Doe",
|
||||
email: "john.d@soylent.net",
|
||||
status: "Onboarding",
|
||||
ltv: "$0",
|
||||
activeProjects: 1,
|
||||
aiSentiment: "Neutral",
|
||||
aiInsight: "Awaiting signed NDA. Send an automated reminder tomorrow at 10 AM."
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Initech",
|
||||
contact: "Bill Lumbergh",
|
||||
email: "bill@initech.com",
|
||||
status: "Active",
|
||||
ltv: "$110,000",
|
||||
activeProjects: 3,
|
||||
aiSentiment: "Good",
|
||||
aiInsight: "Consistent payment history. No immediate actions required."
|
||||
}
|
||||
];
|
||||
|
||||
export default function ClientsCRMPage() {
|
||||
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">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Freelance</span> / Clients CRM
|
||||
</h1>
|
||||
<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-4 py-1.5 rounded-sm text-xs font-semibold flex items-center gap-2 transition-colors">
|
||||
<Plus className="h-4 w-4" />
|
||||
NEW CLIENT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI CRM Intelligence */}
|
||||
<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" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Client Intelligence
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
|
||||
You have a high probability (85%) of closing an upsell with <strong>Acme Corp</strong> this month. Their usage of the current product has doubled. Shall I draft a customized proposal highlighting scale benefits?
|
||||
</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">
|
||||
Draft Proposal Draft
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* KPI Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5">
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Total Active Clients</h4>
|
||||
<div className="text-3xl font-bold text-foreground">14</div>
|
||||
</div>
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5">
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Pipeline LTV</h4>
|
||||
<div className="flex items-end gap-2">
|
||||
<div className="text-3xl font-bold text-foreground">$167k</div>
|
||||
<span className="text-xs text-emerald-500 font-medium mb-1.5 flex items-center"><ArrowUpRight className="h-3 w-3" /> +12%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-5">
|
||||
<h4 className="text-[10px] uppercase tracking-wider text-muted-foreground font-bold mb-1">Average Client Health</h4>
|
||||
<div className="flex items-end gap-2">
|
||||
<div className="text-3xl font-bold text-emerald-400">92/100</div>
|
||||
<span className="text-xs text-muted-foreground font-medium mb-1.5">Excellent</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Clients List */}
|
||||
<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="col-span-3">Client</div>
|
||||
<div className="col-span-2">Status / LTV</div>
|
||||
<div className="col-span-6">AI Relationship Insight</div>
|
||||
<div className="col-span-1 text-right">Actions</div>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-white/5">
|
||||
{clients.map((client) => (
|
||||
<div key={client.id} className="grid grid-cols-12 gap-4 p-4 items-center hover:bg-white/[0.02] transition-colors group">
|
||||
|
||||
{/* Client Details */}
|
||||
<div className="col-span-3 flex items-start gap-3">
|
||||
<div className="h-8 w-8 rounded-sm bg-[#1F172B] border border-white/10 flex items-center justify-center text-primary mt-0.5 shrink-0">
|
||||
<Building2 className="h-4 w-4" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-bold text-foreground hover:text-primary cursor-pointer transition-colors mb-0.5">
|
||||
{client.name}
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground flex items-center gap-2">
|
||||
<span>{client.contact}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status / LTV */}
|
||||
<div className="col-span-2 flex flex-col items-start gap-1">
|
||||
<span className={`text-[10px] uppercase font-bold px-2 py-0.5 rounded-sm border inline-block ${
|
||||
client.status === 'Active' ? 'bg-blue-500/10 text-blue-400 border-blue-500/20' :
|
||||
client.status === 'At Risk' ? 'bg-red-500/10 text-red-400 border-red-500/20' :
|
||||
'bg-orange-500/10 text-orange-400 border-orange-500/20'
|
||||
}`}>
|
||||
{client.status}
|
||||
</span>
|
||||
<span className="text-xs font-semibold text-foreground pl-1">{client.ltv} <span className="text-[10px] text-muted-foreground font-normal">LTV</span></span>
|
||||
</div>
|
||||
|
||||
{/* AI Insight */}
|
||||
<div className="col-span-6 flex items-start gap-3 bg-[#150F1D]/50 border border-white/5 p-2 rounded-sm relative overflow-hidden">
|
||||
<div className={`absolute left-0 top-0 bottom-0 w-0.5 ${
|
||||
client.aiSentiment === 'Excellent' || client.aiSentiment === 'Good' ? 'bg-emerald-500' :
|
||||
client.aiSentiment === 'Frustrated' ? 'bg-red-500' : 'bg-orange-500'
|
||||
}`}></div>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-1.5 mb-1">
|
||||
<Brain className="h-3 w-3 text-primary" />
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-wider">
|
||||
Sentiment: <span className={
|
||||
client.aiSentiment === 'Excellent' || client.aiSentiment === 'Good' ? 'text-emerald-400' :
|
||||
client.aiSentiment === 'Frustrated' ? 'text-red-400' : 'text-orange-400'
|
||||
}>{client.aiSentiment}</span>
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-[11px] text-foreground/70 leading-snug">
|
||||
{client.aiInsight}
|
||||
</p>
|
||||
</div>
|
||||
</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">
|
||||
<Mail 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" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Brain, FileText, CheckCircle2, Clock, AlertCircle, Eye, PenTool } from "lucide-react";
|
||||
|
||||
// Mock Data
|
||||
const columns = [
|
||||
{
|
||||
title: "Drafting",
|
||||
color: "text-muted-foreground",
|
||||
items: [
|
||||
{ id: 1, client: "Stark Industries", title: "Enterprise Dashboard Redesign", value: "$18,500", date: "May 25", status: "Draft" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "In Review",
|
||||
color: "text-blue-400",
|
||||
items: [
|
||||
{ id: 2, client: "Wayne Enterprises", title: "Mobile App V2 Contract", value: "$32,000", date: "May 10", status: "Review" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Sent / Negotiating",
|
||||
color: "text-orange-400",
|
||||
items: [
|
||||
{ id: 3, client: "Acme Corp", title: "Q3 Marketing Retainer", value: "$4,500/mo", date: "May 05", status: "Sent" },
|
||||
{ id: 4, client: "Globex", title: "SEO Audit Proposal", value: "$2,800", date: "May 02", status: "Viewed 3x" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Signed / Won",
|
||||
color: "text-emerald-400",
|
||||
items: [
|
||||
{ id: 5, client: "Soylent Corp", title: "Brand Identity Guidelines", value: "$15,000", date: "Apr 28", status: "Signed" }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export default function ProposalsPage() {
|
||||
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">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Freelance</span> / Proposals & Contracts
|
||||
</h1>
|
||||
<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">
|
||||
<Plus className="h-4 w-4" />
|
||||
CREATE PROPOSAL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Conversion 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>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary mb-1 flex items-center gap-2">
|
||||
AI Conversion Optimizer
|
||||
</h3>
|
||||
<p className="text-xs text-foreground/80 leading-relaxed max-w-3xl">
|
||||
Globex has viewed the "SEO Audit Proposal" 3 times in the last 24 hours. AI indicates high intent. Additionally, historical data shows proposals sent with an <em>interactive pricing table</em> have an 85% higher win rate in your niche.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 shrink-0">
|
||||
<button className="bg-[#150F1D] text-foreground border border-white/10 px-4 py-2 rounded-sm text-xs font-semibold transition-colors">
|
||||
Follow up Globex
|
||||
</button>
|
||||
<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">
|
||||
Apply Interactive Table Template
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Kanban Board */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 flex-1 min-h-0 pb-6">
|
||||
{columns.map((col, idx) => (
|
||||
<div key={idx} className="flex flex-col bg-white/[0.01] rounded-sm border border-white/5 p-4 overflow-hidden">
|
||||
{/* Column Header */}
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className={`text-xs font-bold uppercase tracking-wider ${col.color}`}>{col.title}</h3>
|
||||
<span className="text-[10px] font-bold bg-[#150F1D] px-2 py-0.5 rounded-sm border border-white/5">{col.items.length}</span>
|
||||
</div>
|
||||
|
||||
{/* Column Cards */}
|
||||
<div className="flex-1 overflow-y-auto tiny-scrollbar space-y-3">
|
||||
{col.items.map((item) => (
|
||||
<div key={item.id} className="bg-[#0A0710] border border-white/5 hover:border-primary/50 transition-colors rounded-sm p-4 cursor-pointer group">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-wider">{item.client}</span>
|
||||
<FileText className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
</div>
|
||||
<h4 className="text-sm font-semibold text-foreground mb-3 leading-tight group-hover:text-primary transition-colors">{item.title}</h4>
|
||||
|
||||
<div className="flex justify-between items-end">
|
||||
<span className="text-lg font-bold">{item.value}</span>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<span className={`text-[10px] flex items-center gap-1 ${
|
||||
item.status === 'Signed' ? 'text-emerald-400' :
|
||||
item.status.includes('Viewed') ? 'text-orange-400' : 'text-muted-foreground'
|
||||
}`}>
|
||||
{item.status === 'Signed' ? <CheckCircle2 className="h-3 w-3" /> :
|
||||
item.status.includes('Viewed') ? <Eye className="h-3 w-3" /> :
|
||||
<Clock className="h-3 w-3" />}
|
||||
{item.status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
"use client";
|
||||
|
||||
import { Play, Pause, Brain, Clock, Plus, Tag, ArrowUpRight, DollarSign, Activity } from "lucide-react";
|
||||
import { Area, AreaChart, ResponsiveContainer, XAxis, Tooltip, CartesianGrid } from "recharts";
|
||||
|
||||
// Mock Data
|
||||
const timeData = [
|
||||
{ day: "Mon", billable: 5, nonBillable: 1 },
|
||||
{ day: "Tue", billable: 6.5, nonBillable: 0.5 },
|
||||
{ day: "Wed", billable: 4, nonBillable: 2 },
|
||||
{ day: "Thu", billable: 7, nonBillable: 1 },
|
||||
{ day: "Fri", billable: 5.5, nonBillable: 1.5 },
|
||||
];
|
||||
|
||||
const timeLogs = [
|
||||
{ id: 1, task: "Database Schema Design", project: "Stark Enterprise App", duration: "02:45:00", date: "Today", billable: true },
|
||||
{ id: 2, client: "Acme Corp", task: "Weekly Sync & Planning", project: "Retainer", duration: "01:00:00", date: "Today", billable: true },
|
||||
{ id: 3, task: "Invoice Generation & Emails", project: "Admin", duration: "00:45:00", date: "Yesterday", billable: false },
|
||||
{ id: 4, task: "Frontend Component Refactor", project: "Stark Enterprise App", duration: "04:15:00", date: "Yesterday", billable: true },
|
||||
];
|
||||
|
||||
export default function TimeTrackingPage() {
|
||||
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">
|
||||
|
||||
{/* Top Header */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-white/5 mt-4">
|
||||
<h1 className="text-lg font-medium text-muted-foreground">
|
||||
<span className="text-foreground">Freelance</span> / Time Tracking
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Active Timer & AI Insights Row */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
|
||||
{/* Active Timer Widget */}
|
||||
<div className="rounded-sm border border-primary/30 bg-[#0F0B15] p-6 flex flex-col items-center justify-center relative overflow-hidden shadow-[0_0_30px_rgba(108,91,176,0.15)]">
|
||||
<div className="absolute top-4 left-4 flex items-center gap-2">
|
||||
<span className="relative flex h-3 w-3">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-primary"></span>
|
||||
</span>
|
||||
<span className="text-xs font-bold text-primary uppercase tracking-wider">Tracking</span>
|
||||
</div>
|
||||
|
||||
<div className="text-6xl font-black text-foreground font-mono tracking-tight mt-6 mb-4">
|
||||
01<span className="text-muted-foreground/30">:</span>24<span className="text-muted-foreground/30">:</span>56
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground mb-6 text-center">
|
||||
<strong className="text-foreground">Stark Enterprise App</strong><br/>
|
||||
API Route Optimization
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<button className="h-12 w-12 rounded-full bg-red-500/10 border border-red-500/30 flex items-center justify-center text-red-500 hover:bg-red-500/20 transition-colors">
|
||||
<Pause className="h-5 w-5 fill-current" />
|
||||
</button>
|
||||
<button className="h-12 px-6 rounded-full bg-primary hover:bg-primary/90 text-primary-foreground font-bold transition-colors">
|
||||
Submit Time
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI Invoice Suggester */}
|
||||
<div className="lg:col-span-2 rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col justify-between">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Brain className="h-5 w-5 text-primary" />
|
||||
<h3 className="text-sm font-semibold text-primary">AI Invoice Suggester</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground/80 leading-relaxed mb-6">
|
||||
You have logged <strong>14.5 unbilled hours</strong> for <strong>Stark Industries</strong> this week. Based on your hourly rate of $120/hr, the unbilled amount is <span className="text-emerald-400 font-bold">$1,740</span>. AI suggests generating an invoice today as their accounting cycle ends on the 15th.
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<button className="bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20 border border-emerald-500/20 px-4 py-2 rounded-sm text-xs font-semibold transition-colors flex items-center gap-2">
|
||||
<DollarSign className="h-4 w-4" />
|
||||
Generate $1,740 Invoice
|
||||
</button>
|
||||
<button className="bg-transparent hover:bg-white/5 text-foreground border border-white/10 px-4 py-2 rounded-sm text-xs font-semibold transition-colors">
|
||||
View Time Report
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 flex-1 min-h-[300px] pb-6">
|
||||
|
||||
{/* Weekly Chart */}
|
||||
<div className="rounded-sm border border-white/5 bg-[#0A0710] p-6 flex flex-col">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">This Week</h3>
|
||||
<span className="text-lg font-bold">28h 00m</span>
|
||||
</div>
|
||||
<div className="flex-1 w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={timeData}>
|
||||
<defs>
|
||||
<linearGradient id="colorBillable" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#6C5BB0" stopOpacity={0.3}/>
|
||||
<stop offset="95%" stopColor="#6C5BB0" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#ffffff05" />
|
||||
<XAxis dataKey="day" axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#8F89A5' }} dy={10} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: "#1F172B", border: "none", fontSize: "12px", color: "#FBF9FE", borderRadius: "4px" }}
|
||||
itemStyle={{ color: "#FBF9FE" }}
|
||||
/>
|
||||
<Area type="monotone" dataKey="billable" stroke="#6C5BB0" strokeWidth={2} fillOpacity={1} fill="url(#colorBillable)" />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Time Logs */}
|
||||
<div className="lg:col-span-2 bg-[#0A0710] rounded-sm border border-white/5 overflow-hidden flex flex-col">
|
||||
<div className="p-4 border-b border-white/5 flex justify-between items-center">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Recent Time Logs</h3>
|
||||
<button className="text-xs text-primary font-medium hover:underline">View All</button>
|
||||
</div>
|
||||
<div className="divide-y divide-white/5 flex-1 overflow-y-auto tiny-scrollbar">
|
||||
{timeLogs.map((log) => (
|
||||
<div key={log.id} className="p-4 flex items-center justify-between hover:bg-white/[0.02] transition-colors group cursor-pointer">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-1.5 h-10 rounded-full ${log.billable ? 'bg-primary' : 'bg-muted-foreground/30'}`}></div>
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-foreground mb-0.5">{log.task}</div>
|
||||
<div className="flex items-center gap-2 text-[10px] text-muted-foreground font-medium uppercase tracking-wider">
|
||||
<span className="bg-[#150F1D] px-1.5 py-0.5 rounded-sm border border-white/5">{log.project}</span>
|
||||
<span>{log.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-base font-bold font-mono">{log.duration}</div>
|
||||
<button className="p-1.5 hover:bg-white/10 rounded-sm text-muted-foreground hover:text-foreground transition-colors opacity-0 group-hover:opacity-100">
|
||||
<Play className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user