feat: add space account page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bdd05b0315
commit
d747454f4a
8 changed files with 169 additions and 2 deletions
|
|
@ -146,6 +146,7 @@ func (h *spaceHandler) SpaceOverviewPage(w http.ResponseWriter, r *http.Request)
|
|||
accountCards := make([]blocks.AccountCardInfo, 0, len(accounts))
|
||||
for _, a := range accounts {
|
||||
accountCards = append(accountCards, blocks.AccountCardInfo{
|
||||
SpaceID: space.ID,
|
||||
ID: a.ID,
|
||||
Name: a.Name,
|
||||
Balance: a.Balance,
|
||||
|
|
@ -158,3 +159,17 @@ func (h *spaceHandler) SpaceOverviewPage(w http.ResponseWriter, r *http.Request)
|
|||
Accounts: accountCards,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *spaceHandler) SpaceAccountPage(w http.ResponseWriter, r *http.Request) {
|
||||
spaceID := r.PathValue("spaceID")
|
||||
accountID := r.PathValue("accountID")
|
||||
|
||||
ui.Render(w, r, pages.SpaceAccountPage(pages.SpaceAccountPageProps{
|
||||
SpaceID: spaceID,
|
||||
AccountID: accountID,
|
||||
AccountName: "Money Account",
|
||||
AccountDescription: "Vault Infinite Priority",
|
||||
AccountNumber: "4492",
|
||||
AccountBalance: decimal.NewFromFloat(32093.11),
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ func SetupRoutes(a *app.App) http.Handler {
|
|||
spaceAccessMw := middleware.RequireSpaceAccess(a.SpaceService)
|
||||
g.Use(spaceAccessMw)
|
||||
g.Get("/overview", spaceH.SpaceOverviewPage).Name("page.app.spaces.space.overview")
|
||||
|
||||
g.SubGroup("/accounts/{accountID}", func(g *router.Group) {
|
||||
g.Get("/overview", spaceH.SpaceAccountPage).Name("page.app.spaces.space.accounts.account.overview")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@ package blocks
|
|||
import "github.com/shopspring/decimal"
|
||||
import "strings"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/routeurl"
|
||||
|
||||
type AccountCardInfo struct {
|
||||
SpaceID string
|
||||
ID string
|
||||
Name string
|
||||
Balance decimal.Decimal
|
||||
}
|
||||
|
||||
templ AccountCard(info AccountCardInfo) {
|
||||
<div class="px-2 py-2 block rounded-md hover:bg-sidebar-accent">
|
||||
<a href={ routeurl.URL("page.app.spaces.space.accounts.account.overview", "spaceID", info.SpaceID, "accountID", info.ID) } class="px-2 py-2 block rounded-md hover:bg-sidebar-accent">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="w-10 h-10 shrink-0 overflow-hidden rounded-md bg-muted flex items-center justify-center">
|
||||
|
|
@ -28,5 +30,5 @@ templ AccountCard(info AccountCardInfo) {
|
|||
@icon.ChevronRight()
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
|
|
|
|||
99
internal/ui/pages/space_account.templ
Normal file
99
internal/ui/pages/space_account.templ
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
package pages
|
||||
|
||||
import "github.com/shopspring/decimal"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/card"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/button"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon"
|
||||
import "git.juancwu.dev/juancwu/budgit/internal/ui/utils"
|
||||
|
||||
type SpaceAccountPageProps struct {
|
||||
SpaceID string
|
||||
AccountID string
|
||||
AccountName string
|
||||
AccountDescription string
|
||||
AccountNumber string
|
||||
AccountBalance decimal.Decimal
|
||||
}
|
||||
|
||||
templ SpaceAccountPage(props SpaceAccountPageProps) {
|
||||
{{
|
||||
balanceTextClasses := []string{"text-4xl font-bold"}
|
||||
if props.AccountBalance.IsPositive() {
|
||||
balanceTextClasses = append(balanceTextClasses, "text-green-600 dark:text-green-400")
|
||||
} else {
|
||||
balanceTextClasses = append(balanceTextClasses, "text-red-600 dark:text-red-400")
|
||||
}
|
||||
}}
|
||||
@layouts.App("Space Account", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) {
|
||||
<div class="container px-6 py-8 mx-auto space-y-8">
|
||||
<div class="grid gap-4 grid-cols-1 md:grid-cols-12">
|
||||
@card.Card(card.Props{
|
||||
Class: "rounded-sm col-span-full md:col-span-8",
|
||||
}) {
|
||||
@card.Header() {
|
||||
@card.Title() {
|
||||
{ props.AccountName }
|
||||
}
|
||||
@card.Description(card.DescriptionProps{Class: "text-sm"}) {
|
||||
{ props.AccountDescription }
|
||||
}
|
||||
}
|
||||
@card.Content() {
|
||||
<h1 class={ utils.TwMerge(balanceTextClasses...) }>${ utils.FormatDecimalWithThousands(props.AccountBalance.StringFixedBank(2)) }</h1>
|
||||
<p class="text-sm text-muted-foreground">Available Balance</p>
|
||||
<p class="mt-8 text-sm text-muted-foreground">
|
||||
Account <span>•••• { props.AccountNumber }</span>
|
||||
</p>
|
||||
}
|
||||
}
|
||||
@card.Card(card.Props{Class: "rounded-sm col-span-full md:col-span-4"}) {
|
||||
@card.Header() {
|
||||
@card.Title() {
|
||||
Quick Actions
|
||||
}
|
||||
}
|
||||
@card.Content(card.ContentProps{Class: "space-y-4"}) {
|
||||
@button.Button(button.Props{
|
||||
Class: "w-full flex gap-2 md:gap-4 items-center",
|
||||
Variant: button.VariantDefault,
|
||||
}) {
|
||||
Pay Bills
|
||||
@icon.HandCoins()
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Class: "w-full flex gap-2 md:gap-4 items-center",
|
||||
Variant: button.VariantSecondary,
|
||||
}) {
|
||||
Deposit Funds
|
||||
@icon.BanknoteArrowDown()
|
||||
}
|
||||
@button.Button(button.Props{
|
||||
Class: "w-full flex gap-2 md:gap-4 items-center",
|
||||
Variant: button.VariantLink,
|
||||
}) {
|
||||
Account Settings
|
||||
@icon.Settings()
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
@card.Card() {
|
||||
@card.Header() {
|
||||
<div>
|
||||
@card.Title() {
|
||||
Transaction History
|
||||
}
|
||||
@card.Description() {
|
||||
Overview of your activity for August 2024
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@card.Content() {
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
4
internal/ui/pages/space_account_settings.templ
Normal file
4
internal/ui/pages/space_account_settings.templ
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package pages
|
||||
|
||||
templ SpaceAccountSettings() {
|
||||
}
|
||||
4
internal/ui/pages/space_create_bill.templ
Normal file
4
internal/ui/pages/space_create_bill.templ
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package pages
|
||||
|
||||
templ SpaceCreateBill() {
|
||||
}
|
||||
4
internal/ui/pages/space_create_deposit.templ
Normal file
4
internal/ui/pages/space_create_deposit.templ
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package pages
|
||||
|
||||
templ SpaceCreateDeposit() {
|
||||
}
|
||||
35
internal/ui/utils/currency.go
Normal file
35
internal/ui/utils/currency.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package utils
|
||||
|
||||
import "strings"
|
||||
|
||||
func FormatDecimalWithThousands(numStr string) (string, error) {
|
||||
// Split into integer and decimal parts
|
||||
parts := strings.SplitN(numStr, ".", 2)
|
||||
intPart := parts[0]
|
||||
|
||||
// Handle negative numbers
|
||||
negative := false
|
||||
if strings.HasPrefix(intPart, "-") {
|
||||
negative = true
|
||||
intPart = intPart[1:]
|
||||
}
|
||||
|
||||
// Insert thousand separators
|
||||
var result []byte
|
||||
for i, c := range intPart {
|
||||
if i > 0 && (len(intPart)-i)%3 == 0 {
|
||||
result = append(result, ',')
|
||||
}
|
||||
result = append(result, byte(c))
|
||||
}
|
||||
|
||||
// Reassemble
|
||||
formatted := string(result)
|
||||
if len(parts) == 2 {
|
||||
formatted += "." + parts[1]
|
||||
}
|
||||
if negative {
|
||||
formatted = "-" + formatted
|
||||
}
|
||||
return formatted, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue