all repos — piggy @ main

Dead simple finance manager in Go, HTML and JS.

static/js/records-edit.js (view raw)

  1document.addEventListener('DOMContentLoaded', function () {
  2    handleID();
  3
  4    document.getElementById('save').addEventListener('click', submit);
  5    
  6    if (id === 0) {
  7        document.getElementById('delete').style.display = "none";
  8    } else {
  9        document.getElementById('delete').addEventListener('click', remove);
 10    }
 11});
 12
 13let accounts = [];
 14let bookmakers = [];
 15let id;
 16
 17async function handleID() {
 18    id = getQueryStringID();
 19    const record = id === 0 ? null : await getRecord(id);
 20    accounts = await getAccounts();
 21    bookmakers = await getBookmakers();
 22    document.getElementById("main-container").appendChild(loadRecord(record));
 23}
 24
 25function loadRecord(record) {
 26    const div = document.createElement("div");
 27    div.setAttribute("data-type", "record");
 28    div.setAttribute("data-id", id);
 29    div.classList.add("record");
 30
 31    // record.type
 32    div.appendChild(newInputText("Type", record?.type, "record-type"));
 33
 34    // record.description
 35    div.appendChild(newInputText("Description", record?.description, "record-description"));
 36
 37    // record.done
 38    div.appendChild(newInputCheckbox("Done", record?.done, "record-done"));
 39
 40    // record.entries
 41    div.appendChild(loadEntries(record?.entries ?? [null, null], "record-entries"));
 42
 43    return div;
 44}
 45
 46function loadEntries(entries, name) {
 47    const div = document.createElement("div")
 48    div.className = name;
 49
 50    const newEntry = document.createElement("button");
 51    newEntry.innerText = "Add entry";
 52    newEntry.onclick = () => div.appendChild(loadEntry(null));
 53    div.appendChild(newEntry);
 54
 55    for (const entry of entries) {
 56        div.appendChild(loadEntry(entry));
 57    }
 58    return div;
 59}
 60
 61function loadEntry(entry) {
 62    const div = document.createElement("div");
 63    div.setAttribute("data-type", "entry");
 64    div.setAttribute("data-id", entry?.id ?? 0);
 65    div.classList.add("entry");
 66
 67    const deleteEntry = document.createElement("button");
 68    deleteEntry.innerText = "Delete entry";
 69    deleteEntry.onclick = () => div.remove();
 70    div.appendChild(deleteEntry);
 71
 72    // entry.bookmaker_id
 73    div.appendChild(newInputSelect("Bookmaker", entry?.bookmaker_id, "entry-bookmaker_id", bookmakers))
 74
 75    // entry.account_id
 76    div.appendChild(newInputSelect("Account", entry?.account_id, "entry-account_id", accounts))
 77
 78    // entry.amount
 79    div.appendChild(newInputText("Amount", formatValue(entry?.amount), "entry-amount"))
 80
 81    // entry.refund
 82    div.appendChild(newInputText("Refund", formatValue(entry?.refund), "entry-refund"))
 83
 84    // entry.bonus
 85    div.appendChild(newInputText("Bonus", formatValue(entry?.bonus), "entry-bonus"))
 86
 87    // entry.commission
 88    div.appendChild(newInputText("Commission", formatValue(entry?.commission), "entry-commission"))
 89
 90    // entry.sub_entries
 91    div.appendChild(loadSubEntries(entry?.sub_entries ?? [null], "entry-subentries"));
 92
 93    return div;
 94}
 95
 96function loadSubEntries(subEntries, name) {
 97    const div = document.createElement("div")
 98    div.className = name;
 99
100    const newSubEntry = document.createElement("button");
101    newSubEntry.innerText = "Add subentry";
102    newSubEntry.onclick = () => div.appendChild(loadSubEntry(null));
103    div.appendChild(newSubEntry);
104
105    for (const subEntry of subEntries) {
106        div.appendChild(loadSubEntry(subEntry));
107    }
108    return div;
109}
110
111function loadSubEntry(subEntry) {
112    const div = document.createElement("div");
113    div.setAttribute("data-type", "subentry");
114    div.setAttribute("data-id", subEntry?.id ?? 0);
115    div.classList.add("subentry");
116
117    const deleteSubEntry = document.createElement("button");
118    deleteSubEntry.innerText = "Delete subentry";
119    deleteSubEntry.onclick = () => div.remove();
120    div.appendChild(deleteSubEntry);
121
122    // subentry.description
123    div.appendChild(newInputText("Description", subEntry?.description, "subentry-description"));
124    
125    // subentry.odds
126    div.appendChild(newInputText("Odds", formatValue(subEntry?.odds), "subentry-odds"))
127    
128    // subentry.won
129    div.appendChild(newInputCheckbox("Won", subEntry?.won, "subentry-won"));
130    
131    // subentry.date
132    div.appendChild(newInputDate("Date", subEntry?.date ?? new Date().toISOString(), "subentry-date"));
133
134    return div;
135}
136
137function getInputValueFromNode(node, name) {
138    const element = node.getElementsByClassName(name)[0];
139    return element.type === "checkbox" ? element.checked : element.value;
140}
141
142function buildRecordObject() {
143    const node = document.getElementsByClassName("record")[0];
144    return {
145        id: +node.getAttribute("data-id"),
146        type: getInputValueFromNode(node, "record-type"),
147        description: getInputValueFromNode(node, "record-description"),
148        done: getInputValueFromNode(node, "record-done"),
149        entries: buildEntriesObject(node.getElementsByClassName("record-entries")[0]),
150    }
151}
152
153function buildEntriesObject(entriesNode) {
154    const entriesNodes = entriesNode.getElementsByClassName("entry");
155    
156    const result = [];
157    for (const node of entriesNodes) {
158        result.push({
159            id: +node.getAttribute("data-id"),
160            bookmaker_id: +getInputValueFromNode(node, "entry-bookmaker_id"),
161            account_id: +getInputValueFromNode(node, "entry-account_id"),
162            amount: restoreValue(getInputValueFromNode(node, "entry-amount")),
163            refund: restoreValue(getInputValueFromNode(node, "entry-refund")),
164            bonus: restoreValue(getInputValueFromNode(node, "entry-bonus")),
165            commission: restoreValue(getInputValueFromNode(node, "entry-commission")),
166            sub_entries: buildSubEntriesObject(node.getElementsByClassName("entry-subentries")[0]),
167        });
168    }
169    return result;
170}
171
172function buildSubEntriesObject(subEntriesNode) {
173    const subEntriesNodes = subEntriesNode.getElementsByClassName("subentry");
174    
175    const result = [];
176    for (const node of subEntriesNodes) {
177        result.push({
178            id: +node.getAttribute("data-id"),
179            description: getInputValueFromNode(node, "subentry-description"),
180            odds: restoreValue(getInputValueFromNode(node, "subentry-odds")),
181            won: getInputValueFromNode(node, "subentry-won"),
182            date: getInputValueFromNode(node, "subentry-date"),
183        });
184    }
185    return result;
186}
187
188async function submit() {
189    if (await saveRecord(buildRecordObject())) {
190        location.href = "/records"
191    }
192}
193
194async function remove() {
195    if (await myConfirm(deleteRecord, id)) {
196        location.href = "/records"
197    }
198}