package views import ( "fmt" "strings" "unicode" "task/internal/ticket" ) // GroupByMenu renders a report grouping picker. type GroupByMenu struct { Cursor int Width int Styles StatusMenuStyles } // NewGroupByMenu creates a menu with the given grouping pre-selected. func NewGroupByMenu(current ticket.GroupBy, width int, styles StatusMenuStyles) GroupByMenu { return GroupByMenu{ Cursor: current.Index(), Width: width, Styles: styles, } } // MoveDown moves the selection down. func (m *GroupByMenu) MoveDown() { if m.Cursor < len(ticket.AllGroupBys)-1 { m.Cursor++ } } // MoveUp moves the selection up. func (m *GroupByMenu) MoveUp() { if m.Cursor > 0 { m.Cursor-- } } // JumpToShortcut moves the cursor to the option whose shortcut matches r. func (m *GroupByMenu) JumpToShortcut(r rune) bool { r = unicode.ToLower(r) for i, g := range ticket.AllGroupBys { if g.Shortcut() == r { m.Cursor = i return true } } return false } // Selected returns the currently highlighted grouping. func (m GroupByMenu) Selected() ticket.GroupBy { if m.Cursor < 0 || m.Cursor >= len(ticket.AllGroupBys) { return ticket.GroupByProject } return ticket.AllGroupBys[m.Cursor] } // View renders the grouping menu. func (m GroupByMenu) View() string { var lines []string lines = append(lines, m.Styles.Title.Render("Group report by")) for i, g := range ticket.AllGroupBys { entry := fmt.Sprintf("%c %s", g.Shortcut(), g.Label()) if i == m.Cursor { lines = append(lines, m.Styles.Selected.Render("▸ "+entry)) } else { lines = append(lines, m.Styles.Normal.Render(" "+entry)) } } body := strings.Join(lines, "\n") w := m.Width if w < 20 { w = 20 } return m.Styles.Box.Width(min(40, w-2)).Render(body) }