package screens import ( "context" "strings" "github.com/NicoNex/echotron/v3" "github.com/TelegramExchange/tgex-backend/tg_bot/backend" "github.com/TelegramExchange/tgex-backend/tg_bot/bot" "github.com/rs/zerolog/log" ) // CreativeView - экран просмотра креатива (read-only mode) // Показывает превью креатива и кнопки действий: Редактировать, Тег, Закупить type CreativeView struct { CreativeEditorFields // Встраивание общих полей для отображения превью CreativeID string ProjectID string // Данные проекта для передачи в AddPurchase ProjectTitle string ProjectTelegramID int64 ProjectUsername string ProjectStatus string BackState bot.State renaming bool // режим ввода нового названия } const msgCreativeView = ` 📋 Просмотр креатива Выберите действие: ` func (s *CreativeView) Enter(b *bot.Bot, mode bot.RenderMode) { // Сбрасываем старые ID — при re-enter всегда создаём свежие сообщения s.CreativeMessageID = nil s.ControlPanelMessageID = nil // Загружаем креатив creative, err := b.Backend.GetCreative(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.CreativeID) if err != nil { log.Error().Err(err).Str("creative_id", s.CreativeID).Msg("Failed to get creative") b.SendNew("❌ Не удалось загрузить креатив", Keyboard( Row(Button("← Назад", "back")), )) return } // Загружаем проект для получения данных project, err := b.Backend.GetProject(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.ProjectID) if err != nil { log.Error().Err(err).Str("project_id", s.ProjectID).Msg("Failed to get project") } else { s.ProjectTitle = project.Title s.ProjectTelegramID = project.TelegramID s.ProjectStatus = project.Status if project.Username != nil { s.ProjectUsername = *project.Username } } // Заполняем поля креатива для отображения превью s.Name = &creative.Name if creative.Text != "" { s.Text = &creative.Text } s.MediaItems = nil if len(creative.MediaItems) > 0 { for _, item := range creative.MediaItems { s.MediaItems = append(s.MediaItems, MediaItem{ MediaType: item.MediaType, MediaFileID: item.MediaFileID, }) } } s.Buttons = nil for _, btn := range creative.Buttons { s.Buttons = append(s.Buttons, InlineButton{Text: btn.Text, URL: btn.URL}) } if creative.Tag != "" { s.Tag = &creative.Tag } // Отправляем превью креатива s.SendCreativePreview(b) // Отправляем панель управления с кнопками действий s.showActionPanel(b) } func (s *CreativeView) 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.BackState != nil { b.SetState(s.BackState, bot.EditMessage) } case data == "rename": s.renaming = true s.ShowControlPanel(b, "✏️ Введите новое название креатива:", [][]echotron.InlineKeyboardButton{ Row(Button("← Отмена", "cancel_rename")), }) case data == "cancel_rename": s.renaming = false s.showActionPanel(b) case data == "edit": // Переход к редактированию креатива b.SetState(&CreativeDetails{ CreativeID: s.CreativeID, ProjectID: s.ProjectID, ViewMode: true, // Флаг, что мы открылись из view mode ViewBackTo: s, // Возврат к этому экрану после сохранения ProjectTitle: s.ProjectTitle, BackState: s.BackState, }, bot.EditMessage) case data == "toggle_tag": // Переключение тега (testing <-> production) s.toggleTag(b) case data == "purchase_creative": // Переход к созданию закупа с предвыбором проекта и креатива creativeTitle := "" if s.Name != nil { creativeTitle = *s.Name } b.SetState(&AddPurchase{ ProjectID: s.ProjectID, ProjectTitle: s.ProjectTitle, ProjectTelegramID: s.ProjectTelegramID, ProjectUsername: s.ProjectUsername, ProjectStatus: s.ProjectStatus, CreativeID: s.CreativeID, CreativeTitle: creativeTitle, BackState: s, }, bot.NewMessage) default: log.Warn().Str("callback", data).Msg("Unknown callback in CreativeView") } } func (s *CreativeView) HandleMessage(b *bot.Bot, u *echotron.Update) { if !s.renaming || u.Message == nil || u.Message.Text == "" { return } newName := strings.TrimSpace(u.Message.Text) s.DeleteUserMessage(b, u.Message.ID) input := backend.UpdateCreativeInput{ Name: &newName, } _, err := b.Backend.UpdateCreative( context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.CreativeID, input, ) if err != nil { log.Error().Err(err).Str("creative_id", s.CreativeID).Msg("Failed to rename creative") s.ShowControlPanel(b, "❌ Не удалось переименовать", [][]echotron.InlineKeyboardButton{ Row(Button("← Назад", "cancel_rename")), }) return } s.Name = &newName s.renaming = false s.showActionPanel(b) } func (s *CreativeView) Handle(_ *bot.Bot, _ *echotron.Update) { return } func (s *CreativeView) Exit() {} // showActionPanel показывает панель действий с кнопками func (s *CreativeView) showActionPanel(b *bot.Bot) { tagLabel := s.GetTagLabel() buttons := [][]echotron.InlineKeyboardButton{ Row( Button("✎ Переименовать", "rename"), Button("✎ Редактировать", "edit"), ), Row(Button("+ Закупить", "purchase_creative")), Row( Button("← Назад", "back"), Button(tagLabel, "toggle_tag"), ), } s.ShowControlPanel(b, msgCreativeView, buttons) } // toggleTag переключает тег креатива (testing <-> production) func (s *CreativeView) toggleTag(b *bot.Bot) { newTag := "testing" if s.Tag != nil && *s.Tag == "testing" { newTag = "production" } // Обновляем тег через backend input := backend.UpdateCreativeInput{ Tag: &newTag, } _, err := b.Backend.UpdateCreative( context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.CreativeID, input, ) if err != nil { log.Error().Err(err).Str("creative_id", s.CreativeID).Msg("Failed to update creative tag") s.ShowControlPanel(b, "❌ Не удалось изменить тег\n\nПопробуйте еще раз.", [][]echotron.InlineKeyboardButton{ Row(Button("← Назад", "back")), Row(Button("↻ Попробовать снова", "toggle_tag")), }) return } // Обновляем локальное значение s.Tag = &newTag // Обновляем панель (показывает новый тег) s.showActionPanel(b) }