Pizza Tracker

I built this project in an hour ... and it shows. Despite the low amount of effort I put into this project, it's been really popular amongst my friend groups, and I love it for all its eccentricity.
The pizzas at Thrifty Foods would occasionally go on sale, often down to $3.49! So, instead of having to check their website for when it was on sale, I built out a small site that does this for me.
Pizza Schema
To start, I needed some way to keep track of the different types of pizza, their prices, and their images. Structs were perfect for this:
const (
PizzaURL = "https://www.thriftyfoods.com/product/pizzaristorante-thin-crust-spinach/00000_000000005833617000"
)
type Pizza struct {
Name string
Price float64
ImageURL string
}
type Status struct {
OnSale bool
Price float64
}From there, we just need to fetch the information using the PizzaURL, parse the data, then display it!
Fetching & Parsing
To populate our structs with pizza data, we scrape the pizza link and grab the prices, images, and name from the page.
// Parse and create an array of Pizza structs
func getPizzas(url string) []Pizza {
var pizzas []Pizza
c := colly.NewCollector()
c.OnHTML("div.grid", func(e *colly.HTMLElement) {
imgURL := e.ChildAttr("img", "src")
title := e.ChildText("a.js-ga-productname")
price := e.ChildText("span.price")
if imgURL == "" || title == "" || price == "" {
return
}
cleanedPrice := strings.Replace(price, "$", "", -1)
p, err := strconv.ParseFloat(cleanedPrice, 64)
if err != nil {
return
}
pizza := Pizza{
Name: title,
Price: p,
ImageURL: imgURL,
}
pizzas = append(pizzas, pizza)
})
err := c.Visit(url)
if err != nil {
fmt.Println("Error visiting page:", err)
}
return pizzas
}We now have a complete set of pizzas to display!
Output via Templates
To determine if we should display if the pizzas are on sale or not, we check if the price is lower than $5. If it is, then we display the crazy styled page, and if not, just the boring page.
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/", func(c *gin.Context) {
pizzas := getPizzas(PizzaURL)
onSale := false
if len(pizzas) > 0 && pizzas[0].Price < 5 {
onSale = true
}
c.HTML(200, "index.html", gin.H{
"pizzas": pizzas,
"status": Status{
OnSale: onSale,
Price: pizzas[0].Price
}})
})
r.Run()
}Templating
Here's the fun part! I wanted to get this done quickly, so I imported TailwindCSS from their CDN. I used HTML templates to conditionally render / iterate over all the pizzas.