From 9b2a0b63e348047cfc1344ad7f7aabcbfdd5d8b3 Mon Sep 17 00:00:00 2001 From: Casey Timm Date: Fri, 25 Jul 2025 16:22:57 -0400 Subject: [PATCH] New and imporved! --- package-lock.json | 28 +++ package.json | 1 + src/lib/db.js | 77 +++++++- src/lib/echarts.js | 6 + src/lib/editTransaction.svelte | 128 +++++++++++++ src/lib/transactionList.svelte | 80 ++++++++ src/lib/united.js | 24 +-- src/routes/+layout.server.js | 5 +- src/routes/+layout.svelte | 2 +- src/routes/+page.server.js | 20 ++ src/routes/+page.svelte | 61 ++++++ src/routes/account/[slug]/+page.svelte | 181 +----------------- .../api/transactions/unallocated/+server.js | 6 + .../transactions/underallocated/+server.js | 6 + src/routes/budget/[slug]/+page.server.js | 4 +- united-login.png | Bin 0 -> 50963 bytes 16 files changed, 439 insertions(+), 190 deletions(-) create mode 100644 src/lib/echarts.js create mode 100644 src/lib/editTransaction.svelte create mode 100644 src/lib/transactionList.svelte create mode 100644 src/routes/+page.server.js create mode 100644 src/routes/api/transactions/unallocated/+server.js create mode 100644 src/routes/api/transactions/underallocated/+server.js create mode 100644 united-login.png diff --git a/package-lock.json b/package-lock.json index c84a229..8176700 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@auth/sveltekit": "^1.10.0", "@tailwindcss/vite": "^4.1.11", "cron": "^4.3.2", + "echarts": "^5.6.0", "patchright": "^1.52.5", "postgres": "^3.4.7", "puppeteer": "^24.14.0", @@ -3934,6 +3935,20 @@ "node": ">= 0.4" } }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -8475,6 +8490,19 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" } } } diff --git a/package.json b/package.json index 4401fa6..9ed9469 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@auth/sveltekit": "^1.10.0", "@tailwindcss/vite": "^4.1.11", "cron": "^4.3.2", + "echarts": "^5.6.0", "patchright": "^1.52.5", "postgres": "^3.4.7", "puppeteer": "^24.14.0", diff --git a/src/lib/db.js b/src/lib/db.js index d3c9e8b..903a1c6 100644 --- a/src/lib/db.js +++ b/src/lib/db.js @@ -86,7 +86,7 @@ export async function updateBudget(id, name, amount, notes) { return result; } -export async function getBudgetTransactions(id) { +export async function getBudgetTransactionsByid(id) { // Fetch all transactions associated with a specific budget try { let transactions = await db` @@ -258,6 +258,22 @@ export async function getBudgetTransactionsForAccount(accountID) { return transactions; } +export async function getAllBudgetTransactions(accountID) { + const transactions = await db` + select budget_transaction.id as id, + budget_transaction.budget_id as budget_id, + budget_transaction.transaction_id as transaction_id, + budget_transaction.amount as amount, + budget_transaction.notes as notes, + budget.name as budget_name + from budget_transaction + join transaction on budget_transaction.transaction_id = transaction.id + join budget on budget_transaction.budget_id = budget.id + `; + return transactions; +} + + export async function getHiddenAccounts(age) { const accounts = await db` select @@ -514,4 +530,63 @@ export async function runRules() { } } +export async function getUnallocatedTotal() { + const result = await db` + select sum(amount) as total + from budget_transaction + where transaction_id is null + `; + // result = Result [{ total: 1000.00 }] + return result[0].total; +} + +export async function getUnallocatedTransactions() { + const result = await db` + SELECT TRANSACTION.id as id, + TRANSACTION.amount as amount, + TRANSACTION.description as description, + TRANSACTION.date as date, + TRANSACTION.account_id + FROM TRANSACTION + full join budget_transaction + ON TRANSACTION.id = budget_transaction.transaction_id + WHERE budget_transaction.amount IS NULL + AND TRANSACTION.out_of_budget = FALSE + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Unallocated funds" }, ...] + return result; +} + +export async function getUnderallocatedTransactions() { + const result = await db` + SELECT * + FROM (SELECT TRANSACTION.id, + TRANSACTION.amount AS amount, + TRANSACTION.description, + TRANSACTION.DATE AS date, + TRANSACTION.account_id, + SUM(budget_transaction.amount) AS budget_total + FROM TRANSACTION + full join budget_transaction + ON TRANSACTION.id = budget_transaction.transaction_id + WHERE TRANSACTION.out_of_budget = FALSE + GROUP BY TRANSACTION.id) AS t + WHERE t.amount != t.budget_total + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Unallocated funds" }, ...] + return result; +} + +export async function getLast30DaysTransactionsSums() { + let result = await db` + SELECT cast(date as date) as date, SUM(amount) + from transaction + where date >= (CURRENT_DATE - interval '30 days') + GROUP BY cast(date as date) + order by date desc; + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Recent transaction" }, ...] + return result; +} + export default db; diff --git a/src/lib/echarts.js b/src/lib/echarts.js new file mode 100644 index 0000000..bbf7978 --- /dev/null +++ b/src/lib/echarts.js @@ -0,0 +1,6 @@ +import * as charts from 'echarts'; + +export function echarts(node, option) { + const chart = charts.init(node); + chart.setOption(option); +} \ No newline at end of file diff --git a/src/lib/editTransaction.svelte b/src/lib/editTransaction.svelte new file mode 100644 index 0000000..2728c7c --- /dev/null +++ b/src/lib/editTransaction.svelte @@ -0,0 +1,128 @@ + + + + + + diff --git a/src/lib/transactionList.svelte b/src/lib/transactionList.svelte new file mode 100644 index 0000000..bfbf574 --- /dev/null +++ b/src/lib/transactionList.svelte @@ -0,0 +1,80 @@ + + +
+ {#each transactions as transaction} + {@const applicableBudgets = budgetTransactions.filter( + (bt) => bt.transaction_id === transaction.id + )} + {@const budgetTotal = applicableBudgets.reduce( + (accumulator, currentValue) => accumulator + Number(currentValue.amount), + 0 + )} + {@const remaining = transaction.amount - budgetTotal} +
+
+
+
+
{transaction.description}
+
+ {transaction.date.toDateString()} +
+ {#if !transaction.out_of_budget} +
+ In Budget: {budgetTotal.toFixed(2)} +
+
+ Remaining {remaining.toFixed(2)} +
+ {:else} +
Out of budget
+ {/if} +
+ {#if applicableBudgets.length > 0} +
+ {#each applicableBudgets as budgetTransaction} +
+ {`${budgetTransaction.budget_name}: ${budgetTransaction.amount}`} +
+ {/each} +
+ {/if} + +
+
+ {transaction.amount} +
+
+
+ +
+ +
+
+
+ {/each} + + {#if editing} + (editing = false)} budgets /> + {/if} +
diff --git a/src/lib/united.js b/src/lib/united.js index 0658405..c3182f9 100644 --- a/src/lib/united.js +++ b/src/lib/united.js @@ -21,22 +21,23 @@ export function isNeedCode() { export function isRunning() { return running; } - -export async function pullData(amount = 100) { - running = true; - try { - state = []; - code = null; - needCode = false; - state.push('Starting Browser'); - const browser = await chromium.launchPersistentContext('context', { +const browser = await chromium.launchPersistentContext('context', { channel: 'chrome', - headless: true, + headless: false, viewport: null // do NOT add custom browser headers or userAgent }); +export async function pullData(amount = 100) { + running = true; + state = []; + code = null; + needCode = false; + state.push('Starting Browser'); + + const page = await browser.newPage(); + try { state.push('Navigating to United FCU'); await page.goto('https://online.unitedfcu.com/unitedfederalcredituniononline/uux.aspx#/login'); @@ -260,11 +261,10 @@ export async function pullData(amount = 100) { } state.push('Done'); - await browser.close(); } catch (error) { console.error('Error in pullData:', error); state.push(`Error: ${error.message}`); } - + page.close(); running = false; } diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js index 37f476c..961650b 100644 --- a/src/routes/+layout.server.js +++ b/src/routes/+layout.server.js @@ -1,10 +1,9 @@ -import { getAccounts, getBudgets, getTotal } from '$lib/db'; +import { getAccounts, getBudgets } from '$lib/db'; import { get } from 'svelte/store'; export async function load({ params }) { let accounts = await getAccounts(); let budgets = await getBudgets(); - let total = await getTotal(); - return { accounts, budgets, total }; + return { accounts, budgets }; } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 32adbc9..f966772 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -51,7 +51,7 @@