diff --git a/db/db.go b/db/db.go
index defd07a..cf4aea2 100644
--- a/db/db.go
+++ b/db/db.go
@@ -441,3 +441,115 @@ func (db *DB) DeleteHeatResult(groupID int64, heatNum int) error {
groupID, heatNum)
return err
}
+
+func (db *DB) GetHeatData(groupID int64, heatNum int) (*models.HeatData, error) {
+ heatData := &models.HeatData{}
+ lane1 := int64(0)
+ lane2 := int64(0)
+ lane3 := int64(0)
+ lane4 := int64(0)
+
+ err := db.QueryRow(`
+ SELECT
+ group_id, heat_number,
+ g.name as group_name,
+ (SELECT COUNT(*) FROM heats WHERE group_id = ?) as total_heats,
+ h.lane1_id, h.lane2_id, h.lane3_id, h.lane4_id
+ FROM heats h
+ JOIN groups g ON g.id = h.group_id
+ WHERE h.group_id = ? AND h.heat_num = ?`,
+ groupID, groupID, heatNum).Scan(
+ &heatData.Group.ID, &heatData.HeatNumber,
+ &heatData.Group.Name, &heatData.TotalHeats,
+ &lane1, &lane2, &lane3, &lane4)
+
+ if err != nil {
+ return nil, fmt.Errorf("error getting heat data: %v", err)
+ }
+
+ // Get racer data for each lane
+ if lane1 != 0 {
+ lane1Data, err := db.getLaneData(1, lane1, heatNum, groupID)
+ if err != nil {
+ return nil, err
+ }
+ heatData.Lane1 = lane1Data
+ }
+
+ if lane2 != 0 {
+ lane2Data, err := db.getLaneData(2, lane2, heatNum, groupID)
+ if err != nil {
+ return nil, err
+ }
+ heatData.Lane2 = lane2Data
+ }
+
+ if lane3 != 0 {
+ lane3Data, err := db.getLaneData(3, lane3, heatNum, groupID)
+ if err != nil {
+ return nil, err
+ }
+ heatData.Lane3 = lane3Data
+ }
+
+ if lane4 != 0 {
+ lane4Data, err := db.getLaneData(4, lane4, heatNum, groupID)
+ if err != nil {
+ return nil, err
+ }
+ heatData.Lane4 = lane4Data
+ }
+
+ return heatData, nil
+}
+
+// getLaneData gets the racer data for a specific lane
+func (db *DB) getLaneData(lane int, racerID int64, heatNum int, groupID int64) (*models.LaneData, error) {
+ // Get racer data
+ var racer models.Racer
+ err := db.QueryRow(`
+ SELECT id, first_name, last_name, car_number, car_weight, group_id
+ FROM racers
+ WHERE id = ?`, racerID).Scan(
+ &racer.ID, &racer.FirstName, &racer.LastName, &racer.CarNumber, &racer.CarWeight, &racer.GroupID)
+
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return nil, ErrNotFound
+ }
+ return nil, err
+ }
+
+ // Create lane data with racer info
+ laneData := &models.LaneData{
+ Lane: lane,
+ RacerID: racerID,
+ Name: racer.FirstName + " " + racer.LastName,
+ CarNum: racer.CarNumber,
+ CarWeight: racer.CarWeight,
+ Time: 0,
+ Place: 0,
+ }
+
+ heatResult, err := db.GetHeatResult(groupID, heatNum)
+ if err != nil {
+ return laneData, nil
+ }
+
+ switch lane {
+ case 1:
+ laneData.Time = heatResult.Lane1Time
+ laneData.Place = heatResult.Lane1Position
+ case 2:
+ laneData.Time = heatResult.Lane2Time
+ laneData.Place = heatResult.Lane2Position
+ case 3:
+ laneData.Time = heatResult.Lane3Time
+ laneData.Place = heatResult.Lane3Position
+ case 4:
+ laneData.Time = heatResult.Lane4Time
+ laneData.Place = heatResult.Lane4Position
+ }
+
+ return laneData, nil
+}
diff --git a/derby/derby.go b/derby/derby.go
index 80318f6..d144fb3 100644
--- a/derby/derby.go
+++ b/derby/derby.go
@@ -36,12 +36,15 @@ const (
EventRaceStart EventType = iota
EventLaneFinish
EventRaceComplete
+ EventHeatChanged
+ EventGroupChanged
+ EventHeatRerun
)
// Event represents a race event
type Event struct {
- Type EventType
- Result *Result // Only populated for EventLaneFinish
+ Type EventType
+ Event any // Only populated for EventLaneFinish
}
// DerbyClock represents the connection to the derby clock device
@@ -202,8 +205,8 @@ func (dc *DerbyClock) readLoop() {
if result != nil {
// Send lane finish event
dc.eventChan <- Event{
- Type: EventLaneFinish,
- Result: result,
+ Type: EventLaneFinish,
+ Event: result,
}
}
results = append(results, result)
diff --git a/examples/main.go b/examples/main.go
index 7339aa6..1069e22 100644
--- a/examples/main.go
+++ b/examples/main.go
@@ -162,10 +162,10 @@ func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event,
fmt.Println("\nš Race started!")
case derby.EventLaneFinish:
- result := event.Result
+ result := event.Event.(derby.Result)
fmt.Printf("š Lane %d finished in place %d with time %.4f seconds\n",
result.Lane, result.FinishPlace, result.Time)
- raceResults = append(raceResults, result)
+ raceResults = append(raceResults, &result)
case derby.EventRaceComplete:
fmt.Println("\nš Race complete! Final results:")
diff --git a/models/models.go b/models/models.go
index c003c65..8da323c 100644
--- a/models/models.go
+++ b/models/models.go
@@ -67,3 +67,23 @@ type HeatResult struct {
Lane4Time float64 `json:"lane4_time"`
Lane4Position int `json:"lane4_position"`
}
+
+type LaneData struct {
+ Lane int
+ RacerID int64
+ Name string
+ CarNum string
+ CarWeight float64
+ Time float64
+ Place int
+}
+
+type HeatData struct {
+ Group Group
+ HeatNumber int
+ TotalHeats int
+ Lane1 *LaneData
+ Lane2 *LaneData
+ Lane3 *LaneData
+ Lane4 *LaneData
+}
diff --git a/web/server.go b/web/server.go
index ad2aa9d..a6c8584 100644
--- a/web/server.go
+++ b/web/server.go
@@ -148,9 +148,6 @@ func (s *Server) routes() {
// Add racers list route
s.router.Get("/admin/racers/list", s.handleRacersList())
- // Add admin events route
- s.router.Get("/api/admin-events", s.handleAdminEvents())
-
// Add validate car number route
s.router.Get("/api/validate/car-number", s.handleValidateCarNumber())
@@ -163,7 +160,6 @@ func (s *Server) routes() {
r.Get("/current-heat", s.handleCurrentHeat())
r.Post("/next-heat", s.handleNextHeat())
r.Post("/previous-heat", s.handlePreviousHeat())
- r.Post("/save-result", s.handleSaveHeatResult())
r.Post("/rerun-heat", s.handleRerunHeat())
r.Post("/set-group", s.handleSetRacingGroup())
})
@@ -229,49 +225,36 @@ func (s *Server) forwardEvents() {
// broadcastEvent sends an event to all connected clients
func (s *Server) broadcastEvent(event derby.Event) {
- var message string
-
switch event.Type {
case derby.EventRaceStart:
s.logger.Info("Broadcasting race start event")
- statusMsg := struct {
- Status string `json:"status"`
- }{
- Status: "running",
- }
- statusJSON, _ := json.Marshal(statusMsg)
- message = fmt.Sprintf("event: status\ndata: %s", statusJSON)
+ s.sendEventToAllClients("event: race-status\ndata:
Race Running
")
case derby.EventLaneFinish:
s.logger.Info("Broadcasting lane finish event",
- "lane", event.Result.Lane,
- "time", event.Result.Time,
- "place", event.Result.FinishPlace)
-
- // Create a message for lane finish
- laneData := struct {
- Lane int `json:"lane"`
- Time float64 `json:"time"`
- Place int `json:"place"`
- }{
- Lane: event.Result.Lane,
- Time: event.Result.Time,
- Place: event.Result.FinishPlace,
- }
- laneJSON, _ := json.Marshal(laneData)
- message = fmt.Sprintf("event: lane-finish\ndata: %s", laneJSON)
+ "lane", event.Event.(derby.Result).Lane,
+ "time", event.Event.(derby.Result).Time,
+ "place", event.Event.(derby.Result).FinishPlace)
+
+ s.sendEventToAllClients(fmt.Sprintf("event: lane-%d-time\ndata: %.4f", event.Event.(derby.Result).Lane, event.Event.(derby.Result).Time))
+ s.sendEventToAllClients(fmt.Sprintf("event: lane-%d-position\ndata: %d", event.Event.(derby.Result).Lane, event.Event.(derby.Result).FinishPlace))
+
+ case derby.EventHeatChanged:
+ s.logger.Info("Broadcasting heat changed event")
+ s.sendEventToAllClients(fmt.Sprintf("event: heat-changed-number\ndata: %d out of %d", event.Event.(models.HeatData).HeatNumber, event.Event.(models.HeatData).TotalHeats))
+ s.sendEventToAllClients("event: race-status\ndata: Idle
")
+
+ case derby.EventGroupChanged:
+ s.logger.Info("Broadcasting group changed event")
+ s.sendEventToAllClients("event: group-changed\ndata: Group Changed
")
case derby.EventRaceComplete:
s.logger.Info("Broadcasting race complete event")
- statusMsg := struct {
- Status string `json:"status"`
- }{
- Status: "finished",
- }
- statusJSON, _ := json.Marshal(statusMsg)
- message = fmt.Sprintf("event: status\ndata: %s", statusJSON)
+ s.sendEventToAllClients("event: race-status\ndata: Race Complete
")
}
+}
+func (s *Server) sendEventToAllClients(message string) {
if message == "" {
return
}
@@ -281,17 +264,13 @@ func (s *Server) broadcastEvent(event derby.Event) {
clientCount := len(s.clients)
sentCount := 0
for clientChan := range s.clients {
- select {
- case clientChan <- message:
- sentCount++
- default:
- s.logger.Warn("Client channel is full, event not sent")
- }
+ clientChan <- message
+ sentCount++
}
- s.logger.Info("Event broadcast complete",
+ s.logger.Debug("Event broadcast complete",
"sentCount", sentCount,
"totalClients", clientCount,
- "eventType", event.Type)
+ "message", message)
s.clientsMux.Unlock()
}
@@ -1026,31 +1005,21 @@ func (s *Server) handleRacePublic() http.HandlerFunc {
}
// Get heats for the group
- heats, err := s.db.GetHeats(currentGroup.ID)
+ heatData, err := s.db.GetHeatData(currentGroup.ID, currentHeatNum)
if err != nil {
s.logger.Error("Failed to get heats", "error", err)
http.Error(w, "Failed to get heats", http.StatusInternalServerError)
return
}
- // Get racers for the group
- racers, err := s.db.GetRacersByGroup(currentGroup.ID)
- if err != nil {
- s.logger.Error("Failed to get racers", "error", err)
- http.Error(w, "Failed to get racers", http.StatusInternalServerError)
- return
- }
+ // Get next heat data
+ nextHeatData, _ := s.db.GetHeatData(currentGroup.ID, currentHeatNum+1)
- // Get heat results
- results, err := s.db.GetHeatResults(currentGroup.ID)
- if err != nil {
- s.logger.Error("Failed to get heat results", "error", err)
- http.Error(w, "Failed to get heat results", http.StatusInternalServerError)
- return
- }
+ // Get on-deck heat data
+ onDeckHeatData, _ := s.db.GetHeatData(currentGroup.ID, currentHeatNum+2)
// Render template
- component := templates.RacePublic(currentGroup, heats, racers, currentHeatNum, results)
+ component := templates.RacePublic(heatData, nextHeatData, onDeckHeatData)
if err := component.Render(r.Context(), w); err != nil {
s.logger.Error("Failed to render race public template", "error", err)
http.Error(w, "Failed to render page", http.StatusInternalServerError)
diff --git a/web/static/js/sse.min.js b/web/static/js/sse.min.js
new file mode 100644
index 0000000..2ba734c
--- /dev/null
+++ b/web/static/js/sse.min.js
@@ -0,0 +1 @@
+(function(){var g;htmx.defineExtension("sse",{init:function(e){g=e;if(htmx.createEventSource==undefined){htmx.createEventSource=t}},getSelectors:function(){return["[sse-connect]","[data-sse-connect]","[sse-swap]","[data-sse-swap]"]},onEvent:function(e,t){var r=t.target||t.detail.elt;switch(e){case"htmx:beforeCleanupElement":var n=g.getInternalData(r);var s=n.sseEventSource;if(s){g.triggerEvent(r,"htmx:sseClose",{source:s,type:"nodeReplaced"});n.sseEventSource.close()}return;case"htmx:afterProcessNode":i(r)}}});function t(e){return new EventSource(e,{withCredentials:true})}function a(n){if(g.getAttributeValue(n,"sse-swap")){var s=g.getClosestMatch(n,v);if(s==null){return null}var e=g.getInternalData(s);var a=e.sseEventSource;var t=g.getAttributeValue(n,"sse-swap");var r=t.split(",");for(var i=0;i0){const t=r.querySelectorAll("[sse-swap], [data-sse-swap], [hx-trigger], [data-hx-trigger]");for(let e=0;e
@@ -26,7 +26,7 @@ templ RacePublic(currentGroup models.Group, heats []models.Heat, racers []models
- @raceCurrentHeatLanes(heats, racers, currentHeatNum, results)
+ @raceCurrentHeatLanes(heatData)
@@ -43,8 +43,8 @@ templ RacePublic(currentGroup models.Group, heats []models.Heat, racers []models
Next Heat
- if currentHeatNum < len(heats) {
- @raceNextHeatPreview(heats, racers, currentHeatNum+1)
+ if nextHeat != nil {
+ @raceNextHeatPreview(nextHeat)
} else {
No more heats in this group
}
@@ -57,8 +57,8 @@ templ RacePublic(currentGroup models.Group, heats []models.Heat, racers []models
Upcoming Heat
- if currentHeatNum+1 < len(heats) {
- @raceNextHeatPreview(heats, racers, currentHeatNum+2)
+ if onDeckHeat != nil {
+ @raceNextHeatPreview(onDeckHeat)
} else {
No more heats in this group
}
@@ -67,214 +67,56 @@ templ RacePublic(currentGroup models.Group, heats []models.Heat, racers []models
-
-
}
}
// Helper template for displaying current heat lanes
-templ raceCurrentHeatLanes(heats []models.Heat, racers []models.Racer, currentHeatNum int, results []models.HeatResult) {
- {{
- // Find current heat
- var currentHeat models.Heat
- for _, heat := range heats {
- if heat.HeatNum == currentHeatNum {
- currentHeat = heat
- break
- }
- }
-
- // Find heat result if available
- var currentResult *models.HeatResult
- for _, result := range results {
- if result.HeatNumber == currentHeatNum {
- currentResult = &result
- break
- }
- }
- }}
+templ raceCurrentHeatLanes(heatData *models.HeatData) {
- if currentHeat.Lane1ID != nil {
- @raceLaneCard(1, *currentHeat.Lane1ID, racers, currentResult)
+ if heatData.Lane1 != nil {
+ @raceLaneCard(*heatData.Lane1)
}
- if currentHeat.Lane2ID != nil {
- @raceLaneCard(2, *currentHeat.Lane2ID, racers, currentResult)
+ if heatData.Lane2 != nil {
+ @raceLaneCard(*heatData.Lane2)
}
- if currentHeat.Lane3ID != nil {
- @raceLaneCard(3, *currentHeat.Lane3ID, racers, currentResult)
+ if heatData.Lane3 != nil {
+ @raceLaneCard(*heatData.Lane3)
}
- if currentHeat.Lane4ID != nil {
- @raceLaneCard(4, *currentHeat.Lane4ID, racers, currentResult)
+ if heatData.Lane4 != nil {
+ @raceLaneCard(*heatData.Lane4)
}
}
// Helper template for displaying a lane card
-templ raceLaneCard(lane int, racerID int64, racers []models.Racer, result *models.HeatResult) {
- {{
- // Find racer
- var racer models.Racer
- for _, r := range racers {
- if r.ID == racerID {
- racer = r
- break
- }
- }
-
- // Get time and position from result if available
- var time float64
- var position int
- var hasResult bool
-
- if result != nil {
- hasResult = true
- switch lane {
- case 1:
- time = result.Lane1Time
- position = result.Lane1Position
- case 2:
- time = result.Lane2Time
- position = result.Lane2Position
- case 3:
- time = result.Lane3Time
- position = result.Lane3Position
- case 4:
- time = result.Lane4Time
- position = result.Lane4Position
- }
- }
- }}
-
+templ raceLaneCard(laneData models.LaneData) {
-
+
-
{ racer.FirstName } { racer.LastName }
+
{ laneData.Name }
- Car #: { racer.CarNumber }
- Weight: { fmt.Sprintf("%.1f oz", racer.CarWeight) }
+ Car #: { laneData.CarNum }
+ Weight: { fmt.Sprintf("%.1f oz", laneData.CarWeight) }
Time
-
- if hasResult {
- { fmt.Sprintf("%.3f", time) }
- } else {
- --.-
- }
+
+ { fmt.Sprintf("%.3f", laneData.Time) }
Position
-
- if hasResult {
- { strconv.Itoa(position) }
- } else {
- -
- }
+
+ { strconv.Itoa(laneData.Place) }
@@ -286,19 +128,8 @@ templ raceLaneCard(lane int, racerID int64, racers []models.Racer, result *model
}
// Helper template for displaying next heat preview
-templ raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum int) {
- {{
- // Find the heat
- var nextHeat models.Heat
- for _, heat := range heats {
- if heat.HeatNum == heatNum {
- nextHeat = heat
- break
- }
- }
- }}
-
-
Heat { strconv.Itoa(heatNum) }
+templ raceNextHeatPreview(heatData *models.HeatData) {
+
Heat { strconv.Itoa(heatData.HeatNumber) }
@@ -309,17 +140,17 @@ templ raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum in
- if nextHeat.Lane1ID != nil {
- @raceNextHeatRow(1, *nextHeat.Lane1ID, racers)
+ if heatData.Lane1 != nil {
+ @raceNextHeatRow(*heatData.Lane1)
}
- if nextHeat.Lane2ID != nil {
- @raceNextHeatRow(2, *nextHeat.Lane2ID, racers)
+ if heatData.Lane2 != nil {
+ @raceNextHeatRow(*heatData.Lane2)
}
- if nextHeat.Lane3ID != nil {
- @raceNextHeatRow(3, *nextHeat.Lane3ID, racers)
+ if heatData.Lane3 != nil {
+ @raceNextHeatRow(*heatData.Lane3)
}
- if nextHeat.Lane4ID != nil {
- @raceNextHeatRow(4, *nextHeat.Lane4ID, racers)
+ if heatData.Lane4 != nil {
+ @raceNextHeatRow(*heatData.Lane4)
}
@@ -327,21 +158,10 @@ templ raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum in
}
// Helper template for displaying a row in the next heat preview
-templ raceNextHeatRow(lane int, racerID int64, racers []models.Racer) {
- {{
- // Find racer
- var racer models.Racer
- for _, r := range racers {
- if r.ID == racerID {
- racer = r
- break
- }
- }
- }}
-
+templ raceNextHeatRow(laneData models.LaneData) {
- | { strconv.Itoa(lane) } |
- { racer.FirstName } { racer.LastName } |
- { racer.CarNumber } |
+ { strconv.Itoa(laneData.Lane) } |
+ { laneData.Name } |
+ { laneData.CarNum } |
}
\ No newline at end of file
diff --git a/web/templates/race_public_templ.go b/web/templates/race_public_templ.go
index d2117e3..72d7c40 100644
--- a/web/templates/race_public_templ.go
+++ b/web/templates/race_public_templ.go
@@ -15,7 +15,7 @@ import (
)
// RacePublic renders the public race view
-func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.Racer, currentHeatNum int, results []models.HeatResult) templ.Component {
+func RacePublic(heatData *models.HeatData, nextHeat *models.HeatData, onDeckHeat *models.HeatData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -53,9 +53,9 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
- templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(currentGroup.Name)
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(heatData.Group.Name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 76}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 78}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -66,9 +66,9 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
- templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(currentHeatNum))
+ templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(heatData.HeatNumber))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 116}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 123}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -79,9 +79,9 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
- templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(len(heats)))
+ templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(heatData.TotalHeats))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 148}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 17, Col: 164}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -91,7 +91,7 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = raceCurrentHeatLanes(heats, racers, currentHeatNum, results).Render(ctx, templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = raceCurrentHeatLanes(heatData).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -99,8 +99,8 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if currentHeatNum < len(heats) {
- templ_7745c5c3_Err = raceNextHeatPreview(heats, racers, currentHeatNum+1).Render(ctx, templ_7745c5c3_Buffer)
+ if nextHeat != nil {
+ templ_7745c5c3_Err = raceNextHeatPreview(nextHeat).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -114,8 +114,8 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if currentHeatNum+1 < len(heats) {
- templ_7745c5c3_Err = raceNextHeatPreview(heats, racers, currentHeatNum+2).Render(ctx, templ_7745c5c3_Buffer)
+ if onDeckHeat != nil {
+ templ_7745c5c3_Err = raceNextHeatPreview(onDeckHeat).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -125,13 +125,13 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = LayoutPublic("Race - "+currentGroup.Name).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = LayoutPublic("Race - "+heatData.Group.Name).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -140,7 +140,7 @@ func RacePublic(currentGroup models.Group, heats []models.Heat, racers []models.
}
// Helper template for displaying current heat lanes
-func raceCurrentHeatLanes(heats []models.Heat, racers []models.Racer, currentHeatNum int, results []models.HeatResult) templ.Component {
+func raceCurrentHeatLanes(heatData *models.HeatData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -161,48 +161,30 @@ func raceCurrentHeatLanes(heats []models.Heat, racers []models.Racer, currentHea
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
-
- // Find current heat
- var currentHeat models.Heat
- for _, heat := range heats {
- if heat.HeatNum == currentHeatNum {
- currentHeat = heat
- break
- }
- }
-
- // Find heat result if available
- var currentResult *models.HeatResult
- for _, result := range results {
- if result.HeatNumber == currentHeatNum {
- currentResult = &result
- break
- }
- }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if currentHeat.Lane1ID != nil {
- templ_7745c5c3_Err = raceLaneCard(1, *currentHeat.Lane1ID, racers, currentResult).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane1 != nil {
+ templ_7745c5c3_Err = raceLaneCard(*heatData.Lane1).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if currentHeat.Lane2ID != nil {
- templ_7745c5c3_Err = raceLaneCard(2, *currentHeat.Lane2ID, racers, currentResult).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane2 != nil {
+ templ_7745c5c3_Err = raceLaneCard(*heatData.Lane2).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if currentHeat.Lane3ID != nil {
- templ_7745c5c3_Err = raceLaneCard(3, *currentHeat.Lane3ID, racers, currentResult).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane3 != nil {
+ templ_7745c5c3_Err = raceLaneCard(*heatData.Lane3).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if currentHeat.Lane4ID != nil {
- templ_7745c5c3_Err = raceLaneCard(4, *currentHeat.Lane4ID, racers, currentResult).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane4 != nil {
+ templ_7745c5c3_Err = raceLaneCard(*heatData.Lane4).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -216,7 +198,7 @@ func raceCurrentHeatLanes(heats []models.Heat, racers []models.Racer, currentHea
}
// Helper template for displaying a lane card
-func raceLaneCard(lane int, racerID int64, racers []models.Racer, result *models.HeatResult) templ.Component {
+func raceLaneCard(laneData models.LaneData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -237,46 +219,14 @@ func raceLaneCard(lane int, racerID int64, racers []models.Racer, result *models
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
-
- // Find racer
- var racer models.Racer
- for _, r := range racers {
- if r.ID == racerID {
- racer = r
- break
- }
- }
-
- // Get time and position from result if available
- var time float64
- var position int
- var hasResult bool
-
- if result != nil {
- hasResult = true
- switch lane {
- case 1:
- time = result.Lane1Time
- position = result.Lane1Position
- case 2:
- time = result.Lane2Time
- position = result.Lane2Position
- case 3:
- time = result.Lane3Time
- position = result.Lane3Position
- case 4:
- time = result.Lane4Time
- position = result.Lane4Position
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -409,7 +306,7 @@ func raceLaneCard(lane int, racerID int64, racers []models.Racer, result *models
}
// Helper template for displaying next heat preview
-func raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum int) templ.Component {
+func raceNextHeatPreview(heatData *models.HeatData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -425,62 +322,53 @@ func raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum int
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var17 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var17 == nil {
- templ_7745c5c3_Var17 = templ.NopComponent
+ templ_7745c5c3_Var14 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var14 == nil {
+ templ_7745c5c3_Var14 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
-
- // Find the heat
- var nextHeat models.Heat
- for _, heat := range heats {
- if heat.HeatNum == heatNum {
- nextHeat = heat
- break
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
Heat ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "Heat ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var18 string
- templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(heatNum))
+ var templ_7745c5c3_Var15 string
+ templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(heatData.HeatNumber))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 301, Col: 49}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 132, Col: 61}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
| Lane | Racer | Car # |
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "| Lane | Racer | Car # |
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if nextHeat.Lane1ID != nil {
- templ_7745c5c3_Err = raceNextHeatRow(1, *nextHeat.Lane1ID, racers).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane1 != nil {
+ templ_7745c5c3_Err = raceNextHeatRow(*heatData.Lane1).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if nextHeat.Lane2ID != nil {
- templ_7745c5c3_Err = raceNextHeatRow(2, *nextHeat.Lane2ID, racers).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane2 != nil {
+ templ_7745c5c3_Err = raceNextHeatRow(*heatData.Lane2).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if nextHeat.Lane3ID != nil {
- templ_7745c5c3_Err = raceNextHeatRow(3, *nextHeat.Lane3ID, racers).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane3 != nil {
+ templ_7745c5c3_Err = raceNextHeatRow(*heatData.Lane3).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- if nextHeat.Lane4ID != nil {
- templ_7745c5c3_Err = raceNextHeatRow(4, *nextHeat.Lane4ID, racers).Render(ctx, templ_7745c5c3_Buffer)
+ if heatData.Lane4 != nil {
+ templ_7745c5c3_Err = raceNextHeatRow(*heatData.Lane4).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -489,7 +377,7 @@ func raceNextHeatPreview(heats []models.Heat, racers []models.Racer, heatNum int
}
// Helper template for displaying a row in the next heat preview
-func raceNextHeatRow(lane int, racerID int64, racers []models.Racer) templ.Component {
+func raceNextHeatRow(laneData models.LaneData) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -505,73 +393,51 @@ func raceNextHeatRow(lane int, racerID int64, racers []models.Racer) templ.Compo
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var19 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var19 == nil {
- templ_7745c5c3_Var19 = templ.NopComponent
+ templ_7745c5c3_Var16 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var16 == nil {
+ templ_7745c5c3_Var16 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
-
- // Find racer
- var racer models.Racer
- for _, r := range racers {
- if r.ID == racerID {
- racer = r
- break
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "| ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var20 string
- templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(lane))
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 343, Col: 32}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, " |
| ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var21 string
- templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(racer.FirstName)
+ var templ_7745c5c3_Var17 string
+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(laneData.Lane))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 344, Col: 29}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 163, Col: 41}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " | ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var22 string
- templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(racer.LastName)
+ var templ_7745c5c3_Var18 string
+ templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.Name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 344, Col: 48}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 164, Col: 27}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, " | ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var23 string
- templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(racer.CarNumber)
+ var templ_7745c5c3_Var19 string
+ templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.CarNum)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 345, Col: 29}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_public.templ`, Line: 165, Col: 29}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, " |
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}