This commit is contained in:
2025-03-24 19:17:39 +00:00
commit cf8cd691dc
10 changed files with 232 additions and 0 deletions

17
go.mod Normal file
View File

@@ -0,0 +1,17 @@
module synlotto-website
go 1.24.1
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
golang.org/x/sys v0.30.0 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect
modernc.org/sqlite v1.36.1 // indirect
)

23
go.sum Normal file
View File

@@ -0,0 +1,23 @@
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
modernc.org/sqlite v1.36.1 h1:bDa8BJUH4lg6EGkLbahKe/8QqoF8p9gArSc6fTqYhyQ=
modernc.org/sqlite v1.36.1/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=

61
handlers/draw_handler.go Normal file
View File

@@ -0,0 +1,61 @@
package handlers
import (
"html/template"
"log"
"net/http"
"synlotto-website/models"
)
var tmpl = template.Must(template.ParseFiles(
"templates/layout.html",
"templates/index.html",
"templates/new_draw.html",
))
func Home(w http.ResponseWriter, r *http.Request) {
log.Println("✅ Home hit")
var draws []models.Draw
err := tmpl.ExecuteTemplate(w, "layout", map[string]interface{}{
"Page": "index",
"Data": draws,
})
if err != nil {
log.Println("❌ Template error:", err)
http.Error(w, "Error rendering homepage", http.StatusInternalServerError)
}
}
func NewDraw(w http.ResponseWriter, r *http.Request) {
log.Println("➡️ New draw form opened")
err := tmpl.ExecuteTemplate(w, "layout", map[string]interface{}{
"Page": "new_draw",
"Data": nil,
})
if err != nil {
log.Println("❌ Template error:", err)
http.Error(w, "Error rendering form", http.StatusInternalServerError)
}
}
func Submit(w http.ResponseWriter, r *http.Request) {
log.Println("📝 Form submission received")
err := r.ParseForm()
if err != nil {
http.Error(w, "Invalid form", http.StatusBadRequest)
return
}
date := r.FormValue("date")
numbers := r.FormValue("numbers")
spend := r.FormValue("spend")
ret := r.FormValue("return")
log.Printf("📅 Date: %s | 🔢 Numbers: %s | 💸 Spend: %s | 💰 Return: %s\n", date, numbers, spend, ret)
http.Redirect(w, r, "/", http.StatusSeeOther)
}

16
main.go Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"log"
"net/http"
"synlotto-website/handlers"
)
func main() {
http.HandleFunc("/", handlers.Home)
http.HandleFunc("/new", handlers.NewDraw)
http.HandleFunc("/submit", handlers.Submit)
log.Println("🚀 Lotto Tracker running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

10
models/draw.go Normal file
View File

@@ -0,0 +1,10 @@
package models
type Draw struct {
ID int
Date string
Numbers string
Spend float64
Return float64
ProfitLoss float64
}

31
storage/db.go Normal file
View File

@@ -0,0 +1,31 @@
package storage
import (
"database/sql"
"log"
_ "modernc.org/sqlite"
)
func InitDB(filepath string) *sql.DB {
db, err := sql.Open("sqlite", filepath)
if err != nil {
log.Fatal("❌ Failed to open DB:", err)
}
createTable := `
CREATE TABLE IF NOT EXISTS draws (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT,
numbers TEXT,
spend REAL,
return REAL
);`
_, err = db.Exec(createTable)
if err != nil {
log.Fatal("❌ Failed to create table:", err)
}
return db
}

29
templates/index.html Normal file
View File

@@ -0,0 +1,29 @@
{{ define "index" }}
<a href="/new">+ Add New Draw</a>
{{ if . }}
<table>
<tr>
<th>Date</th>
<th>Numbers</th>
<th>Spend (£)</th>
<th>Return (£)</th>
<th>Profit/Loss (£)</th>
</tr>
{{ range . }}
<tr>
<td>{{ .Date }}</td>
<td>{{ .Numbers }}</td>
<td>{{ printf "%.2f" .Spend }}</td>
<td>{{ printf "%.2f" .Return }}</td>
<td>{{ printf "%.2f" .ProfitLoss }}</td>
</tr>
{{ else }}
<tr><td colspan="5">No draws recorded yet.</td></tr>
{{ end }}
</table>
{{ else }}
<p>No draws recorded yet. <a href="/new">Add your first draw</a></p>
{{ end }}
{{ end }}

26
templates/layout.html Normal file
View File

@@ -0,0 +1,26 @@
{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Lotto Tracker</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: center; }
th { background-color: #f5f5f5; }
.form-section { margin-bottom: 20px; }
</style>
</head>
<body>
<h1>Lotto Tracker</h1>
{{ if eq .Page "index" }}
{{ template "index" .Data }}
{{ else if eq .Page "new_draw" }}
{{ template "new_draw" .Data }}
{{ end }}
</body>
</html>
{{ end }}

19
templates/new_draw.html Normal file
View File

@@ -0,0 +1,19 @@
{{ define "new_draw" }}
<a href="/">← Back to Overview</a>
<h2>New Draw Entry</h2>
<form action="/submit" method="POST">
<div class="form-section">
<label>Date: <input type="date" name="date" required></label>
</div>
<div class="form-section">
<label>Numbers: <input type="text" name="numbers" required></label>
</div>
<div class="form-section">
<label>Spend (£): <input type="number" step="0.01" name="spend" required></label>
</div>
<div class="form-section">
<label>Return (£): <input type="number" step="0.01" name="return" required></label>
</div>
<button type="submit">Save</button>
</form>
{{ end }}

BIN
tracker.db Normal file

Binary file not shown.