HeatTransPlan / frontend /src /components /analysis /HeatPumpTable.tsx
drzg15's picture
Initial code commit with LFS for binaries
c993983
/** HeatPumpTable β€” shows available/excluded heat pumps with comparison data. */
import { useState } from 'react';
import { useAnalysisStore } from '../../store/analysisStore';
export default function HeatPumpTable() {
const hpiResult = useAnalysisStore((s) => s.hpiResult);
const [isExcludedOpen, setIsExcludedOpen] = useState(false);
if (!hpiResult) return null;
const available = hpiResult.heat_pumps.filter((hp) => hp.available);
const excluded = hpiResult.excluded_heat_pumps;
if (available.length === 0 && excluded.length === 0) return null;
return (
<div className="pa-hp-table-wrap">
{/* ── Available heat pumps ── */}
{available.length > 0 && (
<>
<p className="pa-hp-section-label"> Integrable heat pumps</p>
<table className="pa-table pa-hp-table">
<thead>
<tr>
<th>Heat Pump</th>
<th>COP</th>
<th>T_source (Β°C)</th>
<th>T_sink (Β°C)</th>
<th>Q_source (kW)</th>
<th>Q_sink (kW)</th>
</tr>
</thead>
<tbody>
{available
.sort((a, b) => (b.cop ?? 0) - (a.cop ?? 0))
.map((hp) => (
<tr key={hp.name}>
<td>{hp.name}</td>
<td>{hp.cop?.toFixed(2) ?? 'β€”'}</td>
<td>{hp.t_source?.toFixed(1) ?? 'β€”'}</td>
<td>{hp.t_sink?.toFixed(1) ?? 'β€”'}</td>
<td>{hp.q_source?.toFixed(1) ?? 'β€”'}</td>
<td>{hp.q_sink?.toFixed(1) ?? 'β€”'}</td>
</tr>
))}
</tbody>
</table>
</>
)}
{/* ── Excluded heat pumps β€” collapsible, closed by default ── */}
{excluded.length > 0 && (
<div className="pa-excluded-hp">
<p
className="pa-hp-section-label pa-panel-toggle"
onClick={() => setIsExcludedOpen(!isExcludedOpen)}
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}
>
<span> Heat pumps that cannot be integrated</span>
<span style={{ transform: isExcludedOpen ? 'rotate(0deg)' : 'rotate(-90deg)', transition: 'transform 0.2s' }}>β–Ό</span>
</p>
{isExcludedOpen && (
<div className="pa-excluded-list">
{excluded.map((hp) => (
<div key={hp.name} className="pa-excluded-card">
<div className="pa-excluded-card-header">
<span className="pa-excluded-name">{hp.name}</span>
<span className="pa-excluded-badge">Cannot be integrated</span>
</div>
<div className="pa-excluded-reason">
{hp.reason}
</div>
</div>
))}
</div>
)}
</div>
)}
</div>
);
}