fix: currency validation, league mobile layout, settings 2-col, burnout ratio, add setusername
- Require both symbol+code in /setcurrency; add preset picker ($ USD, T Toman, IRR Rial, EUR, GBP) in settings inline menu - League: compact 2-line per entry for mobile; sort buttons in 2x2 grid - Settings: 2-column layout with grouped buttons (timezone+calendar, report+report time, break+accent, rpg+league, currency+rate) - Burnout: cap break ratio at 100% to prevent nonsense values - Add /setusername command (uses existing SanitizeDisplayName) - Update /help with new/changed commands
This commit is contained in:
@@ -179,7 +179,7 @@ func (h *Handler) handleSetRateMsg(ctx context.Context, msg *models.Message) {
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Hourly rate set to %s%.2f", currencySymbol(st.Currency), st.HourlyRate))
|
||||
}
|
||||
|
||||
// handleSetCurrencyMsg handles /setcurrency <symbol> [code].
|
||||
// handleSetCurrencyMsg handles /setcurrency <symbol> <code>.
|
||||
func (h *Handler) handleSetCurrencyMsg(ctx context.Context, msg *models.Message) {
|
||||
args := strings.TrimSpace(strings.TrimPrefix(msg.Text, "/setcurrency"))
|
||||
if args == "" {
|
||||
@@ -189,18 +189,23 @@ func (h *Handler) handleSetCurrencyMsg(ctx context.Context, msg *models.Message)
|
||||
return
|
||||
}
|
||||
st, _ := h.DB.GetOrCreateSettings(user.ID)
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current currency: %s\nUsage: /setcurrency <symbol> [code]\nExamples:\n/setcurrency $ USD\n/setcurrency EUR\n/setcurrency Toman", st.Currency))
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Current currency: %s\nUsage: /setcurrency <symbol> <code>\nExamples:\n/setcurrency $ USD\n/setcurrency T Toman\n/setcurrency IRR Rial", st.Currency))
|
||||
return
|
||||
}
|
||||
parts := strings.Fields(args)
|
||||
if len(parts[0]) > 10 || strings.ContainsFunc(parts[0], func(r rune) bool { return r < 32 || r > 126 }) {
|
||||
h.sendText(ctx, msg.Chat.ID, "Invalid currency symbol. Use a short printable string like $, €, £, or Toman.")
|
||||
if len(parts) < 2 {
|
||||
h.sendText(ctx, msg.Chat.ID, "Please provide both symbol and code.\nUsage: /setcurrency <symbol> <code>\nExamples:\n/setcurrency $ USD\n/setcurrency T Toman\n/setcurrency IRR Rial")
|
||||
return
|
||||
}
|
||||
currency := parts[0]
|
||||
if len(parts) >= 2 {
|
||||
currency = parts[0] + " " + parts[1]
|
||||
if len(parts[0]) > 10 || strings.ContainsFunc(parts[0], func(r rune) bool { return r < 32 || r > 126 }) {
|
||||
h.sendText(ctx, msg.Chat.ID, "Invalid currency symbol. Use a short printable string like $, €, £.")
|
||||
return
|
||||
}
|
||||
if len(parts[1]) > 10 || strings.ContainsFunc(parts[1], func(r rune) bool { return r < 32 || r > 126 }) {
|
||||
h.sendText(ctx, msg.Chat.ID, "Invalid currency code.")
|
||||
return
|
||||
}
|
||||
currency := parts[0] + " " + parts[1]
|
||||
user, err := h.getOrCreateUser(msg.Chat.ID)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, "Error loading profile")
|
||||
@@ -219,7 +224,7 @@ func (h *Handler) handleSetCurrencyMsg(ctx context.Context, msg *models.Message)
|
||||
h.sendText(ctx, msg.Chat.ID, fmt.Sprintf("Currency set to: %s", currency))
|
||||
}
|
||||
|
||||
// currencyCallback shows currency info (inline).
|
||||
// currencyCallback shows the currency picker (inline).
|
||||
func (h *Handler) currencyCallback(ctx context.Context, chatID int64, msgID int, callbackID string) {
|
||||
defer h.answerCb(ctx, callbackID)
|
||||
user, err := h.getOrCreateUser(chatID)
|
||||
@@ -227,12 +232,46 @@ func (h *Handler) currencyCallback(ctx context.Context, chatID int64, msgID int,
|
||||
return
|
||||
}
|
||||
st, _ := h.DB.GetOrCreateSettings(user.ID)
|
||||
text := fmt.Sprintf("Currency: %s\n\nUse /setcurrency <symbol> [code] to change it.\nExamples:\n/setcurrency $ USD\n/setcurrency EUR\n/setcurrency Toman", st.Currency)
|
||||
kb := models.InlineKeyboardMarkup{
|
||||
InlineKeyboard: [][]models.InlineKeyboardButton{
|
||||
{{Text: "Back to Settings", CallbackData: "back_settings"}},
|
||||
},
|
||||
text, kb := buildCurrencyKeyboard(st.Currency)
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// buildCurrencyKeyboard returns the currency preset picker keyboard.
|
||||
func buildCurrencyKeyboard(current string) (string, models.InlineKeyboardMarkup) {
|
||||
presets := []string{"$ USD", "T Toman", "IRR Rial", "€ EUR", "£ GBP"}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, p := range presets {
|
||||
label := p
|
||||
if p == current {
|
||||
label = "> " + label
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: label, CallbackData: "currency_" + p},
|
||||
})
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
||||
})
|
||||
return "Select currency:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
|
||||
// selectCurrency saves the chosen currency preset.
|
||||
func (h *Handler) selectCurrency(ctx context.Context, chatID int64, msgID int, callbackID, currency string) {
|
||||
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
|
||||
}
|
||||
st.Currency = currency
|
||||
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