some more updates

This commit is contained in:
2025-07-25 17:34:32 -04:00
parent 63a6694507
commit f4103953f6
5 changed files with 156 additions and 86 deletions

View File

@ -138,24 +138,15 @@ export async function deleteBudgetTransaction(id) {
}
export async function addBudgetTransaction(budgetId, transactionId, amount, notes, ruleId = null) {
const existingTransactions = await db`
select amount from budget_transaction
where transaction_id = ${transactionId}
const exsisting = await db`
select id from budget_transaction
where budget_id = ${budgetId} and transaction_id = ${transactionId}
`;
const realTransactionAmount = await db`
select amount from transaction
where id = ${transactionId}
`;
if (existingTransactions.length > 0) {
if (
existingTransactions.reduce((acc, curr) => acc + curr.amount, 0) + amount >
realTransactionAmount
) {
return -1;
}
}
if (exsisting.length > 0) {
// If the transaction already exists in the budget, update it
return updateBudgetTransaction(exsisting[0].id, amount, notes);
}
// Add a transaction to a budget
const result = await db`
insert into budget_transaction (budget_id, transaction_id, amount, notes, rule_id)

View File

@ -1,20 +1,30 @@
<script>
import { invalidateAll } from '$app/navigation';
let { transaction, close, budgets } = $props();
import { getContext } from 'svelte';
import { EditSymbol } from '$lib/editSymbol.svelte';
import { TrashBin } from '$lib/trashbin.svelte';
const addToast = getContext('addToast');
let { transaction, close, budgets } = $props();
let id = $derived(transaction.id);
let description = $derived(transaction.description || 'No description');
let amount = $derived(transaction.amount || 0);
let date = $derived(new Date(transaction.date || Date.now()));
let out_of_budget = $derived(transaction.out_of_budget || false);
let budget_id = $derived(transaction.budget_id || null);
let loading = $state(false);
let deleting = $state(false);
let deletingText = $state('');
let deletebt = $state(null);
let notes = $state(transaction.notes || '');
function editBudget(budgetTransaction) {
budget_id = budgetTransaction.budget_id;
amount = budgetTransaction.amount;
notes = budgetTransaction.notes || '';
}
async function saveNotes() {
loading = true;
let res = fetch(`/transcation/${id}`, {
@ -38,6 +48,61 @@
loading = false;
close();
}
async function saveBudget() {
if (budget_id) {
loading = true;
fetch(`/api/budget/${budget_id}/transaction`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
transactionId: id,
amount: amount,
notes: notes
})
}).then((res) => {
invalidateAll();
if (res.ok) {
// Optionally, you can refresh the UI or show a success message
addToast('Transaction added to budget', 'success');
console.log('Transaction added to budget successfully');
} else {
addToast('Failed to add transaction to budget', 'error');
console.error('Failed to add transaction to budget');
}
});
} else {
console.error('No budget selected');
}
loading = false;
close();
}
async function deleteBudgetTransaction(bt) {
deleting = true;
deletingText = `${bt.budget_name}: ${bt.amount}`;
deletebt = bt;
}
async function sendDeletebt() {
loading = true;
if (deletebt) {
let res = await fetch(`/api/budget/${deletebt.id}/transaction`, {
method: 'DELETE'
});
if (res.ok) {
addToast('Budget transaction deleted successfully', 'success');
invalidateAll();
} else {
addToast('Failed to delete budget transaction', 'error');
}
}
deleting = false;
loading = false;
close();
}
</script>
<dialog id="transactionEditModal" class="modal modal-open modal-top}">
@ -65,60 +130,56 @@
Out of Budgets
</label>
<button class="btn btn-neutral" onclick={() => saveNotes()}>Save</button>
<button class="btn btn-neutral" onclick={() => saveNotes()}>Save Transaction</button>
<legend class="fieldset-legend">Add to budget</legend>
<select bind:value={budget_id} class="select">
<option disabled selected>Pick a budget</option>
{#each budgets as budget}
<option value={budget.id}>{budget.name} - {budget.sum}</option>
<legend class="fieldset-legend">Current Budgets</legend>
<div class="flex flex-col">
{#each transaction.budgetTransactions as budgetTransaction}
<div class="flex justify-between">
<span class="text-lg"
>{budgetTransaction.budget_name}: {budgetTransaction.amount}</span
>
<div class="grow justify-end flex">
<button
class="btn btn-square btn-ghost"
onclick={() => editBudget(budgetTransaction)}
>
{@render EditSymbol()}
</button>
</div>
<div>
<button
class="btn btn-square btn-ghost"
onclick={() => deleteBudgetTransaction(budgetTransaction)}
>
{@render TrashBin()}
</button>
</div>
</div>
{/each}
</select>
<legend class="fieldset-legend">Amount</legend>
<input
bind:value={amount}
type="number"
class="input validator"
required
placeholder="Amount"
title="Amount"
/>
<legend class="fieldset-legend">Notes</legend>
<textarea bind:value={notes} class="textarea w-100"></textarea>
<p class="validator-hint">Must a sensible number</p>
<button
class="btn btn-primary"
onclick={() => {
if (budget_id) {
loading = true;
fetch(`/api/budget/${budget_id}/transaction`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
transactionId: id,
amount: amount,
notes: notes
})
}).then((res) => {
invalidateAll();
if (res.ok) {
// Optionally, you can refresh the UI or show a success message
addToast('Transaction added to budget', 'success');
console.log('Transaction added to budget successfully');
} else {
addToast('Failed to add transaction to budget', 'error');
console.error('Failed to add transaction to budget');
}
});
} else {
console.error('No budget selected');
}
loading = false;
close();
}}>Add to Budget</button
>
</div>
{#if deleting}
<legend class="fieldset-legend">Delete Budget Transaction</legend>
<span class="text-xl">Deleting budget transaction - {deletingText}</span>
<span class="text-xl">Are you sure?</span>
<button class="text-xl btn btn-success" onclick={() => (deleting = false)}>Cancel</button>
<button class="text-xl btn btn-error" onclick={() => sendDeletebt()}>Delete</button>
{:else}
<legend class="fieldset-legend">Add to budget</legend>
<select bind:value={budget_id} class="select">
<option disabled selected>Pick a budget</option>
{#each budgets as budget}
<option value={budget.id}>{budget.name} - {budget.sum}</option>
{/each}
</select>
<legend class="fieldset-legend">Amount</legend>
<input bind:value={amount} type="number" required placeholder="Amount" title="Amount" />
<legend class="fieldset-legend">Notes</legend>
<textarea bind:value={notes} class="textarea w-100"></textarea>
<button class="btn btn-primary" onclick={() => saveBudget()}>Save Budget</button>
{/if}
</fieldset>
{/if}
</div>

View File

@ -5,9 +5,10 @@
let { transactions, budgetTransactions, budgets } = $props();
let editing = $state(false);
function editNotes(transaction, remaining) {
function editNotes(transaction, remaining, budgetTransactions) {
currentTransaction = transaction;
currentTransaction.amount = remaining;
currentTransaction.budgetTransactions = budgetTransactions;
editing = true;
}
</script>
@ -65,7 +66,7 @@
<div class="">
<button
class="btn btn-square btn-ghost"
onclick={() => editNotes(transaction, remaining)}
onclick={() => editNotes(transaction, remaining, applicableBudgets)}
>
{@render EditSymbol()}
</button>

View File

@ -8,20 +8,23 @@
let underAllocatedTrans = $derived(data.underAllocatedTrans);
let budgets = $derived(data.budgets);
let budgetTransactions = $derived(data.budgetTransactions);
let last30days = $derived(data.last30DaysTransactionsSums);
let last30days = $derived(data.last30DaysTransactionsSums.reverse());
$inspect(last30days);
let chartData = $derived(
last30days
.reduce((acc, curr) => [...acc, acc[acc.length - 1] + Number(curr.sum)], [Number(total)])
.reverse()
);
let chartDates = $derived(
[
'now',
...last30days.map((day) => `${day.date.getMonth() + 1}/${day.date.getDate()}`)
].reverse()
last30days.reduce(
(acc, curr) => [...acc, acc[acc.length - 1] + Number(curr.sum)],
[Number(total)]
)
);
$inspect(chartData);
let chartDates = $derived([
'now',
...last30days.map((day) => `${day.date.getMonth() + 1}/${day.date.getDate()}`)
]);
const option = $derived({
xAxis: {
type: 'category',
@ -33,7 +36,23 @@
series: [
{
data: chartData,
type: 'line'
type: 'line',
label: {
show: false,
position: 'top',
formatter: (params) => {
return `$${params.value.toFixed(2)}`;
},
fontSize: 20,
padding: 10,
backgroundColor: 'rgba(255, 255, 255, 0.8)',
borderRadius: 5
},
emphasis: {
label: {
show: true // Labels appear on hover
}
}
}
]
});

View File

@ -22,7 +22,6 @@ export async function PATCH({ params, request }) {
const { amount, notes, transactionId } = body;
console.log({ slug, transactionId, amount });
// Call the deleteBudget function from db.js (budgetId, transactionId, amount)
return updateBudgetTransaction(transactionId, amount, notes)
.then(() => new Response(`Budget transaction updated successfully`, { status: 200 }))
.catch(
@ -36,7 +35,6 @@ export async function DELETE({ params, request }) {
const { transactionId } = slug;
console.log({ slug });
// Call the deleteBudget function from db.js (budgetId, transactionId)
return deleteBudgetTransaction(slug)
.then(() => new Response(`Budget transaction deleted successfully`, { status: 200 }))
.catch(