import React from 'react' import { ParsedRow, ParsedComponent, ParsedExcelResponse } from '../../api/uploads' interface Props { parsed: ParsedExcelResponse rows: ParsedRow[] onChange: (rows: ParsedRow[]) => void } const STANDARD_FIELDS: { key: keyof ParsedRow; label: string; width: number; mono?: boolean }[] = [ { key: 'ebene1', label: 'Level 1', width: 140 }, { key: 'ebene2', label: 'Level 2', width: 120 }, { key: 'baureihe', label: 'Series', width: 160 }, { key: 'pim_id', label: 'PIM-ID', width: 110 }, { key: 'produkt_baureihe', label: 'Product Series', width: 150 }, { key: 'gewaehltes_produkt', label: 'Selected Product', width: 150 }, { key: 'name_cad_modell', label: 'CAD-Modell', width: 190, mono: true }, { key: 'gewuenschte_bildnummer', label: 'Image No.', width: 170, mono: true }, { key: 'lagertyp', label: 'Bearing Type', width: 100 }, ] export default function ExcelSpreadsheet({ parsed, rows, onChange }: Props) { const maxComps = Math.max(0, ...rows.map((r) => r.components.length)) function updateField(ri: number, field: keyof ParsedRow, value: string | boolean | null) { const next = rows.map((r, i) => (i === ri ? { ...r, [field]: value } : r)) onChange(next) } function updateComp(ri: number, ci: number, field: keyof ParsedComponent, value: string) { const next = rows.map((r, i) => { if (i !== ri) return r const comps = r.components.map((c, j) => j === ci ? { ...c, [field]: value || null } : c, ) // If the row doesn't have this component slot yet, pad it while (comps.length <= ci) { comps.push({ part_name: null, material: null, component_type: null, column_index: 11 + comps.length * 2 }) } comps[ci] = { ...comps[ci], [field]: value || null } return { ...r, components: comps } }) onChange(next) } const cell = 'w-full px-2 py-1 text-xs bg-transparent border-0 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-accent rounded focus:bg-surface' const th = 'px-2 py-2 text-left text-xs font-semibold text-content-secondary whitespace-nowrap bg-surface-alt border-b border-r border-border-default sticky top-0 z-10' const td = 'border-b border-r border-border-light p-0' return (

{parsed.template_name || parsed.category_key} — {rows.length} rows

Click any cell to edit before creating the order

{maxComps} component columns
{/* Group header row */} {Array.from({ length: maxComps }, (_, i) => ( ))} {/* Field name row */} {STANDARD_FIELDS.map((f) => ( ))} {Array.from({ length: maxComps }, (_, i) => ( ))} {rows.map((row, ri) => ( {/* Row number */} {/* Standard text fields */} {STANDARD_FIELDS.map((f) => ( ))} {/* Rendering checkbox */} {/* Component pairs */} {Array.from({ length: maxComps }, (_, ci) => { const comp = row.components[ci] return ( ) })} ))}
# Standard Fields Rendering Component {i + 1}
# {f.label} Rendering Part Name Material
{row.row_index} updateField(ri, f.key, e.target.value || null)} className={`${cell} ${f.mono ? 'font-mono' : ''}`} /> updateField(ri, 'medias_rendering', e.target.checked)} className="w-3.5 h-3.5" /> updateComp(ri, ci, 'part_name', e.target.value)} className={`${cell} font-mono`} placeholder="—" /> updateComp(ri, ci, 'material', e.target.value)} className={cell} placeholder="—" />
) }