This commit is contained in:
gpt-engineer-app[bot]
2026-02-27 00:55:33 +00:00
parent f6023e3cb3
commit 96e316aa8e
5 changed files with 308 additions and 24 deletions
+136
View File
@@ -0,0 +1,136 @@
import { CheckCircle, XCircle, Clock, MessageSquare } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { useModelStore, type ChecklistItem } from '@/stores/useModelStore';
import { useState } from 'react';
import { toast } from 'sonner';
function ChecklistRow({ item }: { item: ChecklistItem }) {
const { setChecklistItemStatus, setChecklistItemNote } = useModelStore();
const [showNote, setShowNote] = useState(item.status === 'rejected');
const handleApprove = () => {
setChecklistItemStatus(item.id, 'approved');
setShowNote(false);
toast.success(`"${item.label}" aprovado`);
};
const handleReject = () => {
setChecklistItemStatus(item.id, 'rejected');
setShowNote(true);
toast.error(`"${item.label}" reprovado — adicione uma anotação`);
};
const statusColor =
item.status === 'approved' ? 'text-success' :
item.status === 'rejected' ? 'text-destructive' :
'text-muted-foreground';
const StatusIcon =
item.status === 'approved' ? CheckCircle :
item.status === 'rejected' ? XCircle :
Clock;
return (
<div className="rounded-lg border bg-muted/30 p-3 space-y-2">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<StatusIcon className={`h-4 w-4 shrink-0 ${statusColor}`} />
<span className="font-mono text-xs text-foreground truncate">{item.label}</span>
</div>
<div className="flex gap-1 shrink-0">
<Button
variant={item.status === 'approved' ? 'default' : 'ghost'}
size="icon"
className="h-7 w-7"
onClick={handleApprove}
title="Aprovar"
>
<CheckCircle className="h-3.5 w-3.5" />
</Button>
<Button
variant={item.status === 'rejected' ? 'destructive' : 'ghost'}
size="icon"
className="h-7 w-7"
onClick={handleReject}
title="Reprovar"
>
<XCircle className="h-3.5 w-3.5" />
</Button>
</div>
</div>
{(showNote || item.status === 'rejected') && (
<div className="space-y-1">
<div className="flex items-center gap-1">
<MessageSquare className="h-3 w-3 text-muted-foreground" />
<span className="font-mono text-[10px] text-muted-foreground">Anotação</span>
</div>
<Textarea
className="h-16 font-mono text-xs resize-none bg-background"
placeholder="Descreva o problema encontrado…"
value={item.note}
onChange={(e) => setChecklistItemNote(item.id, e.target.value)}
/>
</div>
)}
</div>
);
}
export function InspectionChecklist() {
const { checklist, resetChecklist } = useModelStore();
const approved = checklist.filter(i => i.status === 'approved').length;
const rejected = checklist.filter(i => i.status === 'rejected').length;
const total = checklist.length;
return (
<div className="space-y-3">
<div className="flex items-center justify-between">
<h3 className="font-mono text-xs font-semibold uppercase tracking-widest text-muted-foreground">
Checklist de Inspeção
</h3>
<Button variant="ghost" size="sm" className="h-6 text-[10px]" onClick={resetChecklist}>
Resetar
</Button>
</div>
{/* Progress summary */}
<div className="flex items-center gap-3 rounded-lg border bg-muted/30 px-3 py-2">
<div className="flex-1">
<div className="h-1.5 rounded-full bg-muted overflow-hidden">
<div
className="h-full rounded-full bg-primary transition-all"
style={{ width: `${((approved + rejected) / total) * 100}%` }}
/>
</div>
</div>
<span className="font-mono text-[10px] text-muted-foreground shrink-0">
{approved + rejected}/{total}
</span>
</div>
{/* Status badges */}
<div className="flex gap-2">
{approved > 0 && (
<span className="font-mono text-[10px] text-success flex items-center gap-1">
<CheckCircle className="h-3 w-3" /> {approved}
</span>
)}
{rejected > 0 && (
<span className="font-mono text-[10px] text-destructive flex items-center gap-1">
<XCircle className="h-3 w-3" /> {rejected}
</span>
)}
</div>
{/* Items */}
<div className="space-y-2">
{checklist.map(item => (
<ChecklistRow key={item.id} item={item} />
))}
</div>
</div>
);
}