From 7ec360c5d16c8e08b096de18d05f39b3359a15d0 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 19 Sep 2025 15:01:23 +0200 Subject: [PATCH] Implement proper deposit tracking for coin trackers - Added deposit/withdrawal history section to each coin tracker - Created addDepositEntry function for managing deposits - Fixed updateInvestedChart to use actual deposit history instead of flawed logic - Total Deposited Value now reflects actual money invested, not market performance - Portfolio Value and Total Deposited Value are now properly separated - Supports migration of existing Initial Capital as first deposit --- html/rechner/script.js | 226 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 210 insertions(+), 16 deletions(-) diff --git a/html/rechner/script.js b/html/rechner/script.js index 9ff1a00..3627959 100644 --- a/html/rechner/script.js +++ b/html/rechner/script.js @@ -424,6 +424,86 @@ initialCapitalDiv.appendChild(initialCapitalInput); contentDiv.appendChild(initialCapitalDiv); + // Create deposit tracking section + const depositSectionDiv = document.createElement("div"); + depositSectionDiv.style.marginBottom = "10px"; + depositSectionDiv.style.padding = "10px"; + depositSectionDiv.style.border = "1px solid #444"; + depositSectionDiv.style.borderRadius = "5px"; + depositSectionDiv.style.backgroundColor = "#2a2a2a"; + + const depositSectionLabel = document.createElement("h4"); + depositSectionLabel.textContent = "Deposit/Withdrawal History"; + depositSectionLabel.style.marginTop = "0"; + depositSectionLabel.style.marginBottom = "10px"; + depositSectionDiv.appendChild(depositSectionLabel); + + // Deposit list container + const depositListDiv = document.createElement("div"); + depositListDiv.className = "deposit-list"; + depositSectionDiv.appendChild(depositListDiv); + + // Add deposit controls + const addDepositDiv = document.createElement("div"); + addDepositDiv.style.marginTop = "10px"; + + const depositDateInput = document.createElement("input"); + depositDateInput.type = "date"; + depositDateInput.value = getToday(); + depositDateInput.style.marginRight = "5px"; + + const depositAmountInput = document.createElement("input"); + depositAmountInput.type = "number"; + depositAmountInput.step = "0.01"; + depositAmountInput.placeholder = "Amount (+/-)"; + depositAmountInput.style.marginRight = "5px"; + depositAmountInput.style.width = "120px"; + + const depositNotesInput = document.createElement("input"); + depositNotesInput.type = "text"; + depositNotesInput.placeholder = "Notes (optional)"; + depositNotesInput.style.marginRight = "5px"; + depositNotesInput.style.width = "150px"; + + const addDepositBtn = document.createElement("button"); + addDepositBtn.textContent = "Add Deposit/Withdrawal"; + addDepositBtn.style.fontSize = "12px"; + addDepositBtn.addEventListener("click", () => { + if (depositAmountInput.value && depositDateInput.value) { + addDepositEntry(depositListDiv, { + date: depositDateInput.value, + amount: parseFloat(depositAmountInput.value), + notes: depositNotesInput.value || "" + }, trackerId); + depositAmountInput.value = ""; + depositNotesInput.value = ""; + saveCoinTrackers(); + updateInvestedChart(); + } + }); + + addDepositDiv.appendChild(depositDateInput); + addDepositDiv.appendChild(depositAmountInput); + addDepositDiv.appendChild(depositNotesInput); + addDepositDiv.appendChild(addDepositBtn); + depositSectionDiv.appendChild(addDepositDiv); + + contentDiv.appendChild(depositSectionDiv); + + // Load existing deposits if available + if (data && data.deposits && data.deposits.length > 0) { + data.deposits.forEach(deposit => { + addDepositEntry(depositListDiv, deposit, trackerId); + }); + } else if (data && data.initialCapital && parseFloat(data.initialCapital) > 0) { + // Migrate existing initial capital as first deposit + addDepositEntry(depositListDiv, { + date: "2025-01-01", // Default date for migrated data + amount: parseFloat(data.initialCapital), + notes: "Migrated from Initial Capital" + }, trackerId); + } + // Create a container with positioning context for the table const tableWrapper = document.createElement("div"); tableWrapper.className = "table-wrapper"; @@ -621,6 +701,76 @@ updateRowYieldProjections(tr); }; + // Function to add deposit/withdrawal entries to the deposit history + const addDepositEntry = (depositListDiv, depositData, trackerId) => { + const depositDiv = document.createElement("div"); + depositDiv.style.display = "flex"; + depositDiv.style.alignItems = "center"; + depositDiv.style.marginBottom = "5px"; + depositDiv.style.padding = "5px"; + depositDiv.style.backgroundColor = "#3a3a3a"; + depositDiv.style.borderRadius = "3px"; + + const dateSpan = document.createElement("span"); + dateSpan.textContent = depositData.date; + dateSpan.style.minWidth = "100px"; + dateSpan.style.marginRight = "10px"; + + const amountSpan = document.createElement("span"); + const amount = parseFloat(depositData.amount); + amountSpan.textContent = amount >= 0 ? `+$${amount.toFixed(2)}` : `-$${Math.abs(amount).toFixed(2)}`; + amountSpan.style.minWidth = "80px"; + amountSpan.style.marginRight = "10px"; + amountSpan.style.color = amount >= 0 ? "#4CAF50" : "#f44336"; + amountSpan.style.fontWeight = "bold"; + + const notesSpan = document.createElement("span"); + notesSpan.textContent = depositData.notes || ""; + notesSpan.style.flex = "1"; + notesSpan.style.marginRight = "10px"; + notesSpan.style.fontStyle = "italic"; + notesSpan.style.color = "#ccc"; + + const deleteBtn = document.createElement("button"); + deleteBtn.textContent = "×"; + deleteBtn.style.background = "#f44336"; + deleteBtn.style.color = "white"; + deleteBtn.style.border = "none"; + deleteBtn.style.borderRadius = "50%"; + deleteBtn.style.width = "20px"; + deleteBtn.style.height = "20px"; + deleteBtn.style.fontSize = "12px"; + deleteBtn.style.cursor = "pointer"; + deleteBtn.title = "Delete deposit"; + deleteBtn.addEventListener("click", () => { + if (confirm("Are you sure you want to delete this deposit record?")) { + depositDiv.remove(); + saveCoinTrackers(); + updateInvestedChart(); + } + }); + + depositDiv.appendChild(dateSpan); + depositDiv.appendChild(amountSpan); + depositDiv.appendChild(notesSpan); + depositDiv.appendChild(deleteBtn); + + // Insert deposits in chronological order + let inserted = false; + const existingDeposits = depositListDiv.children; + for (let i = 0; i < existingDeposits.length; i++) { + const existingDate = existingDeposits[i].querySelector('span').textContent; + if (depositData.date < existingDate) { + depositListDiv.insertBefore(depositDiv, existingDeposits[i]); + inserted = true; + break; + } + } + if (!inserted) { + depositListDiv.appendChild(depositDiv); + } + }; + // Enhanced version of addDynamicEntry that supports transaction types const addDynamicEntryWithData = (tbody, rowData, trackerId) => { const tr = document.createElement("tr"); @@ -790,19 +940,32 @@ let totalDeposited = {}; let dailyYieldTotals = {}; // Add this to track daily yields - // Calculate total initial capital across all trackers - let totalInitialCapital = 0; - Array.from(trackerDivs).forEach(div => { - if (div.dataset.showInChart === "false") return; - // Get initialCapital value - const initialCapitalInput = div.querySelector(".content input[type='number']"); - if (initialCapitalInput) { - totalInitialCapital += parseFloat(initialCapitalInput.value || "0") || 0; - } - }); + // Collect all deposit data from all trackers + let allDeposits = {}; Array.from(trackerDivs).forEach(div => { if (div.dataset.showInChart === "false") return; + + // Collect deposits for this tracker + const depositListDiv = div.querySelector(".deposit-list"); + if (depositListDiv) { + Array.from(depositListDiv.children).forEach(depositDiv => { + const dateSpan = depositDiv.querySelector('span:nth-child(1)'); + const amountSpan = depositDiv.querySelector('span:nth-child(2)'); + + if (dateSpan && amountSpan) { + const date = dateSpan.textContent; + const amountText = amountSpan.textContent; + const amount = parseFloat(amountText.replace(/[+\-$]/g, '')) * (amountText.startsWith('-') ? -1 : 1); + + if (!allDeposits[date]) { + allDeposits[date] = 0; + } + allDeposits[date] += amount; + } + }); + } + const table = div.querySelector("table.coin-table"); if (table) { const tbody = table.querySelector("tbody"); @@ -829,9 +992,6 @@ // Calculate daily yield in dollars and accumulate for each date const yieldInDollars = currentVal * (dailyYieldPercent / 100); dailyYieldTotals[date] = (dailyYieldTotals[date] || 0) + yieldInDollars; - - // Set totalDeposited to the initial capital for all dates - totalDeposited[date] = totalInitialCapital; } }); for (const date in trackerDaily) { @@ -840,6 +1000,20 @@ } }); + // Calculate cumulative deposits over time + const sortedDepositDates = Object.keys(allDeposits).sort(); + let cumulativeDeposits = 0; + const allDates = new Set([...Object.keys(portfolioValues), ...sortedDepositDates]); + + Array.from(allDates).sort().forEach(date => { + // Add any deposits that occurred on this date + if (allDeposits[date]) { + cumulativeDeposits += allDeposits[date]; + } + // Set total deposited for this date to the cumulative amount + totalDeposited[date] = cumulativeDeposits; + }); + // Update daily yield history with new calculations for (const date in dailyYieldTotals) { dailyYieldHistory[date] = dailyYieldTotals[date]; @@ -861,7 +1035,7 @@ let labels = dates.map(date => new Date(date).toLocaleDateString()); let dailyFeesData = dates.map(date => dailyYieldHistory[date] || 0); let portfolioData = dates.map(date => portfolioValues[date] || persistedHistory[date]); - let depositedData = dates.map(date => totalDeposited[date] || persistedHistory[date] * 0.9); + let depositedData = dates.map(date => totalDeposited[date] || 0); // Update or create the chart if (investedChart) { @@ -1155,6 +1329,26 @@ const initialCapitalInput = div.querySelector(".content input[type='number']"); const initialCapital = initialCapitalInput ? initialCapitalInput.value : "0.00"; + // Get deposit history + const depositListDiv = div.querySelector(".deposit-list"); + const deposits = []; + if (depositListDiv) { + Array.from(depositListDiv.children).forEach(depositDiv => { + const dateSpan = depositDiv.querySelector('span:nth-child(1)'); + const amountSpan = depositDiv.querySelector('span:nth-child(2)'); + const notesSpan = depositDiv.querySelector('span:nth-child(3)'); + + if (dateSpan && amountSpan) { + const date = dateSpan.textContent; + const amountText = amountSpan.textContent; + // Parse amount from "+$123.45" or "-$123.45" format + const amount = parseFloat(amountText.replace(/[+\-$]/g, '')) * (amountText.startsWith('-') ? -1 : 1); + const notes = notesSpan ? notesSpan.textContent : ""; + deposits.push({ date, amount, notes }); + } + }); + } + const table = div.querySelector("table.coin-table"); const tbody = table.querySelector("tbody"); const rows = []; @@ -1171,8 +1365,8 @@ rows.push({ date, time, currentValue, income, compound, dailyYield, notes, created }); }); const hasData = rows.some(row => row.currentValue !== 0 || row.income !== 0 || row.dailyYield !== 0); - if (hasData) { - trackers.push({ id: trackerId, coinName, platform, initialCapital, rows, showInChart, active }); + if (hasData || deposits.length > 0) { + trackers.push({ id: trackerId, coinName, platform, initialCapital, deposits, rows, showInChart, active }); } }); updateCoinTrackersToBackend(trackers);