Total Gained

Display total stat gained for selected period on the Log page.

// ==UserScript==
// @name         Total Gained
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @description  Display total stat gained for selected period on the Log page.
// @author       Caspie [2794025]
// @license      MIT License
// @match        https://www.torn.com/page.php?sid=log&log=5300
// @match        https://www.torn.com/page.php?sid=log&log=5300&*
// @match        https://www.torn.com/page.php?sid=log&log=5301
// @match        https://www.torn.com/page.php?sid=log&log=5301&*
// @match        https://www.torn.com/page.php?sid=log&log=5302
// @match        https://www.torn.com/page.php?sid=log&log=5302&*
// @match        https://www.torn.com/page.php?sid=log&log=5303
// @match        https://www.torn.com/page.php?sid=log&log=5303&*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @grant        none
// ==/UserScript==

(function(w, d) {
    'use strict';

    const activityLog = d.querySelector('.activity-log');

    if (activityLog) {
        new MutationObserver((entries) => {
            for (const entry of entries) {
                const el = entry.target;

                if (el.className.includes('logWrapper')) {
                    if (el.className.includes('tableView') && !el.querySelector('[class^=notFoundMsg]')) {
                        setTimeout(updateTotalGained, 100);
                        break;
                    } else {
                        d.querySelector('.total-gained')?.remove();
                    }
                }
            }
        }).observe(activityLog, {subtree: true, childList: true});
    }

    const updateTotalGained = () => {
        const panelContainer = activityLog?.querySelector('.panel');

        if (!d.querySelector('.total-gained')) {
            const totalGainedContainer = createElement(
                {
                    nodeName: 'div',
                    className: 'total-gained info-msg-cont green border-round m-top10 m-bottom10',
                },
                activityLog?.querySelector('div:nth-child(1)'),
                'after'
            );
            const infoMsg = createElement(
                {
                    nodeName: 'div',
                    className: 'info-msg border-round',
                },
                totalGainedContainer
            );
            createElement(
                {
                    nodeName: 'i',
                    className: 'info-icon',
                },
                infoMsg,
                true
            );
            const delimiter = createElement(
                {
                    nodeName: 'div',
                    className: 'delimiter',
                },
                infoMsg
            );
            createElement(
                {
                    nodeName: 'div',
                    className: 'msg right-round',
                    textContent: 'Calculating...'
                },
                delimiter
            );
        }

        const totalGainedStart = panelContainer?.querySelector('tbody tr:last-child td:nth-child(4)')?.textContent;
        const totalGainedEnd = panelContainer?.querySelector('tbody tr:first-child td:nth-child(5)')?.textContent;
        const statName = panelContainer?.querySelector('thead tr:first-child th:nth-child(4)')?.textContent.split('_')[0];
        const totalEnergy = panelContainer?.querySelectorAll('tbody tr td:nth-child(3)');
        const totalHappy = panelContainer?.querySelectorAll('tbody tr td:nth-child(7)');
        const colorMode = d.body.classList.contains('dark-mode') ? 'dark' : 'light';
        const statColors = {
            'dark': {
                'strength': '--default-base-navy-color',
                'speed': '--default-base-royal-color',
                'defense': '--default-base-brown-color',
                'dexterity': '--default-base-purple-color',
                'energy': '--default-green-dark-color',
                'happy': '--default-base-gold-color'
            },
            'light': {
                'strength': '--default-base-royal-color',
                'speed': '--default-base-turq-color',
                'defense': '--default-base-brown-color',
                'dexterity': '--default-base-pink-color',
                'energy': '--default-green-dark-color',
                'happy': '--default-base-gold-color'
            }
        };

        if (totalGainedStart && totalGainedEnd) {
            const totalGained = Math.round(convertToFloat(totalGainedEnd) - convertToFloat(totalGainedStart)).toLocaleString();
            const energyUsed = calculateUsage(totalEnergy);
            const happyUsed = calculateUsage(totalHappy);

            d.querySelector('.total-gained .msg').innerHTML = `You gained a total of <strong style="color:var(${statColors[colorMode][statName]});">${totalGained}</strong> ${statName}.
            To achieve it, you used <strong style="color:var(${statColors[colorMode].energy});">${energyUsed}</strong> energy
            and <strong style="color:var(${statColors[colorMode].happy});">${happyUsed}</strong> happy.
            `;
        }
    };

    const calculateUsage = (items) => {
        return Array.from(items).reduce((total, item) => total + parseInt(item.textContent), 0).toLocaleString();
    }

    const convertToFloat = (number) => {
        if (!number) {
            return number;
        }

        let localeTest = 1000;
        localeTest = localeTest.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});

        return parseFloat(number.replaceAll(localeTest[1], '').replace(localeTest[5], '.'))
    }

    const createElement = (el, parent, prepend = false) => {
        const { nodeName = 'div', ...attrs } = el;
        const element = d.createElement(nodeName);

        Object.entries(attrs).forEach(([attr, value]) => {
            element[attr] = value;
        });

        if (prepend == 'after') {
            parent.parentNode.insertBefore(element, parent.nextSibling)
        } else if (prepend == true) {
            parent.prepend(element);
        } else {
            parent.append(element);
        }

        return element;
    };
})(window, document);