wip: recurring transactions
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 4m24s

This commit is contained in:
2025-05-24 17:31:29 +02:00
parent e70d90c60d
commit e625ef21b4
3 changed files with 131 additions and 140 deletions

View File

@@ -84,7 +84,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
} }
transactionsRecurring, err := h.transactionRecurring.GetAllByTreasureChest(user, treasureChest.Id.String()) transactionsRecurring, err := h.transactionRecurring.GetAllByTreasureChest(user, treasureChest.Id.String())
transactionsRec := tr.TransactionRecurringItems(transactionsRecurring) transactionsRec := tr.TransactionRecurringItems(transactionsRecurring, "", "", "")
var comp templ.Component var comp templ.Component
if r.URL.Query().Get("edit") == "true" { if r.URL.Query().Get("edit") == "true" {

View File

@@ -309,7 +309,7 @@ func (s TransactionRecurringImpl) Delete(user *types.User, id string) error {
return err return err
} }
r, err := tx.Exec("DELETE FROM \"transactionRecurring\" WHERE id = ? AND user_id = ?", uuid, user.Id) r, err := tx.Exec("DELETE FROM transaction_recurring WHERE id = ? AND user_id = ?", uuid, user.Id)
err = db.TransformAndLogDbError("transactionRecurring Delete", r, err) err = db.TransformAndLogDbError("transactionRecurring Delete", r, err)
if err != nil { if err != nil {
return err return err

View File

@@ -4,77 +4,72 @@ import "fmt"
import "spend-sparrow/template/svg" import "spend-sparrow/template/svg"
import "spend-sparrow/types" import "spend-sparrow/types"
templ TransactionRecurringItems(transactionsRecurring []*types.TransactionRecurring) { templ TransactionRecurringItems(transactionsRecurring []*types.TransactionRecurring, editId, accountId, treasureChestId string) {
<table id="transaction-recurring-items border-spacing-96" class="p-40 w-full"> <!-- Don't use table, because embedded forms are only valid for cells -->
<thead> <div class="grid gap-4 mt-10 grid-cols-[auto_auto_auto_auto_max-content] items-center text-xl">
<tr> <span class="text-sm text-gray-500">Party</span>
<th class="text-sm text-gray-500">Party</th> <span class="text-sm text-gray-500">Description</span>
<th class="text-sm text-gray-500">Description</th> <span class="text-sm text-gray-500">Interval</span>
<th class="text-sm text-gray-500">Value (€)</th> <span class="text-sm text-right text-gray-500">Value</span>
<th class="text-sm text-gray-500">Actions</th> <span></span>
</tr> for _, transaction := range transactionsRecurring {
</thead> if transaction.Id.String() == editId {
<tbody> @EditTransactionRecurring(transaction, accountId, treasureChestId)
for _, transaction := range transactionsRecurring { } else {
@TransactionRecurringItem(transaction) @TransactionRecurringItem(transaction)
} }
</tbody> }
</table> </div>
} }
templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring) { templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring) {
<tr id={ "transaction-recurring" + transactionRecurring.Id.String() } class="mx-20"> <p class="text-gray-600">
<td> if transactionRecurring.Party != "" {
<p class="text-sm text-gray-500"> { transactionRecurring.Party }
if transactionRecurring.Party != "" { } else {
{ transactionRecurring.Party } &nbsp;
} else { }
&nbsp; </p>
} <p class="text-gray-600">
</p> if transactionRecurring.Description != "" {
</td> { transactionRecurring.Description }
<td> } else {
<p class="text-sm text-gray-500"> &nbsp;
if transactionRecurring.Description != "" { }
{ transactionRecurring.Description } </p>
} else { <p class="text-gray-500 text-sm">
&nbsp; Every <span class="text-xl">{ transactionRecurring.IntervalMonths }</span> month(s)
} </p>
</p> if transactionRecurring.Value < 0 {
</td> <p class="text-right text-red-700">{ displayBalance(transactionRecurring.Value)+" €" }</p>
<td> } else {
if transactionRecurring.Value < 0 { <p class="text-right text-green-700">{ displayBalance(transactionRecurring.Value)+" €" }</p>
<p class="mr-8 min-w-22 text-red-700">{ displayBalance(transactionRecurring.Value)+" €" }</p> }
} else { <div class="flex gap-2">
<p class="mr-8 min-w-22 text-green-700">{ displayBalance(transactionRecurring.Value)+" €" }</p> <button
} hx-get={ "/transaction-recurring/" + transactionRecurring.Id.String() + "?edit=true" }
</td> hx-target={ "#transaction-recurring" + transactionRecurring.Id.String() }
<td class="flex gap-2"> hx-swap="outerHTML"
<button class="button button-neglect px-1 flex items-center gap-2"
hx-get={ "/transaction-recurring/" + transactionRecurring.Id.String() + "?edit=true" } >
hx-target="closest #transaction" @svg.Edit()
hx-swap="outerHTML" <span>
class="button button-neglect px-1 flex items-center gap-2" Edit
> </span>
@svg.Edit() </button>
<span> <button
Edit hx-delete={ "/transaction-recurring/" + transactionRecurring.Id.String() }
</span> hx-target={ "#transaction-recurring" + transactionRecurring.Id.String() }
</button> hx-swap="outerHTML"
<button hx-confirm="Are you sure you want to delete this transaction?"
hx-delete={ "/transaction-recurring/" + transactionRecurring.Id.String() } class="button button-neglect px-1 flex items-center gap-2"
hx-target="closest #transaction" >
hx-swap="outerHTML" @svg.Delete()
hx-confirm="Are you sure you want to delete this transaction?" <span>
class="button button-neglect px-1 flex items-center gap-2" Delete
> </span>
@svg.Delete() </button>
<span> </div>
Delete
</span>
</button>
</td>
</tr>
} }
templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring, accountId, treasureChestId string) { templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring, accountId, treasureChestId string) {
@@ -102,79 +97,75 @@ templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring,
cancelUrl = "/transaction-recurring/" + id cancelUrl = "/transaction-recurring/" + id
} }
}} }}
<div id="transaction" class="border-1 border-gray-300 w-full my-4 p-4 bg-gray-50 rounded-lg"> <form
<form id="transaction-recurring-form"
hx-post={ "/transaction-recurring/" + id } hx-post={ "/transaction-recurring/" + id }
hx-target="closest #transaction" hx-target="closest #transaction"
hx-swap="outerHTML" hx-swap="outerHTML"
class="text-xl flex justify-end gap-4 items-center" class="text-xl flex justify-end gap-4 items-center"
> ></form>
<div class="grid grid-cols-[auto_auto] items-center gap-4 "> <div class="col-span-2">
<div class="col-span-2"> <input
<input name="active"
name="active" id="active"
id="active" type="checkbox"
type="checkbox" checked?={ active }
checked?={ active } class="bg-white input"
class="bg-white input" />
/> <label for="active" class="select-none text-sm text-gray-800">Active</label>
<label for="active" class="select-none text-sm text-gray-800">Active</label>
</div>
<label for="interval-months" class="text-sm text-gray-500">Interval Months</label>
<input
name="interval-months"
type="number"
value={ intervalMonths }
class="bg-white input"
/>
<label for="party" class="text-sm text-gray-500">Party</label>
<input
name="party"
type="text"
value={ party }
class="bg-white input"
/>
<label for="description" class="text-sm text-gray-500">Description</label>
<input
name="description"
type="text"
value={ description }
class="bg-white input"
/>
<label for="value" class="text-sm text-gray-500">Value (€)</label>
<input
name="value"
step="0.01"
type="number"
value={ value }
class="bg-white input"
/>
if accountId != "" {
<input type="text" name="account-id" class="hidden text-sm text-gray-500" value={ accountId }/>
}
if treasureChestId != "" {
<input type="text" name="treasure-chest-id" class="hidden text-sm text-gray-500" value={ treasureChestId }/>
}
</div>
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
@svg.Save()
<span>
Save
</span>
</button>
<button
hx-get={ cancelUrl }
hx-target="closest #transaction"
hx-swap="outerHTML"
class="button button-neglect px-1 flex items-center gap-2"
>
@svg.Cancel()
<span>
Cancel
</span>
</button>
</form>
</div> </div>
<label for="interval-months" class="text-sm text-gray-500">Interval Months</label>
<input
name="interval-months"
type="number"
value={ intervalMonths }
class="bg-white input"
/>
<label for="party" class="text-sm text-gray-500">Party</label>
<input
name="party"
type="text"
value={ party }
class="bg-white input"
/>
<label for="description" class="text-sm text-gray-500">Description</label>
<input
name="description"
type="text"
value={ description }
class="bg-white input"
/>
<label for="value" class="text-sm text-gray-500">Value (€)</label>
<input
name="value"
step="0.01"
type="number"
value={ value }
class="bg-white input"
/>
if accountId != "" {
<input type="text" name="account-id" class="hidden text-sm text-gray-500" value={ accountId }/>
}
if treasureChestId != "" {
<input type="text" name="treasure-chest-id" class="hidden text-sm text-gray-500" value={ treasureChestId }/>
}
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
@svg.Save()
<span>
Save
</span>
</button>
<button
hx-get={ cancelUrl }
hx-target={ "#transaction-recurring" + transactionRecurring.Id.String() }
hx-swap="outerHTML"
class="button button-neglect px-1 flex items-center gap-2"
>
@svg.Cancel()
<span>
Cancel
</span>
</button>
} }
func displayBalance(balance int64) string { func displayBalance(balance int64) string {