add year navigation: year row at top of calendar, clickable year in export, shared buildYearPicker with 12-year grid

This commit is contained in:
2026-06-24 19:47:03 +03:30
parent 8d919decb0
commit 68c8518522
2 changed files with 112 additions and 1 deletions

View File

@@ -79,6 +79,37 @@ func (h *Handler) handleHistoryCallback(ctx context.Context, chatID int64, msgID
h.editCalendar(ctx, chatID, msgID, y, m)
return
}
// Navigate to previous year
if n, _ := fmt.Sscanf(data, "cal_prev_year_%d_%d", &y, &m); n == 2 {
h.editCalendar(ctx, chatID, msgID, y, m)
return
}
// Navigate to next year
if n, _ := fmt.Sscanf(data, "cal_next_year_%d_%d", &y, &m); n == 2 {
h.editCalendar(ctx, chatID, msgID, y, m)
return
}
// Show year picker from calendar
if n, _ := fmt.Sscanf(data, "cal_show_years_%d_%d", &y, &m); n == 2 {
h.editCalendarYearPicker(ctx, chatID, msgID, y, m, y)
return
}
// Navigate year block in picker
var startY, refY, refM int
if n, _ := fmt.Sscanf(data, "cal_years_%d_%d_%d", &startY, &refY, &refM); n == 3 {
h.editCalendarYearPicker(ctx, chatID, msgID, startY+6, refM, refY)
return
}
// Select year from picker
if n, _ := fmt.Sscanf(data, "cal_year_%d", &y); n == 1 {
h.editCalendar(ctx, chatID, msgID, y, 1)
return
}
// Back from year picker to calendar
if n, _ := fmt.Sscanf(data, "cal_years_back_%d_%d", &y, &m); n == 2 {
h.editCalendar(ctx, chatID, msgID, y, m)
return
}
// Open a specific day
if n, _ := fmt.Sscanf(data, "cal_day_%s", &date); n == 1 && len(date) == 10 {
h.editDayView(ctx, chatID, msgID, user, date, loc)
@@ -148,6 +179,36 @@ func (h *Handler) sendCalendar(ctx context.Context, chatID int64, msgID int, yea
h.editCalendar(ctx, chatID, msgID, year, month)
}
// buildYearPicker returns a 12-year grid keyboard centered on centerYear.
// cbPrefix is "cal_" or "exp_". backData is the callback for the Back button.
// navSuffix is appended to the nav callbacks to carry reference info (e.g. "_2026_3").
func buildYearPicker(cbPrefix, backData, navSuffix string, centerYear int) models.InlineKeyboardMarkup {
blockStart := centerYear - 6
kbRows := [][]models.InlineKeyboardButton{
{
{Text: "< 12", CallbackData: fmt.Sprintf("%syears_%d%s", cbPrefix, blockStart-12, navSuffix)},
{Text: fmt.Sprintf("%d", centerYear), CallbackData: "noop"},
{Text: "12 >", CallbackData: fmt.Sprintf("%syears_%d%s", cbPrefix, blockStart+12, navSuffix)},
},
}
for i := 0; i < 12; i += 4 {
row := []models.InlineKeyboardButton{}
for j := i; j < i+4; j++ {
y := blockStart + j
row = append(row, models.InlineKeyboardButton{
Text: fmt.Sprintf("%d", y), CallbackData: fmt.Sprintf("%syear_%d", cbPrefix, y),
})
}
kbRows = append(kbRows, row)
}
if backData != "" {
kbRows = append(kbRows, []models.InlineKeyboardButton{
{Text: "Back", CallbackData: backData},
})
}
return models.InlineKeyboardMarkup{InlineKeyboard: kbRows}
}
// editCalendar renders a monthly calendar grid with event indicators and navigation.
func (h *Handler) editCalendar(ctx context.Context, chatID int64, msgID int, year, month int) {
user, err := h.getOrCreateUser(chatID)
@@ -193,6 +254,13 @@ func (h *Handler) editCalendar(ctx context.Context, chatID int64, msgID int, yea
kbRows := [][]models.InlineKeyboardButton{}
// Year navigation row
kbRows = append(kbRows, []models.InlineKeyboardButton{
{Text: fmt.Sprintf("< %d", year-1), CallbackData: fmt.Sprintf("cal_prev_year_%d_%d", year-1, month)},
{Text: fmt.Sprintf("%d", year), CallbackData: fmt.Sprintf("cal_show_years_%d_%d", year, month)},
{Text: fmt.Sprintf("%d >", year+1), CallbackData: fmt.Sprintf("cal_next_year_%d_%d", year+1, month)},
})
// Weekday header row
headerRow := []models.InlineKeyboardButton{}
for _, wn := range cm.weekDays {
@@ -241,6 +309,17 @@ func (h *Handler) editCalendar(ctx context.Context, chatID int64, msgID int, yea
h.sendOrEdit(ctx, chatID, msgID, text, &kb)
}
// editCalendarYearPicker shows a 12-year grid for year selection.
// refY/refM encode the view to return to via the Back button.
func (h *Handler) editCalendarYearPicker(ctx context.Context, chatID int64, msgID int, centerYear, refM, refY int) {
backData := fmt.Sprintf("cal_years_back_%d_%d", refY, refM)
navSuffix := fmt.Sprintf("_%d_%d", refY, refM)
kb := buildYearPicker("cal_", backData, navSuffix, centerYear)
h.Bot.EditMessageText(ctx, &bot.EditMessageTextParams{
ChatID: chatID, MessageID: msgID, Text: "Select year:", ReplyMarkup: &kb,
})
}
// editDayView opens an existing message as a day view.
func (h *Handler) editDayView(ctx context.Context, chatID int64, msgID int, user *db.User, date string, loc *time.Location) {
h.sendDayView(ctx, chatID, msgID, user, date, loc, false)