feat(treasurechest): #64 implement hirarchical treasure chests
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 4m14s
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 4m14s
This commit is contained in:
@@ -30,8 +30,8 @@ func NewTreasureChestSqlite(db *sqlx.DB) *TreasureChestSqlite {
|
|||||||
func (db TreasureChestSqlite) Insert(userId uuid.UUID, treasureChest *types.TreasureChest) error {
|
func (db TreasureChestSqlite) Insert(userId uuid.UUID, treasureChest *types.TreasureChest) error {
|
||||||
|
|
||||||
_, err := db.db.Exec(`
|
_, err := db.db.Exec(`
|
||||||
INSERT INTO treasure_chest (id, parent_id, user_id, name, account_id, current_balance, created_at, created_by)
|
INSERT INTO treasure_chest (id, parent_id, user_id, name, current_balance, created_at, created_by)
|
||||||
VALUES (?,?,?,?,?,?,?,?)`, treasureChest.Id, treasureChest.ParentId, userId, treasureChest.Name, treasureChest.AccountId, 0, treasureChest.CreatedAt, treasureChest.CreatedBy)
|
VALUES (?,?,?,?,?,?,?)`, treasureChest.Id, treasureChest.ParentId, userId, treasureChest.Name, 0, treasureChest.CreatedAt, treasureChest.CreatedBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("treasureChest Insert: %v", err)
|
log.Error("treasureChest Insert: %v", err)
|
||||||
return types.ErrInternal
|
return types.ErrInternal
|
||||||
@@ -47,12 +47,11 @@ func (db TreasureChestSqlite) Update(userId uuid.UUID, treasureChest *types.Trea
|
|||||||
SET
|
SET
|
||||||
parent_id = ?,
|
parent_id = ?,
|
||||||
name = ?,
|
name = ?,
|
||||||
account_id = ?,
|
|
||||||
current_balance = ?,
|
current_balance = ?,
|
||||||
updated_at = ?,
|
updated_at = ?,
|
||||||
updated_by = ?
|
updated_by = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
AND user_id = ?`, treasureChest.ParentId, treasureChest.Name, treasureChest.AccountId, treasureChest.CurrentBalance, treasureChest.UpdatedAt, treasureChest.UpdatedBy, treasureChest.Id, userId)
|
AND user_id = ?`, treasureChest.ParentId, treasureChest.Name, treasureChest.CurrentBalance, treasureChest.UpdatedAt, treasureChest.UpdatedBy, treasureChest.Id, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("treasureChest Update: %v", err)
|
log.Error("treasureChest Update: %v", err)
|
||||||
return types.ErrInternal
|
return types.ErrInternal
|
||||||
@@ -76,7 +75,7 @@ func (db TreasureChestSqlite) GetAll(userId uuid.UUID) ([]*types.TreasureChest,
|
|||||||
treasureChests := make([]*types.TreasureChest, 0)
|
treasureChests := make([]*types.TreasureChest, 0)
|
||||||
err := db.db.Select(&treasureChests, `
|
err := db.db.Select(&treasureChests, `
|
||||||
SELECT
|
SELECT
|
||||||
id, parent_id, user_id, name, account_id, current_balance,
|
id, parent_id, user_id, name, current_balance,
|
||||||
created_at, created_by, updated_at, updated_by
|
created_at, created_by, updated_at, updated_by
|
||||||
FROM treasure_chest
|
FROM treasure_chest
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
@@ -94,7 +93,7 @@ func (db TreasureChestSqlite) GetAllByParentId(userId uuid.UUID, parentId uuid.U
|
|||||||
treasureChests := make([]*types.TreasureChest, 0)
|
treasureChests := make([]*types.TreasureChest, 0)
|
||||||
err := db.db.Select(&treasureChests, `
|
err := db.db.Select(&treasureChests, `
|
||||||
SELECT
|
SELECT
|
||||||
id, parent_id, user_id, name, account_id, current_balance,
|
id, parent_id, user_id, name, current_balance,
|
||||||
created_at, created_by, updated_at, updated_by
|
created_at, created_by, updated_at, updated_by
|
||||||
FROM treasure_chest
|
FROM treasure_chest
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
@@ -113,7 +112,7 @@ func (db TreasureChestSqlite) Get(userId uuid.UUID, id uuid.UUID) (*types.Treasu
|
|||||||
treasureChest := &types.TreasureChest{}
|
treasureChest := &types.TreasureChest{}
|
||||||
err := db.db.Get(treasureChest, `
|
err := db.db.Get(treasureChest, `
|
||||||
SELECT
|
SELECT
|
||||||
id, parent_id, user_id, name, account_id, current_balance,
|
id, parent_id, user_id, name, current_balance,
|
||||||
created_at, created_by, updated_at, updated_by
|
created_at, created_by, updated_at, updated_by
|
||||||
FROM treasure_chest
|
FROM treasure_chest
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"spend-sparrow/handler/middleware"
|
"spend-sparrow/handler/middleware"
|
||||||
"spend-sparrow/log"
|
|
||||||
"spend-sparrow/service"
|
"spend-sparrow/service"
|
||||||
t "spend-sparrow/template/treasurechest"
|
t "spend-sparrow/template/treasurechest"
|
||||||
"spend-sparrow/types"
|
"spend-sparrow/types"
|
||||||
"spend-sparrow/utils"
|
"spend-sparrow/utils"
|
||||||
|
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TreasureChest interface {
|
type TreasureChest interface {
|
||||||
@@ -18,18 +16,16 @@ type TreasureChest interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TreasureChestImpl struct {
|
type TreasureChestImpl struct {
|
||||||
s service.TreasureChest
|
s service.TreasureChest
|
||||||
account service.Account
|
a service.Auth
|
||||||
a service.Auth
|
r *Render
|
||||||
r *Render
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTreasureChest(s service.TreasureChest, account service.Account, a service.Auth, r *Render) TreasureChest {
|
func NewTreasureChest(s service.TreasureChest, a service.Auth, r *Render) TreasureChest {
|
||||||
return TreasureChestImpl{
|
return TreasureChestImpl{
|
||||||
s: s,
|
s: s,
|
||||||
account: account,
|
a: a,
|
||||||
a: a,
|
r: r,
|
||||||
r: r,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +49,8 @@ func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc {
|
|||||||
handleError(w, r, err)
|
handleError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
accounts, err := h.account.GetAll(user)
|
|
||||||
if err != nil {
|
|
||||||
handleError(w, r, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
comp := t.TreasureChest(treasureChests, accounts)
|
comp := t.TreasureChest(treasureChests)
|
||||||
h.r.RenderLayout(r, w, comp, user)
|
h.r.RenderLayout(r, w, comp, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +63,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
accounts, err := h.account.GetAll(user)
|
treasureChests, err := h.s.GetAll(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, r, err)
|
handleError(w, r, err)
|
||||||
return
|
return
|
||||||
@@ -80,7 +71,7 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
|||||||
|
|
||||||
id := r.PathValue("id")
|
id := r.PathValue("id")
|
||||||
if id == "new" {
|
if id == "new" {
|
||||||
comp := t.EditTreasureChest(nil, accounts)
|
comp := t.EditTreasureChest(nil, treasureChests)
|
||||||
h.r.Render(r, w, comp)
|
h.r.Render(r, w, comp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -93,23 +84,14 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
|||||||
|
|
||||||
var comp templ.Component
|
var comp templ.Component
|
||||||
if r.URL.Query().Get("edit") == "true" {
|
if r.URL.Query().Get("edit") == "true" {
|
||||||
comp = t.EditTreasureChest(treasureChest, accounts)
|
comp = t.EditTreasureChest(treasureChest, treasureChests)
|
||||||
} else {
|
} else {
|
||||||
comp = t.TreasureChestItem(treasureChest, find(accounts, treasureChest.AccountId))
|
comp = t.TreasureChestItem(treasureChest)
|
||||||
}
|
}
|
||||||
h.r.Render(r, w, comp)
|
h.r.Render(r, w, comp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func find(accounts []*types.Account, id uuid.UUID) *types.Account {
|
|
||||||
for _, account := range accounts {
|
|
||||||
if account.Id == id {
|
|
||||||
return account
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
user := middleware.GetUser(r)
|
user := middleware.GetUser(r)
|
||||||
@@ -125,24 +107,21 @@ func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
|||||||
id := r.PathValue("id")
|
id := r.PathValue("id")
|
||||||
parentId := r.FormValue("parent-id")
|
parentId := r.FormValue("parent-id")
|
||||||
name := r.FormValue("name")
|
name := r.FormValue("name")
|
||||||
accountId := r.FormValue("account-id")
|
|
||||||
log.Info("accountId: %s", accountId)
|
|
||||||
if id == "new" {
|
if id == "new" {
|
||||||
treasureChest, err = h.s.Add(user, parentId, name, accountId)
|
treasureChest, err = h.s.Add(user, parentId, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, r, err)
|
handleError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
treasureChest, err = h.s.Update(user, id, parentId, name, accountId)
|
treasureChest, err = h.s.Update(user, id, parentId, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(w, r, err)
|
handleError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account, err := h.account.Get(user, accountId)
|
|
||||||
|
|
||||||
comp := t.TreasureChestItem(treasureChest, account)
|
comp := t.TreasureChestItem(treasureChest)
|
||||||
h.r.Render(r, w, comp)
|
h.r.Render(r, w, comp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -122,7 +122,7 @@ func createHandler(d *sqlx.DB, serverSettings *types.Settings) http.Handler {
|
|||||||
indexHandler := handler.NewIndex(authService, render)
|
indexHandler := handler.NewIndex(authService, render)
|
||||||
authHandler := handler.NewAuth(authService, render)
|
authHandler := handler.NewAuth(authService, render)
|
||||||
accountHandler := handler.NewAccount(accountService, authService, render)
|
accountHandler := handler.NewAccount(accountService, authService, render)
|
||||||
treasureChestHandler := handler.NewTreasureChest(treasureChestService, accountService, authService, render)
|
treasureChestHandler := handler.NewTreasureChest(treasureChestService, authService, render)
|
||||||
|
|
||||||
indexHandler.Handle(router)
|
indexHandler.Handle(router)
|
||||||
accountHandler.Handle(router)
|
accountHandler.Handle(router)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TreasureChest interface {
|
type TreasureChest interface {
|
||||||
Add(user *types.User, parentId, name, accountId string) (*types.TreasureChest, error)
|
Add(user *types.User, parentId, name string) (*types.TreasureChest, error)
|
||||||
Update(user *types.User, id, parentId, name, accountId string) (*types.TreasureChest, error)
|
Update(user *types.User, id, parentId, name string) (*types.TreasureChest, error)
|
||||||
Get(user *types.User, id string) (*types.TreasureChest, error)
|
Get(user *types.User, id string) (*types.TreasureChest, error)
|
||||||
GetAll(user *types.User) ([]*types.TreasureChest, error)
|
GetAll(user *types.User) ([]*types.TreasureChest, error)
|
||||||
Delete(user *types.User, id string) error
|
Delete(user *types.User, id string) error
|
||||||
@@ -48,7 +48,7 @@ func NewTreasureChest(db db.TreasureChest, account Account, random Random, clock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId string) (*types.TreasureChest, error) {
|
func (s TreasureChestImpl) Add(user *types.User, parentId, name string) (*types.TreasureChest, error) {
|
||||||
treasureChestMetric.WithLabelValues("add").Inc()
|
treasureChestMetric.WithLabelValues("add").Inc()
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
@@ -64,11 +64,6 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
accountUuid, err := uuid.Parse(accountId)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("treasureChest add: %v", err)
|
|
||||||
return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentUuid := uuid.Nil
|
parentUuid := uuid.Nil
|
||||||
if parentId != "" {
|
if parentId != "" {
|
||||||
@@ -82,18 +77,12 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin
|
|||||||
parentUuid = parent.Id
|
parentUuid = parent.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.account.Get(user, accountId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
treasureChest := &types.TreasureChest{
|
treasureChest := &types.TreasureChest{
|
||||||
Id: newId,
|
Id: newId,
|
||||||
ParentId: parentUuid,
|
ParentId: parentUuid,
|
||||||
UserId: user.Id,
|
UserId: user.Id,
|
||||||
|
|
||||||
Name: name,
|
Name: name,
|
||||||
AccountId: accountUuid,
|
|
||||||
|
|
||||||
CurrentBalance: 0,
|
CurrentBalance: 0,
|
||||||
|
|
||||||
@@ -116,7 +105,7 @@ func (s TreasureChestImpl) Add(user *types.User, parentId, name, accountId strin
|
|||||||
return savedtreasureChest, nil
|
return savedtreasureChest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accountId string) (*types.TreasureChest, error) {
|
func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string) (*types.TreasureChest, error) {
|
||||||
treasureChestMetric.WithLabelValues("update").Inc()
|
treasureChestMetric.WithLabelValues("update").Inc()
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
@@ -125,11 +114,6 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
accountUuid, err := uuid.Parse(accountId)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("treasureChest update: %v", err)
|
|
||||||
return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest)
|
|
||||||
}
|
|
||||||
id, err := uuid.Parse(idStr)
|
id, err := uuid.Parse(idStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("treasureChest update: %v", err)
|
log.Error("treasureChest update: %v", err)
|
||||||
@@ -143,10 +127,6 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou
|
|||||||
}
|
}
|
||||||
return nil, types.ErrInternal
|
return nil, types.ErrInternal
|
||||||
}
|
}
|
||||||
_, err = s.account.Get(user, accountId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
parentUuid := uuid.Nil
|
parentUuid := uuid.Nil
|
||||||
if parentId != "" {
|
if parentId != "" {
|
||||||
@@ -157,13 +137,18 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name, accou
|
|||||||
if parent.ParentId != uuid.Nil {
|
if parent.ParentId != uuid.Nil {
|
||||||
return nil, fmt.Errorf("Only a depth of 1 allowed: %w", ErrBadRequest)
|
return nil, fmt.Errorf("Only a depth of 1 allowed: %w", ErrBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
children, err := s.db.GetAllByParentId(user.Id, treasureChest.Id)
|
||||||
|
if len(children) > 0 {
|
||||||
|
return nil, fmt.Errorf("Only a depth of 1 allowed: %w", ErrBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
parentUuid = parent.Id
|
parentUuid = parent.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := s.clock.Now()
|
timestamp := s.clock.Now()
|
||||||
treasureChest.Name = name
|
treasureChest.Name = name
|
||||||
treasureChest.ParentId = parentUuid
|
treasureChest.ParentId = parentUuid
|
||||||
treasureChest.AccountId = accountUuid
|
|
||||||
treasureChest.UpdatedAt = ×tamp
|
treasureChest.UpdatedAt = ×tamp
|
||||||
treasureChest.UpdatedBy = &user.Id
|
treasureChest.UpdatedBy = &user.Id
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,47 @@
|
|||||||
package treasurechest
|
package treasurechest
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
import "spend-sparrow/template/svg"
|
import "spend-sparrow/template/svg"
|
||||||
import "spend-sparrow/types"
|
import "spend-sparrow/types"
|
||||||
|
|
||||||
import "github.com/google/uuid"
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
// TODO: Incorporate parent-id and hirarchical view
|
func sortTree(nodes []*types.TreasureChest) []*types.TreasureChest {
|
||||||
xxx
|
|
||||||
|
|
||||||
templ TreasureChest(treasureChests []*types.TreasureChest, accounts []*types.Account) {
|
var (
|
||||||
|
roots []*types.TreasureChest
|
||||||
|
result []*types.TreasureChest
|
||||||
|
)
|
||||||
|
children := make(map[uuid.UUID][]*types.TreasureChest)
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.ParentId == uuid.Nil {
|
||||||
|
roots = append(roots, node)
|
||||||
|
} else {
|
||||||
|
children[node.ParentId] = append(children[node.ParentId], node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, root := range roots {
|
||||||
|
result = append(result, root)
|
||||||
|
result = append(result, children[root.Id]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareStrings(a, b string) int {
|
||||||
|
if a < b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
templ TreasureChest(treasureChests []*types.TreasureChest) {
|
||||||
<div class="max-w-6xl mt-10 mx-auto">
|
<div class="max-w-6xl mt-10 mx-auto">
|
||||||
<button
|
<button
|
||||||
hx-get="/treasurechest/new"
|
hx-get="/treasurechest/new"
|
||||||
@@ -17,50 +50,34 @@ templ TreasureChest(treasureChests []*types.TreasureChest, accounts []*types.Acc
|
|||||||
class="ml-auto button button-primary px-2 flex-1 flex items-center gap-2 justify-center"
|
class="ml-auto button button-primary px-2 flex-1 flex items-center gap-2 justify-center"
|
||||||
>
|
>
|
||||||
@svg.Plus()
|
@svg.Plus()
|
||||||
<p class="">New Treasure Chest</p>
|
<p>New Treasure Chest</p>
|
||||||
</button>
|
</button>
|
||||||
<div id="treasurechest-items" class="my-6 flex flex-col items-center">
|
<div id="treasurechest-items" class="my-6 flex flex-col items-center">
|
||||||
for _, treasureChest := range treasureChests {
|
for _, treasureChest := range sortTree(treasureChests) {
|
||||||
@TreasureChestItem(treasureChest, find(accounts, treasureChest.AccountId))
|
@TreasureChestItem(treasureChest)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
func find(accounts []*types.Account, id uuid.UUID) *types.Account {
|
templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.TreasureChest) {
|
||||||
for _, account := range accounts {
|
|
||||||
if account.Id == id {
|
|
||||||
return account
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func selected(accountId uuid.UUID, treasureChest *types.TreasureChest) bool {
|
|
||||||
if treasureChest != nil && accountId == treasureChest.AccountId {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
templ EditTreasureChest(treasureChest *types.TreasureChest, accounts []*types.Account) {
|
|
||||||
{{
|
{{
|
||||||
var (
|
var (
|
||||||
id string
|
id string
|
||||||
name string
|
name string
|
||||||
accountId uuid.UUID
|
parentId uuid.UUID
|
||||||
cancelUrl string
|
cancelUrl string
|
||||||
)
|
)
|
||||||
|
|
||||||
if treasureChest == nil {
|
if treasureChest == nil {
|
||||||
id = "new"
|
id = "new"
|
||||||
name = ""
|
name = ""
|
||||||
accountId = uuid.Nil
|
parentId = uuid.Nil
|
||||||
cancelUrl = "/empty"
|
cancelUrl = "/empty"
|
||||||
} else {
|
} else {
|
||||||
id = treasureChest.Id.String()
|
id = treasureChest.Id.String()
|
||||||
name = treasureChest.Name
|
name = treasureChest.Name
|
||||||
accountId = treasureChest.AccountId
|
parentId = treasureChest.ParentId
|
||||||
cancelUrl = "/treasurechest/" + id
|
cancelUrl = "/treasurechest/" + id
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -79,13 +96,13 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, accounts []*types.Ac
|
|||||||
placeholder="Treasure Chest Name"
|
placeholder="Treasure Chest Name"
|
||||||
class="bg-white input"
|
class="bg-white input"
|
||||||
/>
|
/>
|
||||||
<select name="account-id" class="mr-auto bg-white input">
|
<select name="parent-id" class="mr-auto bg-white input">
|
||||||
<option value="" class="text-gray-500">- Please select Account -</option>
|
<option value="" class="text-gray-500">-</option>
|
||||||
for _, account := range accounts {
|
for _, parent := range filterNoChildNoSelf(parents, id) {
|
||||||
<option
|
<option
|
||||||
selected?={ accountId == account.Id }
|
selected?={ parentId == parent.Id }
|
||||||
value={ account.Id.String() }
|
value={ parent.Id.String() }
|
||||||
>{ account.Name }</option>
|
>{ parent.Name }</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
|
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
|
||||||
@@ -109,17 +126,18 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, accounts []*types.Ac
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ TreasureChestItem(treasureChest *types.TreasureChest, account *types.Account) {
|
templ TreasureChestItem(treasureChest *types.TreasureChest) {
|
||||||
{{
|
{{
|
||||||
var identation string
|
var identation string
|
||||||
if treasureChest.Name == "Versicherung" {
|
if treasureChest.ParentId != uuid.Nil {
|
||||||
identation = " ml-36"
|
identation = " mt-2 ml-36"
|
||||||
|
} else {
|
||||||
|
identation = " mt-8"
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
<div id="treasurechest" class={ "border-1 border-gray-300 w-full my-4 p-4 bg-gray-50 rounded-lg" + identation }>
|
<div id="treasurechest" class={ "border-1 border-gray-300 w-full p-4 bg-gray-50 rounded-lg" + identation }>
|
||||||
<div class="text-xl flex justify-end items-center gap-4">
|
<div class="text-xl flex justify-end items-center gap-4">
|
||||||
<p class="mr-20">{ treasureChest.Name }</p>
|
<p class="mr-auto">{ treasureChest.Name }</p>
|
||||||
<p class="mr-auto text-sm text-gray-500">{ account.Name }</p>
|
|
||||||
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
||||||
<button
|
<button
|
||||||
hx-get={ "/treasurechest/" + treasureChest.Id.String() + "?edit=true" }
|
hx-get={ "/treasurechest/" + treasureChest.Id.String() + "?edit=true" }
|
||||||
@@ -147,6 +165,18 @@ templ TreasureChestItem(treasureChest *types.TreasureChest, account *types.Accou
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterNoChildNoSelf(nodes []*types.TreasureChest, selfId string) []*types.TreasureChest {
|
||||||
|
var result []*types.TreasureChest
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.ParentId == uuid.Nil && node.Id.String() != selfId {
|
||||||
|
result = append(result, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func displayBalance(balance int64) string {
|
func displayBalance(balance int64) string {
|
||||||
|
|
||||||
euros := float64(balance) / 100
|
euros := float64(balance) / 100
|
||||||
|
|||||||
@@ -7,14 +7,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// The TreasureChest is a fictional account.
|
// The TreasureChest is a fictional account.
|
||||||
// The money it "holds" is actually in the linked Account
|
// The money it "holds" distributed across all accounts
|
||||||
|
//
|
||||||
|
// At the time of writing this, linking it to a specific account doesn't really make sense
|
||||||
|
// Imagne a TreasureChest for free time activities, where some money is spend in cash and some other with credit card
|
||||||
type TreasureChest struct {
|
type TreasureChest struct {
|
||||||
Id uuid.UUID
|
Id uuid.UUID
|
||||||
ParentId uuid.UUID `db:"parent_id"`
|
ParentId uuid.UUID `db:"parent_id"`
|
||||||
UserId uuid.UUID `db:"user_id"`
|
UserId uuid.UUID `db:"user_id"`
|
||||||
|
|
||||||
AccountId uuid.UUID `db:"account_id"`
|
Name string
|
||||||
Name string
|
|
||||||
|
|
||||||
CurrentBalance int64 `db:"current_balance"`
|
CurrentBalance int64 `db:"current_balance"`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user