Refactor sidebar and add new modules
This commit is contained in:
27
src/App.tsx
27
src/App.tsx
@@ -35,6 +35,9 @@ import InvoiceDetail from "./pages/dashboard/InvoiceDetail";
|
|||||||
import HotelManagement from "./pages/dashboard/HotelManagement";
|
import HotelManagement from "./pages/dashboard/HotelManagement";
|
||||||
import RestaurantPOS from "./pages/dashboard/RestaurantPOS";
|
import RestaurantPOS from "./pages/dashboard/RestaurantPOS";
|
||||||
import Personalization from "./pages/dashboard/Personalization";
|
import Personalization from "./pages/dashboard/Personalization";
|
||||||
|
import Security from "./pages/dashboard/Security";
|
||||||
|
import VehicleManagement from "./pages/dashboard/VehicleManagement";
|
||||||
|
import Sustainability from "./pages/dashboard/Sustainability";
|
||||||
// Hotel pages
|
// Hotel pages
|
||||||
import HotelRooms from "./pages/dashboard/hotel/Rooms";
|
import HotelRooms from "./pages/dashboard/hotel/Rooms";
|
||||||
import HotelCheckIn from "./pages/dashboard/hotel/CheckIn";
|
import HotelCheckIn from "./pages/dashboard/hotel/CheckIn";
|
||||||
@@ -257,6 +260,30 @@ const AppRouter = () => (
|
|||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
} />
|
} />
|
||||||
|
|
||||||
|
<Route path="/dashboard/security" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<DashboardLayout>
|
||||||
|
<Security />
|
||||||
|
</DashboardLayout>
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
|
||||||
|
<Route path="/dashboard/vehicle-management" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<DashboardLayout>
|
||||||
|
<VehicleManagement />
|
||||||
|
</DashboardLayout>
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
|
||||||
|
<Route path="/dashboard/sustainability" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<DashboardLayout>
|
||||||
|
<Sustainability />
|
||||||
|
</DashboardLayout>
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
|
||||||
<Route path="/dashboard/hotel-management" element={
|
<Route path="/dashboard/hotel-management" element={
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<DashboardLayout>
|
<DashboardLayout>
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ import {
|
|||||||
Map,
|
Map,
|
||||||
Shield,
|
Shield,
|
||||||
Radio,
|
Radio,
|
||||||
Sparkles
|
Sparkles,
|
||||||
|
Leaf
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
@@ -155,6 +156,9 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ icon: Brain, label: 'Personalization', path: '/dashboard/personalization' },
|
{ icon: Brain, label: 'Personalization', path: '/dashboard/personalization' },
|
||||||
|
{ icon: Shield, label: 'Security', path: '/dashboard/security' },
|
||||||
|
{ icon: Car, label: 'Vehicle Management', path: '/dashboard/vehicle-management' },
|
||||||
|
{ icon: Leaf, label: 'Sustainability', path: '/dashboard/sustainability' },
|
||||||
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
|
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
|
||||||
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
|
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
|
||||||
];
|
];
|
||||||
|
|||||||
151
src/components/security/AccessControl.tsx
Normal file
151
src/components/security/AccessControl.tsx
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Users, Lock, Key, Shield, Search, Plus } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockRoles = [
|
||||||
|
{ id: 1, name: 'Super Admin', users: 2, permissions: 100, color: 'red' },
|
||||||
|
{ id: 2, name: 'Admin', users: 8, permissions: 85, color: 'orange' },
|
||||||
|
{ id: 3, name: 'Manager', users: 24, permissions: 60, color: 'blue' },
|
||||||
|
{ id: 4, name: 'Staff', users: 156, permissions: 35, color: 'green' },
|
||||||
|
{ id: 5, name: 'Guest', users: 489, permissions: 10, color: 'gray' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockPermissions = [
|
||||||
|
{ module: 'User Management', read: true, write: true, delete: true },
|
||||||
|
{ module: 'Content Management', read: true, write: true, delete: false },
|
||||||
|
{ module: 'Financial Reports', read: true, write: false, delete: false },
|
||||||
|
{ module: 'System Settings', read: true, write: true, delete: true }
|
||||||
|
];
|
||||||
|
|
||||||
|
const AccessControl = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Users</CardTitle>
|
||||||
|
<Users className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">679</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Active accounts</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Roles</CardTitle>
|
||||||
|
<Shield className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">5</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Permission groups</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Active Sessions</CardTitle>
|
||||||
|
<Key className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">342</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Currently logged in</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Failed Logins</CardTitle>
|
||||||
|
<Lock className="h-4 w-4 text-red-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">23</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Last 24 hours</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>User Roles</CardTitle>
|
||||||
|
<CardDescription>Manage user roles and permissions</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Add Role
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{mockRoles.map((role) => (
|
||||||
|
<div key={role.id} className="border rounded-lg p-4 flex items-center justify-between hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center gap-4 flex-1">
|
||||||
|
<div className={`w-12 h-12 rounded-full bg-${role.color}-100 flex items-center justify-center`}>
|
||||||
|
<Shield className={`h-6 w-6 text-${role.color}-600`} />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<h3 className="font-semibold text-gray-900">{role.name}</h3>
|
||||||
|
<p className="text-sm text-gray-600">{role.users} users • {role.permissions}% permissions</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm">Edit</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Permission Matrix</CardTitle>
|
||||||
|
<CardDescription>View and manage module permissions</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b">
|
||||||
|
<th className="text-left py-3 px-4 font-semibold">Module</th>
|
||||||
|
<th className="text-center py-3 px-4 font-semibold">Read</th>
|
||||||
|
<th className="text-center py-3 px-4 font-semibold">Write</th>
|
||||||
|
<th className="text-center py-3 px-4 font-semibold">Delete</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{mockPermissions.map((perm, idx) => (
|
||||||
|
<tr key={idx} className="border-b hover:bg-gray-50">
|
||||||
|
<td className="py-3 px-4">{perm.module}</td>
|
||||||
|
<td className="text-center py-3 px-4">
|
||||||
|
<Badge className={perm.read ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}>
|
||||||
|
{perm.read ? '✓' : '✗'}
|
||||||
|
</Badge>
|
||||||
|
</td>
|
||||||
|
<td className="text-center py-3 px-4">
|
||||||
|
<Badge className={perm.write ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}>
|
||||||
|
{perm.write ? '✓' : '✗'}
|
||||||
|
</Badge>
|
||||||
|
</td>
|
||||||
|
<td className="text-center py-3 px-4">
|
||||||
|
<Badge className={perm.delete ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}>
|
||||||
|
{perm.delete ? '✓' : '✗'}
|
||||||
|
</Badge>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccessControl;
|
||||||
175
src/components/security/AuditLogs.tsx
Normal file
175
src/components/security/AuditLogs.tsx
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { FileText, Download, Search, Filter } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockLogs = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
action: 'User Login',
|
||||||
|
user: 'admin@karibeo.com',
|
||||||
|
ip: '192.168.1.100',
|
||||||
|
timestamp: '2025-10-10 15:23:45',
|
||||||
|
status: 'success',
|
||||||
|
details: 'Successful authentication via password'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
action: 'Permission Changed',
|
||||||
|
user: 'manager@karibeo.com',
|
||||||
|
ip: '192.168.1.105',
|
||||||
|
timestamp: '2025-10-10 14:45:12',
|
||||||
|
status: 'success',
|
||||||
|
details: 'Updated role permissions for Staff group'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
action: 'Failed Login',
|
||||||
|
user: 'unknown@example.com',
|
||||||
|
ip: '45.123.67.89',
|
||||||
|
timestamp: '2025-10-10 14:15:03',
|
||||||
|
status: 'failed',
|
||||||
|
details: 'Invalid credentials - 3rd attempt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
action: 'Data Export',
|
||||||
|
user: 'analyst@karibeo.com',
|
||||||
|
ip: '192.168.1.110',
|
||||||
|
timestamp: '2025-10-10 13:30:22',
|
||||||
|
status: 'success',
|
||||||
|
details: 'Exported user analytics report'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
action: 'System Settings',
|
||||||
|
user: 'admin@karibeo.com',
|
||||||
|
ip: '192.168.1.100',
|
||||||
|
timestamp: '2025-10-10 12:18:55',
|
||||||
|
status: 'success',
|
||||||
|
details: 'Modified security policies'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
action: 'User Deletion',
|
||||||
|
user: 'admin@karibeo.com',
|
||||||
|
ip: '192.168.1.100',
|
||||||
|
timestamp: '2025-10-10 11:45:30',
|
||||||
|
status: 'success',
|
||||||
|
details: 'Deleted inactive user account'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const AuditLogs = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
return status === 'success'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-red-100 text-red-800';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>System Audit Logs</CardTitle>
|
||||||
|
<CardDescription>Complete history of system activities and changes</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
<Filter className="h-4 w-4 mr-2" />
|
||||||
|
Filter
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
<Download className="h-4 w-4 mr-2" />
|
||||||
|
Export
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="relative">
|
||||||
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||||
|
<Input
|
||||||
|
placeholder="Search logs by user, action, or IP..."
|
||||||
|
className="pl-10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
{mockLogs.map((log) => (
|
||||||
|
<div key={log.id} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div className="flex items-start gap-3 flex-1">
|
||||||
|
<div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<FileText className="h-5 w-5 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-gray-900">{log.action}</h3>
|
||||||
|
<Badge className={getStatusColor(log.status)}>
|
||||||
|
{log.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">{log.details}</p>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-gray-500">
|
||||||
|
<span className="font-medium">{log.user}</span>
|
||||||
|
<span>IP: {log.ip}</span>
|
||||||
|
<span>{log.timestamp}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="ghost" size="sm" className="ml-2">
|
||||||
|
Details
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Events</CardTitle>
|
||||||
|
<FileText className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">12,489</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Last 30 days</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Failed Actions</CardTitle>
|
||||||
|
<FileText className="h-4 w-4 text-red-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">87</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Requiring attention</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Storage Used</CardTitle>
|
||||||
|
<FileText className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">2.4 GB</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Of 10 GB limit</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AuditLogs;
|
||||||
150
src/components/security/ComplianceMonitor.tsx
Normal file
150
src/components/security/ComplianceMonitor.tsx
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { CheckCircle, AlertTriangle, FileText, Shield } from 'lucide-react';
|
||||||
|
|
||||||
|
const complianceStandards = [
|
||||||
|
{ name: 'GDPR', status: 'compliant', score: 98, lastAudit: '2025-09-15' },
|
||||||
|
{ name: 'PCI DSS', status: 'compliant', score: 95, lastAudit: '2025-09-20' },
|
||||||
|
{ name: 'ISO 27001', status: 'compliant', score: 92, lastAudit: '2025-08-30' },
|
||||||
|
{ name: 'SOC 2', status: 'review', score: 88, lastAudit: '2025-09-10' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const requirements = [
|
||||||
|
{ category: 'Data Protection', completed: 24, total: 25, priority: 'high' },
|
||||||
|
{ category: 'Access Management', completed: 18, total: 20, priority: 'high' },
|
||||||
|
{ category: 'Encryption', completed: 15, total: 15, priority: 'critical' },
|
||||||
|
{ category: 'Incident Response', completed: 10, total: 12, priority: 'medium' },
|
||||||
|
{ category: 'Documentation', completed: 8, total: 10, priority: 'low' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const ComplianceMonitor = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
return status === 'compliant'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-yellow-100 text-yellow-800';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPriorityColor = (priority: string) => {
|
||||||
|
switch (priority) {
|
||||||
|
case 'critical': return 'text-red-600';
|
||||||
|
case 'high': return 'text-orange-600';
|
||||||
|
case 'medium': return 'text-yellow-600';
|
||||||
|
default: return 'text-blue-600';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Overall Score</CardTitle>
|
||||||
|
<Shield className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">93%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Excellent compliance</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Standards</CardTitle>
|
||||||
|
<CheckCircle className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">4</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Active certifications</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Open Issues</CardTitle>
|
||||||
|
<AlertTriangle className="h-4 w-4 text-orange-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">7</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Require attention</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Last Audit</CardTitle>
|
||||||
|
<FileText className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">15</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Days ago</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Compliance Standards</CardTitle>
|
||||||
|
<CardDescription>Status of regulatory compliance standards</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{complianceStandards.map((standard) => (
|
||||||
|
<div key={standard.name} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<h3 className="font-semibold text-gray-900">{standard.name}</h3>
|
||||||
|
<Badge className={getStatusColor(standard.status)}>
|
||||||
|
{standard.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-600">
|
||||||
|
Last audit: {standard.lastAudit}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center justify-between text-sm">
|
||||||
|
<span className="text-gray-600">Compliance Score</span>
|
||||||
|
<span className="font-semibold">{standard.score}%</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={standard.score} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Compliance Requirements</CardTitle>
|
||||||
|
<CardDescription>Progress on compliance requirements by category</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{requirements.map((req) => (
|
||||||
|
<div key={req.category} className="border rounded-lg p-4">
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<h3 className="font-semibold text-gray-900">{req.category}</h3>
|
||||||
|
<span className={`text-xs font-semibold uppercase ${getPriorityColor(req.priority)}`}>
|
||||||
|
{req.priority}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-600">
|
||||||
|
{req.completed} of {req.total}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={(req.completed / req.total) * 100} className="h-2" />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ComplianceMonitor;
|
||||||
160
src/components/security/ThreatDetection.tsx
Normal file
160
src/components/security/ThreatDetection.tsx
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { AlertTriangle, Shield, Activity, Eye, RefreshCw } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockThreats = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
type: 'SQL Injection Attempt',
|
||||||
|
severity: 'high',
|
||||||
|
ip: '192.168.1.105',
|
||||||
|
timestamp: '2025-10-10 14:32:11',
|
||||||
|
status: 'blocked',
|
||||||
|
description: 'Attempted SQL injection on login form'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
type: 'Brute Force Attack',
|
||||||
|
severity: 'critical',
|
||||||
|
ip: '45.123.67.89',
|
||||||
|
timestamp: '2025-10-10 14:15:03',
|
||||||
|
status: 'monitoring',
|
||||||
|
description: 'Multiple failed login attempts detected'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
type: 'XSS Attack',
|
||||||
|
severity: 'medium',
|
||||||
|
ip: '172.16.0.42',
|
||||||
|
timestamp: '2025-10-10 13:45:22',
|
||||||
|
status: 'blocked',
|
||||||
|
description: 'Cross-site scripting attempt in comment section'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
type: 'DDoS Pattern',
|
||||||
|
severity: 'high',
|
||||||
|
ip: '203.45.12.78',
|
||||||
|
timestamp: '2025-10-10 12:22:15',
|
||||||
|
status: 'mitigated',
|
||||||
|
description: 'Unusual traffic spike detected and throttled'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const ThreatDetection = () => {
|
||||||
|
const getSeverityColor = (severity: string) => {
|
||||||
|
switch (severity) {
|
||||||
|
case 'critical': return 'bg-red-100 text-red-800 border-red-300';
|
||||||
|
case 'high': return 'bg-orange-100 text-orange-800 border-orange-300';
|
||||||
|
case 'medium': return 'bg-yellow-100 text-yellow-800 border-yellow-300';
|
||||||
|
default: return 'bg-blue-100 text-blue-800 border-blue-300';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'blocked': return 'bg-green-100 text-green-800';
|
||||||
|
case 'monitoring': return 'bg-blue-100 text-blue-800';
|
||||||
|
case 'mitigated': return 'bg-purple-100 text-purple-800';
|
||||||
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Active Threats</CardTitle>
|
||||||
|
<AlertTriangle className="h-4 w-4 text-red-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">24</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">+3 in last hour</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Blocked Attacks</CardTitle>
|
||||||
|
<Shield className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">1,847</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Last 24 hours</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Security Score</CardTitle>
|
||||||
|
<Activity className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">94%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Excellent protection</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Monitoring</CardTitle>
|
||||||
|
<Eye className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">Active</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Real-time protection</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Recent Threats</CardTitle>
|
||||||
|
<CardDescription>Latest security incidents and threats detected</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
<RefreshCw className="h-4 w-4 mr-2" />
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{mockThreats.map((threat) => (
|
||||||
|
<div key={threat.id} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<h3 className="font-semibold text-gray-900">{threat.type}</h3>
|
||||||
|
<Badge className={getSeverityColor(threat.severity)}>
|
||||||
|
{threat.severity}
|
||||||
|
</Badge>
|
||||||
|
<Badge className={getStatusColor(threat.status)}>
|
||||||
|
{threat.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">{threat.description}</p>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-gray-500">
|
||||||
|
<span>IP: {threat.ip}</span>
|
||||||
|
<span>{threat.timestamp}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="ghost" size="sm">
|
||||||
|
View Details
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThreatDetection;
|
||||||
98
src/components/sustainability/CarbonFootprint.tsx
Normal file
98
src/components/sustainability/CarbonFootprint.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { TrendingDown, Leaf, Factory, Zap } from 'lucide-react';
|
||||||
|
|
||||||
|
const CarbonFootprint = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Emissions</CardTitle>
|
||||||
|
<Factory className="h-4 w-4 text-gray-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">1,247 tons</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">CO2 this year</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Reduction</CardTitle>
|
||||||
|
<TrendingDown className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">-18%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">From last year</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Offset</CardTitle>
|
||||||
|
<Leaf className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">340 tons</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">27% offset</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Goal Progress</CardTitle>
|
||||||
|
<Zap className="h-4 w-4 text-yellow-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">72%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">On track</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Emissions by Source</CardTitle>
|
||||||
|
<CardDescription>Breakdown of carbon emissions</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Transportation</span>
|
||||||
|
<span className="text-sm text-gray-600">624 tons (50%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={50} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Energy</span>
|
||||||
|
<span className="text-sm text-gray-600">374 tons (30%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={30} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Operations</span>
|
||||||
|
<span className="text-sm text-gray-600">187 tons (15%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={15} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Other</span>
|
||||||
|
<span className="text-sm text-gray-600">62 tons (5%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={5} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CarbonFootprint;
|
||||||
83
src/components/sustainability/EnergyManagement.tsx
Normal file
83
src/components/sustainability/EnergyManagement.tsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { Zap, Sun, Wind, Battery } from 'lucide-react';
|
||||||
|
|
||||||
|
const EnergyManagement = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Usage</CardTitle>
|
||||||
|
<Zap className="h-4 w-4 text-yellow-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">45,230 kWh</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">This month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Solar Energy</CardTitle>
|
||||||
|
<Sun className="h-4 w-4 text-orange-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">12,450 kWh</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">27% of total</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Wind Energy</CardTitle>
|
||||||
|
<Wind className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">8,120 kWh</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">18% of total</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Efficiency</CardTitle>
|
||||||
|
<Battery className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">+12%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Improvement</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Energy Sources</CardTitle>
|
||||||
|
<CardDescription>Breakdown of energy consumption by source</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Renewable</span>
|
||||||
|
<span className="text-sm text-gray-600">20,570 kWh (45%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={45} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Grid</span>
|
||||||
|
<span className="text-sm text-gray-600">24,660 kWh (55%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={55} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EnergyManagement;
|
||||||
108
src/components/sustainability/SustainabilityGoals.tsx
Normal file
108
src/components/sustainability/SustainabilityGoals.tsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { Target, CheckCircle, Clock, TrendingUp } from 'lucide-react';
|
||||||
|
|
||||||
|
const goals = [
|
||||||
|
{ id: 1, title: 'Reduce Carbon Emissions by 25%', progress: 72, status: 'on-track', deadline: '2025-12-31' },
|
||||||
|
{ id: 2, title: 'Achieve 50% Renewable Energy', progress: 45, status: 'on-track', deadline: '2025-12-31' },
|
||||||
|
{ id: 3, title: 'Zero Waste to Landfill', progress: 93, status: 'ahead', deadline: '2026-06-30' },
|
||||||
|
{ id: 4, title: 'Water Consumption -30%', progress: 38, status: 'at-risk', deadline: '2025-12-31' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const SustainabilityGoals = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'ahead': return 'bg-green-100 text-green-800';
|
||||||
|
case 'on-track': return 'bg-blue-100 text-blue-800';
|
||||||
|
case 'at-risk': return 'bg-yellow-100 text-yellow-800';
|
||||||
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Active Goals</CardTitle>
|
||||||
|
<Target className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">4</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">In progress</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Completed</CardTitle>
|
||||||
|
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">8</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Goals achieved</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">On Track</CardTitle>
|
||||||
|
<TrendingUp className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">75%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Success rate</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">At Risk</CardTitle>
|
||||||
|
<Clock className="h-4 w-4 text-yellow-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">1</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Needs attention</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Sustainability Goals</CardTitle>
|
||||||
|
<CardDescription>Track progress towards environmental targets</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{goals.map((goal) => (
|
||||||
|
<div key={goal.id} className="border rounded-lg p-4">
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<h3 className="font-semibold text-gray-900">{goal.title}</h3>
|
||||||
|
<Badge className={getStatusColor(goal.status)}>
|
||||||
|
{goal.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-600">
|
||||||
|
Due: {goal.deadline}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center justify-between text-sm">
|
||||||
|
<span className="text-gray-600">Progress</span>
|
||||||
|
<span className="font-semibold">{goal.progress}%</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={goal.progress} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SustainabilityGoals;
|
||||||
90
src/components/sustainability/WasteTracking.tsx
Normal file
90
src/components/sustainability/WasteTracking.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { Trash2, Recycle, TrendingUp, Package } from 'lucide-react';
|
||||||
|
|
||||||
|
const WasteTracking = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Waste</CardTitle>
|
||||||
|
<Trash2 className="h-4 w-4 text-gray-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">2,340 kg</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">This month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Recycled</CardTitle>
|
||||||
|
<Recycle className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">1,755 kg</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">75% recycling rate</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Composted</CardTitle>
|
||||||
|
<Package className="h-4 w-4 text-brown-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">420 kg</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">18% of total</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Improvement</CardTitle>
|
||||||
|
<TrendingUp className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">+8%</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">From last month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Waste Management</CardTitle>
|
||||||
|
<CardDescription>Distribution of waste by type</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Recyclable</span>
|
||||||
|
<span className="text-sm text-gray-600">1,755 kg (75%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={75} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Organic</span>
|
||||||
|
<span className="text-sm text-gray-600">420 kg (18%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={18} className="h-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-sm font-medium">Landfill</span>
|
||||||
|
<span className="text-sm text-gray-600">165 kg (7%)</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={7} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WasteTracking;
|
||||||
116
src/components/vehicles/DriverManagement.tsx
Normal file
116
src/components/vehicles/DriverManagement.tsx
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Users, Star, AlertTriangle, Award, TrendingUp } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockDrivers = [
|
||||||
|
{ id: 1, name: 'Carlos Martinez', status: 'active', rating: 4.9, trips: 245, vehicle: 'V001' },
|
||||||
|
{ id: 2, name: 'Maria Rodriguez', status: 'active', rating: 4.8, trips: 198, vehicle: 'V005' },
|
||||||
|
{ id: 3, name: 'Juan Perez', status: 'off-duty', rating: 4.7, trips: 312, vehicle: '-' },
|
||||||
|
{ id: 4, name: 'Ana Garcia', status: 'active', rating: 5.0, trips: 156, vehicle: 'V002' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const DriverManagement = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
return status === 'active'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-gray-100 text-gray-800';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Drivers</CardTitle>
|
||||||
|
<Users className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">48</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Registered drivers</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Active Now</CardTitle>
|
||||||
|
<TrendingUp className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">32</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Currently driving</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Avg Rating</CardTitle>
|
||||||
|
<Star className="h-4 w-4 text-yellow-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">4.8</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Out of 5.0</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Top Performer</CardTitle>
|
||||||
|
<Award className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">Ana G.</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">5.0 rating</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Driver List</CardTitle>
|
||||||
|
<CardDescription>Manage your driver team</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button>Add Driver</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{mockDrivers.map((driver) => (
|
||||||
|
<div key={driver.id} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-4 flex-1">
|
||||||
|
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
|
||||||
|
<Users className="h-6 w-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-gray-900">{driver.name}</h3>
|
||||||
|
<Badge className={getStatusColor(driver.status)}>
|
||||||
|
{driver.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-sm text-gray-600">
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<Star className="h-3 w-3 fill-yellow-500 text-yellow-500" />
|
||||||
|
{driver.rating}
|
||||||
|
</span>
|
||||||
|
<span>{driver.trips} trips</span>
|
||||||
|
<span>Vehicle: {driver.vehicle}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm">View Profile</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DriverManagement;
|
||||||
120
src/components/vehicles/FleetOverview.tsx
Normal file
120
src/components/vehicles/FleetOverview.tsx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Car, TrendingUp, AlertTriangle, Wrench, MapPin, DollarSign } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockVehicles = [
|
||||||
|
{ id: 'V001', model: 'Toyota Camry 2023', status: 'active', location: 'Downtown', fuel: 85, mileage: 45230 },
|
||||||
|
{ id: 'V002', model: 'Honda Accord 2022', status: 'active', location: 'Airport', fuel: 92, mileage: 38450 },
|
||||||
|
{ id: 'V003', model: 'Tesla Model 3', status: 'charging', location: 'Station A', fuel: 45, mileage: 22100 },
|
||||||
|
{ id: 'V004', model: 'Ford Explorer 2023', status: 'maintenance', location: 'Service Center', fuel: 30, mileage: 52780 },
|
||||||
|
{ id: 'V005', model: 'Chevrolet Suburban', status: 'active', location: 'Hotel Zone', fuel: 78, mileage: 31250 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const FleetOverview = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'active': return 'bg-green-100 text-green-800';
|
||||||
|
case 'charging': return 'bg-blue-100 text-blue-800';
|
||||||
|
case 'maintenance': return 'bg-orange-100 text-orange-800';
|
||||||
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Vehicles</CardTitle>
|
||||||
|
<Car className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">54</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Active fleet</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">In Service</CardTitle>
|
||||||
|
<TrendingUp className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">48</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">89% availability</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Maintenance</CardTitle>
|
||||||
|
<Wrench className="h-4 w-4 text-orange-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">6</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Due this week</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Monthly Cost</CardTitle>
|
||||||
|
<DollarSign className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">$8,450</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">-5% from last month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Active Vehicles</CardTitle>
|
||||||
|
<CardDescription>Real-time fleet status</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button>Add Vehicle</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{mockVehicles.map((vehicle) => (
|
||||||
|
<div key={vehicle.id} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-4 flex-1">
|
||||||
|
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
|
||||||
|
<Car className="h-6 w-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-gray-900">{vehicle.model}</h3>
|
||||||
|
<Badge className={getStatusColor(vehicle.status)}>
|
||||||
|
{vehicle.status}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-sm text-gray-600">
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<MapPin className="h-3 w-3" />
|
||||||
|
{vehicle.location}
|
||||||
|
</span>
|
||||||
|
<span>Fuel: {vehicle.fuel}%</span>
|
||||||
|
<span>{vehicle.mileage.toLocaleString()} mi</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm">Details</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FleetOverview;
|
||||||
126
src/components/vehicles/MaintenanceSchedule.tsx
Normal file
126
src/components/vehicles/MaintenanceSchedule.tsx
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Wrench, Calendar, AlertTriangle, CheckCircle } from 'lucide-react';
|
||||||
|
|
||||||
|
const mockMaintenance = [
|
||||||
|
{ id: 1, vehicle: 'V004 - Ford Explorer', type: 'Oil Change', status: 'scheduled', date: '2025-10-12', priority: 'medium' },
|
||||||
|
{ id: 2, vehicle: 'V007 - Tesla Model S', type: 'Tire Rotation', status: 'overdue', date: '2025-10-08', priority: 'high' },
|
||||||
|
{ id: 3, vehicle: 'V012 - Honda CR-V', type: 'Brake Inspection', status: 'scheduled', date: '2025-10-15', priority: 'high' },
|
||||||
|
{ id: 4, vehicle: 'V003 - Tesla Model 3', type: 'Battery Check', status: 'completed', date: '2025-10-09', priority: 'low' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const MaintenanceSchedule = () => {
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'completed': return 'bg-green-100 text-green-800';
|
||||||
|
case 'scheduled': return 'bg-blue-100 text-blue-800';
|
||||||
|
case 'overdue': return 'bg-red-100 text-red-800';
|
||||||
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPriorityColor = (priority: string) => {
|
||||||
|
switch (priority) {
|
||||||
|
case 'high': return 'bg-red-100 text-red-800';
|
||||||
|
case 'medium': return 'bg-yellow-100 text-yellow-800';
|
||||||
|
default: return 'bg-blue-100 text-blue-800';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Scheduled</CardTitle>
|
||||||
|
<Calendar className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">12</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">This month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Overdue</CardTitle>
|
||||||
|
<AlertTriangle className="h-4 w-4 text-red-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">3</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Requires attention</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Completed</CardTitle>
|
||||||
|
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">45</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">This month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Total Cost</CardTitle>
|
||||||
|
<Wrench className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">$2,340</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">This month</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Maintenance Schedule</CardTitle>
|
||||||
|
<CardDescription>Upcoming and recent maintenance activities</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button>Schedule Service</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{mockMaintenance.map((item) => (
|
||||||
|
<div key={item.id} className="border rounded-lg p-4 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-4 flex-1">
|
||||||
|
<div className="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center">
|
||||||
|
<Wrench className="h-6 w-6 text-orange-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-gray-900">{item.type}</h3>
|
||||||
|
<Badge className={getStatusColor(item.status)}>
|
||||||
|
{item.status}
|
||||||
|
</Badge>
|
||||||
|
<Badge className={getPriorityColor(item.priority)}>
|
||||||
|
{item.priority}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-sm text-gray-600">
|
||||||
|
<span>{item.vehicle}</span>
|
||||||
|
<span>{item.date}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm">Manage</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MaintenanceSchedule;
|
||||||
63
src/components/vehicles/VehicleTracking.tsx
Normal file
63
src/components/vehicles/VehicleTracking.tsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { MapPin, Navigation, Clock, Activity } from 'lucide-react';
|
||||||
|
|
||||||
|
const VehicleTracking = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Live Vehicle Tracking</CardTitle>
|
||||||
|
<CardDescription>Real-time GPS tracking of your fleet</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="bg-gray-100 rounded-lg h-96 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<MapPin className="h-16 w-16 text-gray-400 mx-auto mb-4" />
|
||||||
|
<p className="text-gray-600">Map integration would be displayed here</p>
|
||||||
|
<p className="text-sm text-gray-500 mt-2">Showing real-time location of all vehicles</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Active Routes</CardTitle>
|
||||||
|
<Navigation className="h-4 w-4 text-blue-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">32</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Currently in transit</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Avg Speed</CardTitle>
|
||||||
|
<Activity className="h-4 w-4 text-green-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">45 mph</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Fleet average</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">ETA</CardTitle>
|
||||||
|
<Clock className="h-4 w-4 text-purple-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">18 min</div>
|
||||||
|
<p className="text-xs text-gray-600 mt-1">Nearest vehicle</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VehicleTracking;
|
||||||
52
src/pages/dashboard/Security.tsx
Normal file
52
src/pages/dashboard/Security.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import ThreatDetection from '@/components/security/ThreatDetection';
|
||||||
|
import AccessControl from '@/components/security/AccessControl';
|
||||||
|
import AuditLogs from '@/components/security/AuditLogs';
|
||||||
|
import ComplianceMonitor from '@/components/security/ComplianceMonitor';
|
||||||
|
import { Shield } from 'lucide-react';
|
||||||
|
|
||||||
|
const Security = () => {
|
||||||
|
const [activeTab, setActiveTab] = useState('threats');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 p-6">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center gap-3 mb-6">
|
||||||
|
<Shield className="w-8 h-8 text-orange-600" />
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900">Security Center</h1>
|
||||||
|
<p className="text-gray-600">Monitor and manage system security</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
||||||
|
<TabsList className="grid w-full grid-cols-4 lg:w-auto">
|
||||||
|
<TabsTrigger value="threats">Threat Detection</TabsTrigger>
|
||||||
|
<TabsTrigger value="access">Access Control</TabsTrigger>
|
||||||
|
<TabsTrigger value="audit">Audit Logs</TabsTrigger>
|
||||||
|
<TabsTrigger value="compliance">Compliance</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="threats">
|
||||||
|
<ThreatDetection />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="access">
|
||||||
|
<AccessControl />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="audit">
|
||||||
|
<AuditLogs />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="compliance">
|
||||||
|
<ComplianceMonitor />
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Security;
|
||||||
52
src/pages/dashboard/Sustainability.tsx
Normal file
52
src/pages/dashboard/Sustainability.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import CarbonFootprint from '@/components/sustainability/CarbonFootprint';
|
||||||
|
import EnergyManagement from '@/components/sustainability/EnergyManagement';
|
||||||
|
import WasteTracking from '@/components/sustainability/WasteTracking';
|
||||||
|
import SustainabilityGoals from '@/components/sustainability/SustainabilityGoals';
|
||||||
|
import { Leaf } from 'lucide-react';
|
||||||
|
|
||||||
|
const Sustainability = () => {
|
||||||
|
const [activeTab, setActiveTab] = useState('carbon');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 p-6">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center gap-3 mb-6">
|
||||||
|
<Leaf className="w-8 h-8 text-green-600" />
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900">Sustainability Dashboard</h1>
|
||||||
|
<p className="text-gray-600">Track and improve environmental impact</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
||||||
|
<TabsList className="grid w-full grid-cols-4 lg:w-auto">
|
||||||
|
<TabsTrigger value="carbon">Carbon Footprint</TabsTrigger>
|
||||||
|
<TabsTrigger value="energy">Energy</TabsTrigger>
|
||||||
|
<TabsTrigger value="waste">Waste</TabsTrigger>
|
||||||
|
<TabsTrigger value="goals">Goals</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="carbon">
|
||||||
|
<CarbonFootprint />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="energy">
|
||||||
|
<EnergyManagement />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="waste">
|
||||||
|
<WasteTracking />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="goals">
|
||||||
|
<SustainabilityGoals />
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sustainability;
|
||||||
52
src/pages/dashboard/VehicleManagement.tsx
Normal file
52
src/pages/dashboard/VehicleManagement.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import FleetOverview from '@/components/vehicles/FleetOverview';
|
||||||
|
import VehicleTracking from '@/components/vehicles/VehicleTracking';
|
||||||
|
import MaintenanceSchedule from '@/components/vehicles/MaintenanceSchedule';
|
||||||
|
import DriverManagement from '@/components/vehicles/DriverManagement';
|
||||||
|
import { Car } from 'lucide-react';
|
||||||
|
|
||||||
|
const VehicleManagement = () => {
|
||||||
|
const [activeTab, setActiveTab] = useState('fleet');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 p-6">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center gap-3 mb-6">
|
||||||
|
<Car className="w-8 h-8 text-orange-600" />
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900">Vehicle Management</h1>
|
||||||
|
<p className="text-gray-600">Monitor and manage your fleet</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
||||||
|
<TabsList className="grid w-full grid-cols-4 lg:w-auto">
|
||||||
|
<TabsTrigger value="fleet">Fleet Overview</TabsTrigger>
|
||||||
|
<TabsTrigger value="tracking">Tracking</TabsTrigger>
|
||||||
|
<TabsTrigger value="maintenance">Maintenance</TabsTrigger>
|
||||||
|
<TabsTrigger value="drivers">Drivers</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="fleet">
|
||||||
|
<FleetOverview />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="tracking">
|
||||||
|
<VehicleTracking />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="maintenance">
|
||||||
|
<MaintenanceSchedule />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="drivers">
|
||||||
|
<DriverManagement />
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VehicleManagement;
|
||||||
Reference in New Issue
Block a user