235 lines
6.5 KiB
Svelte
235 lines
6.5 KiB
Svelte
<script>
|
|
import { EditSymbol } from '$lib/editSymbol.svelte';
|
|
import { TrashBin } from '$lib/trashbin.svelte';
|
|
import { getContext } from 'svelte';
|
|
import { invalidate, invalidateAll } from '$app/navigation';
|
|
import { loadingModal } from '$lib/loadingModal.svelte';
|
|
let { transactions } = $props();
|
|
const addToast = getContext('addToast');
|
|
|
|
let newData = $state({
|
|
amount: 0,
|
|
notes: '',
|
|
name: '',
|
|
id: null
|
|
});
|
|
let toDelete = $state('');
|
|
let toDeleteName = $state('');
|
|
let loading = $state(false);
|
|
let newTransaction = $state({
|
|
name: '',
|
|
id: null
|
|
});
|
|
let searchString = $state('');
|
|
let debounceString = $state('');
|
|
let searchResults = $state([]);
|
|
let searching = $state(false);
|
|
|
|
async function search() {
|
|
if (searching) return; // Prevent multiple searches at the same time
|
|
searching = true;
|
|
const res = await fetch(`/api/transactions?c=100&p=${searchString}`);
|
|
const data = await res.json();
|
|
searchResults = data;
|
|
searching = false;
|
|
}
|
|
|
|
async function updateTransactionID() {
|
|
loading = true;
|
|
EditBudgetTransactionModal.close();
|
|
if (!newTransaction.id) {
|
|
addToast('Please select a transaction to update', 'warning');
|
|
return;
|
|
}
|
|
if (newTransaction.id == newData.id) {
|
|
addToast('No changes made to the transaction', 'info');
|
|
return;
|
|
}
|
|
const response = await fetch(`/api/budget/transaction/${newData.id}`, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
transactionId: newTransaction.id
|
|
})
|
|
});
|
|
if (response.ok) {
|
|
addToast('Transaction updated successfully', 'success');
|
|
invalidateAll();
|
|
} else {
|
|
addToast('Failed to update transaction', 'error');
|
|
}
|
|
loading = false;
|
|
}
|
|
|
|
async function saveTransaction() {
|
|
loading = true;
|
|
EditBudgetTransactionModal.close();
|
|
let res = await fetch(`/api/budget/${budget.id}/transaction`, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
amount: $state.snapshot(newData.amount),
|
|
notes: $state.snapshot(newData.notes),
|
|
transactionId: $state.snapshot(newData.id)
|
|
})
|
|
});
|
|
loading = false;
|
|
console.log(res.ok);
|
|
if (res.ok) {
|
|
// Optionally, you can refresh the UI or show a success message
|
|
addToast('Transaction updated successfully', 'success');
|
|
invalidateAll();
|
|
} else {
|
|
console.error('Failed to update transaction');
|
|
addToast('Failed to update transaction', 'error');
|
|
}
|
|
}
|
|
|
|
function edit(transaction) {
|
|
newData.amount = transaction.budget_amount;
|
|
newData.name = transaction.description;
|
|
newData.notes = transaction.notes || '';
|
|
newData.id = transaction.budget_transaction_id;
|
|
searchString = transaction.notes || '';
|
|
search();
|
|
EditBudgetTransactionModal.showModal();
|
|
}
|
|
|
|
function deleteTransaction(transaction) {
|
|
toDelete = transaction.budget_transaction_id;
|
|
DeleteTransactionModal.showModal();
|
|
}
|
|
</script>
|
|
|
|
<ul class="list bg-base-100 rounded-box shadow-md">
|
|
{#each transactions as tras}
|
|
<li class="list-row">
|
|
<div>
|
|
{#if tras.id == null}
|
|
{#if tras.budget_name}
|
|
<div>{tras.budget_name}</div>
|
|
{:else}
|
|
<span class="badge badge-warning">Orphan</span>
|
|
{/if}
|
|
{:else}
|
|
<div>{tras?.description}</div>
|
|
<div class="text-xs uppercase font-semibold opacity-60">
|
|
{tras?.date?.toDateString()}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="text-center">{tras.notes}</div>
|
|
|
|
<div class="text-lg uppercase font-semibold text-right w-32">{tras?.budget_amount}</div>
|
|
<div>
|
|
<button class="btn btn-square btn-ghost" onclick={() => edit(tras)}
|
|
>{@render EditSymbol()}</button
|
|
>
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-square btn-ghost" onclick={() => deleteTransaction(tras)}
|
|
>{@render TrashBin()}</button
|
|
>
|
|
</div>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
|
|
<dialog id="EditBudgetTransactionModal" class="modal">
|
|
<div class="modal-box">
|
|
<h1>{newData.name}</h1>
|
|
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-full border p-4">
|
|
<legend class="fieldset-legend">Reassign</legend>
|
|
<div class="join w-full">
|
|
<label class="input">
|
|
<svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
<g
|
|
stroke-linejoin="round"
|
|
stroke-linecap="round"
|
|
stroke-width="2.5"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
>
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.3-4.3"></path>
|
|
</g>
|
|
</svg>
|
|
<input type="search" required placeholder="Search" bind:value={searchString} />
|
|
</label>
|
|
<button class="btn btn-neutral join-item" onclick={() => search()} disabled={searching}
|
|
>Search</button
|
|
>
|
|
</div>
|
|
<div class="join w-full">
|
|
<select class="select" bind:value={newTransaction.id} disabled={searching}>
|
|
<option value="" disabled selected>Select a Transaction</option>
|
|
{#each searchResults as res}
|
|
<option value={res?.id}
|
|
>{res?.description} - {new Date(res?.date).toDateString()} - {res?.amount}}</option
|
|
>
|
|
{/each}
|
|
</select>
|
|
<button class="btn btn-neutral join-item" onclick={() => updateTransactionID()}
|
|
>Update</button
|
|
>
|
|
</div>
|
|
</fieldset>
|
|
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-full border p-4">
|
|
<legend class="fieldset-legend">Edit</legend>
|
|
|
|
<label class="label">Amount</label>
|
|
<input
|
|
bind:value={newData.amount}
|
|
type="text"
|
|
placeholder="Amount"
|
|
class="input input-bordered w-full"
|
|
/>
|
|
|
|
<label class="label">Notes</label>
|
|
<textarea bind:value={newData.notes} class="textarea w-full" placeholder="Budget Notes"
|
|
></textarea>
|
|
|
|
<button onclick={() => saveTransaction()} class="btn btn-primary mt-4">Save</button>
|
|
</fieldset>
|
|
</div>
|
|
<form method="dialog" class="modal-backdrop">
|
|
<button>close</button>
|
|
</form>
|
|
</dialog>
|
|
|
|
<dialog id="DeleteTransactionModal" class="modal">
|
|
<div class="modal-box">
|
|
<p>Are you sure you want to delete</p>
|
|
<span>{toDelete}</span>
|
|
<button
|
|
class="btn btn-error mt-4"
|
|
onclick={async () => {
|
|
let res = await fetch(`/api/budget/${toDelete}/transaction/`, {
|
|
method: 'DELETE'
|
|
});
|
|
if (res.ok) {
|
|
console.log('Rule deleted successfully');
|
|
DeleteTransactionModal.close();
|
|
invalidateAll();
|
|
addToast('Transaction deleted successfully', 'success');
|
|
} else {
|
|
console.error('Failed to delete transaction');
|
|
addToast('Failed to delete transaction', 'error');
|
|
}
|
|
}}>Delete</button
|
|
>
|
|
</div>
|
|
<form method="dialog" class="modal-backdrop">
|
|
<button>close</button>
|
|
</form>
|
|
</dialog>
|
|
|
|
{#if loading}
|
|
{@render loadingModal()}
|
|
{/if}
|