// ==UserScript==
// @name [GC] Bank Account Optimizer
// @namespace http://tampermonkey.net/
// @version 1.2
// @license MIT
// @description Adds the ability to have multiple virtual bank accounts within your bank as well as transfer/withdraw from each
// @author Heda
// @match https://www.grundos.cafe/bank/
// @grant none
// ==/UserScript==
(function () {
'use strict';
const parseNP = str => parseInt(str.replace(/,/g, '').match(/\d+/)?.[0] || '0');
const formatNP = num => num.toLocaleString() + " NP";
const accountInfo = [...document.querySelectorAll('p')].find(p =>
p.innerHTML.includes('Account Type') && p.innerHTML.includes('Current Balance')
);
if (!accountInfo) return;
const accountType = (accountInfo.innerHTML.match(/<strong class="green">(.+?)<\/strong>/) || [])[1] || "Unknown";
const baseMainBalance = parseNP((accountInfo.innerHTML.match(/Current Balance<\/strong> : ([\d,]+) NP/) || [])[1]);
const balances = {
account1: getStoredBalance("account1", baseMainBalance),
account2: getStoredBalance("account2", 0),
account3: getStoredBalance("account3", 0)
};
const dropdowns = [];
const container = document.createElement("div");
Object.assign(container.style, {
display: "flex",
flexWrap: "wrap",
gap: "20px",
margin: "20px 0"
});
const hr = document.querySelector('hr');
hr.parentNode.insertBefore(container, hr);
container.appendChild(createAccountBox(1, balances.account1, true));
container.appendChild(createAccountBox(2, balances.account2));
container.appendChild(createAccountBox(3, balances.account3));
updateTransferDropdowns();
hookDepositForms();
function getStoredBalance(key, fallback) {
const stored = localStorage.getItem(key);
return stored !== null ? parseInt(stored) : fallback;
}
function saveBalance(key, value) {
localStorage.setItem(key, value.toString());
const display = document.querySelector(`#${key}`);
if (display) display.innerText = formatNP(value);
}
function getAccountName(key, fallback) {
return localStorage.getItem(`${key}_name`) || fallback;
}
function saveAccountName(key, name) {
localStorage.setItem(`${key}_name`, name);
const title = document.querySelector(`#title-${key}`);
if (title) title.textContent = name;
updateTransferDropdowns();
}
function updateTransferDropdowns() {
dropdowns.forEach(({ dropdown, fromKey }) => {
dropdown.innerHTML = "";
Object.keys(balances).forEach(key => {
if (key !== fromKey) {
const option = document.createElement("option");
option.value = key;
option.textContent = getAccountName(key, key);
dropdown.appendChild(option);
}
});
});
}
function resetToDefault(key) {
const value = balances[key];
balances.account1 += value;
balances[key] = 0;
saveBalance("account1", balances.account1);
saveBalance(key, 0);
saveAccountName(key, key === "account2" ? "Account #2" : "Account #3");
}
function resetMainToBase() {
balances.account1 = baseMainBalance;
saveBalance("account1", balances.account1);
}
function createAccountBox(accountNum, balance, isMain = false) {
const key = `account${accountNum}`;
const box = document.createElement("div");
Object.assign(box.style, {
border: "2px solid #999",
padding: "15px 20px",
borderRadius: "10px",
background: "#333",
color: "#fff",
minWidth: "300px",
flex: "1",
position: "relative"
});
const inputStyle = `
padding: 6px;
height: 32px;
border-radius: 5px;
border: 1px solid #888;
background: #444;
color: white;
width: 100%;
`;
const labelStyle = `
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 6px;
height: 32px;
border-radius: 5px;
background: #555;
color: white;
cursor: pointer;
user-select: none;
font-size: 14px;
font-weight: bold;
`;
const accountName = getAccountName(key, `Account #${accountNum}`);
const title = document.createElement("div");
title.id = `title-${key}`;
title.style.cssText = "font-size: 22px; font-weight: bold; text-decoration: underline; color: #fff; text-shadow: 1px 1px 2px #000; text-align: center; margin-bottom: 10px;";
title.textContent = accountName;
const resetButton = document.createElement("label");
resetButton.textContent = "✕";
resetButton.title = isMain ? "Reset to actual balance from bank" : "Click to set account to default";
Object.assign(resetButton.style, {
position: "absolute",
top: "5px",
left: "5px",
background: "#555",
color: "white",
padding: "4px 8px",
borderRadius: "6px",
cursor: "pointer",
fontWeight: "bold",
fontSize: "16px"
});
resetButton.onclick = () => isMain ? resetMainToBase() : resetToDefault(key);
const details = document.createElement("div");
details.style.textAlign = "center";
details.innerHTML = `
<p><strong style="color:#ccc;">Account Type:</strong> <span style="color:#9f9;">${accountType}</span></p>
<p><strong style="color:#ccc;">Current Balance:</strong> <span id="${key}" style="color:#fff;">${formatNP(balance)}</span></p>
<hr style="border: 1px solid #888; margin: 12px auto;">
`;
const row = document.createElement("div");
Object.assign(row.style, {
display: "flex",
justifyContent: "space-between",
gap: "15px"
});
const renameInput = document.createElement("input");
renameInput.placeholder = "Rename...";
renameInput.style = inputStyle;
const renameBtn = document.createElement("label");
renameBtn.textContent = "Rename";
renameBtn.style = labelStyle;
renameBtn.onclick = () => {
const name = renameInput.value.trim();
if (name) {
saveAccountName(key, name);
renameInput.value = '';
}
};
const transferInput = document.createElement("input");
transferInput.placeholder = "Amount";
transferInput.style = inputStyle;
const transferDropdown = document.createElement("select");
transferDropdown.style = inputStyle;
const transferBtn = document.createElement("label");
transferBtn.textContent = "Transfer NP";
transferBtn.style = labelStyle;
transferBtn.onclick = () => {
const amount = parseNP(transferInput.value);
const toKey = transferDropdown.value;
if (amount <= 0 || balances[key] < amount || !(toKey in balances)) {
alert("Invalid or insufficient funds");
return;
}
balances[key] -= amount;
balances[toKey] += amount;
saveBalance(key, balances[key]);
saveBalance(toKey, balances[toKey]);
transferInput.value = "";
};
dropdowns.push({ dropdown: transferDropdown, fromKey: key });
const withdrawInput = document.createElement("input");
withdrawInput.placeholder = "Amount";
withdrawInput.style = inputStyle;
const withdrawBtn = document.createElement("label");
withdrawBtn.textContent = "Withdraw";
withdrawBtn.style = labelStyle;
withdrawBtn.onclick = () => {
const amount = parseNP(withdrawInput.value);
if (amount <= 0 || balances[key] < amount) {
alert("Invalid or insufficient funds");
return;
}
const form = document.querySelector('form[action="/bank/withdraw_np/"]');
const amountInput = form?.querySelector('input[name="amount"]');
if (!form || !amountInput) {
alert("Could not find withdrawal form");
return;
}
amountInput.value = amount;
balances[key] -= amount;
saveBalance(key, balances[key]);
setTimeout(() => form.submit(), 100);
};
const renameCol = document.createElement("div");
renameCol.style.flex = "1";
renameCol.append(renameInput, renameBtn);
const transferCol = document.createElement("div");
transferCol.style.flex = "1";
transferCol.append(transferInput, transferDropdown, transferBtn);
const withdrawCol = document.createElement("div");
withdrawCol.style.flex = "1";
withdrawCol.append(withdrawInput, withdrawBtn);
row.append(renameCol, transferCol, withdrawCol);
box.append(resetButton, title, details, row);
return box;
}
function hookDepositForms() {
const depositForm = document.querySelector('form[action="/bank/deposit_np/"]:not(.button-group)');
const depositAllForm = document.querySelector('form.button-group[action="/bank/deposit_np/"]');
if (depositForm) {
depositForm.addEventListener("submit", () => {
const amount = parseNP(depositForm.querySelector('input[name="amount"]')?.value || '0');
if (amount > 0) {
balances.account1 += amount;
saveBalance("account1", balances.account1);
}
});
}
if (depositAllForm) {
const button = depositAllForm.querySelector('button[name="amount"]');
depositAllForm.addEventListener("submit", () => {
const amount = parseNP(button?.value || '0');
if (amount > 0) {
balances.account1 += amount;
saveBalance("account1", balances.account1);
}
});
}
}
})();