Dashboard.tsx 13.1 KB
import React from 'react';
import { 
  Printer, 
  Tag, 
  AlertTriangle, 
  Clock, 
  TrendingUp, 
  Plus,
  FileText,
  Users,
  UserCircle,
  Package,
  MapPin,
  ArrowUpRight,
  ArrowDownRight
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "../ui/card";
import { Button } from "../ui/button";
import { Badge } from "../ui/badge";
import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
  LineChart,
  Line,
  PieChart,
  Pie,
  Cell
} from 'recharts';
import { ScrollArea } from "../ui/scroll-area";

// --- Mock Data ---

const WEEKLY_PRINT_DATA = [
  { day: 'Mon', labels: 145 },
  { day: 'Tue', labels: 230 },
  { day: 'Wed', labels: 185 },
  { day: 'Thu', labels: 278 },
  { day: 'Fri', labels: 190 },
  { day: 'Sat', labels: 120 },
  { day: 'Sun', labels: 85 },
];

const CATEGORY_DATA = [
  { name: 'Prep', value: 450, color: '#3b82f6' },
  { name: 'Grab & Go', value: 320, color: '#10b981' },
  { name: 'Catering', value: 150, color: '#f59e0b' },
  { name: 'Delivery', value: 80, color: '#6366f1' },
];

const RECENT_LABELS = [
  { id: '1-251201', product: 'Chicken Breast', template: '2" Prep', user: 'Alice J.', time: '10 mins ago', status: 'active' },
  { id: '1-251202', product: 'Caesar Salad', template: '3" Grab\'n\'Go', user: 'Bob S.', time: '25 mins ago', status: 'active' },
  { id: '1-251203', product: 'Tomato Soup', template: '2" Prep', user: 'Charlie B.', time: '40 mins ago', status: 'expired' },
  { id: '1-251204', product: 'Roast Beef', template: '2" x 2" Prep', user: 'Alice J.', time: '1 hour ago', status: 'active' },
  { id: '1-251205', product: 'Iced Tea', template: 'Beverage Label', user: 'David W.', time: '1 hour ago', status: 'active' },
];

const ACTIVE_TIMERS = [
  { title: 'Coffee Station', time: '12:45', status: 'running' },
  { title: 'Sanitizer Bucket', time: '04:20', status: 'warning' },
  { title: 'Hot Hold Unit 1', time: '00:00', status: 'expired' },
];

export function Dashboard() {
  return (
    <div className="space-y-6">
      {/* Top Hierarchy / Welcome Bar */}
      <div className="bg-white border border-gray-200 p-4 rounded-xl shadow-sm flex flex-col md:flex-row justify-between items-center gap-4">
        <div>
           <h1 className="text-xl font-bold" style={{ color: '#2b328f' }}>Dashboard Overview</h1>
           <p className="text-sm text-gray-500">Welcome back, Admin. Here's what's happening today.</p>
        </div>
        <div className="flex items-center gap-3">
           <Button className="bg-blue-600 text-white hover:bg-blue-700 font-medium">
             <Plus className="w-4 h-4 mr-2" /> New Label
           </Button>
           <Button variant="outline">
             View Reports
           </Button>
        </div>
      </div>

      {/* KPI Cards */}
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        <KPICard 
          title="Labels Printed Today" 
          value="342" 
          trend="+12%" 
          trendUp={true} 
          icon={Printer} 
          color="text-blue-600" 
          bgColor="bg-blue-50"
        />
        <KPICard 
          title="Active Templates" 
          value="24" 
          trend="+2 New" 
          trendUp={true} 
          icon={FileText} 
          color="text-indigo-600" 
          bgColor="bg-indigo-50"
        />
        <KPICard 
          title="Active Users" 
          value="8" 
          trend="Online Now" 
          trendUp={true} 
          icon={Users} 
          color="text-emerald-600" 
          bgColor="bg-emerald-50"
        />
        <KPICard 
          title="Locations" 
          value="12" 
          trend="+1 New" 
          trendUp={true} 
          icon={MapPin} 
          color="text-sky-600" 
          bgColor="bg-sky-50"
        />
        <KPICard 
          title="People" 
          value="48" 
          trend="+3 New" 
          trendUp={true} 
          icon={UserCircle} 
          color="text-violet-600" 
          bgColor="bg-violet-50"
        />
        <KPICard 
          title="Menu Products" 
          value="156" 
          trend="+8 New" 
          trendUp={true} 
          icon={Package} 
          color="text-amber-600" 
          bgColor="bg-amber-50"
        />
      </div>

      {/* Main Content Grid */}
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
        
        {/* Left Column (Charts) */}
        <div className="lg:col-span-2 space-y-6">
          {/* Print Volume Chart */}
          <Card className="shadow-sm border-gray-200">
            <CardHeader>
              <CardTitle className="text-base font-bold text-gray-800 flex items-center gap-2">
                <TrendingUp className="w-5 h-5 text-gray-500" />
                Weekly Print Volume
              </CardTitle>
              <CardDescription>Number of labels printed over the last 7 days</CardDescription>
            </CardHeader>
            <CardContent>
              <div className="h-[300px] w-full">
                <ResponsiveContainer width="100%" height="100%">
                  <LineChart data={WEEKLY_PRINT_DATA}>
                    <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" />
                    <XAxis 
                      dataKey="day" 
                      axisLine={false} 
                      tickLine={false} 
                      tick={{ fill: '#6b7280', fontSize: 12 }} 
                      dy={10}
                    />
                    <YAxis 
                      axisLine={false} 
                      tickLine={false} 
                      tick={{ fill: '#6b7280', fontSize: 12 }} 
                    />
                    <Tooltip 
                      contentStyle={{ borderRadius: '8px', border: 'none', boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)' }}
                      cursor={{ stroke: '#d1d5db', strokeWidth: 1 }}
                    />
                    <Line 
                      type="monotone" 
                      dataKey="labels" 
                      stroke="#2563eb" 
                      strokeWidth={3} 
                      dot={{ r: 4, fill: '#2563eb', strokeWidth: 2, stroke: '#fff' }}
                      activeDot={{ r: 6 }}
                    />
                  </LineChart>
                </ResponsiveContainer>
              </div>
            </CardContent>
          </Card>

          {/* Recent Labels Table */}
          <Card className="shadow-sm border-gray-200">
             <CardHeader className="flex flex-row items-center justify-between">
              <div>
                <CardTitle className="text-base font-bold text-gray-800 flex items-center gap-2">
                  <Tag className="w-5 h-5 text-gray-500" />
                  Recent Labels
                </CardTitle>
                <CardDescription>Latest printed labels across all locations</CardDescription>
              </div>
              <Button variant="ghost" size="sm" className="text-blue-600">View All</Button>
            </CardHeader>
            <CardContent>
              <div className="space-y-4">
                {RECENT_LABELS.map((label) => (
                  <div key={label.id} className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-100 hover:bg-gray-100 transition-colors">
                    <div className="flex items-center gap-3">
                      <div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold text-xs">
                        {label.template.substring(0, 2)}
                      </div>
                      <div>
                        <p className="text-sm font-semibold text-gray-900">{label.product}</p>
                        <p className="text-xs text-gray-500">{label.id} • {label.user}</p>
                      </div>
                    </div>
                    <div className="flex items-center gap-4">
                      <span className="text-xs text-gray-500 font-medium">{label.time}</span>
                      <Badge 
                        variant="secondary" 
                        className={label.status === 'expired' ? 'bg-red-100 text-red-700' : 'bg-green-100 text-green-700'}
                      >
                        {label.status}
                      </Badge>
                    </div>
                  </div>
                ))}
              </div>
            </CardContent>
          </Card>
        </div>

        {/* Right Column (Widgets) */}
        <div className="space-y-6">
          
          {/* Category Distribution */}
          <Card className="shadow-sm border-gray-200">
            <CardHeader>
              <CardTitle className="text-base font-bold text-gray-800 flex items-center gap-2">
                <Package className="w-5 h-5 text-gray-500" />
                By Category
              </CardTitle>
            </CardHeader>
            <CardContent>
              <div className="h-[200px] relative">
                <ResponsiveContainer width="100%" height="100%">
                  <PieChart>
                    <Pie
                      data={CATEGORY_DATA}
                      cx="50%"
                      cy="50%"
                      innerRadius={60}
                      outerRadius={80}
                      paddingAngle={5}
                      dataKey="value"
                    >
                      {CATEGORY_DATA.map((entry, index) => (
                        <Cell key={`cell-${index}`} fill={entry.color} />
                      ))}
                    </Pie>
                    <Tooltip />
                  </PieChart>
                </ResponsiveContainer>
                <div className="absolute inset-0 flex items-center justify-center flex-col pointer-events-none">
                  <span className="text-2xl font-bold text-gray-900">1000</span>
                  <span className="text-xs text-gray-500">Total</span>
                </div>
              </div>
              <div className="mt-4 space-y-2">
                {CATEGORY_DATA.map((item) => (
                  <div key={item.name} className="flex items-center justify-between text-sm">
                    <div className="flex items-center gap-2">
                      <div className="w-3 h-3 rounded-full" style={{ backgroundColor: item.color }} />
                      <span className="text-gray-600">{item.name}</span>
                    </div>
                    <span className="font-medium text-gray-900">{item.value}</span>
                  </div>
                ))}
              </div>
            </CardContent>
          </Card>

          {/* Active Timers Widget */}
          <Card className="shadow-sm border-gray-200 bg-gray-900 text-white">
            <CardHeader>
              <CardTitle className="text-base font-bold flex items-center gap-2 text-white">
                <Clock className="w-5 h-5 text-blue-400" />
                Active Timers
              </CardTitle>
            </CardHeader>
            <CardContent>
              <div className="space-y-3">
                {ACTIVE_TIMERS.map((timer, idx) => (
                  <div key={idx} className="flex items-center justify-between border-b border-gray-800 last:border-0 pb-3 last:pb-0">
                    <span className="text-sm font-medium text-gray-300">{timer.title}</span>
                    <div className="flex items-center gap-2">
                      <span className={`font-mono font-bold ${timer.status === 'expired' ? 'text-red-500 animate-pulse' : 'text-white'}`}>
                        {timer.time}
                      </span>
                      {timer.status === 'running' && <div className="w-2 h-2 rounded-full bg-green-500" />}
                      {timer.status === 'warning' && <div className="w-2 h-2 rounded-full bg-yellow-500" />}
                      {timer.status === 'expired' && <div className="w-2 h-2 rounded-full bg-red-500" />}
                    </div>
                  </div>
                ))}
              </div>
              <Button className="w-full mt-4 bg-blue-600 hover:bg-blue-700 text-white">
                Manage Alerts
              </Button>
            </CardContent>
          </Card>

        </div>
      </div>
    </div>
  );
}

// --- Sub Components ---

function KPICard({ title, value, trend, trendUp, icon: Icon, color, bgColor }: any) {
  return (
    <Card className="border-gray-200 shadow-sm hover:shadow-md transition-shadow">
      <CardContent className="p-6">
        <div className="flex justify-between items-start">
          <div>
            <p className="text-sm font-medium text-gray-500 mb-1">{title}</p>
            <h3 className="text-2xl font-bold text-gray-900">{value}</h3>
          </div>
          <div className={`p-2 rounded-lg ${bgColor}`}>
            <Icon className={`w-5 h-5 ${color}`} />
          </div>
        </div>
        <div className="mt-4 flex items-center text-sm">
          {trendUp ? (
            <ArrowUpRight className="w-4 h-4 text-green-500 mr-1" />
          ) : (
            <ArrowDownRight className="w-4 h-4 text-red-500 mr-1" />
          )}
          <span className={trendUp ? 'text-green-600 font-medium' : 'text-red-600 font-medium'}>
            {trend}
          </span>
          <span className="text-gray-400 ml-1">vs last period</span>
        </div>
      </CardContent>
    </Card>
  );
}