some more updates
This commit is contained in:
@ -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 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;
|
||||
const exsisting = await db`
|
||||
select id from budget_transaction
|
||||
where budget_id = ${budgetId} and transaction_id = ${transactionId}
|
||||
`;
|
||||
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)
|
||||
|
||||
@ -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,8 +130,43 @@
|
||||
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">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}
|
||||
</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>
|
||||
@ -75,50 +175,11 @@
|
||||
{/each}
|
||||
</select>
|
||||
<legend class="fieldset-legend">Amount</legend>
|
||||
<input
|
||||
bind:value={amount}
|
||||
type="number"
|
||||
class="input validator"
|
||||
required
|
||||
placeholder="Amount"
|
||||
title="Amount"
|
||||
/>
|
||||
<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>
|
||||
<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
|
||||
>
|
||||
<button class="btn btn-primary" onclick={() => saveBudget()}>Save Budget</button>
|
||||
{/if}
|
||||
</fieldset>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -8,19 +8,22 @@
|
||||
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()
|
||||
last30days.reduce(
|
||||
(acc, curr) => [...acc, acc[acc.length - 1] + Number(curr.sum)],
|
||||
[Number(total)]
|
||||
)
|
||||
);
|
||||
let chartDates = $derived(
|
||||
[
|
||||
|
||||
$inspect(chartData);
|
||||
let chartDates = $derived([
|
||||
'now',
|
||||
...last30days.map((day) => `${day.date.getMonth() + 1}/${day.date.getDate()}`)
|
||||
].reverse()
|
||||
);
|
||||
]);
|
||||
|
||||
const option = $derived({
|
||||
xAxis: {
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@ -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(
|
||||
|
||||
Reference in New Issue
Block a user