Enhance account management: add functionality to hide accounts and retrieve hidden accounts; update API to handle account visibility settings.

This commit is contained in:
2025-07-08 21:00:49 -04:00
parent 61d2a258fc
commit aaa675b6ee
5 changed files with 179 additions and 73 deletions

View File

@ -11,6 +11,14 @@ export async function setAccountInTotal(accountId, total) {
` `
} }
export async function setAccountHide(accountId, hide) {
return await db`
update account
set hide = ${hide}
where id = ${accountId}
`
}
export async function deleteBudget(id) { export async function deleteBudget(id) {
return await db` return await db`
UPDATE budget UPDATE budget
@ -148,9 +156,31 @@ export async function getAccounts(age) {
org.name as org_name, org.name as org_name,
balance, balance,
available_balance, available_balance,
balance_date balance_date,
hide,
in_total
from account from account
left join org on org.id = account.org_id left join org on org.id = account.org_id
where account.hide is false
`
// users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...]
return accounts
}
export async function getHiddenAccounts(age) {
const accounts = await db`
select
account.id as id,
account.name as name,
org.name as org_name,
balance,
available_balance,
balance_date,
hide,
in_total
from account
left join org on org.id = account.org_id
where account.hide is true
` `
// users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...] // users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...]
return accounts return accounts

View File

@ -4,10 +4,11 @@ import { getTransactions } from '$lib/db';
/** @type {import('./$types').PageServerLoad} */ /** @type {import('./$types').PageServerLoad} */
export async function load({ params }) { export async function load({ params }) {
const transactions = await getTransactions(params.slug); const transactions = await getTransactions(params.slug);
const slug = params.slug;
if (transactions) { if (transactions) {
return {transactions}; return {transactions, slug};
} }
error(404, 'Not found'); error(404, 'Not found');
} }

View File

@ -1,74 +1,148 @@
<script> <script>
let { data } = $props(); let { data } = $props();
let trans = $state(data.transactions); console.log(data);
let notes = $state(""); let trans = $state(data.transactions);
let currentTransaction = $state(null); let notes = $state('');
let currentTransaction = $state(null);
let account = $state(data.accounts.find((a) => a.id == data.slug) || {});
let hide = $state(account?.hide || false);
let inTotal = $state(account?.in_total || false);
function editNotes(transaction) { function editNotes(transaction) {
my_modal_3.showModal() my_modal_3.showModal();
currentTransaction = transaction; currentTransaction = transaction;
notes = transaction.notes; notes = transaction.notes;
} }
async function saveNotes() { async function saveNotes() {
let res = fetch(`/transcation/${currentTransaction.id}`, { let res = fetch(`/transcation/${currentTransaction.id}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ notes:$state.snapshot(notes) }) body: JSON.stringify({ notes: $state.snapshot(notes) })
}) });
my_modal_3.close(); my_modal_3.close();
let result = await res; let result = await res;
if (result.ok) { if (result.ok) {
// Update the transaction in the data // Update the transaction in the data
currentTransaction.notes = notes; currentTransaction.notes = notes;
// Optionally, you can also update the UI or show a success message // Optionally, you can also update the UI or show a success message
} else { } else {
// Handle error case // Handle error case
console.error("Failed to save notes"); console.error('Failed to save notes');
}
}
async function saveSettings() {
let res = await fetch(`/api/account/${account.id}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
hide: $state.snapshot(hide),
in_total: $state.snapshot(inTotal)
})
});
if (res.ok) {
settings_modal.close();
// Optionally, you can refresh the account data or show a success message
} else {
console.error('Failed to save settings');
}
} }
}
</script> </script>
<div class="flex justify-between mb-4"> <div class="flex mb-4">
<h1 class="text-2xl font-bold">Account: {data.account.name}</h1> <div class="w-128 flex-none justify-bottom"><h1 class="text-xl font-bold">{account?.name}</h1></div>
</div> <div class="w-64 grow">{account?.amount}</div>
<div class="w-14 flex-none text-right">
<svg onclick={()=>settings_modal.showModal()} fill="#000000" height="20px" width="20px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 478.703 478.703" xml:space="preserve">
<g>
<g>
<path fill="#FEFEFE" d="M454.2,189.101l-33.6-5.7c-3.5-11.3-8-22.2-13.5-32.6l19.8-27.7c8.4-11.8,7.1-27.9-3.2-38.1l-29.8-29.8
c-5.6-5.6-13-8.7-20.9-8.7c-6.2,0-12.1,1.9-17.1,5.5l-27.8,19.8c-10.8-5.7-22.1-10.4-33.8-13.9l-5.6-33.2
c-2.4-14.3-14.7-24.7-29.2-24.7h-42.1c-14.5,0-26.8,10.4-29.2,24.7l-5.8,34c-11.2,3.5-22.1,8.1-32.5,13.7l-27.5-19.8
c-5-3.6-11-5.5-17.2-5.5c-7.9,0-15.4,3.1-20.9,8.7l-29.9,29.8c-10.2,10.2-11.6,26.3-3.2,38.1l20,28.1
c-5.5,10.5-9.9,21.4-13.3,32.7l-33.2,5.6c-14.3,2.4-24.7,14.7-24.7,29.2v42.1c0,14.5,10.4,26.8,24.7,29.2l34,5.8
c3.5,11.2,8.1,22.1,13.7,32.5l-19.7,27.4c-8.4,11.8-7.1,27.9,3.2,38.1l29.8,29.8c5.6,5.6,13,8.7,20.9,8.7c6.2,0,12.1-1.9,17.1-5.5
l28.1-20c10.1,5.3,20.7,9.6,31.6,13l5.6,33.6c2.4,14.3,14.7,24.7,29.2,24.7h42.2c14.5,0,26.8-10.4,29.2-24.7l5.7-33.6
c11.3-3.5,22.2-8,32.6-13.5l27.7,19.8c5,3.6,11,5.5,17.2,5.5l0,0c7.9,0,15.3-3.1,20.9-8.7l29.8-29.8c10.2-10.2,11.6-26.3,3.2-38.1
l-19.8-27.8c5.5-10.5,10.1-21.4,13.5-32.6l33.6-5.6c14.3-2.4,24.7-14.7,24.7-29.2v-42.1
C478.9,203.801,468.5,191.501,454.2,189.101z M451.9,260.401c0,1.3-0.9,2.4-2.2,2.6l-42,7c-5.3,0.9-9.5,4.8-10.8,9.9
c-3.8,14.7-9.6,28.8-17.4,41.9c-2.7,4.6-2.5,10.3,0.6,14.7l24.7,34.8c0.7,1,0.6,2.5-0.3,3.4l-29.8,29.8c-0.7,0.7-1.4,0.8-1.9,0.8
c-0.6,0-1.1-0.2-1.5-0.5l-34.7-24.7c-4.3-3.1-10.1-3.3-14.7-0.6c-13.1,7.8-27.2,13.6-41.9,17.4c-5.2,1.3-9.1,5.6-9.9,10.8l-7.1,42
c-0.2,1.3-1.3,2.2-2.6,2.2h-42.1c-1.3,0-2.4-0.9-2.6-2.2l-7-42c-0.9-5.3-4.8-9.5-9.9-10.8c-14.3-3.7-28.1-9.4-41-16.8
c-2.1-1.2-4.5-1.8-6.8-1.8c-2.7,0-5.5,0.8-7.8,2.5l-35,24.9c-0.5,0.3-1,0.5-1.5,0.5c-0.4,0-1.2-0.1-1.9-0.8l-29.8-29.8
c-0.9-0.9-1-2.3-0.3-3.4l24.6-34.5c3.1-4.4,3.3-10.2,0.6-14.8c-7.8-13-13.8-27.1-17.6-41.8c-1.4-5.1-5.6-9-10.8-9.9l-42.3-7.2
c-1.3-0.2-2.2-1.3-2.2-2.6v-42.1c0-1.3,0.9-2.4,2.2-2.6l41.7-7c5.3-0.9,9.6-4.8,10.9-10c3.7-14.7,9.4-28.9,17.1-42
c2.7-4.6,2.4-10.3-0.7-14.6l-24.9-35c-0.7-1-0.6-2.5,0.3-3.4l29.8-29.8c0.7-0.7,1.4-0.8,1.9-0.8c0.6,0,1.1,0.2,1.5,0.5l34.5,24.6
c4.4,3.1,10.2,3.3,14.8,0.6c13-7.8,27.1-13.8,41.8-17.6c5.1-1.4,9-5.6,9.9-10.8l7.2-42.3c0.2-1.3,1.3-2.2,2.6-2.2h42.1
c1.3,0,2.4,0.9,2.6,2.2l7,41.7c0.9,5.3,4.8,9.6,10,10.9c15.1,3.8,29.5,9.7,42.9,17.6c4.6,2.7,10.3,2.5,14.7-0.6l34.5-24.8
c0.5-0.3,1-0.5,1.5-0.5c0.4,0,1.2,0.1,1.9,0.8l29.8,29.8c0.9,0.9,1,2.3,0.3,3.4l-24.7,34.7c-3.1,4.3-3.3,10.1-0.6,14.7
c7.8,13.1,13.6,27.2,17.4,41.9c1.3,5.2,5.6,9.1,10.8,9.9l42,7.1c1.3,0.2,2.2,1.3,2.2,2.6v42.1H451.9z"/>
<path fill="#FEFEFE" d="M239.4,136.001c-57,0-103.3,46.3-103.3,103.3s46.3,103.3,103.3,103.3s103.3-46.3,103.3-103.3S296.4,136.001,239.4,136.001
z M239.4,315.601c-42.1,0-76.3-34.2-76.3-76.3s34.2-76.3,76.3-76.3s76.3,34.2,76.3,76.3S281.5,315.601,239.4,315.601z"/>
</g>
</g>
</svg>
</div>
</div>
<h1>Transcations</h1> <h1>Transcations</h1>
<table class="table w-full"> <table class="table w-full">
<thead> <thead>
<tr> <tr>
<th>Date</th> <th>Date</th>
<th>Description</th> <th>Description</th>
<th>Amount</th> <th>Amount</th>
<th>Notes</th> <th>Notes</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each trans as transaction} {#each trans as transaction}
<tr class="hover:bg-base-300" onclick={() => editNotes(transaction)}> <tr class="hover:bg-base-300" onclick={() => editNotes(transaction)}>
<td>{transaction.date.toDateString()}</td> <td>{transaction.date.toDateString()}</td>
<td>{transaction.description}</td> <td>{transaction.description}</td>
<td>{transaction.amount}</td> <td>{transaction.amount}</td>
<td>{transaction.notes}</td> <td>{transaction.notes}</td>
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
<dialog id="my_modal_3" class="modal"> <dialog id="my_modal_3" class="modal">
<div class="modal-box"> <div class="modal-box">
<form method="dialog"> <form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button> <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form> </form>
<h3>{currentTransaction?.description}</h3> <h3>{currentTransaction?.description}</h3>
<h4>${currentTransaction?.amount}</h4> <h4>${currentTransaction?.amount}</h4>
<p> {currentTransaction?.date?.toDateString()}</p> <p>{currentTransaction?.date?.toDateString()}</p>
<div> <div>
<textarea bind:value={notes} class="textarea w-100"></textarea> <textarea bind:value={notes} class="textarea w-100"></textarea>
</div> </div>
<button onclick={() => saveNotes()} class="btn btn-primary mt-4">Save</button> <button onclick={() => saveNotes()} class="btn btn-primary mt-4">Save</button>
</div> </div>
</dialog>
<dialog id="settings_modal" class="modal">
<div class="modal-box">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
<h3>{account?.name}</h3>
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">Options</legend>
<label class="label">
<input type="checkbox" bind:checked={hide} class="toggle" />
Hide
</label>
<label class="label">
<input type="checkbox" bind:checked={inTotal} class="toggle" />
Use in total
</label>
</fieldset>
<button onclick={() => saveSettings()} class="btn btn-primary mt-4">Save</button>
</div>
</dialog> </dialog>

View File

@ -1,13 +1,14 @@
import { setAccountInTotal } from "$lib/db"; import { setAccountInTotal, setAccountHide } from "$lib/db";
export async function POST({ request }) { export async function POST({ request, params }) {
const body = await request.json(); const body = await request.json();
const { slug, total } = body; const { hide, in_total } = body;
const { slug } = params;
console.log(`Setting account ${slug} in total to ${total}`); console.log(`Setting account ${slug} in total to ${in_total} and hide to ${hide}`);
try { try {
const res = await setAccountInTotal(slug, total); const res = await setAccountInTotal(slug, in_total) && await setAccountHide(slug, body.hide);
return new Response(JSON.stringify({ success: true, data: res }), { return new Response(JSON.stringify({ success: true, data: res }), {
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'

View File

@ -37,7 +37,7 @@
class="cursor-pointer hover:scale-110 transition" class="cursor-pointer hover:scale-110 transition"
onclick={()=> DeleteBudgetModal.showModal()} onclick={()=> DeleteBudgetModal.showModal()}
> >
<path d="M 14.984375 2.4863281 A 1.0001 1.0001 0 0 0 14 3.5 L 14 4 L 8.5 4 A 1.0001 1.0001 0 0 0 7.4863281 5 L 6 5 A 1.0001 1.0001 0 1 0 6 7 L 24 7 A 1.0001 1.0001 0 1 0 24 5 L 22.513672 5 A 1.0001 1.0001 0 0 0 21.5 4 L 16 4 L 16 3.5 A 1.0001 1.0001 0 0 0 14.984375 2.4863281 z M 6 9 L 7.7929688 24.234375 C 7.9109687 25.241375 8.7633438 26 9.7773438 26 L 20.222656 26 C 21.236656 26 22.088031 25.241375 22.207031 24.234375 L 24 9 L 6 9 z"/> <path fill="#FEFEFE" d="M 14.984375 2.4863281 A 1.0001 1.0001 0 0 0 14 3.5 L 14 4 L 8.5 4 A 1.0001 1.0001 0 0 0 7.4863281 5 L 6 5 A 1.0001 1.0001 0 1 0 6 7 L 24 7 A 1.0001 1.0001 0 1 0 24 5 L 22.513672 5 A 1.0001 1.0001 0 0 0 21.5 4 L 16 4 L 16 3.5 A 1.0001 1.0001 0 0 0 14.984375 2.4863281 z M 6 9 L 7.7929688 24.234375 C 7.9109687 25.241375 8.7633438 26 9.7773438 26 L 20.222656 26 C 21.236656 26 22.088031 25.241375 22.207031 24.234375 L 24 9 L 6 9 z"/>
</svg> </svg>
</div> </div>
</div> </div>