Esketit - Add Net Return and Colorize Fields

Adds Net Return to the statement and colorizes contributing fields.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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);

})();