refactor: break up large functions, add RPG/league/salary/burnout, fix bugs, add tests
- Refactor GenerateMonthlyReport (198→70), HandleCallback (128→85), handleHistoryCallback (131→38), handleExportCallback (100→25), checkAchievements (86→25) into extracted helper functions - Add RPG system (XP, levels, streak, achievements, burnout) - Add WorkTime League leaderboard - Add salary estimation with configurable currency/rate - Add input sanitization (SanitizeNote, SanitizeDisplayName) - Add settings select-style pickers for toggles (report, RPG, league) - Add break threshold inline picker UI - Add event notes with pending state and /note command - Add multi-calendar support (Jalali, Hijri) - Add Excel export with theme picker - Fix: getTodayBreakThreshold uses user's timezone (was UTC) - Fix: acknowledgeCallback passes real callback ID - Fix: currency symbol safety with currencySymbol() helper - Fix: count work hours in summary on day-off days - Fix: unsilence all error returns from SQL Exec/Bot API/migrations - Remove stale db/schema.sql and unreferenced computeWeekTotals - Extract constants: DateLayout, TimeLayout, secondsPerHour, etc. - Add 12 new tests (XP, salary, sanitize, currency, dateutil) - Remove duplicate package doc comment in totals.go
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
||||
// handleSetReportTime parses a HH:MM argument and updates the user's report time.
|
||||
func (h *Handler) handleSetReportTime(ctx context.Context, msg *models.Message) {
|
||||
args := ""
|
||||
if len(msg.Text) > 16 { // "/setreporttime " is 15 chars
|
||||
if len(msg.Text) > 16 {
|
||||
args = strings.TrimSpace(msg.Text[15:])
|
||||
}
|
||||
if args == "" {
|
||||
@@ -24,7 +24,8 @@ func (h *Handler) handleSetReportTime(ctx context.Context, msg *models.Message)
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
return
|
||||
}
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current report time: %s\nUsage: /setreporttime HH:MM (24-hour)", user.ReportTime))
|
||||
st, _ := h.DB.GetOrCreateSettings(user.ID)
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current report time: %s\nUsage: /setreporttime HH:MM (24-hour)", st.ReportTime))
|
||||
return
|
||||
}
|
||||
if len(args) != 5 || args[2] != ':' {
|
||||
@@ -42,8 +43,13 @@ func (h *Handler) handleSetReportTime(ctx context.Context, msg *models.Message)
|
||||
h.sendText(ctx, msg.Chat.ID, "Error updating report time")
|
||||
return
|
||||
}
|
||||
user.ReportTime = args
|
||||
if err := h.DB.UpdateUser(user); err != nil {
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error updating report time")
|
||||
return
|
||||
}
|
||||
st.ReportTime = args
|
||||
if err := h.DB.UpdateSettings(st); err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error updating report time")
|
||||
return
|
||||
}
|
||||
@@ -57,7 +63,12 @@ func (h *Handler) handleAccentMsg(ctx context.Context, msg *models.Message) {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
return
|
||||
}
|
||||
text, kb := h.buildAccentKeyboard(user)
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
return
|
||||
}
|
||||
text, kb := h.buildAccentKeyboard(st)
|
||||
h.sendWithKB(ctx, msg.Chat.ID, text, kb)
|
||||
}
|
||||
|
||||
@@ -92,20 +103,23 @@ func (h *Handler) handleSetTimezone(ctx context.Context, msg *models.Message) {
|
||||
return
|
||||
}
|
||||
now := time.Now().In(loc)
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Timezone set to %s (current time: %s)", args, now.Format("15:04")))
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Timezone set to %s (current time: %s)", args, now.Format(TimeLayout)))
|
||||
}
|
||||
|
||||
// getTodayBreakThreshold returns today's break threshold in seconds for the given chat.
|
||||
func (h *Handler) getTodayBreakThreshold(chatID int64) int64 {
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return 300
|
||||
return defaultBreakThreshold
|
||||
}
|
||||
now := time.Now()
|
||||
date := now.Format("2006-01-02")
|
||||
loc, err := time.LoadLocation(user.Timezone)
|
||||
if err != nil {
|
||||
loc = time.UTC
|
||||
}
|
||||
date := time.Now().In(loc).Format(DateLayout)
|
||||
day, err := h.DB.GetDay(user.ID, date)
|
||||
if err != nil {
|
||||
return 300
|
||||
return defaultBreakThreshold
|
||||
}
|
||||
return day.MinBreakThreshold
|
||||
}
|
||||
@@ -133,7 +147,7 @@ func (h *Handler) handleSetBreakMsg(ctx context.Context, msg *models.Message) {
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
date := now.Format("2006-01-02")
|
||||
date := now.Format(DateLayout)
|
||||
day, err := h.DB.GetOrCreateDay(user.ID, date)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error updating break threshold")
|
||||
@@ -149,30 +163,45 @@ func (h *Handler) handleSetBreakMsg(ctx context.Context, msg *models.Message) {
|
||||
|
||||
// settingsCallback shows the settings inline menu.
|
||||
func (h *Handler) settingsCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildSettingsKeyboard(user, bt)
|
||||
text, kb := h.buildSettingsKeyboard(user, st, bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// buildSettingsKeyboard returns the settings menu text and inline keyboard.
|
||||
func (h *Handler) buildSettingsKeyboard(user *db.User, breakThreshold int64) (string, models.InlineKeyboardMarkup) {
|
||||
func (h *Handler) buildSettingsKeyboard(user *db.User, st *db.UserSettings, breakThreshold int64) (string, models.InlineKeyboardMarkup) {
|
||||
reportStatus := "disabled"
|
||||
if user.ReportEnabled {
|
||||
if st.ReportEnabled {
|
||||
reportStatus = "enabled"
|
||||
}
|
||||
rpgStatus := "disabled"
|
||||
if st.RPGEnabled {
|
||||
rpgStatus = "enabled"
|
||||
}
|
||||
leagueStatus := "disabled"
|
||||
if st.LeagueOptIn {
|
||||
leagueStatus = "on"
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{
|
||||
{{Text: fmt.Sprintf("Timezone: %s", user.Timezone), CallbackData: "timezone"}},
|
||||
{{Text: fmt.Sprintf("Accent: %s", user.ExportAccent), CallbackData: "accent"}},
|
||||
{{Text: fmt.Sprintf("Accent: %s", st.ExportAccent), CallbackData: "accent"}},
|
||||
{{Text: fmt.Sprintf("Calendar: %s", user.Calendar), CallbackData: "caltype"}},
|
||||
{{Text: fmt.Sprintf("Report: %s", reportStatus), CallbackData: "reporttoggle"}},
|
||||
{{Text: fmt.Sprintf("Report time: %s", user.ReportTime), CallbackData: "reporttime"}},
|
||||
{{Text: fmt.Sprintf("Report time: %s", st.ReportTime), CallbackData: "reporttime"}},
|
||||
{{Text: fmt.Sprintf("Break threshold: %dm", breakThreshold/60), CallbackData: "breakthreshold"}},
|
||||
{{Text: "History", CallbackData: "history"}},
|
||||
{{Text: fmt.Sprintf("RPG: %s", rpgStatus), CallbackData: "rpgtoggle"}},
|
||||
{{Text: fmt.Sprintf("League: %s", leagueStatus), CallbackData: "leaguetoggle"}},
|
||||
{{Text: fmt.Sprintf("Currency: %s", st.Currency), CallbackData: "currency"}},
|
||||
{{Text: fmt.Sprintf("Rate: %.2f", st.HourlyRate), CallbackData: "setrate"}},
|
||||
{{Text: "Back to Menu", CallbackData: "back_menu"}},
|
||||
}
|
||||
return "Settings:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
@@ -180,18 +209,22 @@ func (h *Handler) buildSettingsKeyboard(user *db.User, breakThreshold int64) (st
|
||||
|
||||
// accentCallback shows the accent color picker (inline edit).
|
||||
func (h *Handler) accentCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildAccentKeyboard(user)
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildAccentKeyboard(st)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// timezoneCallback shows the current timezone and instructions to change it.
|
||||
func (h *Handler) timezoneCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -206,7 +239,7 @@ func (h *Handler) timezoneCallback(ctx context.Context, chatID int64, msgID int,
|
||||
}
|
||||
|
||||
// buildAccentKeyboard returns the accent color picker keyboard.
|
||||
func (h *Handler) buildAccentKeyboard(user *db.User) (string, models.InlineKeyboardMarkup) {
|
||||
func (h *Handler) buildAccentKeyboard(st *db.UserSettings) (string, models.InlineKeyboardMarkup) {
|
||||
type accentOption struct {
|
||||
name string
|
||||
color string
|
||||
@@ -220,7 +253,7 @@ func (h *Handler) buildAccentKeyboard(user *db.User) (string, models.InlineKeybo
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, a := range accents {
|
||||
label := fmt.Sprintf("%s (%s)", a.name, a.color)
|
||||
if a.name == user.ExportAccent {
|
||||
if a.name == st.ExportAccent {
|
||||
label = "> " + label
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
@@ -235,7 +268,7 @@ func (h *Handler) buildAccentKeyboard(user *db.User) (string, models.InlineKeybo
|
||||
|
||||
// selectAccent sets the user's export accent color after validation.
|
||||
func (h *Handler) selectAccent(ctx context.Context, chatID int64, msgID int, callbackID, name string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -244,8 +277,12 @@ func (h *Handler) selectAccent(ctx context.Context, chatID int64, msgID int, cal
|
||||
if !valid[name] {
|
||||
return
|
||||
}
|
||||
user.ExportAccent = name
|
||||
if err := h.DB.UpdateUser(user); err != nil {
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st.ExportAccent = name
|
||||
if err := h.DB.UpdateSettings(st); err != nil {
|
||||
return
|
||||
}
|
||||
kb := models.InlineKeyboardMarkup{
|
||||
@@ -258,12 +295,16 @@ func (h *Handler) selectAccent(ctx context.Context, chatID int64, msgID int, cal
|
||||
|
||||
// reportTimeCallback shows the current report time setting.
|
||||
func (h *Handler) reportTimeCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("Current report time: %s\nUse /setreporttime HH:MM to change it.", user.ReportTime)
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("Current report time: %s\nUse /setreporttime HH:MM to change it.", st.ReportTime)
|
||||
kb := models.InlineKeyboardMarkup{
|
||||
InlineKeyboard: [][]models.InlineKeyboardButton{
|
||||
{{Text: "Back to Settings", CallbackData: "back_settings"}},
|
||||
@@ -274,7 +315,7 @@ func (h *Handler) reportTimeCallback(ctx context.Context, chatID int64, msgID in
|
||||
|
||||
// breakThresholdCallback shows the break threshold picker.
|
||||
func (h *Handler) breakThresholdCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildBreakThresholdKeyboard(bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
@@ -309,9 +350,9 @@ func (h *Handler) buildBreakThresholdKeyboard(current int64) (string, models.Inl
|
||||
|
||||
// selectBreakThreshold saves the chosen break threshold and returns to settings.
|
||||
func (h *Handler) selectBreakThreshold(ctx context.Context, chatID int64, msgID int, callbackID, valStr string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
mins, err := strconv.Atoi(valStr)
|
||||
if err != nil || mins < 0 || mins > 480 {
|
||||
if err != nil || mins < 0 || mins > maxBreakThresholdMins {
|
||||
return
|
||||
}
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
@@ -319,7 +360,7 @@ func (h *Handler) selectBreakThreshold(ctx context.Context, chatID int64, msgID
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
date := now.Format("2006-01-02")
|
||||
date := now.Format(DateLayout)
|
||||
day, err := h.DB.GetOrCreateDay(user.ID, date)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -329,25 +370,33 @@ func (h *Handler) selectBreakThreshold(ctx context.Context, chatID int64, msgID
|
||||
return
|
||||
}
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildSettingsKeyboard(user, bt)
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildSettingsKeyboard(user, st, bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// backToSettings returns to the main settings menu.
|
||||
func (h *Handler) backToSettings(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildSettingsKeyboard(user, bt)
|
||||
text, kb := h.buildSettingsKeyboard(user, st, bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// calTypeCallback shows the calendar type selector.
|
||||
func (h *Handler) calTypeCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -382,7 +431,7 @@ func (h *Handler) buildCalendarKeyboard(user *db.User) (string, models.InlineKey
|
||||
|
||||
// selectCalendar sets the user's calendar after validation.
|
||||
func (h *Handler) selectCalendar(ctx context.Context, chatID int64, msgID int, callbackID, name string) {
|
||||
h.answerCb(ctx, callbackID)
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
valid := map[string]bool{"gregorian": true, "jalali": true, "hijri": true}
|
||||
if !valid[name] {
|
||||
return
|
||||
@@ -396,6 +445,185 @@ func (h *Handler) selectCalendar(ctx context.Context, chatID int64, msgID int, c
|
||||
return
|
||||
}
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildSettingsKeyboard(user, bt)
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildSettingsKeyboard(user, st, bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// handleRPGSettingsMsg shows the RPG enable/disable picker (command).
|
||||
func (h *Handler) handleRPGSettingsMsg(ctx context.Context, msg *models.Message) {
|
||||
user, err := h.getOrCreateUser(msg.Chat.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
return
|
||||
}
|
||||
text, kb := h.buildRPGToggleKeyboard(user.ID)
|
||||
h.sendWithKB(ctx, msg.Chat.ID, text, kb)
|
||||
}
|
||||
|
||||
// handleLeagueSettingsMsg shows the League enable/disable picker (command).
|
||||
func (h *Handler) handleLeagueSettingsMsg(ctx context.Context, msg *models.Message) {
|
||||
user, err := h.getOrCreateUser(msg.Chat.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
return
|
||||
}
|
||||
text, kb := h.buildLeagueToggleKeyboard(user.ID)
|
||||
h.sendWithKB(ctx, msg.Chat.ID, text, kb)
|
||||
}
|
||||
|
||||
// rpgToggleCallback shows the RPG enable/disable picker (inline).
|
||||
func (h *Handler) rpgToggleCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildRPGToggleKeyboard(user.ID)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// leagueToggleCallback shows the League enable/disable picker (inline).
|
||||
func (h *Handler) leagueToggleCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildLeagueToggleKeyboard(user.ID)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// reportToggleCallback shows the Report enable/disable picker (inline) — replaces simple toggle.
|
||||
func (h *Handler) reportToggleCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, kb := h.buildReportToggleKeyboard(user.ID)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// buildRPGToggleKeyboard returns the RPG enable/disable picker.
|
||||
func (h *Handler) buildRPGToggleKeyboard(userID int64) (string, models.InlineKeyboardMarkup) {
|
||||
st, err := h.DB.GetOrCreateSettings(userID)
|
||||
current := false
|
||||
if err == nil {
|
||||
current = st.RPGEnabled
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, opt := range []struct {
|
||||
label string
|
||||
data string
|
||||
value bool
|
||||
}{
|
||||
{"Enabled", "rpg_enable", true},
|
||||
{"Disabled", "rpg_disable", false},
|
||||
} {
|
||||
label := opt.label
|
||||
if opt.value == current {
|
||||
label = "> " + label
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: label, CallbackData: opt.data},
|
||||
})
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
||||
})
|
||||
return "RPG System:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
|
||||
// buildLeagueToggleKeyboard returns the League enable/disable picker.
|
||||
func (h *Handler) buildLeagueToggleKeyboard(userID int64) (string, models.InlineKeyboardMarkup) {
|
||||
st, err := h.DB.GetOrCreateSettings(userID)
|
||||
current := false
|
||||
if err == nil {
|
||||
current = st.LeagueOptIn
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, opt := range []struct {
|
||||
label string
|
||||
data string
|
||||
value bool
|
||||
}{
|
||||
{"Enabled", "league_enable", true},
|
||||
{"Disabled", "league_disable", false},
|
||||
} {
|
||||
label := opt.label
|
||||
if opt.value == current {
|
||||
label = "> " + label
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: label, CallbackData: opt.data},
|
||||
})
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
||||
})
|
||||
return "WorkTime League:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
|
||||
// buildReportToggleKeyboard returns the Report enable/disable picker.
|
||||
func (h *Handler) buildReportToggleKeyboard(userID int64) (string, models.InlineKeyboardMarkup) {
|
||||
st, err := h.DB.GetOrCreateSettings(userID)
|
||||
current := true
|
||||
if err == nil {
|
||||
current = st.ReportEnabled
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, opt := range []struct {
|
||||
label string
|
||||
data string
|
||||
value bool
|
||||
}{
|
||||
{"Enabled", "report_enable", true},
|
||||
{"Disabled", "report_disable", false},
|
||||
} {
|
||||
label := opt.label
|
||||
if opt.value == current {
|
||||
label = "> " + label
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: label, CallbackData: opt.data},
|
||||
})
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
||||
})
|
||||
return "Daily Report:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
|
||||
// handleSelectCallback handles binary select callbacks (report_enable, rpg_enable, etc.).
|
||||
func (h *Handler) handleSelectCallback(ctx context.Context, chatID int64, msgID int, callbackID string, setting string, value bool) {
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st, err := h.DB.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch setting {
|
||||
case "report_enable":
|
||||
st.ReportEnabled = value
|
||||
case "rpg_enable":
|
||||
st.RPGEnabled = value
|
||||
if value {
|
||||
h.DB.GetOrCreateRPGStats(user.ID)
|
||||
}
|
||||
case "league_enable":
|
||||
st.LeagueOptIn = value
|
||||
}
|
||||
if err := h.DB.UpdateSettings(st); err != nil {
|
||||
return
|
||||
}
|
||||
bt := h.getTodayBreakThreshold(chatID)
|
||||
text, kb := h.buildSettingsKeyboard(user, st, bt)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user