package screens import ( "context" "fmt" "example.com/m/bot" "example.com/m/ui" "github.com/NicoNex/echotron/v3" "github.com/rs/zerolog/log" ) const addPurchaseCreativesPerPage = 5 const addPurchaseProjectsPerPage = 6 type AddPurchase struct { WorkspaceID string ProjectID string ProjectTitle string CreativeID string CreativeTitle string ProjectPage int CreativePage int ActivePicker string // "" | "project_list" | "creative_list" BackState bot.State lastProjects map[string]string lastCreatives map[string]string } func (s *AddPurchase) Enter(b *bot.Bot, mode bot.RenderMode) { // JWT уже создан в Bot.Update(), просто берем из сессии jwt := b.Session.JWT if jwt == "" { log.Error().Msg("JWT is empty in session") b.SendNew("❌ Ошибка авторизации. Попробуйте /start", Keyboard()) return } s.renderSelection(b, mode, jwt) } func (s *AddPurchase) renderSelection(b *bot.Bot, mode bot.RenderMode, jwt string) { text := "Создание закупа\n\n" text += "Выберите проект и креатив.\n\n" var buttons [][]echotron.InlineKeyboardButton projectLabel := "Проект: не выбрано" if s.ProjectTitle != "" { projectLabel = fmt.Sprintf("Проект: %s", s.ProjectTitle) } creativeLabel := "Креатив: не выбрано" if s.CreativeTitle != "" { creativeLabel = fmt.Sprintf("Креатив: %s", s.CreativeTitle) } if s.ActivePicker == "" { buttons = append(buttons, Row( Button(projectLabel, "pick_project"), )) buttons = append(buttons, Row( Button(creativeLabel, "pick_creative"), )) } switch s.ActivePicker { case "project_list": page, err := b.Backend.GetProjects( context.Background(), jwt, s.WorkspaceID, s.ProjectPage+1, addPurchaseProjectsPerPage, ) if err != nil { log.Error().Err(err).Msg("Failed to get projects") b.SendNew("❌ Не удалось загрузить проекты", Keyboard()) return } s.lastProjects = make(map[string]string) for _, project := range page.Items { s.lastProjects[project.ID] = project.Title } if len(page.Items) == 0 { text += "У вас нет проектов. Создайте проект и попробуйте снова.\n\n" } else { text += fmt.Sprintf("Проекты%s\n\n", ui.FormatPageInfo(s.ProjectPage, page.Pages)) var slots []echotron.InlineKeyboardButton for _, project := range page.Items { slots = append(slots, Button(project.Title, fmt.Sprintf("project:%s", project.ID))) } if page.Pages >= 2 { for len(slots) < addPurchaseProjectsPerPage { slots = append(slots, Button(" ", "empty")) } } for i := 0; i < len(slots); i += 2 { row := []echotron.InlineKeyboardButton{slots[i]} if i+1 < len(slots) { row = append(row, slots[i+1]) } else { row = append(row, Button(" ", "empty")) } buttons = append(buttons, row) } if navRow := ui.BuildNavigationRow(ui.PaginationConfig{ CurrentPage: s.ProjectPage, TotalPages: page.Pages, }); navRow != nil { buttons = append(buttons, navRow) } } buttons = append(buttons, Row( Button("← Назад", "back_to_selection"), )) case "creative_list": if s.ProjectID == "" { text += "Сначала выберите проект, чтобы увидеть список креативов.\n\n" buttons = append(buttons, Row( Button("← Назад", "back_to_selection"), )) break } page, err := b.Backend.GetCreatives( context.Background(), jwt, s.WorkspaceID, &s.ProjectID, false, s.CreativePage+1, addPurchaseCreativesPerPage, ) if err != nil { log.Error().Err(err).Msg("Failed to get creatives") b.SendNew("❌ Не удалось загрузить креативы", Keyboard()) return } s.lastCreatives = make(map[string]string) for _, creative := range page.Items { s.lastCreatives[creative.ID] = creative.Name } if len(page.Items) == 0 { text += `Для создания закупа сначала нужно создать креатив. Вернитесь назад и создайте креатив в разделе Креативы` } else { text += fmt.Sprintf("Креативы%s\n\n", ui.FormatPageInfo(s.CreativePage, page.Pages)) var slots []echotron.InlineKeyboardButton for _, creative := range page.Items { slots = append(slots, Button(creative.Name, fmt.Sprintf("creative:%s", creative.ID))) } if page.Pages >= 2 { for len(slots) < addPurchaseCreativesPerPage { slots = append(slots, Button(" ", "empty")) } } for i := 0; i < len(slots); i += 2 { row := []echotron.InlineKeyboardButton{slots[i]} if i+1 < len(slots) { row = append(row, slots[i+1]) } else { row = append(row, Button(" ", "empty")) } buttons = append(buttons, row) } if navRow := ui.BuildNavigationRow(ui.PaginationConfig{ CurrentPage: s.CreativePage, TotalPages: page.Pages, }); navRow != nil { buttons = append(buttons, navRow) } } buttons = append(buttons, Row( Button("← Назад", "back_to_selection"), )) } if s.ActivePicker == "" { if s.ProjectID != "" && s.CreativeID != "" { buttons = append(buttons, Row( Button("← Отмена", "back"), Button("→ Далее", "next"), )) } else { buttons = append(buttons, Row( Button("← Отмена", "back"), )) } } keyboard := Keyboard(buttons...) b.Render(text, keyboard, mode) } func (s *AddPurchase) 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) } case "pick_project": s.ActivePicker = "project_list" s.Enter(b, bot.EditMessage) case "pick_creative": s.ActivePicker = "creative_list" s.Enter(b, bot.EditMessage) case "back_to_selection": s.ActivePicker = "" s.Enter(b, bot.EditMessage) case "prev": if s.ActivePicker == "project_list" { if s.ProjectPage > 0 { s.ProjectPage-- } s.Enter(b, bot.EditMessage) return } if s.ActivePicker == "creative_list" { if s.CreativePage > 0 { s.CreativePage-- } s.Enter(b, bot.EditMessage) return } case "next": if s.ActivePicker == "project_list" { s.ProjectPage++ s.Enter(b, bot.EditMessage) return } if s.ActivePicker == "creative_list" { s.CreativePage++ s.Enter(b, bot.EditMessage) return } if s.ProjectID != "" && s.CreativeID != "" { b.SetState(&SelectChannelsForPurchase{ WorkspaceID: s.WorkspaceID, ProjectID: s.ProjectID, ProjectTitle: s.ProjectTitle, CreativeID: s.CreativeID, CreativeTitle: s.CreativeTitle, Channels: []PurchaseChannelInput{}, BackState: s.BackState, }, bot.EditMessage) } default: if len(data) > 8 && data[:8] == "project:" { projectID := data[8:] if s.lastProjects != nil { s.ProjectTitle = s.lastProjects[projectID] } s.ProjectID = projectID s.CreativeID = "" s.CreativeTitle = "" s.CreativePage = 0 s.ActivePicker = "" s.Enter(b, bot.EditMessage) return } if len(data) > 9 && data[:9] == "creative:" { creativeID := data[9:] if s.lastCreatives != nil { s.CreativeTitle = s.lastCreatives[creativeID] } s.CreativeID = creativeID s.ActivePicker = "" s.Enter(b, bot.EditMessage) return } else { s.Enter(b, bot.NewMessage) } } } func (s *AddPurchase) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *AddPurchase) Handle(_ *bot.Bot, _ *echotron.Update) { return }