package templates import ( "encoding/json" "fmt" "time" "veola/internal/db" "veola/internal/models" ) type ItemResultsData struct { Page Item models.Item Badge BadgeData History []models.PricePoint Results []models.Result Page_ int TotalPages int Order string HistoryChartJSON string // RunMsg / RunError carry feedback from a "Run Now" poll. Both empty on a // normal page load; PostRunItem sets exactly one. RunMsg string RunError string // EndingSoon, when non-nil, surfaces the soonest-ending auction across this // item's results so users can act before close. EndingSoon *db.EndingSoon } type BadgeData struct { Label string Class string // v-badge-low / v-badge-avg / v-badge-target / "" } type GlobalResultsData struct { Page Items []models.Item Results []ItemResultRow ItemID int64 From string To string // EndingSoon mirrors the per-item field but spans every watched item. EndingSoon *db.EndingSoon } type ItemResultRow struct { models.Result ItemName string } // endingSoonStrip surfaces the next auction about to close. Hidden when nil // (the handler decides cutoff: 24h by default). The data-ends-at attribute // drives the live countdown in flair.js. templ endingSoonStrip(e *db.EndingSoon) { if e != nil {
| Title | Price | Store | Ends | Found | Alert | |
|---|---|---|---|---|---|---|
|
if r.ImageURL != "" {
|
if r.URL != "" {
{ r.Title }
} else {
{ r.Title }
}
if r.MatchedQuery != "" {
via "{ r.MatchedQuery }"
}
|
{ fmtPrice(r.Price, r.Currency) } | { r.Source } | @endsInCell(r.EndsAt) | { humanTime(r.FoundAt) } | if r.Alerted { sent } |
| Item | Title | Price | Store | Ends | Found | Alert |
|---|---|---|---|---|---|---|
| { r.ItemName } |
if r.URL != "" {
{ r.Title }
} else {
{ r.Title }
}
if r.MatchedQuery != "" {
via "{ r.MatchedQuery }"
}
|
{ fmtPrice(r.Price, r.Currency) } | { r.Source } | @endsInCell(r.EndsAt) | { humanTime(r.FoundAt) } | if r.Alerted { sent } |