This commit is contained in:
Jordy Hoogeveen
2026-09-15 14:02:17 +02:00
parent 750dc69e56
commit 0b67f346e1
19 changed files with 449 additions and 161 deletions
+27 -25
View File
@@ -2,7 +2,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 { GREEN, RED, CAT_COLORS } from "../constants/index.js";
import {
VCard, DonutChart, Overlay, ModalBox, ModalHeader, ModalFooter,
EmojiPicker, AppIcon, ConfirmDeleteDialog, EmptyState,
@@ -130,14 +130,14 @@ function AanpassenPopup({ cat, onClose }) {
<div style={{
display: "flex", alignItems: "center", gap: 8,
background: darkMode ? "rgba(255,255,255,0.03)" : "#f8fafc",
border: `1px solid ${T.border}`, borderLeft: `3px solid ${PURPLE}`,
border: `1px solid ${T.border}`, borderLeft: `3px solid ${T.accent}`,
borderRadius: 10, padding: "10px 12px",
}}>
<input value={nieuwNaam}
onChange={(e) => { setNieuwNaam(e.target.value); setErr(""); }}
placeholder="Naam" style={{ ...is, flex: 1 }} />
<EuroInput value={nieuwVal} onChange={setNieuwVal} is={is} T={T} />
<button onClick={addNieuw} style={addBtn}>+ Voeg toe</button>
<button onClick={addNieuw} style={addBtn(T)}>+ Voeg toe</button>
</div>
{err && <ErrMsg msg={err} />}
</div>
@@ -275,12 +275,12 @@ function EVVoortgangTabel() {
<Overlay onClose={closeModal}>
<ModalBox maxWidth={560}>
<ModalHeader
icon="📊" iconBg={PURPLE}
icon="📊" iconBg={T.accent}
title={editDatum ? "Rij bewerken" : "Nieuw geïnvesteerde fiat"}
subtitle="Vul de waarden in voor dit moment"
subtitleColor={T.muted}
onClose={closeModal}
headerBg={darkMode ? `${PURPLE}08` : "#f8f5ff"}
headerBg={darkMode ? `${T.accent}08` : T.inputBg}
T={T}
/>
<div style={{ padding: "20px 22px", overflowY: "auto", maxHeight: "70vh" }}>
@@ -325,7 +325,7 @@ function EVVoortgangTabel() {
</div>
<ModalFooter T={T}>
<button onClick={closeModal} style={cancelBtn(T)}>Annuleren</button>
<button onClick={addRow} style={primaryBtn}>{editDatum ? "Opslaan" : "Toevoegen"}</button>
<button onClick={addRow} style={primaryBtn(T)}>{editDatum ? "Opslaan" : "Toevoegen"}</button>
</ModalFooter>
</ModalBox>
</Overlay>
@@ -334,7 +334,7 @@ function EVVoortgangTabel() {
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 16 }}>
<div style={{ fontWeight: 700, fontSize: 14, color: T.text }}>Geïnvesteerde Fiat</div>
{!locked && (
<button onClick={openModal} style={primaryBtn}>+ Toevoegen</button>
<button onClick={openModal} style={primaryBtn(T)}>+ Toevoegen</button>
)}
</div>
@@ -349,7 +349,9 @@ function EVVoortgangTabel() {
<tr>
<th style={th}>Datum<span {...grip("datum")} /></th>
{cats.map((c) => (
<th key={c.id} style={{ ...th, color: c.color }}>
// title: een lange categorienaam ("Crowdfunding") wordt bij
// de standaardbreedte afgekapt, dus hover geeft de volle naam.
<th key={c.id} style={{ ...th, color: c.color }} title={c.naam}>
{c.naam}<span {...grip(c.id)} />
</th>
))}
@@ -369,14 +371,14 @@ function EVVoortgangTabel() {
<tr key={i}>
<td style={td}>{fmtDatum(row.datum)}</td>
{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: T.accentTekst }}>{fmt(row.nettoWaarde || 0)}</td>
<td style={{ ...td, fontWeight: 700, color: vColor }}>{vLabel}</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 }}>
<button onClick={() => openEdit(row)} style={editBtn}>✏️</button>
<button onClick={() => openEdit(row)} style={editBtn(T)}>✏️</button>
<button onClick={() => removeRow(row.datum)} style={deleteSmBtn}>×</button>
</div>
</td>
@@ -422,7 +424,7 @@ function DoelProgressie({ ev, data, setData, totVerdeling, locked, T }) {
<span style={{ fontWeight: 600, fontSize: 14 }}>Gewenst doel EV</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<span style={{ fontWeight: 700, fontSize: 15, color: PURPLE_LIGHT }}>{fmt(totVerdeling)}</span>
<span style={{ fontWeight: 700, fontSize: 15, color: T.accentTekst }}>{fmt(totVerdeling)}</span>
{editing ? (
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
<span style={{ color: T.muted, fontSize: 13 }}>/</span>
@@ -432,10 +434,10 @@ function DoelProgressie({ ev, data, setData, totVerdeling, locked, T }) {
onKeyDown={(e) => { if (e.key === "Enter") save(); if (e.key === "Escape") setEditing(false); }}
style={{
width: 130, padding: "4px 8px", borderRadius: 8, fontSize: 13,
background: T.inputBg, border: `1px solid ${PURPLE}`, color: T.text, outline: "none",
background: T.inputBg, border: `1px solid ${T.accent}`, color: T.text, outline: "none",
}}
/>
<button onClick={save} style={{ padding: "4px 10px", background: PURPLE, border: "none", borderRadius: 7, color: "#fff", cursor: "pointer", fontSize: 12, fontWeight: 700 }}>OK</button>
<button onClick={save} style={{ padding: "4px 10px", background: T.accent, border: "none", borderRadius: 7, color: "#fff", cursor: "pointer", fontSize: 12, fontWeight: 700 }}>OK</button>
</div>
) : (
<>
@@ -445,13 +447,13 @@ function DoelProgressie({ ev, data, setData, totVerdeling, locked, T }) {
)}
</>
)}
<span style={{ color: PURPLE_LIGHT, fontWeight: 700, fontSize: 13 }}>{Math.round(progressPct * 100)}%</span>
<span style={{ color: T.accentTekst, fontWeight: 700, fontSize: 13 }}>{Math.round(progressPct * 100)}%</span>
</div>
</div>
<div style={{ height: 12, background: "rgba(255,255,255,0.07)", borderRadius: 99, overflow: "hidden" }}>
<div style={{
height: "100%", width: `${progressPct * 100}%`,
background: `linear-gradient(90deg,${PURPLE},#a855f7)`,
background: `linear-gradient(90deg, ${T.accent}, ${T.accentLicht})`,
borderRadius: 99, transition: "width 0.7s ease",
}} />
</div>
@@ -494,9 +496,9 @@ export default function EigenVermogenTab() {
total: fmt(totVerdeling), totalColor: GREEN,
},
{
title: "Geïnvesteerde Fiat", accent: PURPLE_LIGHT,
title: "Geïnvesteerde Fiat", accent: T.accentTekst,
rows: cats.map((c) => ({ label: c.naam, value: evRows.length > 0 ? fmt(sumCat(c.id)) : "—", color: c.color })),
total: evRows.length > 0 ? fmt(totGeinv) : "—", totalColor: PURPLE_LIGHT,
total: evRows.length > 0 ? fmt(totGeinv) : "—", totalColor: T.accentTekst,
},
{
title: "Rendement", accent: "#f59e0b",
@@ -579,16 +581,16 @@ export default function EigenVermogenTab() {
{!locked && (
<div style={{ marginBottom: 16 }}>
<button onClick={() => setShowAddCat(true)} style={{
padding: "10px 20px", background: `${PURPLE}22`,
border: `1px solid ${PURPLE}44`, borderRadius: 10,
color: PURPLE_LIGHT, cursor: "pointer", fontWeight: 700, fontSize: 13,
padding: "10px 20px", background: `${T.accent}22`,
border: `1px solid ${T.accent}44`, borderRadius: 10,
color: T.accentTekst, cursor: "pointer", fontWeight: 700, fontSize: 13,
}}>+ Nieuwe categorie</button>
</div>
)}
{showAddCat && (
<Overlay onClose={() => setShowAddCat(false)}>
<ModalBox maxWidth={400}>
<ModalHeader icon="➕" iconBg={PURPLE} title="Nieuwe categorie" subtitle="Voeg een EV-categorie toe" subtitleColor={PURPLE_LIGHT} onClose={() => setShowAddCat(false)} headerBg={darkMode ? `${PURPLE}08` : "#f8f5ff"} T={T} />
<ModalHeader icon="➕" iconBg={T.accent} title="Nieuwe categorie" subtitle="Voeg een EV-categorie toe" subtitleColor={T.accentTekst} onClose={() => setShowAddCat(false)} headerBg={darkMode ? `${T.accent}08` : T.inputBg} T={T} />
<div style={{ padding: "20px 22px" }}>
<div style={{ fontSize: 11, color: T.muted, fontWeight: 700, textTransform: "uppercase", marginBottom: 6 }}>Naam *</div>
<input autoFocus placeholder="Bijv. Aandelen" value={newNaam}
@@ -608,7 +610,7 @@ export default function EigenVermogenTab() {
</div>
<ModalFooter T={T}>
<button onClick={() => setShowAddCat(false)} style={{ flex: 1, padding: "10px", background: "transparent", border: `1px solid ${T.border}`, borderRadius: 10, color: T.muted, cursor: "pointer", fontWeight: 600, fontSize: 13 }}>Annuleren</button>
<button onClick={addCat} style={{ flex: 2, padding: "10px", background: `linear-gradient(135deg, ${PURPLE}, #a855f7)`, border: "none", borderRadius: 10, color: "#fff", fontWeight: 700, cursor: "pointer", fontSize: 13 }}>Aanmaken</button>
<button onClick={addCat} style={{ flex: 2, padding: "10px", background: T.accentGradient, border: "none", borderRadius: 10, color: "#fff", fontWeight: 700, cursor: "pointer", fontSize: 13 }}>Aanmaken</button>
</ModalFooter>
</ModalBox>
</Overlay>
@@ -668,9 +670,9 @@ function ErrMsg({ msg }) {
}}>{msg}</div>
);
}
const primaryBtn = { padding: "10px 20px", background: PURPLE, border: "none", borderRadius: 8, color: "#fff", fontWeight: 700, cursor: "pointer", fontSize: 13 };
const editBtn = { padding: "2px 10px", background: `${PURPLE}22`, border: `1px solid ${PURPLE}44`, borderRadius: 6, color: PURPLE_LIGHT, cursor: "pointer", fontSize: 12, fontWeight: 600 };
const primaryBtn = (T) => ({ padding: "10px 20px", background: T.accent, border: "none", borderRadius: 8, color: "#fff", fontWeight: 700, cursor: "pointer", fontSize: 13 });
const editBtn = (T) => ({ padding: "2px 10px", background: `${T.accent}22`, border: `1px solid ${T.accent}44`, borderRadius: 6, color: T.accentTekst, cursor: "pointer", fontSize: 12, fontWeight: 600 });
const deleteSmBtn = { padding: "2px 8px", background: "rgba(239,68,68,0.1)", border: "1px solid rgba(239,68,68,0.25)", borderRadius: 6, color: RED, cursor: "pointer", fontSize: 12 };
const trashBtn = { padding: "10px 14px", background: "rgba(239,68,68,0.08)", border: "1px solid rgba(239,68,68,0.25)", borderRadius: 10, color: RED, cursor: "pointer", fontWeight: 600, fontSize: 13 };
const addBtn = { padding: "6px 14px", background: `${PURPLE}22`, border: `1px solid ${PURPLE}44`, borderRadius: 8, color: PURPLE_LIGHT, cursor: "pointer", fontSize: 12, fontWeight: 700, flexShrink: 0 };
const addBtn = (T) => ({ padding: "6px 14px", background: `${T.accent}22`, border: `1px solid ${T.accent}44`, borderRadius: 8, color: T.accentTekst, cursor: "pointer", fontSize: 12, fontWeight: 700, flexShrink: 0 });
const cancelBtn = (T) => ({ padding: "10px", background: "transparent", border: `1px solid ${T.border}`, borderRadius: 10, color: T.muted, cursor: "pointer", fontWeight: 600, fontSize: 13 });