package screens import ( "context" "fmt" "example.com/m/bot" "github.com/NicoNex/echotron/v3" "github.com/rs/zerolog/log" ) type PurchaseDetails struct { WorkspaceID string ProjectID string PurchaseID string BackState bot.State } func (s *PurchaseDetails) 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.renderDetails(b, mode, jwt) } func (s *PurchaseDetails) renderDetails(b *bot.Bot, mode bot.RenderMode, jwt string) { purchase, err := b.Backend.GetPurchase( context.Background(), jwt, s.WorkspaceID, s.ProjectID, s.PurchaseID, ) if err != nil { log.Error().Err(err).Msg("Failed to get purchase") b.SendNew("❌ Не удалось загрузить закуп", bot.Keyboard()) return } // Получаем информацию о креативе creative, err := b.Backend.GetCreative( context.Background(), jwt, s.WorkspaceID, purchase.CreativeID, ) if err != nil { log.Error().Err(err).Msg("Failed to get creative") creative = nil } text := "📦 Детали закупа\n\n" // Информация о креативе if creative != nil { text += fmt.Sprintf("Креатив: %s\n", creative.Name) } else { text += fmt.Sprintf("Креатив ID: %s\n", purchase.CreativeID) } // Статус закупа statusText := "Активный" if purchase.Status == "archived" { statusText = "Архивирован" } text += fmt.Sprintf("Статус: %s\n\n", statusText) // Информация о каналах if len(purchase.Channels) == 0 { text += "Каналы не добавлены\n" } else { text += fmt.Sprintf("Каналы (%d):\n\n", len(purchase.Channels)) for i, ch := range purchase.Channels { // Определяем статус emoji statusEmoji := "📌" switch ch.Status { case "planned": statusEmoji = "📝" case "approved": statusEmoji = "✅" case "rejected": statusEmoji = "❌" case "in_progress": statusEmoji = "🔄" case "completed": statusEmoji = "✔️" } // Название канала channelName := "Без названия" if ch.Channel.Title != nil { channelName = *ch.Channel.Title } else if ch.Channel.Username != nil { channelName = "@" + *ch.Channel.Username } text += fmt.Sprintf("%d. %s %s\n", i+1, statusEmoji, channelName) // Стоимость if ch.PlannedCost != nil { text += fmt.Sprintf(" 💰 Стоимость: %.0f₽\n", *ch.PlannedCost) } // Комментарий if ch.Comment != nil && *ch.Comment != "" { text += fmt.Sprintf(" 💬 %s\n", *ch.Comment) } // Тип invite link inviteLinkTypeText := "публичная" if ch.InviteLinkType == "approval" { inviteLinkTypeText = "с одобрением" } text += fmt.Sprintf(" 🔗 Ссылка: %s\n", inviteLinkTypeText) text += "\n" } } var buttons [][]echotron.InlineKeyboardButton // Кнопка назад buttons = append(buttons, bot.Row( bot.Button("← Назад", "back"), )) keyboard := bot.Keyboard(buttons...) b.Render(text, keyboard, mode) } func (s *PurchaseDetails) 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 *PurchaseDetails) HandleCallback(b *bot.Bot, u *echotron.Update) { if u.CallbackQuery == nil || u.CallbackQuery.Data == "" { return } data := u.CallbackQuery.Data switch data { case "back": if s.BackState != nil { b.SetState(s.BackState, bot.EditMessage) } default: s.Enter(b, bot.NewMessage) } } func (s *PurchaseDetails) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *PurchaseDetails) Handle(_ *bot.Bot, _ *echotron.Update) { return }