fix: resolve go vet error and dayStart logic in ComputeDailyTotals
- Fix 'string(d)' int-to-rune conversion in rpg_test.go by using fmt.Sprintf - Fix ComputeDailyTotals dayStart logic: initial state should be StateWorking when dayStart > 0, correctly counting work from dayStart to first out event - Update README project structure to reflect new domain/handler/repo layout - Implement missing achievements: rpg_pioneer (on RPG enable) and salary_setter (on first rate set) - Add tryUnlockAchievement helper to Handler
This commit is contained in:
111
internal/handler/league.go
Normal file
111
internal/handler/league.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-telegram/bot/models"
|
||||
|
||||
"worktimeBot/internal/domain"
|
||||
)
|
||||
|
||||
// -- Command --
|
||||
|
||||
func (h *Handler) handleLeague(ctx context.Context, msg *models.Message, user *domain.User) {
|
||||
st, err := h.Repo.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading settings")
|
||||
return
|
||||
}
|
||||
if !st.LeagueOptIn {
|
||||
h.sendText(ctx, msg.Chat.ID, "League participation is disabled.\nEnable it in Settings or use /leaguetoggle.")
|
||||
return
|
||||
}
|
||||
text := h.buildLeagueText(domain.LeagueSortXP)
|
||||
kb := h.buildLeagueKeyboard(string(domain.LeagueSortXP))
|
||||
h.sendWithKB(ctx, msg.Chat.ID, text, kb)
|
||||
}
|
||||
|
||||
// -- Callback --
|
||||
|
||||
func (h *Handler) leagueCallback(ctx context.Context, chatID int64, msgID int, cbID string, user *domain.User, orderBy string) {
|
||||
defer h.answerCb(ctx, cbID)
|
||||
st, err := h.Repo.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !st.LeagueOptIn {
|
||||
kb := backKeyboard()
|
||||
h.editText(ctx, chatID, msgID, "League participation is disabled.\nEnable it in Settings to view rankings.", &kb)
|
||||
return
|
||||
}
|
||||
text := h.buildLeagueText(domain.LeagueSortOption(orderBy))
|
||||
kb := h.buildLeagueKeyboard(orderBy)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// -- Builders --
|
||||
|
||||
func (h *Handler) buildLeagueText(orderBy domain.LeagueSortOption) string {
|
||||
entries, err := h.Repo.GetLeagueRankings(string(orderBy))
|
||||
if err != nil {
|
||||
return "League rankings unavailable."
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
return "No participants in the league yet.\nEnable League participation in Settings to join!"
|
||||
}
|
||||
var b strings.Builder
|
||||
orderLabel := map[string]string{"xp": "XP", "level": "Level", "streak": "Streak", "hours": "Hours"}
|
||||
b.WriteString(fmt.Sprintf("WorkTime League - %s\n\n", orderLabel[string(orderBy)]))
|
||||
for i, e := range entries {
|
||||
rank := i + 1
|
||||
name := e.Username
|
||||
if name == "" {
|
||||
name = "Anonymous"
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("%d %s\n", rank, name))
|
||||
b.WriteString(fmt.Sprintf(" XP:%d Lv:%d S:%d %.1fh\n", e.XP, e.Level, e.Streak, e.TotalHours))
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("\n%d participant(s)\n", len(entries)))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (h *Handler) buildLeagueRankText(userID int64) string {
|
||||
entries, err := h.Repo.GetLeagueRankings("xp")
|
||||
if err != nil || len(entries) == 0 {
|
||||
return ""
|
||||
}
|
||||
for i, e := range entries {
|
||||
if e.UserID == userID {
|
||||
return fmt.Sprintf("League rank: #%d of %d", i+1, len(entries))
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (h *Handler) buildLeagueKeyboard(currentOrder string) models.InlineKeyboardMarkup {
|
||||
type sortBtn struct{ label, data string }
|
||||
orders := []sortBtn{
|
||||
{"XP", "league_xp"},
|
||||
{"Level", "league_level"},
|
||||
{"Streak", "league_streak"},
|
||||
{"Hours", "league_hours"},
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for i := 0; i < len(orders); i += 2 {
|
||||
row := []models.InlineKeyboardButton{}
|
||||
for j := i; j < i+2 && j < len(orders); j++ {
|
||||
label := orders[j].label
|
||||
if orders[j].data == "league_"+currentOrder {
|
||||
label = "> " + label
|
||||
}
|
||||
row = append(row, models.InlineKeyboardButton{Text: label, CallbackData: orders[j].data})
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Menu", CallbackData: "back_menu"},
|
||||
})
|
||||
return models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
Reference in New Issue
Block a user