From dc0793bf59ad5ade131241e9d4049241d5762c48 Mon Sep 17 00:00:00 2001 From: AmanTahiliani Date: Fri, 27 Mar 2026 00:44:00 -0400 Subject: [PATCH] Fixed Date Logic --- internal/ui/calendar.go | 18 ++++++++++++++++ internal/ui/dashboard.go | 44 ++++++++++++++++++++++++++++++++------- internal/ui/racedetail.go | 39 +++++++++++++++++----------------- internal/ui/util.go | 14 +++++++++++++ 4 files changed, 89 insertions(+), 26 deletions(-) diff --git a/internal/ui/calendar.go b/internal/ui/calendar.go index e86f61b..befd4b9 100644 --- a/internal/ui/calendar.go +++ b/internal/ui/calendar.go @@ -151,6 +151,24 @@ func (m *CalendarModel) ensureCursorVisible() { func (m CalendarModel) findNextRaceIndex() int { now := time.Now() + + // First: return the index of a meeting currently underway (started but not ended). + for i, meeting := range m.meetings { + start, err := time.Parse(time.RFC3339, meeting.DateStart) + if err != nil { + start, _ = time.Parse("2006-01-02", meeting.DateStart[:min(len(meeting.DateStart), 10)]) + } + end, err2 := time.Parse(time.RFC3339, meeting.DateEnd) + if err2 != nil { + end, _ = time.Parse("2006-01-02", meeting.DateEnd[:min(len(meeting.DateEnd), 10)]) + end = end.Add(24 * time.Hour) + } + if now.After(start.Local()) && now.Before(end.Local()) { + return i + } + } + + // Second: return the next upcoming meeting (start is in the future). for i, meeting := range m.meetings { start, err := time.Parse(time.RFC3339, meeting.DateStart) if err != nil { diff --git a/internal/ui/dashboard.go b/internal/ui/dashboard.go index ce5fc7b..476c9e1 100644 --- a/internal/ui/dashboard.go +++ b/internal/ui/dashboard.go @@ -110,15 +110,30 @@ func (m DashboardModel) Update(msg tea.Msg) (DashboardModel, tea.Cmd) { m.meetings = msg.meetings now := time.Now() + // First priority: find a meeting that has already started but not yet ended + // (i.e. we're currently in a GP weekend). for i := range m.meetings { mtg := m.meetings[i] + start, _ := time.Parse(time.RFC3339, mtg.DateStart) end, _ := time.Parse(time.RFC3339, mtg.DateEnd) - if now.Before(end.Local()) || now.Sub(end.Local()) < 24*time.Hour { // also keep showing for 24h after + if now.After(start.Local()) && now.Before(end.Local().Add(24*time.Hour)) { m.next = &mtg break } } + // Second priority: if no ongoing weekend, find the next upcoming meeting. + if m.next == nil { + for i := range m.meetings { + mtg := m.meetings[i] + start, _ := time.Parse(time.RFC3339, mtg.DateStart) + if now.Before(start.Local()) { + m.next = &mtg + break + } + } + } + if m.next != nil { return m, fetchDashboardSessions(m.client, int(m.next.MeetingKey)) } @@ -166,21 +181,32 @@ func (m DashboardModel) View() string { Foreground(lipgloss.Color(colorF1Red)). Bold(true) + // Determine if the weekend has started + now := time.Now() + meetingStart, _ := time.Parse(time.RFC3339, m.next.DateStart) + meetingStart = meetingStart.Local() + weekendUnderway := now.After(meetingStart) + sb.WriteString("\n") - sb.WriteString(titleStyle.Render(fmt.Sprintf(" NEXT RACE: %s", m.next.MeetingOfficialName)) + "\n") + if weekendUnderway { + sb.WriteString(titleStyle.Render(fmt.Sprintf(" CURRENT RACE: %s", m.next.MeetingOfficialName)) + "\n") + } else { + sb.WriteString(titleStyle.Render(fmt.Sprintf(" NEXT RACE: %s", m.next.MeetingOfficialName)) + "\n") + } sb.WriteString(fmt.Sprintf(" %s • %s\n", countryFlag(m.next.CountryCode), m.next.Location)) - now := time.Now() end, _ := time.Parse(time.RFC3339, m.next.DateEnd) endLocal := end.Local() - // Show countdown to first session if available, else use start date + // Show countdown to next session if available, else use start date var nextStart time.Time + var nextSession *models.Session startFound := false - for _, s := range m.sessions { - st, _ := time.Parse(time.RFC3339, s.DateStart) + for i := range m.sessions { + st, _ := time.Parse(time.RFC3339, m.sessions[i].DateStart) if now.Before(st.Local()) { nextStart = st.Local() + nextSession = &m.sessions[i] startFound = true break } @@ -201,7 +227,11 @@ func (m DashboardModel) View() string { hours := int(diff.Hours()) % 24 mins := int(diff.Minutes()) % 60 secs := int(diff.Seconds()) % 60 - sb.WriteString(fmt.Sprintf(" Starts in: %dd %02dh %02dm %02ds\n", days, hours, mins, secs)) + if nextSession != nil { + sb.WriteString(fmt.Sprintf(" Next: %s in %dd %02dh %02dm %02ds\n", nextSession.SessionName, days, hours, mins, secs)) + } else { + sb.WriteString(fmt.Sprintf(" Starts in: %dd %02dh %02dm %02ds\n", days, hours, mins, secs)) + } } else { sb.WriteString(" " + lipgloss.NewStyle().Foreground(lipgloss.Color(colorMuted)).Render("Weekend Finished") + "\n") } diff --git a/internal/ui/racedetail.go b/internal/ui/racedetail.go index cccdc4f..a69e637 100644 --- a/internal/ui/racedetail.go +++ b/internal/ui/racedetail.go @@ -141,17 +141,28 @@ func (m RaceDetailModel) Update(msg tea.Msg) (RaceDetailModel, tea.Cmd) { return m, nil } m.sessions = msg.sessions - // Auto-select the Race session and load its data - raceIdx := -1 + + // Auto-select the best session to show: + // 1. The last session that has already started (ongoing or completed). + // 2. If no session has started yet, fall back to the first session. + now := time.Now() + autoIdx := -1 for i, s := range m.sessions { - if s.SessionName == "Race" { - raceIdx = i - break + st, err := time.Parse(time.RFC3339, s.DateStart) + if err != nil { + continue + } + if now.After(st.Local()) { + autoIdx = i // keep updating — we want the LAST one that has started } } - if raceIdx >= 0 { - m.sessionCursor = raceIdx - sess := m.sessions[raceIdx] + if autoIdx < 0 && len(m.sessions) > 0 { + autoIdx = 0 // nothing started yet, show first session + } + + if autoIdx >= 0 { + m.sessionCursor = autoIdx + sess := m.sessions[autoIdx] m.selectedSession = &sess m.loadingResults = true m.driversLoaded = false @@ -159,17 +170,7 @@ func (m RaceDetailModel) Update(msg tea.Msg) (RaceDetailModel, tea.Cmd) { m.results = nil m.rcMsgs = nil m.weather = nil - m.drivers = make(map[int]models.Driver) - cmds = append(cmds, m.spinner.Tick, fetchSessionData(m.client, sess.SessionKey)) - } else if len(m.sessions) > 0 { - // Fallback: select last session - lastIdx := len(m.sessions) - 1 - m.sessionCursor = lastIdx - sess := m.sessions[lastIdx] - m.selectedSession = &sess - m.loadingResults = true - m.driversLoaded = false - m.secondaryLoading = false + m.overtakes = nil m.drivers = make(map[int]models.Driver) cmds = append(cmds, m.spinner.Tick, fetchSessionData(m.client, sess.SessionKey)) } diff --git a/internal/ui/util.go b/internal/ui/util.go index adedbdc..87db1d0 100644 --- a/internal/ui/util.go +++ b/internal/ui/util.go @@ -288,7 +288,15 @@ func renderPointsBar(points, maxPoints float64, width int, color string) string } // meetingStatus returns a status indicator for a meeting. +// isNext is true when this meeting is the "current or next" highlighted one. func meetingStatus(m models.Meeting, now time.Time, isNext bool) string { + start, err := time.Parse(time.RFC3339, m.DateStart) + if err != nil { + start, _ = time.Parse("2006-01-02", m.DateStart[:min(len(m.DateStart), 10)]) + } else { + start = start.Local() + } + end, err := time.Parse(time.RFC3339, m.DateEnd) if err != nil { end, err = time.Parse("2006-01-02", m.DateEnd[:min(len(m.DateEnd), 10)]) @@ -296,8 +304,14 @@ func meetingStatus(m models.Meeting, now time.Time, isNext bool) string { return " " } end = end.Add(24 * time.Hour) + } else { + end = end.Local() } + // Currently underway: started but not ended + if now.After(start) && now.Before(end) { + return styleNext.Render("▶") + } if end.Before(now) { return stylePast.Render("✓") }