VirtualLabo / src /components /lab /ResultsPanel.tsx
rinogeek's picture
Update
e1633a4
import { Card } from "@/components/ui/card";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
import { Trash2, Download } from "lucide-react";
interface ResultsPanelProps {
results: { observation: string; equation: string; application: string }[];
onClear: () => void;
}
const ResultsPanel = ({ results, onClear }: ResultsPanelProps) => {
const handleClear = () => {
onClear();
};
const handleExportCSV = () => {
// Create CSV content
const headers = ['#', 'Observation', 'Heure'];
const rows = results.map((result, index) => [
index + 1,
`"${result.observation.replace(/"/g, '""')} [Eq: ${result.equation.replace(/"/g, '""')}] [App: ${(result.application || '').replace(/"/g, '""')}]"`, // Escape quotes in CSV
new Date().toLocaleTimeString('fr-FR', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
]);
const csvContent = [
headers.join(','),
...rows.map(row => row.join(','))
].join('\n');
// Create blob and download
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', `observations-${Date.now()}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return (
<Card className="shadow-elegant h-full flex flex-col">
<div className="flex items-center justify-between p-4 border-b border-border">
<div>
<h3 className="font-semibold text-lg">Observations</h3>
<p className="text-xs text-muted-foreground">{results.length} événement(s)</p>
</div>
<div className="flex gap-2">
{results.length > 0 && (
<>
<Button variant="ghost" size="sm" onClick={handleExportCSV} title="Exporter en CSV">
<Download className="w-4 h-4" />
</Button>
<Button variant="ghost" size="sm" onClick={handleClear} title="Effacer">
<Trash2 className="w-4 h-4" />
</Button>
</>
)}
</div>
</div>
<ScrollArea className="flex-1 p-4">
{results.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center py-12">
<div className="text-4xl mb-3">📝</div>
<p className="text-sm text-muted-foreground">
Les résultats de vos expériences apparaîtront ici
</p>
<p className="text-xs text-muted-foreground mt-2 max-w-xs">
Glissez plusieurs substances sur le plan de travail pour observer les réactions
</p>
</div>
) : (
<div className="space-y-3">
{results.map((result, index) => (
<div
key={index}
className="p-3 bg-gradient-card border border-border rounded-lg animate-slide-in flex flex-col gap-2"
>
<div className="flex items-start gap-2">
<div className="w-6 h-6 rounded-full bg-primary/10 text-primary flex items-center justify-center text-xs font-bold flex-shrink-0">
{index + 1}
</div>
<div className="flex-1 min-w-0 break-words">
<p className="text-sm leading-relaxed break-words">{result.observation}</p>
<p className="text-xs text-muted-foreground mt-1">
{new Date().toLocaleTimeString('fr-FR', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})}
</p>
</div>
</div>
{result.equation && (
<div className="mt-1 p-2 bg-muted/50 rounded-md border border-border/50 w-full">
<p className="text-[10px] font-semibold text-muted-foreground mb-1 uppercase tracking-wider">Équation chimique</p>
<p className="text-sm font-mono text-primary font-medium break-words overflow-wrap-anywhere">
{result.equation}
</p>
</div>
)}
{result.application && (
<div className="mt-1 p-2 bg-primary/5 rounded-md border border-primary/20 w-full">
<p className="text-[10px] font-semibold text-primary/80 mb-1 uppercase tracking-wider">Application pratique</p>
<p className="text-sm text-foreground/90 break-words">
{result.application}
</p>
</div>
)}
</div>
))}
</div>
)}
</ScrollArea>
{results.length > 0 && (
<div className="p-3 border-t border-border bg-muted/30">
<p className="text-xs text-muted-foreground">
💾 <span className="font-medium">Conseil :</span> Notez vos observations importantes pour votre compte-rendu
</p>
</div>
)}
</Card>
);
};
export default ResultsPanel;