Spaces:
Sleeping
Sleeping
| 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; | |