Esketit - Add Net Return and Colorize Fields

Adds Net Return to the statement and colorizes contributing fields.

// ==UserScript==
// @name         Esketit - Add Net Return and Colorize Fields
// @namespace    http://esketit.com/
// @version      20250729
// @description  Adds Net Return to the statement and colorizes contributing fields.
// @author       rs232
// @match        https://*esketit.com/investor/account-statement
// @icon         https://www.google.com/s2/favicons?sz=32&domain_url=https%3A%2F%2Fwww.esketit.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Define the colors for easy modification
    const DARK_GREEN = "#2E8B57";
    const PALE_GREEN = "#F0FFF0";

    // Define amber colors as requested
    const LIGHTER_AMBER_BACKGROUND = "#FFF8E1"; // A very light, almost cream amber
    const DARKER_AMBER_TEXT = "#E65100";      // A darker, more orange-brown amber

    // Helper function to parse currency strings.
    function parseCurrency(value) {
        if (!value) return 0;
        return parseFloat(value.replace('€', '').trim().replace(/\s/g, '').replace(',', '.')) || 0;
    }

    // Helper function to find a table row by its first cell's text.
    function findRowByLabel(label) {
        const rows = document.querySelectorAll('tr');
        for (const row of rows) {
            const firstCell = row.querySelector('td:first-child');
            if (firstCell && firstCell.textContent.trim() === label) {
                return row;
            }
        }
        return null;
    }

    // Function to apply colors to summary rows based on their value.
    function colorizeSummaryRows() {
        const rowsToColorize = {
            green: ["Interest received", "Bonus received", "Referral bonus received", "Secondary market income"],
            red: ["Secondary market expense"],
            amber: ["Sold on secondary market"]
        };

        // Handle green rows
        rowsToColorize.green.forEach(label => {
            const row = findRowByLabel(label);
            if (row) {
                const valueCell = row.querySelector('td:nth-child(2)');
                const labelCell = row.querySelector('td:first-child');
                const value = valueCell ? parseCurrency(valueCell.textContent) : 0;

                if (value > 0) {
                    labelCell.style.color = DARK_GREEN;
                    valueCell.style.color = DARK_GREEN;
                    row.style.backgroundColor = PALE_GREEN;
                } else {
                    labelCell.style.color = "";
                    valueCell.style.color = "";
                    row.style.backgroundColor = "";
                }
            }
        });

        // Handle red rows
        rowsToColorize.red.forEach(label => {
            const row = findRowByLabel(label);
            if (row) {
                const valueCell = row.querySelector('td:nth-child(2)');
                const labelCell = row.querySelector('td:first-child');
                const value = valueCell ? parseCurrency(valueCell.textContent) : 0;

                if (value < 0) {
                    labelCell.style.color = '#FA5053';
                    valueCell.style.color = '#FA5053';
                    row.style.backgroundColor = "#FFeeea"; // pale red
                } else {
                    labelCell.style.color = "";
                    valueCell.style.color = "";
                    row.style.backgroundColor = "";
                }
            }
        });

        // Handle amber rows with the new lighter background and darker text
        rowsToColorize.amber.forEach(label => {
            const row = findRowByLabel(label);
            if (row) {
                const valueCell = row.querySelector('td:nth-child(2)');
                const labelCell = row.querySelector('td:first-child');
                const value = valueCell ? parseCurrency(valueCell.textContent) : 0;

                if (value > 0) {
                    labelCell.style.color = DARKER_AMBER_TEXT;       // Darker amber text
                    valueCell.style.color = DARKER_AMBER_TEXT;       // Darker amber text
                    row.style.backgroundColor = LIGHTER_AMBER_BACKGROUND; // Lighter amber background
                } else {
                    labelCell.style.color = "";
                    valueCell.style.color = "";
                    row.style.backgroundColor = "";
                }
            }
        });
    }

    // This function will be called periodically to recalculate and update the UI.
    function updateNetReturn() {
        const closingBalanceRow = findRowByLabel("Closing balance");
        const interestReceivedRow = findRowByLabel("Interest received");

        if (closingBalanceRow && interestReceivedRow) {
            const interestValueCell = interestReceivedRow.querySelector('td:nth-child(2)');
            const interestValue = interestValueCell ? parseCurrency(interestValueCell.textContent) : 0;

            if (interestValue !== 0 || findRowByLabel("Secondary market expense")?.querySelector('td:nth-child(2)')?.textContent.trim() !== '€0,00') {
                 let netReturnTotal = 0;
                 const labelsForNetReturn = [
                     "Interest received",
                     "Bonus received",
                     "Referral bonus received",
                     "Secondary market income",
                     "Secondary market expense"
                 ];

                 labelsForNetReturn.forEach(label => {
                     const row = findRowByLabel(label);
                     if (row) {
                         const valueCell = row.querySelector('td:nth-child(2)');
                         if (valueCell) {
                             netReturnTotal += parseCurrency(valueCell.textContent);
                         }
                     }
                 });

                 const formattedNetReturn = `€${netReturnTotal.toFixed(2).replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '\u00A0')}`;
                 let netReturnRow = document.getElementById('net-return-row');

                 const exampleRow = findRowByLabel("Opening balance");
                 const exampleLabelCell = exampleRow ? exampleRow.querySelector('td:first-child') : null;
                 const exampleValueCell = exampleRow ? exampleRow.querySelector('td:nth-child(2)') : null;

                 if (!netReturnRow) {
                     netReturnRow = document.createElement('tr');
                     netReturnRow.id = 'net-return-row';

                     if (exampleRow && exampleRow.hasAttribute('data-v-344f568a')) {
                         netReturnRow.setAttribute('data-v-344f568a', exampleRow.getAttribute('data-v-344f568a'));
                     }

                     const labelCell = exampleLabelCell ? exampleLabelCell.cloneNode(false) : document.createElement('td');
                     const valueCell = exampleValueCell ? exampleValueCell.cloneNode(false) : document.createElement('td');

                     labelCell.textContent = 'Net return';
                     labelCell.style.fontWeight = 'bold';
                     labelCell.style.color = '#ffffff'; // Swapped text color

                     valueCell.textContent = formattedNetReturn;
                     valueCell.style.fontWeight = 'bold';
                     valueCell.style.color = PALE_GREEN; // Swapped text color
                     valueCell.style.textAlign = 'right';

                     netReturnRow.appendChild(labelCell);
                     netReturnRow.appendChild(valueCell);

                     closingBalanceRow.parentNode.insertBefore(netReturnRow, closingBalanceRow.nextSibling);
                 } else {
                     const valueCell = netReturnRow.querySelector('td:nth-child(2)');
                     if (valueCell) {
                         valueCell.textContent = formattedNetReturn;
                         valueCell.style.fontWeight = 'bold';
                         valueCell.style.color = PALE_GREEN; // Swapped text color
                         valueCell.style.textAlign = 'right';
                     }
                     const labelCell = netReturnRow.querySelector('td:first-child');
                     if (labelCell) {
                         labelCell.style.fontWeight = 'bold';
                         labelCell.style.color = PALE_GREEN; // Swapped text color
                     }
                 }
                 netReturnRow.style.backgroundColor = DARK_GREEN; // Swapped background color

                 colorizeSummaryRows();
            }
        }
    }

    // Set up a continuous polling loop to update the Net Return and colors.
    setInterval(updateNetReturn, 500);

})();