FinecoBank.com MyCards: Show only the credit card transactions

This script adds a button in the page "My Cards" of FinecoBank.com that allows to show the list (and the total amount) of the only credit card transactions.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name           FinecoBank.com MyCards: Show only the credit card transactions
// @name:it        FinecoBank.com MyCards: Mostra soltanto le operazioni della carta di credito
// @description    This script adds a button in the page "My Cards" of FinecoBank.com that allows to show the list (and the total amount) of the only credit card transactions.
// @description:it Questo script aggiunge un bottone nella pagina "My Cards" di FinecoBank.com che consente di visualizzare la lista (e l'ammontare totale) delle sole operazioni con carta di credito.
// @match          https://finecobank.com/*
// @grant          none
// @require        https://update.greasyfork.org/scripts/547732/1651464/BasicLib.js
//// @run-at         document-start
// @version        1.2.1
// @author         Cyrano68
// @license        MIT
// @namespace https://greasyfork.org/users/788550
// ==/UserScript==

(function()
{
    "use strict";

    const blib = window.BasicLib;
    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: Using library 'BasicLib' (version: ${blib.getVersion()})`);

    const myVersion = GM_info.script.version;
    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: HELLO! Loading script (version: ${myVersion})...`);

    let currUrl = window.location.href;
    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: currUrl='${currUrl}'`);

    const targetUrls = ["https://finecobank.com/conto-e-carte/mycards", "https://finecobank.com/pvt/banking/mycards"];
    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: targetUrls='${targetUrls}'`);

    document.addEventListener("DOMContentLoaded", onDOMContentLoaded);
    window.addEventListener("load", onWindowLoaded);

    function onDOMContentLoaded()
    {
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onDOMContentLoaded - document.readyState=${document.readyState}`);

        const myCSS = document.createElement("style");

        // SEE: https://getcssscan.com/css-buttons-examples
        myCSS.textContent = `
            .button-3 {
                appearance: none;
                background-color: #2ea44f;
                border: 1px solid rgba(27, 31, 35, .15);
                border-radius: 6px;
                box-shadow: rgba(27, 31, 35, .1) 0 1px 0;
                box-sizing: border-box;
                color: #fff;
                cursor: pointer;
                display: inline-block;
                font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
                font-size: 14px;
                font-weight: 600;
                line-height: 20px;
                padding: 6px 16px;
                position: relative;
                text-align: center;
                text-decoration: none;
                user-select: none;
                -webkit-user-select: none;
                touch-action: manipulation;
                vertical-align: middle;
                white-space: nowrap;
            }
            .button-3:focus:not(:focus-visible):not(.focus-visible) {
                box-shadow: none;
                outline: none;
            }
            .button-3:hover {
                background-color: #2c974b;
            }
            .button-3:focus {
                box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px;
                outline: none;
            }
            .button-3:disabled {
                background-color: #94d3a2;
                border-color: rgba(27, 31, 35, .1);
                color: rgba(255, 255, 255, .8);
                cursor: default;
            }
            .button-3:active {
                background-color: #298e46;
                box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset;
            }
        `;

        document.body.appendChild(myCSS);
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onDOMContentLoaded - myCSS.outerHTML='${myCSS.outerHTML}'`);
    }

    function onWindowLoaded()
    {
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onWindowLoaded - document.readyState=${document.readyState}`);

        let index = {value: -1};
        if (blib.textMatchesArray(currUrl, targetUrls, index))
        {
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onWindowLoaded - Function 'blib.textMatchesArray(currUrl, targetUrls, index)' returned true, index=${index.value}`);
            addMyObjects();
        }

        // Sometimes the javascript is not able to understand when the url changed, expecially in a SPA (single-page-application).
        // Therefore I start a timer that periodically will check the current url and, if needed, add/remove the "MyObjects".
        // NOTE: The start of the "CheckUrlTimer" is delayed of a random value.
        const delay_ms = blib.getMathRandomInteger(1234);
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onWindowLoaded - delay_ms=${delay_ms}`);
        setTimeout(checkUrl, delay_ms);
    }

    function checkUrl()
    {
        blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: checkUrl");

        let timerId = 0;
        const interval_ms = 1234; // 1.234s

        timerId = blib.setInterval2((inputTimerId) =>
        {
            // NOTE: The "inputTimerId" will be undefined when this callback is called by the "setInterval" function
            // and will have a valid value when this callback is called by the "setInterval2" function.
            //

            const effectiveTimerId = (inputTimerId === undefined) ? timerId : inputTimerId;
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onCheckUrlTimeout - timerId=${timerId}, inputTimerId=${inputTimerId}, effectiveTimerId=${effectiveTimerId}`);

            const prevUrl = currUrl;
            currUrl = window.location.href;
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onCheckUrlTimeout - prevUrl='${prevUrl}, currUrl='${currUrl}'`);

            if (currUrl !== prevUrl)
            {
                let index = {value: -1};
                if (blib.textMatchesArray(currUrl, targetUrls, index))
                {
                    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onCheckUrlTimeout - Function 'blib.textMatchesArray(currUrl, targetUrls, index)' returned true, index=${index.value} - Entered in the target url '${targetUrls[index.value]}'`);
                    addMyObjects();
                }
                else if (blib.textMatchesArray(prevUrl, targetUrls, index))
                {
                    blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onCheckUrlTimeout - Function 'blib.textMatchesArray(prevUrl, targetUrls, index)' returned true, index=${index.value} - Exited from the target url '${targetUrls[index.value]}'`);
                    removeMyObjects();
                }
            }
        }, interval_ms, false);
    }

    function addMyObjects()
    {
        blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: addMyObjects");

        let timerId = 0;
        const interval_ms = 250;

        timerId = blib.setInterval2((inputTimerId) =>
        {
            // NOTE: The "inputTimerId" will be undefined when this callback is called by the "setInterval" function
            // and will have a valid value when this callback is called by the "setInterval2" function.
            //

            const effectiveTimerId = (inputTimerId === undefined) ? timerId : inputTimerId;
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - timerId=${timerId}, inputTimerId=${inputTimerId}, effectiveTimerId=${effectiveTimerId}`);

            const divMovimenti = document.querySelector("div.movimenti-container");
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - divMovimenti=${divMovimenti}`);
            if (divMovimenti !== null)
            {
                blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - data READY");

                clearInterval(effectiveTimerId);
                blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - TIMER STOPPED - effectiveTimerId=${effectiveTimerId}`);

                // Create a new button that will allow to show only the credit card entries.
                const myButton = Object.assign(document.createElement("button"), {id: "myButton", textContent: "SHOW ONLY CREDIT CARD", className: "button-3"});
                myButton.addEventListener("click", showOnlyCC);
                blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - myButton.outerHTML='${myButton.outerHTML}'`);

                // The button is placed before the "divMovimenti".
                divMovimenti.before(myButton);

                blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - DONE`);
            }
            else
            {
                blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: onAddMyObjectsTimeout - data NOT READY... wait");
            }
        }, interval_ms, true);
    }

    function removeMyObjects()
    {
        blib.consoleLog("==> FinecoBank_com_Inbox_DeleteAll: removeMyObjects");

        const myButton = document.querySelector("button#myButton");
        if ((myButton !== undefined) && (myButton !== null))
        {
            myButton.remove();
        }

        const mySpan = document.querySelector("span#mySpan");
        if ((mySpan !== undefined) && (mySpan !== null))
        {
            mySpan.remove();
        }
    }

    function showOnlyCC()
    {
        blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: showOnlyCC");

        // First of all delete the span tag (eventually added in a previous click) that shows the total amount of the credit card transactions.
        const mySpan = document.querySelector("span#mySpan");
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: showOnlyCC - mySpan=${mySpan}`);
        if (mySpan !== null)
        {
            mySpan.remove();
        }

        // Then remove the bancomat entries.
        const bancomatEntries = document.querySelectorAll("div.movimenti-container div.text-right > img[src$='Bancomat.svg']");
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: showOnlyCC - bancomatEntries.length=${bancomatEntries.length}`);

        // Sometimes there was a problem when the bancomat entries were removed. In details, it happened when in the same day there was a visa entry and a bancomat entry.
        // After the bancomat entry was removed if I tried to expand the visa entry (in order to see the details of the transaction) an error was generated.
        // Therefore I decided to hide the bancomat entries instead of remove them.
        bancomatEntries.forEach((bancomatEntry, i) =>
        {
            // The bancomat entries will be hidden.
            const divAccordionWrapper = bancomatEntry.closest("div.accordionWrapper");
            blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: showOnlyCC - i=${i}, divAccordionWrapper=${divAccordionWrapper}`);
            if (divAccordionWrapper !== null)
            {
                divAccordionWrapper.style.display = "none";  // Hide node.
            }
        });

        // Finally calculate the total amount of the credit card transactions.
        calculateTotalCC();
    }

    function calculateTotalCC()
    {
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: calculateTotalCC`);

        const allEntries = document.querySelectorAll("div.accordionWrapper");
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: calculateTotalCC - allEntries.length=${allEntries.length}`);

        const ccEntries = Array.from(allEntries).filter((entry) => {return (entry.style.display !== "none");});
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: calculateTotalCC - ccEntries.length=${ccEntries.length}`);

        let totalCC = 0;
        ccEntries.forEach((ccEntry, i) =>
        {
            //consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: calculateTotalCC - i=${i}`);
            const spanAmount = ccEntry.querySelector("div.text-right.amountDetail > span.detailAmount");

            let amountText = spanAmount.textContent.slice(0,-4);

            // Try to understand the type of decimal point (dot or comma) used in the page (it is supposed that there are always two digits after the decimal point).
            if (amountText.slice(-3,-2) === ",")
            {
                // The decimal point is a comma (",")... therefore remove the "thousand" separators (".") and transform the comma decimal point in dot decimal point.
                amountText = amountText.replace(/\./g,"").replace(/\,/g,".");
            }
            else
            {
                // The decimal point is a dot (".")... Therefore only remove the "thousand" separators (",").
                amountText = amountText.replace(/\,/g,"");
            }

            // Now the variable "amountText2" is a string that contains numbers and at most the dot decimal point... i.e it can be parsed with "parseFloat".
            const amountValue = parseFloat(amountText);
            totalCC += amountValue;
        });

        addMySpan(totalCC);
    }

    function addMySpan(totalCC)
    {
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: addMySpan - totalCC=${totalCC}`);

        // Add a span (next to the new button) that shows the total amount of the credit card transactions.
        const totalCCText = " TOTAL: " + Number(Math.abs(totalCC)).toLocaleString("it-IT", {style: "currency", currency: "EUR"});
        const mySpan = Object.assign(document.createElement("span"), {id: "mySpan", textContent: totalCCText, style: "color: blue; font-weight: bold; font-size: 16px"});
        blib.consoleLog(`==> FinecoBank_com_MyCards_ShowOnlyCC: addMySpan - mySpan.outerHTML='${mySpan.outerHTML}'`);

        const myButton = document.querySelector("button#myButton");

        // The span is placed after the "myButton".
        myButton.after(mySpan);
    }

    blib.consoleLog("==> FinecoBank_com_MyCards_ShowOnlyCC: Script loaded");
})();