feat: add tag combobox to make tagging expenses easier
This commit is contained in:
parent
0e5d196432
commit
ef37360da7
9 changed files with 671 additions and 106 deletions
|
|
@ -11,7 +11,7 @@ import (
|
|||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/input"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/label"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/radio"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/components/tagcombobox"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/layouts"
|
||||
)
|
||||
|
||||
|
|
@ -37,15 +37,6 @@ func progressBarColor(status model.BudgetStatus) string {
|
|||
}
|
||||
}
|
||||
|
||||
func budgetTagSelected(tags []*model.Tag, tagID string) bool {
|
||||
for _, t := range tags {
|
||||
if t.ID == tagID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
templ SpaceBudgetsPage(space *model.Space, budgets []*model.BudgetWithSpent, tags []*model.Tag) {
|
||||
@layouts.Space("Budgets", space) {
|
||||
<div class="space-y-4">
|
||||
|
|
@ -190,23 +181,17 @@ templ AddBudgetForm(spaceID string, tags []*model.Tag) {
|
|||
class="space-y-4"
|
||||
>
|
||||
@csrf.Token()
|
||||
// Tag selector (multi-select)
|
||||
// Tag selector
|
||||
<div>
|
||||
@label.Label(label.Props{}) {
|
||||
@label.Label(label.Props{For: "budget-tags"}) {
|
||||
Tags
|
||||
}
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "budget-tags", Multiple: true}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_ids", Multiple: true, ShowPills: true, SelectedCountText: "{n} tags selected"}) {
|
||||
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select tags..."})
|
||||
}
|
||||
@selectbox.Content() {
|
||||
for _, t := range tags {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: t.ID}) {
|
||||
{ t.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@tagcombobox.TagCombobox(tagcombobox.Props{
|
||||
ID: "budget-tags",
|
||||
Name: "tags",
|
||||
Tags: tags,
|
||||
Placeholder: "Search or create tags...",
|
||||
})
|
||||
</div>
|
||||
// Amount
|
||||
<div>
|
||||
|
|
@ -290,6 +275,10 @@ templ AddBudgetForm(spaceID string, tags []*model.Tag) {
|
|||
|
||||
templ EditBudgetForm(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag) {
|
||||
{{ editDialogID := "edit-budget-" + b.ID }}
|
||||
{{ budgetTagNames := make([]string, len(b.Tags)) }}
|
||||
for i, t := range b.Tags {
|
||||
{{ budgetTagNames[i] = t.Name }}
|
||||
}
|
||||
<form
|
||||
hx-patch={ fmt.Sprintf("/app/spaces/%s/budgets/%s", spaceID, b.ID) }
|
||||
hx-target="#budgets-list-wrapper"
|
||||
|
|
@ -298,23 +287,18 @@ templ EditBudgetForm(spaceID string, b *model.BudgetWithSpent, tags []*model.Tag
|
|||
class="space-y-4"
|
||||
>
|
||||
@csrf.Token()
|
||||
// Tag selector (multi-select with pre-selected tags)
|
||||
// Tag selector
|
||||
<div>
|
||||
@label.Label(label.Props{}) {
|
||||
@label.Label(label.Props{For: "edit-budget-tags-" + b.ID}) {
|
||||
Tags
|
||||
}
|
||||
@selectbox.SelectBox(selectbox.Props{ID: "edit-budget-tags-" + b.ID, Multiple: true}) {
|
||||
@selectbox.Trigger(selectbox.TriggerProps{Name: "tag_ids", Multiple: true, ShowPills: true, SelectedCountText: "{n} tags selected"}) {
|
||||
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select tags..."})
|
||||
}
|
||||
@selectbox.Content() {
|
||||
for _, t := range tags {
|
||||
@selectbox.Item(selectbox.ItemProps{Value: t.ID, Selected: budgetTagSelected(b.Tags, t.ID)}) {
|
||||
{ t.Name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@tagcombobox.TagCombobox(tagcombobox.Props{
|
||||
ID: "edit-budget-tags-" + b.ID,
|
||||
Name: "tags",
|
||||
Value: budgetTagNames,
|
||||
Tags: tags,
|
||||
Placeholder: "Search or create tags...",
|
||||
})
|
||||
</div>
|
||||
// Amount
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -48,21 +48,21 @@ templ SpaceExpensesPage(space *model.Space, expenses []*model.ExpenseWithTagsAnd
|
|||
// List of expenses
|
||||
<div class="border rounded-lg">
|
||||
<div id="expenses-list-wrapper">
|
||||
@ExpensesListContent(space.ID, expenses, methods, currentPage, totalPages)
|
||||
@ExpensesListContent(space.ID, expenses, methods, tags, currentPage, totalPages)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
templ ExpensesListContent(spaceID string, expenses []*model.ExpenseWithTagsAndMethod, methods []*model.PaymentMethod, currentPage, totalPages int) {
|
||||
templ ExpensesListContent(spaceID string, expenses []*model.ExpenseWithTagsAndMethod, methods []*model.PaymentMethod, tags []*model.Tag, currentPage, totalPages int) {
|
||||
<h2 class="text-lg font-semibold p-4">History</h2>
|
||||
<div id="expenses-list" class="divide-y">
|
||||
if len(expenses) == 0 {
|
||||
<p class="p-4 text-sm text-muted-foreground">No expenses recorded yet.</p>
|
||||
}
|
||||
for _, exp := range expenses {
|
||||
@ExpenseListItem(spaceID, exp, methods)
|
||||
@ExpenseListItem(spaceID, exp, methods, tags)
|
||||
}
|
||||
</div>
|
||||
if totalPages > 1 {
|
||||
|
|
@ -109,7 +109,7 @@ templ ExpensesListContent(spaceID string, expenses []*model.ExpenseWithTagsAndMe
|
|||
}
|
||||
}
|
||||
|
||||
templ ExpenseListItem(spaceID string, exp *model.ExpenseWithTagsAndMethod, methods []*model.PaymentMethod) {
|
||||
templ ExpenseListItem(spaceID string, exp *model.ExpenseWithTagsAndMethod, methods []*model.PaymentMethod, tags []*model.Tag) {
|
||||
<div id={ "expense-" + exp.ID } class="p-4 flex justify-between items-start gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
|
|
@ -166,7 +166,7 @@ templ ExpenseListItem(spaceID string, exp *model.ExpenseWithTagsAndMethod, metho
|
|||
Update the details of this transaction.
|
||||
}
|
||||
}
|
||||
@expense.EditExpenseForm(spaceID, exp, methods)
|
||||
@expense.EditExpenseForm(spaceID, exp, methods, tags)
|
||||
}
|
||||
}
|
||||
// Delete button
|
||||
|
|
@ -208,12 +208,12 @@ templ ExpenseListItem(spaceID string, exp *model.ExpenseWithTagsAndMethod, metho
|
|||
</div>
|
||||
}
|
||||
|
||||
templ ExpenseCreatedResponse(spaceID string, expenses []*model.ExpenseWithTagsAndMethod, balance int, allocated int, currentPage, totalPages int) {
|
||||
@ExpensesListContent(spaceID, expenses, nil, currentPage, totalPages)
|
||||
templ ExpenseCreatedResponse(spaceID string, expenses []*model.ExpenseWithTagsAndMethod, balance int, allocated int, tags []*model.Tag, currentPage, totalPages int) {
|
||||
@ExpensesListContent(spaceID, expenses, nil, tags, currentPage, totalPages)
|
||||
@expense.BalanceCard(spaceID, balance, allocated, true)
|
||||
}
|
||||
|
||||
templ ExpenseUpdatedResponse(spaceID string, exp *model.ExpenseWithTagsAndMethod, balance int, allocated int, methods []*model.PaymentMethod) {
|
||||
@ExpenseListItem(spaceID, exp, methods)
|
||||
templ ExpenseUpdatedResponse(spaceID string, exp *model.ExpenseWithTagsAndMethod, balance int, allocated int, methods []*model.PaymentMethod, tags []*model.Tag) {
|
||||
@ExpenseListItem(spaceID, exp, methods, tags)
|
||||
@expense.BalanceCard(exp.SpaceID, balance, allocated, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ templ SpaceRecurringPage(space *model.Space, recs []*model.RecurringExpenseWithT
|
|||
<p class="p-4 text-sm text-muted-foreground">No recurring transactions set up yet.</p>
|
||||
}
|
||||
for _, re := range recs {
|
||||
@recurring.RecurringItem(space.ID, re, methods)
|
||||
@recurring.RecurringItem(space.ID, re, methods, tags)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue