This commit is contained in:
Jordy Hoogeveen
2026-09-10 14:03:34 +02:00
parent 09cc6ae488
commit 1b14553417
12 changed files with 299 additions and 58 deletions
+33 -10
View File
@@ -1,6 +1,7 @@
import { useState } from "react";
import { useApp } from "../context/AppContext.jsx";
import { fmt, fmtDatum } from "../utils/format.js";
import { useKolomBreedtes } from "../hooks/useKolomBreedtes.js";
import { PURPLE, PURPLE_LIGHT, GREEN, RED, CAT_COLORS } from "../constants/index.js";
import {
VCard, DonutChart, Overlay, ModalBox, ModalHeader, ModalFooter,
@@ -250,8 +251,22 @@ function EVVoortgangTabel() {
const removeRow = (datum) => setEvRows(evRows.filter((r) => r.datum !== datum));
const th = { padding: "8px 10px", fontSize: 11, color: T.muted, fontWeight: 600, textAlign: "left", whiteSpace: "nowrap", background: T.card, position: "sticky", top: 0, zIndex: 1, borderBottom: `1px solid ${T.border}` };
const td = { padding: "7px 10px", fontSize: 12, color: T.text, borderBottom: `1px solid ${T.border}` };
// Kolommen in weergave-volgorde, met hun standaardbreedte. De categorieën
// zijn dynamisch, dus de lijst wordt per render opgebouwd.
const kolommen = [
{ id: "datum", breedte: 100 },
...cats.map((c) => ({ id: c.id, breedte: 100 })),
{ id: "nettoWaarde", breedte: 115 },
{ id: "verschil", breedte: 105 },
{ id: "opmerkingen", breedte: 150 },
...(!locked ? [{ id: "acties", breedte: 75 }] : []),
];
const { breedtes, totaal, grip } = useKolomBreedtes("ev_kolom_breedtes", kolommen);
// overflow/ellipsis horen bij tableLayout "fixed": de inhoud rekt de kolom
// niet meer op, dus zonder afkappen loopt lange tekst de buurcel binnen.
const th = { padding: "8px 10px", fontSize: 11, color: T.muted, fontWeight: 600, textAlign: "left", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", background: T.popupBg, position: "sticky", top: 0, zIndex: 1, borderBottom: `1px solid ${T.border}` };
const td = { padding: "7px 10px", fontSize: 12, color: T.text, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", borderBottom: `1px solid ${T.border}` };
return (
<div>
@@ -326,15 +341,22 @@ function EVVoortgangTabel() {
{evRows.length > 0 ? (
<div style={{ overflowX: "auto" }}>
<div style={{ maxHeight: 340, overflowY: "auto" }}>
<table style={{ width: "100%", borderCollapse: "collapse", minWidth: 600 }}>
<table style={{ width: totaal, borderCollapse: "collapse", tableLayout: "fixed" }}>
<colgroup>
{kolommen.map((k) => <col key={k.id} style={{ width: breedtes[k.id] }} />)}
</colgroup>
<thead>
<tr>
<th style={th}>Datum</th>
{cats.map((c) => <th key={c.id} style={{ ...th, color: c.color }}>{c.naam}</th>)}
<th style={th}>Netto Waarde</th>
<th style={th}>Verschil</th>
<th style={th}>Opmerkingen</th>
{!locked && <th style={th}></th>}
<th style={th}>Datum<span {...grip("datum")} /></th>
{cats.map((c) => (
<th key={c.id} style={{ ...th, color: c.color }}>
{c.naam}<span {...grip(c.id)} />
</th>
))}
<th style={th}>Netto Waarde<span {...grip("nettoWaarde")} /></th>
<th style={th}>Verschil<span {...grip("verschil")} /></th>
<th style={th}>Opmerkingen<span {...grip("opmerkingen")} /></th>
{!locked && <th style={th}><span {...grip("acties")} /></th>}
</tr>
</thead>
<tbody>
@@ -349,7 +371,8 @@ function EVVoortgangTabel() {
{cats.map((c) => <td key={c.id} style={{ ...td, color: c.color }}>{fmt(row[c.id] || 0)}</td>)}
<td style={{ ...td, fontWeight: 700, color: PURPLE_LIGHT }}>{fmt(row.nettoWaarde || 0)}</td>
<td style={{ ...td, fontWeight: 700, color: vColor }}>{vLabel}</td>
<td style={{ ...td, color: T.muted }}>{row.opmerkingen || "—"}</td>
{/* title: bij een smalle kolom is de tekst afgekapt */}
<td style={{ ...td, color: T.muted }} title={row.opmerkingen || ""}>{row.opmerkingen || "—"}</td>
{!locked && (
<td style={td}>
<div style={{ display: "flex", gap: 6 }}>
+28 -10
View File
@@ -1,6 +1,7 @@
import { useState } from "react";
import { useApp } from "../context/AppContext.jsx";
import { fmt, fmtDatum } from "../utils/format.js";
import { useKolomBreedtes } from "../hooks/useKolomBreedtes.js";
import { PURPLE, PURPLE_LIGHT, RED, GREEN } from "../constants/index.js";
import { VCard, DonutChart, Overlay, ModalBox, ModalHeader, ModalFooter } from "../components/ui/index.jsx";
@@ -261,8 +262,21 @@ export default function VoortgangTab() {
setData({ ...data, schuld: { ...schuld, schuldHistory: schuldHistory.filter((s) => s.datum !== datum) } });
};
const th = { padding: "8px 10px", fontSize: 11, color: T.muted, fontWeight: 600, textAlign: "left", whiteSpace: "nowrap", background: T.card, position: "sticky", top: 0, zIndex: 1, borderBottom: `1px solid ${T.border}` };
const td = { padding: "7px 10px", fontSize: 12, color: T.text, borderBottom: `1px solid ${T.border}` };
// Kolommen in weergave-volgorde, met hun standaardbreedte.
const kolommen = [
{ id: "datum", breedte: 120 },
{ id: "ev", breedte: 175 },
{ id: "schuld", breedte: 160 },
{ id: "netto", breedte: 175 },
{ id: "opmerkingen", breedte: 340 },
...(!locked ? [{ id: "acties", breedte: 90 }] : []),
];
const { breedtes, totaal, grip } = useKolomBreedtes("voortgang_kolom_breedtes", kolommen);
// overflow/ellipsis horen bij tableLayout "fixed": de inhoud rekt de kolom
// niet meer op, dus zonder afkappen loopt lange tekst de buurcel binnen.
const th = { padding: "8px 10px", fontSize: 11, color: T.muted, fontWeight: 600, textAlign: "left", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", background: T.popupBg, position: "sticky", top: 0, zIndex: 1, borderBottom: `1px solid ${T.border}` };
const td = { padding: "7px 10px", fontSize: 12, color: T.text, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", borderBottom: `1px solid ${T.border}` };
return (
<div>
@@ -396,15 +410,18 @@ export default function VoortgangTab() {
)}
{voortgangRows.length > 0 ? (
<div style={{ overflowX: "auto" }}>
<table style={{ width: "100%", borderCollapse: "collapse", minWidth: 560 }}>
<table style={{ width: totaal, borderCollapse: "collapse", tableLayout: "fixed" }}>
<colgroup>
{kolommen.map((k) => <col key={k.id} style={{ width: breedtes[k.id] }} />)}
</colgroup>
<thead>
<tr>
<th style={th}>Datum</th>
<th style={{ ...th, color: GREEN }}>Eigen Vermogen</th>
<th style={{ ...th, color: RED }}>Schuld</th>
<th style={{ ...th, color: PURPLE_LIGHT }}>Nettowaarde</th>
<th style={th}>Opmerkingen</th>
{!locked && <th style={th}></th>}
<th style={th}>Datum<span {...grip("datum")} /></th>
<th style={{ ...th, color: GREEN }}>Eigen Vermogen<span {...grip("ev")} /></th>
<th style={{ ...th, color: RED }}>Schuld<span {...grip("schuld")} /></th>
<th style={{ ...th, color: PURPLE_LIGHT }}>Nettowaarde<span {...grip("netto")} /></th>
<th style={th}>Opmerkingen<span {...grip("opmerkingen")} /></th>
{!locked && <th style={th}><span {...grip("acties")} /></th>}
</tr>
</thead>
<tbody>
@@ -414,7 +431,8 @@ export default function VoortgangTab() {
<td style={{ ...td, color: GREEN, fontWeight: 600 }}>{row.ev !== null ? fmt(row.ev) : "—"}</td>
<td style={{ ...td, color: RED, fontWeight: 600 }}>{row.schuld !== null ? fmt(row.schuld) : "—"}</td>
<td style={{ ...td, fontWeight: 700, color: row.netto !== null ? (row.netto >= 0 ? GREEN : RED) : T.muted }}>{row.netto !== null ? fmt(row.netto) : "—"}</td>
<td style={{ ...td, color: T.muted }}>{row.opmerkingen || "—"}</td>
{/* title: bij een smalle kolom is de tekst afgekapt */}
<td style={{ ...td, color: T.muted }} title={row.opmerkingen || ""}>{row.opmerkingen || "—"}</td>
{!locked && (
<td style={{ ...td, whiteSpace: "nowrap" }}>
<button onClick={() => setEditRow(row)} style={{ padding: "2px 8px", background: `${PURPLE}22`, border: `1px solid ${PURPLE}44`, borderRadius: 6, color: PURPLE_LIGHT, cursor: "pointer", fontSize: 12, marginRight: 4 }}>✏️</button>