196 lines
5.4 KiB
Plaintext
196 lines
5.4 KiB
Plaintext
package treasurechest
|
|
|
|
import "fmt"
|
|
import "spend-sparrow/internal/template/svg"
|
|
import "spend-sparrow/internal/types"
|
|
import "github.com/google/uuid"
|
|
|
|
templ TreasureChest(treasureChests []*types.TreasureChest, monthlySums map[uuid.UUID]int64) {
|
|
<div class="max-w-6xl mt-10 mx-auto">
|
|
<button
|
|
hx-get="/treasurechest/new"
|
|
hx-target="#treasurechest-items"
|
|
hx-swap="afterbegin"
|
|
class="ml-auto text-center button button-primary px-2 flex items-center gap-2"
|
|
>
|
|
@svg.Plus()
|
|
New Treasure Chest
|
|
</button>
|
|
<div id="treasurechest-items" class="my-6 flex flex-col">
|
|
for _, treasureChest := range treasureChests {
|
|
@TreasureChestItem(treasureChest, monthlySums)
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.TreasureChest, transactionsRecurring templ.Component) {
|
|
{{
|
|
var (
|
|
id string
|
|
name string
|
|
parentId uuid.UUID
|
|
cancelUrl string
|
|
)
|
|
|
|
indentation := " mt-10"
|
|
if treasureChest == nil {
|
|
id = "new"
|
|
name = ""
|
|
parentId = uuid.Nil
|
|
cancelUrl = "/empty"
|
|
} else {
|
|
id = treasureChest.Id.String()
|
|
name = treasureChest.Name
|
|
if treasureChest.ParentId != nil {
|
|
parentId = *treasureChest.ParentId
|
|
indentation = " mt-2 ml-14"
|
|
}
|
|
cancelUrl = "/treasurechest/" + id
|
|
}
|
|
}}
|
|
<div id={ "treasurechest-" + id } class={ "border-1 border-gray-300 p-4 bg-gray-50 rounded-lg" + indentation }>
|
|
<form
|
|
hx-post={ "/treasurechest/" + id }
|
|
hx-target={ "#treasurechest-" + id }
|
|
hx-swap="outerHTML"
|
|
class="text-xl flex justify-end gap-4 items-center"
|
|
>
|
|
<div class="grow grid grid-cols-[auto_1fr] items-center gap-4">
|
|
<label for="name" class="text-sm text-gray-500">Name</label>
|
|
<input
|
|
autofocus
|
|
name="name"
|
|
type="text"
|
|
value={ name }
|
|
placeholder="Treasure Chest Name"
|
|
class="bg-white input max-w-96"
|
|
/>
|
|
<label for="parent-id" class="text-sm text-gray-500">Parent</label>
|
|
<select name="parent-id" class="mr-auto bg-white input">
|
|
<option value="" class="text-gray-500">-</option>
|
|
for _, parent := range filterNoChildNoSelf(parents, id) {
|
|
<option
|
|
selected?={ parentId == parent.Id }
|
|
value={ parent.Id.String() }
|
|
>{ parent.Name }</option>
|
|
}
|
|
</select>
|
|
</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={ "#treasurechest-" + id }
|
|
hx-swap="outerHTML"
|
|
class="button button-neglect px-1 flex items-center gap-2"
|
|
>
|
|
@svg.Cancel()
|
|
<span>
|
|
Cancel
|
|
</span>
|
|
</button>
|
|
</form>
|
|
if id != "new" {
|
|
<div class="m-10 border-b-gray-400 border-b-1"></div>
|
|
<div class="flex">
|
|
<h3 class="text-sm text-gray-500">Monthly Transactions</h3>
|
|
<button
|
|
hx-get={ "/transaction-recurring?id=new&treasure-chest-id=" + id }
|
|
hx-target="next #transaction-recurring"
|
|
hx-swap="outerHTML"
|
|
class="button button-primary ml-auto px-2 flex items-center gap-2"
|
|
>
|
|
@svg.Plus()
|
|
<p>New Monthly Transaction</p>
|
|
</button>
|
|
</div>
|
|
@transactionsRecurring
|
|
}
|
|
</div>
|
|
}
|
|
|
|
templ TreasureChestItem(treasureChest *types.TreasureChest, monthlySums map[uuid.UUID]int64) {
|
|
{{
|
|
var indentation string
|
|
viewTransactions := ""
|
|
if treasureChest.ParentId != nil {
|
|
indentation = " mt-2 ml-14"
|
|
} else {
|
|
indentation = " mt-10"
|
|
viewTransactions = "hidden"
|
|
}
|
|
}}
|
|
<div id={ "treasurechest-" + treasureChest.Id.String() } class={ "border-1 border-gray-300 p-4 bg-gray-50 rounded-lg" + indentation }>
|
|
<div class="text-xl flex justify-end items-center gap-4">
|
|
<p class="mr-auto">{ treasureChest.Name }</p>
|
|
<p class="mr-20 text-gray-600">
|
|
if treasureChest.ParentId != nil {
|
|
+ { displayBalance(monthlySums[treasureChest.Id]) } <span class="text-gray-500 text-sm"> per month</span>
|
|
}
|
|
</p>
|
|
if treasureChest.ParentId != nil {
|
|
if treasureChest.CurrentBalance < 0 {
|
|
<p class="mr-20 min-w-20 text-right text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
|
} else {
|
|
<p class="mr-20 min-w-20 text-right text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
|
}
|
|
}
|
|
<a
|
|
href={ templ.URL("/transaction?treasure-chest-id=" + treasureChest.Id.String()) }
|
|
class={ "button button-neglect px-1 flex items-center gap-2 " + viewTransactions }
|
|
title="View transactions"
|
|
>
|
|
@svg.Eye()
|
|
<span>
|
|
View
|
|
</span>
|
|
</a>
|
|
<button
|
|
hx-get={ "/treasurechest/" + treasureChest.Id.String() + "?edit=true" }
|
|
hx-target={ "#treasurechest-" + treasureChest.Id.String() }
|
|
hx-swap="outerHTML"
|
|
class="button button-neglect px-1 flex items-center gap-2"
|
|
>
|
|
@svg.Edit()
|
|
<span>
|
|
Edit
|
|
</span>
|
|
</button>
|
|
<button
|
|
hx-delete={ "/treasurechest/" + treasureChest.Id.String() }
|
|
hx-target={ "#treasurechest-" + treasureChest.Id.String() }
|
|
hx-swap="outerHTML"
|
|
class="button button-neglect px-1 flex items-center gap-2"
|
|
>
|
|
@svg.Delete()
|
|
<span>
|
|
Delete
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
func filterNoChildNoSelf(nodes []*types.TreasureChest, selfId string) []*types.TreasureChest {
|
|
var result []*types.TreasureChest
|
|
|
|
for _, node := range nodes {
|
|
if node.ParentId == nil && node.Id.String() != selfId {
|
|
result = append(result, node)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func displayBalance(balance int64) string {
|
|
|
|
euros := float64(balance) / 100
|
|
return fmt.Sprintf("%.2f €", euros)
|
|
}
|