import React, { useState, useMemo, useRef, useEffect } from 'react'; import { CopyIcon, ClipboardTableIcon, SearchIcon, TrashIcon, LoadingSpinner, CheckIcon, XMarkIcon } from './Icons'; import { convertArrayToTsv } from '../services/export'; import { translations } from '../constants'; interface StepDisplayProps { title: string; summary?: string[]; headers: string[]; rows: string[][]; onDataChange: (newRows: string[][]) => void; canAddRows?: boolean; canDeleteRows?: boolean; onEnrichRow?: (productName: string, productUrl?: string) => Promise; isEnriching?: boolean; t: typeof translations.de; } export const StepDisplay: React.FC = ({ title, summary, headers, rows, onDataChange, canAddRows = false, canDeleteRows = false, onEnrichRow, isEnriching = false, t }) => { const [copySuccess, setCopySuccess] = useState(''); const [filterQuery, setFilterQuery] = useState(''); const [isAddingRow, setIsAddingRow] = useState(false); const [newRowValue, setNewRowValue] = useState(''); const [newRowUrl, setNewRowUrl] = useState(''); const inputRef = useRef(null); const filteredRows = useMemo(() => { if (!filterQuery) { return rows; } return rows.filter(row => row.some(cell => cell.toLowerCase().includes(filterQuery.toLowerCase()) ) ); }, [rows, filterQuery]); useEffect(() => { if (isAddingRow && inputRef.current) { inputRef.current.focus(); } }, [isAddingRow]); const handleCellChange = (originalRowIndex: number, colIndex: number, value: string) => { const newRows = rows.map((row, rIdx) => rIdx === originalRowIndex ? row.map((cell, cIdx) => cIdx === colIndex ? value : cell) : row ); onDataChange(newRows); }; const fallbackCopyTextToClipboard = (text: string) => { const textArea = document.createElement("textarea"); textArea.value = text; // Ensure textarea is not visible but part of DOM textArea.style.position = "fixed"; textArea.style.left = "-9999px"; textArea.style.top = "0"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { document.execCommand('copy'); setCopySuccess(t.copySuccess); setTimeout(() => setCopySuccess(''), 2000); } catch (err) { console.error('Fallback: Oops, unable to copy', err); setCopySuccess(t.copyFailure); setTimeout(() => setCopySuccess(''), 2000); } document.body.removeChild(textArea); }; const handleCopyToClipboard = (text: string) => { if (!navigator.clipboard) { fallbackCopyTextToClipboard(text); return; } navigator.clipboard.writeText(text).catch(err => { console.error('Failed to copy text: ', err); fallbackCopyTextToClipboard(text); }); }; const handleCopyTable = () => { const tsvString = convertArrayToTsv(headers, filteredRows); if (!navigator.clipboard) { fallbackCopyTextToClipboard(tsvString); return; } navigator.clipboard.writeText(tsvString).then(() => { setCopySuccess(t.copySuccess); setTimeout(() => setCopySuccess(''), 2000); }).catch(err => { console.error('Failed to copy table: ', err); fallbackCopyTextToClipboard(tsvString); }); }; const handleAddRowClick = () => { if (onEnrichRow) { setIsAddingRow(true); } else { const newEmptyRow = Array(headers.length).fill(''); onDataChange([...rows, newEmptyRow]); } }; const handleConfirmAddRow = () => { if (newRowValue.trim() && onEnrichRow) { onEnrichRow(newRowValue.trim(), newRowUrl.trim()); setNewRowValue(''); setNewRowUrl(''); setIsAddingRow(false); } }; const handleCancelAddRow = () => { setNewRowValue(''); setNewRowUrl(''); setIsAddingRow(false); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); handleConfirmAddRow(); } else if (e.key === 'Escape') { handleCancelAddRow(); } }; const handleDeleteRow = (rowIndexToDelete: number) => { const newRows = rows.filter((_, index) => index !== rowIndexToDelete); onDataChange(newRows); }; const getColumnStyle = (header: string): React.CSSProperties => { const lowerHeader = header.toLowerCase(); const wideColumnHeaders = [ 'beschreibung', 'description', 'painpoint', 'gain', 'nutzen', 'benefit', 'kernbotschaft', 'core message', 'li-dm', 'verantwortungsbereich', 'area of responsibility' ]; if (wideColumnHeaders.some(keyword => lowerHeader.includes(keyword))) { return { width: '25%' }; } return {}; }; const loadingText = t.loadingButton.replace('...', ''); const isLoadingCell = (cell: string) => cell.toLowerCase().includes(loadingText.toLowerCase()); return (

{title}

{copySuccess && {copySuccess}}
{summary && summary.length > 0 && (

{t.summaryTitle}

    {summary.map((item, index) =>
  • {item}
  • )}
)}
setFilterQuery(e.target.value)} placeholder={t.filterPlaceholder} className="block w-full rounded-md border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 py-2 pl-10 pr-3 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm" />
{headers.map((header, index) => ( ))} {canDeleteRows && } {filteredRows.map((row, rowIndex) => { const originalRowIndex = rows.findIndex(originalRow => originalRow === row); return ( {row.map((cell, colIndex) => (
{header}Aktionen
{isLoadingCell(cell) ? (
{t.loadingButton}
) : (