Codex Deploy
Prepare local Hugging Face deployment
191b322
import React from 'react';
import { QualityCheck, SafetyCheck, User } from '../types';
import {
ShieldCheck,
CheckCircle2,
XCircle,
Clock,
Plus,
Search,
Filter,
AlertTriangle,
Camera,
User as UserIcon,
ChevronRight,
MoreVertical
} from 'lucide-react';
interface QCSafetyProps {
qualityChecks: QualityCheck[];
safetyChecks: SafetyCheck[];
users: User[];
}
const QCSafety: React.FC<QCSafetyProps> = ({ qualityChecks, safetyChecks, users }) => {
const [activeTab, setActiveTab] = React.useState<'QUALITY' | 'SAFETY'>('QUALITY');
const getInspectorName = (uid: string) => {
return users.find(u => u.uid === uid)?.name || 'Unknown Inspector';
};
return (
<div className="space-y-6">
{/* Header & Tabs */}
<div className="bg-white p-4 rounded-2xl border border-slate-200 shadow-sm flex flex-wrap items-center justify-between gap-4">
<div className="flex bg-slate-100 p-1 rounded-xl">
<button
onClick={() => setActiveTab('QUALITY')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-bold text-sm transition-all ${activeTab === 'QUALITY' ? 'bg-white text-blue-600 shadow-sm' : 'text-slate-500 hover:text-slate-700'}`}
>
<CheckCircle2 className="w-4 h-4" />
Quality Checks
</button>
<button
onClick={() => setActiveTab('SAFETY')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-bold text-sm transition-all ${activeTab === 'SAFETY' ? 'bg-white text-blue-600 shadow-sm' : 'text-slate-500 hover:text-slate-700'}`}
>
<ShieldCheck className="w-4 h-4" />
Safety Audits
</button>
</div>
<button className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-xl font-bold text-sm hover:bg-blue-700 transition-all shadow-lg shadow-blue-200">
<Plus className="w-4 h-4" />
{activeTab === 'QUALITY' ? 'New Inspection' : 'New Audit'}
</button>
</div>
{activeTab === 'QUALITY' ? (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{qualityChecks.map(check => (
<div key={check.id} className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden hover:border-blue-300 transition-all group">
<div className="p-6 border-b border-slate-100 bg-slate-50/50 flex items-center justify-between">
<div className="flex items-center gap-4">
<div className={`w-10 h-10 rounded-xl flex items-center justify-center ${
check.status === 'PASSED' ? 'bg-emerald-50 text-emerald-600' :
check.status === 'FAILED' ? 'bg-red-50 text-red-600' : 'bg-amber-50 text-amber-600'
}`}>
{check.status === 'PASSED' ? <CheckCircle2 className="w-6 h-6" /> :
check.status === 'FAILED' ? <XCircle className="w-6 h-6" /> : <Clock className="w-6 h-6" />}
</div>
<div>
<h3 className="font-bold text-slate-800">{check.title}</h3>
<p className="text-xs text-slate-500">{check.location} • {new Date(check.date).toLocaleDateString()}</p>
</div>
</div>
<button className="p-2 text-slate-400 hover:text-slate-600 hover:bg-white rounded-lg transition-all">
<MoreVertical className="w-4 h-4" />
</button>
</div>
<div className="p-6 space-y-4">
<div className="space-y-3">
{check.items.map((item, idx) => (
<div key={idx} className="flex items-start gap-3 p-3 bg-slate-50 rounded-xl">
{item.isOk ? (
<CheckCircle2 className="w-4 h-4 text-emerald-500 mt-0.5 shrink-0" />
) : (
<XCircle className="w-4 h-4 text-red-500 mt-0.5 shrink-0" />
)}
<div>
<p className="text-sm font-medium text-slate-700">{item.description}</p>
{item.remarks && <p className="text-[10px] text-slate-500 mt-1 italic">{item.remarks}</p>}
</div>
</div>
))}
</div>
<div className="flex items-center justify-between pt-4 border-t border-slate-100">
<div className="flex items-center gap-2">
<div className="w-6 h-6 bg-slate-200 rounded-full flex items-center justify-center">
<UserIcon className="w-3 h-3 text-slate-500" />
</div>
<span className="text-[10px] font-bold text-slate-500 uppercase">{getInspectorName(check.inspectorUid)}</span>
</div>
<div className="flex items-center gap-1 text-[10px] font-bold text-blue-600">
<Camera className="w-3 h-3" />
{check.photos?.length || 0} Photos
</div>
</div>
</div>
</div>
))}
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{safetyChecks.map(audit => (
<div key={audit.id} className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm hover:border-blue-300 transition-all group">
<div className="flex items-start justify-between mb-6">
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${
audit.status === 'SAFE' ? 'bg-emerald-50 text-emerald-600' :
audit.status === 'CRITICAL' ? 'bg-red-50 text-red-600' : 'bg-amber-50 text-amber-600'
}`}>
<ShieldCheck className="w-6 h-6" />
</div>
<div className="text-right">
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Safety Score</span>
<p className={`text-2xl font-bold ${
audit.score >= 90 ? 'text-emerald-600' :
audit.score >= 70 ? 'text-amber-600' : 'text-red-600'
}`}>{audit.score}%</p>
</div>
</div>
<h3 className="font-bold text-slate-800 mb-4">Safety Audit - {new Date(audit.date).toLocaleDateString()}</h3>
<div className="space-y-4 mb-6">
<div>
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-2">Hazards Identified</span>
<div className="flex flex-wrap gap-2">
{audit.hazardsIdentified.map((hazard, idx) => (
<span key={idx} className="px-2 py-1 bg-red-50 text-red-600 text-[10px] font-bold rounded-lg border border-red-100">
{hazard}
</span>
))}
</div>
</div>
<div>
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-2">Corrective Actions</span>
<div className="flex flex-wrap gap-2">
{audit.correctiveActions.map((action, idx) => (
<span key={idx} className="px-2 py-1 bg-blue-50 text-blue-600 text-[10px] font-bold rounded-lg border border-blue-100">
{action}
</span>
))}
</div>
</div>
</div>
<div className="flex items-center justify-between pt-4 border-t border-slate-100">
<div className="flex items-center gap-2">
<div className="w-6 h-6 bg-slate-200 rounded-full flex items-center justify-center">
<UserIcon className="w-3 h-3 text-slate-500" />
</div>
<span className="text-[10px] font-bold text-slate-500 uppercase">{getInspectorName(audit.inspectorUid)}</span>
</div>
<span className={`px-2 py-1 rounded-full text-[10px] font-bold border ${
audit.status === 'SAFE' ? 'text-emerald-600 bg-emerald-50 border-emerald-100' :
audit.status === 'CRITICAL' ? 'text-red-600 bg-red-50 border-red-100' : 'text-amber-600 bg-amber-50 border-amber-100'
}`}>
{audit.status}
</span>
</div>
</div>
))}
</div>
)}
</div>
);
};
export default QCSafety;