123 рядки
3.4 KiB
Go
123 рядки
3.4 KiB
Go
package item
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.entityseven.com/rilaxik/pllist/internal/domain"
|
|
"git.entityseven.com/rilaxik/pllist/internal/service"
|
|
"git.entityseven.com/rilaxik/pllist/internal/telegram/shared"
|
|
)
|
|
|
|
const (
|
|
addItemPrompt = "Send the item title (1-200 characters). /cancel to stop."
|
|
renameItemPrompt = "Send the new item title (1-200 characters). /cancel to stop."
|
|
notePrompt = "Send the item note (up to 1000 characters). /cancel to stop."
|
|
quantityPrompt = "Send the quantity (positive number, e.g. 1.5). /cancel to stop."
|
|
deleteItemText = "Delete this item? This cannot be undone."
|
|
itemTruncateLength = 60
|
|
)
|
|
|
|
func listMenuText(itemPage service.ItemPage) string {
|
|
var text strings.Builder
|
|
fmt.Fprintf(&text, "<b>%s</b>\nRole: %s\n\n",
|
|
shared.Escape(itemPage.Access.List.Title), itemPage.Access.Role)
|
|
writeItemsText(&text, itemPage)
|
|
if itemPage.Total > len(itemPage.Items) {
|
|
fmt.Fprintf(&text, "\n\nShowing %d of %d. Open Manage items for the rest.",
|
|
len(itemPage.Items), itemPage.Total)
|
|
}
|
|
return text.String()
|
|
}
|
|
|
|
func itemsText(itemPage service.ItemPage) string {
|
|
var text strings.Builder
|
|
fmt.Fprintf(&text, "<b>%s</b>\n\n", shared.Escape(itemPage.Access.List.Title))
|
|
writeItemsText(&text, itemPage)
|
|
if itemPage.Total > 0 {
|
|
fmt.Fprintf(&text, "\n\nPage %d/%d\nTap an item to manage it.",
|
|
itemPage.Page, itemPage.PageCount())
|
|
}
|
|
return text.String()
|
|
}
|
|
|
|
func writeItemsText(text *strings.Builder, itemPage service.ItemPage) {
|
|
text.WriteString("<b>Items:</b>\n")
|
|
if itemPage.Total == 0 {
|
|
text.WriteString("No items yet.\n\n<i>0 items</i>")
|
|
return
|
|
}
|
|
for _, item := range itemPage.Items {
|
|
fmt.Fprintf(text, "%s %s\n", itemIcon(item), shared.Escape(titleWithQuantity(item)))
|
|
}
|
|
fmt.Fprintf(text, "\n<i>%s</i>", itemCountLabel(itemPage.Total))
|
|
}
|
|
|
|
func itemCountLabel(total int) string {
|
|
label := "items"
|
|
if total == 1 {
|
|
label = "item"
|
|
}
|
|
return fmt.Sprintf("%d %s", total, label)
|
|
}
|
|
|
|
func itemText(itemAccess service.ItemAccess, userID int64) string {
|
|
item := itemAccess.Item
|
|
var text strings.Builder
|
|
fmt.Fprintf(&text, "<b>%s %s</b>\nStatus: %s\n",
|
|
itemIcon(item), shared.Escape(titleWithQuantity(item)), item.Status)
|
|
if item.Note != "" {
|
|
fmt.Fprintf(&text, "Note: %s\n", shared.Escape(item.Note))
|
|
}
|
|
|
|
switch {
|
|
case !item.Reserved():
|
|
text.WriteString("Reserved: no")
|
|
case item.ReservedByID != nil && *item.ReservedByID == userID:
|
|
text.WriteString("Reserved: yes (you)")
|
|
default:
|
|
text.WriteString("Reserved: yes")
|
|
}
|
|
return text.String()
|
|
}
|
|
|
|
func itemLabel(item domain.Item, userID int64) string {
|
|
title := shared.Truncate(item.Title, 32)
|
|
label := fmt.Sprintf("%s %s x%s", itemIcon(item), title, formatQuantity(item.Quantity))
|
|
if item.Reserved() {
|
|
if item.ReservedByID != nil && *item.ReservedByID == userID {
|
|
label += " · yours"
|
|
} else {
|
|
label += " · reserved"
|
|
}
|
|
}
|
|
return shared.Truncate(label, itemTruncateLength)
|
|
}
|
|
|
|
func itemIcon(item domain.Item) string {
|
|
if item.Done() {
|
|
return "✓"
|
|
}
|
|
return urgencyEmoji(item.Urgency)
|
|
}
|
|
|
|
func titleWithQuantity(item domain.Item) string {
|
|
return fmt.Sprintf("%s x%s", item.Title, formatQuantity(item.Quantity))
|
|
}
|
|
|
|
func formatQuantity(quantity float64) string {
|
|
return strconv.FormatFloat(quantity, 'f', -1, 64)
|
|
}
|
|
|
|
func urgencyEmoji(urgency domain.Urgency) string {
|
|
switch urgency {
|
|
case domain.UrgencyHigh:
|
|
return "🔴"
|
|
case domain.UrgencyLow:
|
|
return "🟢"
|
|
default:
|
|
return "🟡"
|
|
}
|
|
}
|