package screens import ( "context" "fmt" "example.com/m/bot" "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, err := s.ensureJWT(b) if err != nil { log.Error().Err(err).Msg("Failed to get JWT") b.SendNew("❌ Ошибка авторизации. Попробуйте /start", bot.Keyboard()) return } s.renderSelection(b, mode, jwt) } func (s *AddPurchase) renderSelection(b *bot.Bot, mode bot.RenderMode, jwt string) { text := "… › Закупы › Создание\n\nСоздание закупа\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, bot.Row( bot.Button(projectLabel, "pick_project"), )) buttons = append(buttons, bot.Row( bot.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("❌ Не удалось загрузить проекты", bot.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 { pageInfo := "" if page.Pages > 1 { pageInfo = fmt.Sprintf(" (стр. %d/%d)", page.Page, page.Pages) } text += fmt.Sprintf("Проекты%s\n\n", pageInfo) for _, project := range page.Items { buttons = append(buttons, bot.Row( bot.Button(project.Title, fmt.Sprintf("project:%s", project.ID)), )) } var navRow []echotron.InlineKeyboardButton if s.ProjectPage > 0 { navRow = append(navRow, bot.Button("←", "prev_project")) } if s.ProjectPage+1 < page.Pages { navRow = append(navRow, bot.Button("→", "next_project")) } if len(navRow) > 0 { buttons = append(buttons, navRow) } } buttons = append(buttons, bot.Row( bot.Button("← Назад", "back_to_selection"), )) case "creative_list": if s.ProjectID == "" { text += "Сначала выберите проект, чтобы увидеть список креативов.\n\n" buttons = append(buttons, bot.Row( bot.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("❌ Не удалось загрузить креативы", bot.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 { pageInfo := "" if page.Pages > 1 { pageInfo = fmt.Sprintf(" (стр. %d/%d)", page.Page, page.Pages) } text += fmt.Sprintf("Креативы%s\n\n", pageInfo) for _, creative := range page.Items { buttons = append(buttons, bot.Row( bot.Button(creative.Name, fmt.Sprintf("creative:%s", creative.ID)), )) } var navRow []echotron.InlineKeyboardButton if s.CreativePage > 0 { navRow = append(navRow, bot.Button("←", "prev_creative")) } if s.CreativePage+1 < page.Pages { navRow = append(navRow, bot.Button("→", "next_creative")) } if len(navRow) > 0 { buttons = append(buttons, navRow) } } buttons = append(buttons, bot.Row( bot.Button("← Назад", "back_to_selection"), )) } if s.ActivePicker == "" { if s.ProjectID != "" && s.CreativeID != "" { buttons = append(buttons, bot.Row( bot.Button("← Отмена", "back"), bot.Button("→ Далее", "next"), )) } else { buttons = append(buttons, bot.Row( bot.Button("← Отмена", "back"), )) } } keyboard := bot.Keyboard(buttons...) b.Render(text, keyboard, mode) } func (s *AddPurchase) 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 *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_project": if s.ProjectPage > 0 { s.ProjectPage-- } s.Enter(b, bot.EditMessage) case "next_project": s.ProjectPage++ s.Enter(b, bot.EditMessage) case "prev_creative": if s.CreativePage > 0 { s.CreativePage-- } s.Enter(b, bot.EditMessage) case "next_creative": s.CreativePage++ s.Enter(b, bot.EditMessage) case "next": 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 }