223 lines
6.0 KiB
Go
223 lines
6.0 KiB
Go
package screens
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
|
||
"example.com/m/adapter/backend"
|
||
"example.com/m/bot"
|
||
"github.com/NicoNex/echotron/v3"
|
||
"github.com/rs/zerolog/log"
|
||
)
|
||
|
||
type PlacementPurchasePlan struct {
|
||
WorkspaceID string
|
||
ProjectID string
|
||
AddPlacementState *AddPlacement
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||
jwt, err := s.ensureJWT(b)
|
||
if err != nil {
|
||
log.Error().Err(err).Msg("Failed to get JWT")
|
||
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", bot.Keyboard())
|
||
return
|
||
}
|
||
|
||
s.renderChannels(b, mode, jwt)
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) renderChannels(b *bot.Bot, mode bot.RenderMode, jwt string) {
|
||
channels, err := b.Backend.GetPurchasePlanChannels(
|
||
context.Background(),
|
||
jwt,
|
||
s.WorkspaceID,
|
||
s.ProjectID,
|
||
)
|
||
if err != nil {
|
||
log.Error().Err(err).Msg("Failed to get purchase plan channels")
|
||
b.SendNew("❌ Не удалось загрузить каналы", bot.Keyboard())
|
||
return
|
||
}
|
||
|
||
text := "<b>📋 План закупа — Каналы</b>\n\n"
|
||
|
||
var buttons [][]echotron.InlineKeyboardButton
|
||
|
||
if len(channels) == 0 {
|
||
text += "Список каналов пуст.\n\n"
|
||
} else {
|
||
text += "Нажмите на канал для удаления:\n\n"
|
||
|
||
for _, ch := range channels {
|
||
channelName := "Без названия"
|
||
if ch.Channel.Title != nil {
|
||
channelName = *ch.Channel.Title
|
||
} else if ch.Channel.Username != nil {
|
||
channelName = "@" + *ch.Channel.Username
|
||
}
|
||
|
||
// Показываем статус и стоимость
|
||
statusEmoji := "📌"
|
||
switch ch.Status {
|
||
case "planned":
|
||
statusEmoji = "📝"
|
||
case "approved":
|
||
statusEmoji = "✅"
|
||
case "rejected":
|
||
statusEmoji = "❌"
|
||
case "in_progress":
|
||
statusEmoji = "🔄"
|
||
case "completed":
|
||
statusEmoji = "✔️"
|
||
}
|
||
|
||
buttonText := fmt.Sprintf("%s %s", statusEmoji, channelName)
|
||
if ch.PlannedCost != nil {
|
||
buttonText += fmt.Sprintf(" (%.0f₽)", *ch.PlannedCost)
|
||
}
|
||
|
||
buttons = append(buttons, bot.Row(
|
||
bot.Button(buttonText, fmt.Sprintf("remove:%s", ch.ID)),
|
||
))
|
||
}
|
||
}
|
||
|
||
// Инструкция по добавлению канала
|
||
text += "\n<b>Добавление канала:</b>\nОтправьте username канала (без @)"
|
||
|
||
// Навигация
|
||
var navRow []echotron.InlineKeyboardButton
|
||
navRow = append(navRow, bot.Button("« Назад", "back"))
|
||
navRow = append(navRow, bot.Button("Далее →", "next"))
|
||
buttons = append(buttons, navRow)
|
||
|
||
keyboard := bot.Keyboard(buttons...)
|
||
b.Render(text, keyboard, mode)
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) ensureJWT(b *bot.Bot) (string, error) {
|
||
if b.Session.JWT != "" {
|
||
return b.Session.JWT, nil
|
||
}
|
||
|
||
jwt, err := b.Backend.GetJWTByTelegramID(context.Background(), b.ChatID)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
b.Session.JWT = jwt
|
||
return jwt, nil
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||
if u.CallbackQuery == nil || u.CallbackQuery.Data == "" {
|
||
return
|
||
}
|
||
|
||
data := u.CallbackQuery.Data
|
||
|
||
switch {
|
||
case data == "back":
|
||
if s.AddPlacementState != nil {
|
||
b.SetState(s.AddPlacementState, bot.EditMessage)
|
||
}
|
||
|
||
case data == "next":
|
||
// TODO: переход к следующему шагу (детали размещения)
|
||
b.Edit("🚧 Следующий шаг в разработке", bot.Keyboard(
|
||
bot.Row(bot.Button("« Назад", "back_to_purchase_plan")),
|
||
))
|
||
|
||
case data == "back_to_purchase_plan":
|
||
s.Enter(b, bot.EditMessage)
|
||
|
||
case strings.HasPrefix(data, "remove:"):
|
||
parts := strings.Split(data, ":")
|
||
if len(parts) == 2 {
|
||
purchasePlanChannelID := parts[1] // ID записи PurchasePlanChannel
|
||
|
||
jwt, err := s.ensureJWT(b)
|
||
if err != nil {
|
||
log.Error().Err(err).Msg("Failed to get JWT")
|
||
return
|
||
}
|
||
|
||
// Удаляем канал из плана закупа
|
||
err = b.Backend.RemoveChannelFromPurchasePlan(
|
||
context.Background(),
|
||
jwt,
|
||
s.WorkspaceID,
|
||
s.ProjectID,
|
||
purchasePlanChannelID,
|
||
)
|
||
if err != nil {
|
||
log.Error().Err(err).Str("purchase_plan_channel_id", purchasePlanChannelID).Msg("Failed to remove channel")
|
||
b.Edit("❌ Не удалось удалить канал", bot.Keyboard(
|
||
bot.Row(bot.Button("« Назад", "back_to_purchase_plan")),
|
||
))
|
||
return
|
||
}
|
||
|
||
// Обновляем экран
|
||
s.Enter(b, bot.EditMessage)
|
||
}
|
||
|
||
default:
|
||
s.Enter(b, bot.NewMessage)
|
||
}
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) HandleMessage(b *bot.Bot, u *echotron.Update) {
|
||
if u.Message == nil || u.Message.Text == "" {
|
||
return
|
||
}
|
||
|
||
username := strings.TrimSpace(u.Message.Text)
|
||
|
||
// Убираем @ если пользователь его добавил
|
||
username = strings.TrimPrefix(username, "@")
|
||
|
||
if username == "" {
|
||
return
|
||
}
|
||
|
||
jwt, err := s.ensureJWT(b)
|
||
if err != nil {
|
||
log.Error().Err(err).Msg("Failed to get JWT")
|
||
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", bot.Keyboard())
|
||
return
|
||
}
|
||
|
||
// Отправляем запрос на добавление канала
|
||
input := backend.AttachChannelToPurchasePlanInput{
|
||
Username: username,
|
||
}
|
||
|
||
_, err = b.Backend.AttachChannelToPurchasePlan(
|
||
context.Background(),
|
||
jwt,
|
||
s.WorkspaceID,
|
||
s.ProjectID,
|
||
input,
|
||
)
|
||
|
||
if err != nil {
|
||
log.Error().Err(err).Str("username", username).Msg("Failed to attach channel")
|
||
|
||
// Проверяем, содержит ли ошибка информацию о том, что канал не найден
|
||
if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "404") {
|
||
b.SendNew(fmt.Sprintf("❌ Канал @%s не найден в Telegram.\n\nПроверьте правильность username и попробуйте еще раз.", username), bot.Keyboard())
|
||
} else {
|
||
b.SendNew("❌ Не удалось добавить канал. Попробуйте позже.", bot.Keyboard())
|
||
}
|
||
return
|
||
}
|
||
|
||
// Обновляем экран со списком каналов
|
||
s.Enter(b, bot.NewMessage)
|
||
}
|
||
|
||
func (s *PlacementPurchasePlan) Handle(_ *bot.Bot, _ *echotron.Update) { return }
|