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
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user