Sales History Reformatter (Beta)

Replaces table in Sales History with one that only contains practical information

// ==UserScript==
// @name         Sales History Reformatter (Beta)
// @description  Replaces table in Sales History with one that only contains practical information
// @version      0.4
// @license      GNU GPLv3
// @match        https://www.neopets.com/market.phtml?type=sales
// @author       Posterboy
// @icon         https://images.neopets.com/new_shopkeepers/t_1900.gif
// @namespace    https://www.youtube.com/@Neo_PosterBoy
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // ================================
    // Scrape and Remove Existing Table
    // ================================

    window.addEventListener('load', () => {

        // Locate the table
        const targetText = "Only purchases of 1000 NP or greater will be displayed here.";
        const targetElement = [...document.body.getElementsByTagName('p')].find(p => p.innerText.includes(targetText));

        if (targetElement) {
            const tableContainer = targetElement.nextElementSibling;

            // Ensure that a valid table container is found
            if (tableContainer && tableContainer.tagName === 'P') {
                const existingTable = tableContainer.querySelector('table');

                if (existingTable) {
                    // Add loading message and remove the existing table
                    const loadingMessage = document.createElement('p');
                    loadingMessage.textContent = 'Loading... Please wait.';
                    tableContainer.insertBefore(loadingMessage, existingTable);
                    existingTable.remove();

                    // Extract sales history table rows
                    const rows = existingTable.querySelectorAll('tbody tr');
                    let itemsData = {};

                    // Loop through each row to extract item info (item name, price, quantity)
                    rows.forEach(row => {
                        const cells = row.querySelectorAll('td');
                        if (cells.length >= 4) {
                            const item = cells[1].innerText.trim();
                            const price = cells[3].innerText.trim();

                            // Don't include header or footer in data
                            if (item && price && !item.includes('Clear Sales History') && item !== "Item") {
                                const cleanItem = item.split('\n')[0].trim();
                                const cleanPrice = formatPrice(price);

                                const itemKey = `${cleanItem} - ${cleanPrice}`;

                                // If the item-price combination already exists, increment the quantity
                                if (itemsData[itemKey]) {
                                    itemsData[itemKey].quantity += 1;
                                } else {
                                    itemsData[itemKey] = {
                                        quantity: 1,
                                        price: cleanPrice,
                                        name: cleanItem
                                    };
                                }
                            }
                        }
                    });
                    console.log("Items Data:", itemsData); //Optional for debugging

    // ========================
    // Insert New Table
    // ========================

                    // Function to format the price with commas and append " NP"
                    function formatPrice(price) {
                        const number = parseInt(price.replace(/[^\d.-]/g, '').trim(), 10);
                        return number.toLocaleString() + " NP";
                    }

                    // Sort the items by quantity (descending) and then by price (descending)
                    const sortedItems = Object.entries(itemsData).sort((a, b) => {
                        if (b[1].quantity !== a[1].quantity) {
                            return b[1].quantity - a[1].quantity;
                        }
                        return parseInt(b[1].price.replace(/[^\d.-]/g, ''), 10) - parseInt(a[1].price.replace(/[^\d.-]/g, ''), 10);
                    });
                    console.log("Sorted Items:", sortedItems);

                    // Create a new table to display the sorted result
                    let resultTable = document.createElement('table');
                    resultTable.style.border = '1px solid #ddd';
                    resultTable.style.margin = '20px auto';
                    resultTable.style.width = '80%';
                    resultTable.style.borderCollapse = 'collapse';
                    resultTable.style.padding = '8px';

                    // Imitate style used by original table
                    let tableHeader = `
                        <tr>
                            <td bgcolor="#dddd77" align="center"><b>Quantity</b></td>
                            <td bgcolor="#dddd77" align="center"><b>Item</b></td>
                            <td bgcolor="#dddd77" align="center"><b>Price</b></td>
                        </tr>
                    `;
                    resultTable.innerHTML = tableHeader;

                    let previousQuantity = null;

                    // Add each sorted item to the table
                    sortedItems.forEach(([itemName, data]) => {
                        let row = document.createElement('tr');

                        // Add a separator row if the quantity changes between consecutive items
                        if (previousQuantity !== null && previousQuantity !== data.quantity) {
                            let separatorRow = document.createElement('tr');
                            separatorRow.style.borderTop = '4px solid #dddd77';
                            resultTable.appendChild(separatorRow);
                        }

                        // Create the row for the current item
                        row.innerHTML = `
                            <td bgcolor="#ffffcc" align="center">${data.quantity}</td>
                            <td bgcolor="#ffffcc" align="center">${data.name}</td>
                            <td bgcolor="#ffffcc" align="center">${data.price}</td>
                        `;
                        resultTable.appendChild(row);

                        previousQuantity = data.quantity;
                    });

    // Append Clear History Button
                    const clearButtonRow = document.createElement('tr');
                    clearButtonRow.innerHTML = `
                        <td bgcolor="#dddd77" align="center" valign="center" colspan="3">
                            <form action="market.phtml" method="post">
                                <input type="hidden" name="type" value="sales">
                                <input type="hidden" name="clearhistory" value="true">
                                <input type="submit" value="Clear Sales History">
                            </form>
                        </td>
                    `;

                    resultTable.appendChild(clearButtonRow);
                    tableContainer.insertBefore(resultTable, loadingMessage.nextSibling);
                    loadingMessage.remove();
                }
            }
        }
    });
})();