Budget/index.js

259 lines
8.4 KiB
JavaScript

var gui = require('gui');
var fs = require('fs');
const { waitForAddAccountWindow } = require('./waitForAddAccountWindow');
const { waitForDataEntryWindow } = require('./waitForDataEntryWindow');
const { waitForCloseAccountWindow } = require('./waitForCloseAccountWindow');
const { getAccounts, toListViewEntries, getSummation } = require('./utils');
const { waitForChartWindow } = require('./waitForChartWindow');
function mainWindow(projectData) {
var rh = 14;
var sp = 4;
var y = sp;
let internalProjectData = projectData;
let invalidate = false;
let gadgets = [];
const cycleId = 1;
const listViewId = 2;
const balanceId = 3;
const addButtonId = 4;
cols = 56;
gadgets.push({
kind: 'cycle', id: cycleId,
left: sp, top: y, width: 120, height: rh, border: false,
items: getAccounts(internalProjectData), value: 0
});
gadgets.push({
kind: 'button', id: addButtonId,
left: -(sp + 80),
top: y,
width: 80,
label: "+Transfer",
height: rh
});
gadgets.push({
kind: 'listview', id: listViewId,
left: sp,
top: y + rh + sp,
width: 500 - sp - sp,
height: 186,
items: toListViewEntries(internalProjectData[0].entries, cols),
value: 0
});
gadgets.push({
kind: 'text', id: balanceId,
label: 'Balance:',
left: 100,
top: -(sp + rh),
width: 400 - sp,
height: rh,
value: getSummation(internalProjectData[0].entries).toFixed(2)
});
let win = gui.createWindow({
title: 'Budget',
width: 500,
height: 14 + 4 + 4 + 200 + 4,
left: 20,
top: 15,
gadgets: gadgets,
});
/* Set up menu bar */
gui.setMenu(win, [
{
title: 'Project',
items: [
{ label: 'New', id: 101, key: 'N' },
{ label: 'Open...', id: 102, key: 'O' },
{ label: 'Save...', id: 103, key: 'S' },
{ label: '---' },
{ label: 'Quit', id: 199, key: 'Q' }
]
},
{
title: 'Accounts',
items: [
{ label: "Add...", id: 104, key: 'A' },
{ label: "Close...", id: 105, key: 'C' }
]
},
{
title: 'Charts',
items: [
{ label: "---" },
{ label: "New", id: 106 }
]
}
]);
let currentAccountIndex = 0;
let updateView = (accountIndex, data) => {
if (accountIndex != null) {
gui.set(win, cycleId, getAccounts(data));
gui.set(win, cycleId, accountIndex);
} else {
accountIndex = gui.get(win, cycleId);
}
// sort
data[accountIndex].entries = data[accountIndex].entries.sort((a, b) => a.date - b.date);
gui.set(win, 2, toListViewEntries(data[accountIndex].entries, cols));
gui.set(win, 3, getSummation(data[accountIndex].entries).toFixed(2));
}
let doNew = () => {
return [
{
name: "Current",
entries: []
}
];
}
let doOpen = () => {
var r = gui.fileRequest({ title: 'Open File', pattern: '#?.json' });
if (r) {
return JSON.parse(fs.readFileSync(r.file));
}
}
let doSave = () => {
var r = gui.fileRequest({ title: 'Save File', pattern: '#?.json', save: true });
if (r) {
fs.writeFileSync(r.file, JSON.stringify(internalProjectData));
}
}
gui.setMenuItem(win, 105, { disabled: internalProjectData.length <= 1 });
while (!invalidate) {
var evt = gui.waitEvent(win);
if (!evt) continue;
if (evt.type === 'close') {
invalidate = true;
internalProjectData = null;
}
if (evt.type === 'menu') {
if (evt.id === 101) {
internalProjectData = doNew();
updateView(0, internalProjectData);
}
else if (evt.id === 102) {
internalProjectData = doOpen();
updateView(0, internalProjectData);
}
else if (evt.id === 103) {
doSave();
}
else if (evt.id === 104) {
let indexOfNewAccount = waitForAddAccountWindow(internalProjectData);
if (indexOfNewAccount > -1) {
currentAccountIndex = indexOfNewAccount;
}
updateView(currentAccountIndex, internalProjectData);
}
else if (evt.id === 105) {
if (internalProjectData.length > 1) {
const rValue = waitForCloseAccountWindow(internalProjectData, internalProjectData[currentAccountIndex]);
if (rValue === -1) {
internalProjectData.splice(currentAccountIndex, 1);
updateView(0, internalProjectData);
}
} else {
gui.alert("Cannot close last remaining Account");
}
}
else if (evt.id === 106) {
waitForChartWindow(projectData[currentAccountIndex]);
}
else if (evt.id === 199) {
invalidate = true;
internalProjectData = null;
}
}
if (evt.type === 'gadgetup') {
if (evt.id === cycleId) {
currentAccountIndex = evt.code;
updateView(null, internalProjectData);
} else if (evt.id === listViewId) {
let selectedEntry = evt.code;
const entry = waitForDataEntryWindow(internalProjectData[currentAccountIndex].entries[evt.code], internalProjectData);
if (entry != null) {
console.log(entry);
if (entry === -1) {
console.log(selectedEntry);
internalProjectData[currentAccountIndex].entries.splice(selectedEntry, 1);
} else {
internalProjectData[currentAccountIndex].entries[selectedEntry] = entry;
}
if (entry.targetAccount) {
const targetAccount = internalProjectData.find(d => d.name === entry.targetAccount);
if (targetAccount) {
targetAccount.entries.push({
date: entry.date,
subject: "(" + internalProjectData[currentAccountIndex].name + ")" + entry.subject,
amount: -entry.amount
});
}
}
updateView(currentAccountIndex, internalProjectData);
}
} else if (evt.id === addButtonId) {
const entry = waitForDataEntryWindow(null, internalProjectData);
if (entry != null) {
internalProjectData[currentAccountIndex].entries.push(entry);
if (entry.targetAccount) {
const targetAccount = internalProjectData.find(d => d.name === entry.targetAccount);
if (targetAccount) {
targetAccount.entries.push({
date: entry.date,
subject: "(" + internalProjectData[currentAccountIndex].name + ")" + entry.subject,
amount: -entry.amount
});
}
}
updateView(currentAccountIndex, internalProjectData);
}
}
}
};
gui.closeWindow(win);
}
let projectData = [
{ "name": "Current", "entries": [
{ "date": 1704067200000, "subject": "Salary", "amount": 2182.15000000000009 },
{ "date": 1704153600000, "subject": "(Savings) Initial Deposit", "targetAccount": "Current", "amount": -500 },
{ "date": 1704240000000, "subject": "Rent", "amount": -800 },
{ "date": 1704326400000, "subject": "Groceries", "amount": -24.19 }]
},
{ "name": "Savings", "entries": [
{ "date": 1704153600000, "subject": "Initial Deposit", "amount": 500 }]
}
];
exports.projectData = projectData;
mainWindow(projectData);