From 70a55b51bd3dd36479c5b20b90aad35c134703e2 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Fri, 7 Mar 2025 12:42:55 -0900 Subject: [PATCH] Update events --- derby/derby.go | 8 +- examples/main.go | 4 +- models/models.go | 15 + web/server.go | 376 ++++++++++++--------- web/templates/race_manage.templ | 151 +++++---- web/templates/race_manage_templ.go | 522 ++++++++++++++++------------- web/templates/race_public.templ | 4 +- 7 files changed, 613 insertions(+), 467 deletions(-) diff --git a/derby/derby.go b/derby/derby.go index d144fb3..3c5fdbf 100644 --- a/derby/derby.go +++ b/derby/derby.go @@ -43,8 +43,8 @@ const ( // Event represents a race event type Event struct { - Type EventType - Event any // Only populated for EventLaneFinish + Type EventType + Result *Result // Only populated for EventLaneFinish } // DerbyClock represents the connection to the derby clock device @@ -205,8 +205,8 @@ func (dc *DerbyClock) readLoop() { if result != nil { // Send lane finish event dc.eventChan <- Event{ - Type: EventLaneFinish, - Event: result, + Type: EventLaneFinish, + Result: result, } } results = append(results, result) diff --git a/examples/main.go b/examples/main.go index 1069e22..7339aa6 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.Event.(derby.Result) + result := event.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 8da323c..ecbe318 100644 --- a/models/models.go +++ b/models/models.go @@ -87,3 +87,18 @@ type HeatData struct { Lane3 *LaneData Lane4 *LaneData } + +// Event types that can be sent on the event channel +type AdminEventType int + +const ( + EventHeatChanged AdminEventType = iota + EventGroupChanged + EventHeatRerun +) + +// Event represents a race event +type AdminEvent struct { + Type AdminEventType + Event any +} diff --git a/web/server.go b/web/server.go index cde9b1b..f275914 100644 --- a/web/server.go +++ b/web/server.go @@ -29,17 +29,19 @@ var content embed.FS // Server represents the web server for the derby clock type Server struct { - router *chi.Mux - clock *derby.DerbyClock - events <-chan derby.Event - clients map[chan string]bool - clientsMux sync.Mutex - port int - server *http.Server - shutdown chan struct{} - logger *slog.Logger - db *db.DB - adminEvents chan string + router *chi.Mux + clock *derby.DerbyClock + events <-chan derby.Event + clients map[chan string]bool + clientsMux sync.Mutex + adminclients map[chan string]bool + adminclientsMux sync.Mutex + port int + server *http.Server + shutdown chan struct{} + logger *slog.Logger + db *db.DB + adminEvents chan string } // NewServer creates a new web server @@ -115,54 +117,49 @@ func (s *Server) routes() { r.Post("/reset", s.handleReset()) r.Post("/force-end", s.handleForceEnd()) r.Get("/events", s.handleEvents()) + r.Get("/validate/car-number", s.handleValidateCarNumber()) + r.Route("/groups", func(r chi.Router) { + r.Post("/", s.handleCreateGroup()) + r.Put("/{id}", s.handleUpdateGroup()) + r.Delete("/{id}", s.handleDeleteGroup()) + }) + r.Route("/racers", func(r chi.Router) { + r.Post("/", s.handleCreateRacer()) + r.Put("/{id}", s.handleUpdateRacer()) + r.Delete("/{id}", s.handleDeleteRacer()) + }) + r.Route("/heats", func(r chi.Router) { + r.Post("/generate", s.handleGenerateHeats()) + }) + r.Route("/api/race", func(r chi.Router) { + r.Get("/current-heat", s.handleCurrentHeat()) + r.Post("/next-heat", s.handleNextHeat()) + r.Post("/previous-heat", s.handlePreviousHeat()) + r.Post("/rerun-heat", s.handleRerunHeat()) + r.Post("/set-group", s.handleSetRacingGroup()) + }) + r.Route("/admin", func(r chi.Router) { + r.Get("/events", s.handleAdminEvents()) + }) }) s.router.Get("/admin", s.handleAdmin()) s.router.Get("/register", s.handleRegister()) s.router.Get("/register/form", s.handleRegisterForm()) - s.router.Route("/api/groups", func(r chi.Router) { - r.Post("/", s.handleCreateGroup()) - r.Put("/{id}", s.handleUpdateGroup()) - r.Delete("/{id}", s.handleDeleteGroup()) - }) - - s.router.Route("/api/racers", func(r chi.Router) { - r.Post("/", s.handleCreateRacer()) - r.Put("/{id}", s.handleUpdateRacer()) - r.Delete("/{id}", s.handleDeleteRacer()) - }) - // Add heats page route s.router.Get("/heats", s.handleHeats()) s.router.Get("/heats-content", s.handleHeatsContent()) - // Add heats API routes - s.router.Route("/api/heats", func(r chi.Router) { - r.Post("/generate", s.handleGenerateHeats()) - }) - // Main page s.router.Get("/", s.handleIndex()) // Add racers list route s.router.Get("/admin/racers/list", s.handleRacersList()) - // Add validate car number route - s.router.Get("/api/validate/car-number", s.handleValidateCarNumber()) - // Add race manager routes s.router.Get("/race", s.handleRacePublic()) s.router.Get("/race/manage", s.handleRaceManage()) - - // Add race API routes - s.router.Route("/api/race", func(r chi.Router) { - r.Get("/current-heat", s.handleCurrentHeat()) - r.Post("/next-heat", s.handleNextHeat()) - r.Post("/previous-heat", s.handlePreviousHeat()) - r.Post("/rerun-heat", s.handleRerunHeat()) - r.Post("/set-group", s.handleSetRacingGroup()) - }) } // Start starts the web server @@ -216,7 +213,7 @@ func (s *Server) forwardEvents() { return } // Process the event and send to clients - s.broadcastEvent(event) + s.broadcastRaceEvent(event) case <-s.shutdown: return } @@ -224,37 +221,89 @@ func (s *Server) forwardEvents() { } // broadcastEvent sends an event to all connected clients -func (s *Server) broadcastEvent(event derby.Event) { +func (s *Server) broadcastRaceEvent(event derby.Event) { + var heatResult models.HeatResult switch event.Type { case derby.EventRaceStart: s.logger.Info("Broadcasting race start event") - s.sendEventToAllClients("event: race-status\ndata:
Race Running
") + s.sendRaceEventToAllClients("event: race-status\ndata:
Race Running
") + heatGroup, _ := s.db.GetCurrentRacingGroup() + heatResult.GroupID = heatGroup.ID + heatResult.HeatNumber, _ = s.db.GetCurrentHeatNumber(heatGroup.ID) case derby.EventLaneFinish: s.logger.Info("Broadcasting lane finish event", - "lane", event.Event.(derby.Result).Lane, - "time", event.Event.(derby.Result).Time, - "place", event.Event.(derby.Result).FinishPlace) + "lane", event.Result.Lane, + "time", event.Result.Time, + "place", event.Result.FinishPlace) + + switch event.Result.Lane { + case 1: + heatResult.Lane1Time = event.Result.Time + heatResult.Lane1Position = event.Result.FinishPlace + case 2: + heatResult.Lane2Time = event.Result.Time + heatResult.Lane2Position = event.Result.FinishPlace + case 3: + heatResult.Lane3Time = event.Result.Time + heatResult.Lane3Position = event.Result.FinishPlace + case 4: + heatResult.Lane4Time = event.Result.Time + heatResult.Lane4Position = event.Result.FinishPlace + } + s.sendRaceEventToAllClients(fmt.Sprintf("event: lane-%d-time\ndata: %.4f", event.Result.Lane, event.Result.Time)) + s.sendRaceEventToAllClients(fmt.Sprintf("event: lane-%d-position\ndata: %d", event.Result.Lane, event.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.EventRaceComplete: + s.logger.Info("Broadcasting race complete event") + s.sendRaceEventToAllClients("event: race-status\ndata:
Race Complete
") + s.db.SaveHeatResult(heatResult) + } +} - case derby.EventHeatChanged: +// broadcastEvent sends an event to all connected clients +func (s *Server) broadcastAdminEvent(event models.AdminEvent) { + switch event.Type { + case models.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
") + if heatData, ok := event.Event.(models.HeatData); ok { + component := templates.CurrentHeatDisplay(&heatData) + var sb strings.Builder + err := component.Render(context.Background(), &sb) + if err != nil { + s.logger.Error("Failed to render current heat display", "error", err) + } + s.sendAdminEventToAllClients(fmt.Sprintf("event: current-heat\ndata: %s", sb.String())) + nextHeatData, _ := s.db.GetHeatData(heatData.Group.ID, heatData.HeatNumber+1) + component = templates.NextHeatDisplay(nextHeatData) + var sb2 strings.Builder + err = component.Render(context.Background(), &sb2) + if err != nil { + s.logger.Error("Failed to render next heat display", "error", err) + } + s.sendAdminEventToAllClients(fmt.Sprintf("event: next-heat\ndata: %s", sb2.String())) + s.sendAdminEventToAllClients(fmt.Sprintf("event: heat-number\ndata: Current Heat: %d of %d", heatData.HeatNumber, heatData.TotalHeats)) + } else { + s.logger.Error("Failed to convert event to HeatData") + } - case derby.EventGroupChanged: - s.logger.Info("Broadcasting group changed event") - s.sendEventToAllClients("event: group-changed\ndata:
Group Changed
") + case models.EventGroupChanged: + s.logger.Info("Broadcasting group changed event", + "group", event.Event) - case derby.EventRaceComplete: - s.logger.Info("Broadcasting race complete event") - s.sendEventToAllClients("event: race-status\ndata:
Race Complete
") + if heatResults, ok := event.Event.([]models.HeatResult); ok { + component := templates.ResultsDisplay(heatResults) + var sb strings.Builder + err := component.Render(context.Background(), &sb) + if err != nil { + s.logger.Error("Failed to render current heat results", "error", err) + } + s.sendAdminEventToAllClients(fmt.Sprintf("event: results\ndata: %s", sb.String())) + } } } -func (s *Server) sendEventToAllClients(message string) { +func (s *Server) sendRaceEventToAllClients(message string) { if message == "" { return } @@ -274,6 +323,26 @@ func (s *Server) sendEventToAllClients(message string) { s.clientsMux.Unlock() } +func (s *Server) sendAdminEventToAllClients(message string) { + if message == "" { + return + } + + // Send to all clients + s.adminclientsMux.Lock() + clientCount := len(s.adminclients) + sentCount := 0 + for clientChan := range s.adminclients { + clientChan <- message + sentCount++ + } + s.logger.Debug("Event broadcast complete", + "sentCount", sentCount, + "totalClients", clientCount, + "message", message) + s.adminclientsMux.Unlock() +} + // handleIndex handles the index page func (s *Server) handleIndex() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -336,9 +405,6 @@ func (s *Server) handleEvents() http.HandlerFunc { w.Header().Set("Connection", "keep-alive") w.Header().Set("Access-Control-Allow-Origin", "*") - // Debug message to confirm connection - fmt.Fprintf(w, "event: debug\ndata: {\"message\":\"SSE connection established\"}\n\n") - // Flush headers to ensure they're sent to the client if flusher, ok := w.(http.Flusher); ok { flusher.Flush() @@ -391,6 +457,67 @@ func (s *Server) handleEvents() http.HandlerFunc { } } +// handleAdminEvents handles SSE events +func (s *Server) handleAdminEvents() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // Set headers for SSE + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + w.Header().Set("Access-Control-Allow-Origin", "*") + + // Flush headers to ensure they're sent to the client + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } else { + http.Error(w, "Streaming unsupported!", http.StatusInternalServerError) + return + } + + // Create a channel for this client + clientChan := make(chan string, 10) + + // Add client to map with mutex protection + s.adminclientsMux.Lock() + s.adminclients[clientChan] = true + clientCount := len(s.adminclients) + s.adminclientsMux.Unlock() + + s.logger.Info("New client connected", + "clientIP", r.RemoteAddr, + "totalClients", clientCount) + + // Remove client when connection is closed + defer func() { + s.adminclientsMux.Lock() + delete(s.adminclients, clientChan) + remainingClients := len(s.adminclients) + s.adminclientsMux.Unlock() + close(clientChan) + + s.logger.Info("Client disconnected", + "clientIP", r.RemoteAddr, + "remainingClients", remainingClients) + }() + + // Keep connection open and send events as they arrive + for { + select { + case msg, ok := <-clientChan: + if !ok { + return + } + fmt.Fprintf(w, "%s\n\n", msg) + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } + case <-r.Context().Done(): + return + } + } + } +} + // handleAdmin renders the admin page func (s *Server) handleAdmin() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -937,29 +1064,6 @@ func (s *Server) handleRacersList() http.HandlerFunc { } } -// handleAdminEvents handles admin events with SSE -func (s *Server) handleAdminEvents() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - // Set SSE headers - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - - // Send events to client - for { - select { - case event := <-s.adminEvents: - fmt.Fprintf(w, "data: %s\n\n", event) - if f, ok := w.(http.Flusher); ok { - f.Flush() - } - case <-r.Context().Done(): - return - } - } - } -} - // handleValidateCarNumber handles the validate car number API endpoint func (s *Server) handleValidateCarNumber() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -1272,28 +1376,19 @@ func (s *Server) handleNextHeat() http.HandlerFunc { return } - // Reset the clock - if err := s.clock.Reset(); err != nil { - s.logger.Error("Failed to reset clock", "error", err) - } + heatData, _ := s.db.GetHeatData(currentGroup.ID, currentHeatNum+1) // Broadcast event to admin page - s.broadcastAdminEvent("heat-changed") + s.broadcastAdminEvent(models.AdminEvent{ + Type: models.EventHeatChanged, + Event: heatData, + }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) } } -// broadcastAdminEvent sends an event to all admin clients -func (s *Server) broadcastAdminEvent(event string) { - // Create a simple event message - eventMsg := fmt.Sprintf(`{"event":"%s"}`, event) - - // Send to all admin clients - s.adminEvents <- eventMsg -} - // handlePreviousHeat goes back to the previous heat func (s *Server) handlePreviousHeat() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -1326,61 +1421,13 @@ func (s *Server) handlePreviousHeat() http.HandlerFunc { return } - // Reset the clock - if err := s.clock.Reset(); err != nil { - s.logger.Error("Failed to reset clock", "error", err) - } + heatData, _ := s.db.GetHeatData(currentGroup.ID, currentHeatNum-1) // Broadcast event to admin page - s.broadcastAdminEvent("heat-changed") - - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(map[string]string{"status": "success"}) - } -} - -// handleSaveHeatResult saves the result of a heat -func (s *Server) handleSaveHeatResult() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - // Parse request body - var request struct { - GroupID int64 `json:"group_id"` - HeatNumber int `json:"heat_number"` - Lane1Time float64 `json:"lane1_time"` - Lane1Position int `json:"lane1_position"` - Lane2Time float64 `json:"lane2_time"` - Lane2Position int `json:"lane2_position"` - Lane3Time float64 `json:"lane3_time"` - Lane3Position int `json:"lane3_position"` - Lane4Time float64 `json:"lane4_time"` - Lane4Position int `json:"lane4_position"` - } - - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) - return - } - - // Create heat result - result := models.HeatResult{ - GroupID: request.GroupID, - HeatNumber: request.HeatNumber, - Lane1Time: request.Lane1Time, - Lane1Position: request.Lane1Position, - Lane2Time: request.Lane2Time, - Lane2Position: request.Lane2Position, - Lane3Time: request.Lane3Time, - Lane3Position: request.Lane3Position, - Lane4Time: request.Lane4Time, - Lane4Position: request.Lane4Position, - } - - // Save heat result - if err := s.db.SaveHeatResult(result); err != nil { - s.logger.Error("Failed to save heat result", "error", err) - http.Error(w, "Failed to save heat result", http.StatusInternalServerError) - return - } + s.broadcastAdminEvent(models.AdminEvent{ + Type: models.EventHeatChanged, + Event: heatData, + }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) @@ -1413,13 +1460,13 @@ func (s *Server) handleRerunHeat() http.HandlerFunc { return } - // Reset the clock - if err := s.clock.Reset(); err != nil { - s.logger.Error("Failed to reset clock", "error", err) - } + heatData, _ := s.db.GetHeatData(currentGroup.ID, currentHeatNum) // Broadcast event to admin page - s.broadcastAdminEvent("heat-rerun") + s.broadcastAdminEvent(models.AdminEvent{ + Type: models.EventHeatChanged, + Event: heatData, + }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) @@ -1446,13 +1493,20 @@ func (s *Server) handleSetRacingGroup() http.HandlerFunc { return } - // Reset the clock - if err := s.clock.Reset(); err != nil { - s.logger.Error("Failed to reset clock", "error", err) - } + heatData, _ := s.db.GetHeatData(request.GroupID, 1) // Broadcast event to admin page - s.broadcastAdminEvent("group-changed") + s.broadcastAdminEvent(models.AdminEvent{ + Type: models.EventHeatChanged, + Event: heatData, + }) + + heatResults, _ := s.db.GetHeatResults(request.GroupID) + + s.broadcastAdminEvent(models.AdminEvent{ + Type: models.EventGroupChanged, + Event: heatResults, + }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) diff --git a/web/templates/race_manage.templ b/web/templates/race_manage.templ index 0078dbf..05b1674 100644 --- a/web/templates/race_manage.templ +++ b/web/templates/race_manage.templ @@ -29,7 +29,7 @@ templ RaceManage(heatData *models.HeatData, nextHeat *models.HeatData, groups []
-
Current Heat: { strconv.Itoa(heatData.HeatNumber) } of { strconv.Itoa(heatData.TotalHeats) }
+
Current Heat: { strconv.Itoa(heatData.HeatNumber) } of { strconv.Itoa(heatData.TotalHeats) }
} } +templ ResultsDisplay(results []models.HeatResult) { +
+
+

Heat Results

+
+
+
+ + + + + + + + + + + + for _, result := range results { + + + + + + + + } + +
HeatLane 1Lane 2Lane 3Lane 4
{ strconv.Itoa(result.HeatNumber) }{ fmt.Sprintf("%.4f", result.Lane1Time) } ({ strconv.Itoa(result.Lane1Position) }){ fmt.Sprintf("%.4f", result.Lane2Time) } ({ strconv.Itoa(result.Lane2Position) }){ fmt.Sprintf("%.4f", result.Lane3Time) } ({ strconv.Itoa(result.Lane3Position) }){ fmt.Sprintf("%.4f", result.Lane4Time) } ({ strconv.Itoa(result.Lane4Position) })
+
+
+
+} + // Find the current heat -templ currentHeatDisplay(heatData *models.HeatData) { +templ CurrentHeatDisplay(heatData *models.HeatData) {

Current Heat: { strconv.Itoa(heatData.HeatNumber) }

@@ -178,10 +154,10 @@ templ raceLaneInfo(laneData models.LaneData) {

Car #: { laneData.CarNum }

- Time: { fmt.Sprintf("%.3f", laneData.Time) } + Time: { fmt.Sprintf("%.3f", laneData.Time) }
- Position: { strconv.Itoa(laneData.Place) } + Position: { strconv.Itoa(laneData.Place) }
@@ -189,6 +165,41 @@ templ raceLaneInfo(laneData models.LaneData) {
} +templ NextHeatDisplay(nextHeat *models.HeatData) { + if nextHeat != nil { +
+
+

Next Heat: { strconv.Itoa(nextHeat.HeatNumber) }

+
+
+ + + + + + + + + + if nextHeat.Lane1 != nil { + @raceNextHeatRow(*nextHeat.Lane1) + } + if nextHeat.Lane2 != nil { + @raceNextHeatRow(*nextHeat.Lane2) + } + if nextHeat.Lane3 != nil { + @raceNextHeatRow(*nextHeat.Lane3) + } + if nextHeat.Lane4 != nil { + @raceNextHeatRow(*nextHeat.Lane4) + } + +
LaneRacerCar #
+
+
+ } +} + // Helper template for displaying a racer in the next heat templ nextHeatRacer(laneData models.LaneData) { diff --git a/web/templates/race_manage_templ.go b/web/templates/race_manage_templ.go index f1d78ef..5ab7f64 100644 --- a/web/templates/race_manage_templ.go +++ b/web/templates/race_manage_templ.go @@ -94,14 +94,14 @@ func RaceManage(heatData *models.HeatData, nextHeat *models.HeatData, groups []m return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
Current Heat: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
Current Heat: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, 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_manage.templ`, Line: 32, Col: 85} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 32, Col: 153} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -114,7 +114,7 @@ func RaceManage(heatData *models.HeatData, nextHeat *models.HeatData, groups []m var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, 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_manage.templ`, Line: 32, Col: 126} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 32, Col: 194} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -140,211 +140,31 @@ func RaceManage(heatData *models.HeatData, nextHeat *models.HeatData, groups []m return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, ">Next Heat
Timer Control

0.000

Ready
Gate Status: Unknown

Heat Results

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, ">Next Heat
Timer Control
Ready
Gate Status: Unknown
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - for _, result := range results { - var templ_7745c5c3_Var7 = []any{"table-primary"} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } + templ_7745c5c3_Err = ResultsDisplay(results).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
HeatLane 1Lane 2Lane 3Lane 4
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.HeatNumber)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 89, Col: 85} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane1Time)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 90, Col: 91} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " (") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane1Position)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 90, Col: 131} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, ")") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane2Time)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 91, Col: 91} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, " (") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane2Position)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 91, Col: 131} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, ")") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var14 string - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane3Time)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 92, Col: 91} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " (") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var15 string - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane3Position)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 92, Col: 131} - } - _, 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, 22, ")") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane4Time)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 93, Col: 91} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " (") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var17 string - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane4Position)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 93, Col: 131} - } - _, 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, 24, ")
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = currentHeatDisplay(heatData).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = CurrentHeatDisplay(heatData).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, 15, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - if nextHeat != nil { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "

Next 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(nextHeat.HeatNumber)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 111, Col: 87} - } - _, 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, 28, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if nextHeat.Lane1 != nil { - templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane1).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if nextHeat.Lane2 != nil { - templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane2).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if nextHeat.Lane3 != nil { - templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane3).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if nextHeat.Lane4 != nil { - templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane4).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
LaneRacerCar #
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } + templ_7745c5c3_Err = NextHeatDisplay(nextHeat).Render(ctx, templ_7745c5c3_Buffer) + 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, 16, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -358,8 +178,182 @@ func RaceManage(heatData *models.HeatData, nextHeat *models.HeatData, groups []m }) } +func ResultsDisplay(results []models.HeatResult) 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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

Heat Results

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, result := range results { + var templ_7745c5c3_Var8 = []any{"table-primary"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
HeatLane 1Lane 2Lane 3Lane 4
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.HeatNumber)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 106, Col: 69} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane1Time)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 107, Col: 75} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " (") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane1Position)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 107, Col: 115} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, ")") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane2Time)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 108, Col: 75} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " (") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane2Position)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 108, Col: 115} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, ")") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane3Time)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 109, Col: 75} + } + _, 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, " (") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane3Position)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 109, Col: 115} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, ")") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 string + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.4f", result.Lane4Time)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 110, Col: 75} + } + _, 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, 27, " (") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var18 string + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(result.Lane4Position)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 110, Col: 115} + } + _, 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, 28, ")
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + // Find the current heat -func currentHeatDisplay(heatData *models.HeatData) templ.Component { +func CurrentHeatDisplay(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 { @@ -380,20 +374,20 @@ func currentHeatDisplay(heatData *models.HeatData) templ.Component { templ_7745c5c3_Var19 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "

Current Heat: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "

Current Heat: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var20 string templ_7745c5c3_Var20, 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_manage.templ`, Line: 148, Col: 78} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 124, Col: 78} } _, 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, 32, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -421,7 +415,7 @@ func currentHeatDisplay(heatData *models.HeatData) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -451,72 +445,72 @@ func raceLaneInfo(laneData models.LaneData) templ.Component { templ_7745c5c3_Var21 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
Lane ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
Lane ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var22 string templ_7745c5c3_Var22, 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_manage.templ`, Line: 174, Col: 67} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 150, Col: 67} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 177, Col: 54} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 153, Col: 54} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

Car #: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "

Car #: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var24 string templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.CarNum) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 178, Col: 61} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 154, Col: 61} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "

Time: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

Time: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var25 string templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.3f", laneData.Time)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 181, Col: 89} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 157, Col: 89} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
Position: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
Position: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var26 string templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(laneData.Place)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 184, Col: 87} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 160, Col: 87} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -524,8 +518,7 @@ func raceLaneInfo(laneData models.LaneData) templ.Component { }) } -// Helper template for displaying a racer in the next heat -func nextHeatRacer(laneData models.LaneData) templ.Component { +func NextHeatDisplay(nextHeat *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 { @@ -546,46 +539,119 @@ func nextHeatRacer(laneData models.LaneData) templ.Component { templ_7745c5c3_Var27 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") + if nextHeat != nil { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

Next Heat: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var28 string + templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(nextHeat.HeatNumber)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 172, Col: 79} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if nextHeat.Lane1 != nil { + templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane1).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if nextHeat.Lane2 != nil { + templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane2).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if nextHeat.Lane3 != nil { + templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane3).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if nextHeat.Lane4 != nil { + templ_7745c5c3_Err = raceNextHeatRow(*nextHeat.Lane4).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
LaneRacerCar #
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +// Helper template for displaying a racer in the next heat +func nextHeatRacer(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 { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var29 := templ.GetChildren(ctx) + if templ_7745c5c3_Var29 == nil { + templ_7745c5c3_Var29 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var28 string - templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(laneData.Lane)) + var templ_7745c5c3_Var30 string + templ_7745c5c3_Var30, 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_manage.templ`, Line: 195, Col: 41} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 206, Col: 41} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var29 string - templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.Name) + var templ_7745c5c3_Var31 string + templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 196, Col: 27} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 207, Col: 27} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var30 string - templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.CarNum) + var templ_7745c5c3_Var32 string + templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(laneData.CarNum) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 197, Col: 29} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates/race_manage.templ`, Line: 208, Col: 29} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/web/templates/race_public.templ b/web/templates/race_public.templ index 3922b55..b9da0a8 100644 --- a/web/templates/race_public.templ +++ b/web/templates/race_public.templ @@ -107,7 +107,7 @@ templ raceLaneCard(laneData models.LaneData) {
Time
-
+
{ fmt.Sprintf("%.3f", laneData.Time) }
@@ -115,7 +115,7 @@ templ raceLaneCard(laneData models.LaneData) {
Position
-
+
{ strconv.Itoa(laneData.Place) }