package templates import ( "fmt" "veola/internal/models" ) type ItemFormData struct { Page IsEdit bool Item models.Item Categories []string Errors []string } func itemSelected(have, want string) bool { return have == want } type selectOpt struct { Value string Label string } // conditionOptions are the eBay-only item-condition filters. Values match the // vocabulary mapped to Browse API condition IDs in internal/ebay. func conditionOptions() []selectOpt { return []selectOpt{ {"", "— any —"}, {"new", "New"}, {"used", "Used"}, {"refurbished", "Refurbished"}, {"parts", "For parts / not working"}, } } // regionOptions are the eBay-only item-location filters, keyed by ISO 3166-1 // alpha-2 country code (the value the Browse API itemLocationCountry filter // expects). func regionOptions() []selectOpt { return []selectOpt{ {"", "— any —"}, {"US", "United States"}, {"GB", "United Kingdom"}, {"DE", "Germany"}, {"FR", "France"}, {"IT", "Italy"}, {"ES", "Spain"}, {"CA", "Canada"}, {"AU", "Australia"}, {"JP", "Japan"}, {"CN", "China"}, {"HK", "Hong Kong"}, } } type marketplaceOpt struct { Value string Label string } func marketplaceOptions() []marketplaceOpt { return []marketplaceOpt{ {"ebay.com", "eBay (US)"}, {"ebay.co.uk", "eBay (UK)"}, {"ebay.de", "eBay (DE)"}, {"ebay.fr", "eBay (FR)"}, {"ebay.com.au", "eBay (AU)"}, {"ebay.ca", "eBay (CA)"}, {"yahoo.co.jp", "Yahoo Auctions JP"}, {"mercari.jp", "Mercari JP"}, } } func isKnownMarketplace(v string) bool { for _, o := range marketplaceOptions() { if o.Value == v { return true } } return false } func itemHasMarketplace(it models.Item, v string) bool { for _, m := range it.Marketplaces { if m == v { return true } } return false } // customMarketplacesCSV returns the comma-separated list of marketplaces on // the item that are NOT in the curated list, so the user can keep editing // unusual values without losing them. func customMarketplacesCSV(it models.Item) string { var custom []string for _, m := range it.Marketplaces { if !isKnownMarketplace(m) { custom = append(custom, m) } } return joinCSV(custom) } func joinCSV(vs []string) string { out := "" for i, v := range vs { if i > 0 { out += ", " } out += v } return out } func itemHasJapanMarketplace(it models.Item) bool { for _, m := range it.Marketplaces { if m == "yahoo.co.jp" || m == "mercari.jp" { return true } } return false } func newCategory(v string, known []string) string { if v == "" { return "" } for _, c := range known { if c == v { return "" } } return v } templ itemFormBody(d ItemFormData) {

if d.IsEdit { Edit { d.Item.Name } } else { Add Item }

if len(d.Errors) > 0 {
} @itemFormInner(d)
} templ itemFormInner(d ItemFormData) {
@CSRFInput(d.CSRFToken)
Each is searched independently; the lowest price across all wins. Cost scales with the number of queries.
At least one of search queries or URL is required.
Blank = alert on every new result.
for _, m := range marketplaceOptions() { }
Yahoo Auctions JP and Mercari JP search in Japanese. English queries return few or no results.
Pick one or more. Each is polled per cycle; one failure does not stop the others.
Drop results below this price. Filters out accessories and obvious junk.
Drop results whose title contains any of these. Case-insensitive substring match.
eBay marketplaces only. Ignored for Yahoo JP, Mercari, and custom actors.
Restrict to items located in this country. eBay marketplaces only.
Advanced
Leave blank to use the configured default for the selected marketplace.
if d.IsEdit { Cancel } else { Cancel Running preview… apify runs can take 30–60s. }
if !d.IsEdit {
} } func formAction(d ItemFormData) templ.SafeURL { if d.IsEdit { return templ.SafeURL(fmt.Sprintf("/items/%d", d.Item.ID)) } return templ.SafeURL("/items/preview") } type pollOpt struct { Minutes int Label string } func pollOptions() []pollOpt { return []pollOpt{ {15, "15 min"}, {30, "30 min"}, {60, "1 hr"}, {120, "2 hr"}, {360, "6 hr"}, {720, "12 hr"}, {1440, "24 hr"}, } } func optFloat(p *float64) string { if p == nil { return "" } return fmt.Sprintf("%.2f", *p) } templ ItemForm(d ItemFormData) { @Layout(d.Page, itemFormBody(d)) }