Files
tgex-backend/tg_bot/screens/add_purchase.go
Artem Tsyrulnikov 09145e510a fix
2026-02-03 22:21:08 +03:00

326 lines
8.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package screens
import (
"context"
"fmt"
"github.com/NicoNex/echotron/v3"
"github.com/TelegramExchange/tgex-backend/tg_bot/backend"
"github.com/TelegramExchange/tgex-backend/tg_bot/bot"
"github.com/TelegramExchange/tgex-backend/tg_bot/screens/ui"
"github.com/rs/zerolog/log"
)
const addPurchaseCreativesPerPage = 5
const addPurchaseProjectsPerPage = 6
type AddPurchase struct {
ProjectID string
ProjectTitle string
ProjectTelegramID int64
ProjectUsername string
ProjectStatus string
ProjectDefaultLinkType string
CreativeID string
CreativeTitle string
ProjectPage int
CreativePage int
ActivePicker string // "" | "project_list" | "creative_list"
BackState bot.State
lastProjects map[string]projectInfo
lastCreatives map[string]creativeInfo
}
type projectInfo struct {
Title string
TelegramID int64
Username string
Status string
DefaultInviteType string
}
type creativeInfo struct {
Title string
}
func (s *AddPurchase) Enter(b *bot.Bot, mode bot.RenderMode) {
s.renderSelection(b, mode)
}
func (s *AddPurchase) renderSelection(b *bot.Bot, mode bot.RenderMode) {
text := "<b>Создание закупа</b>\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(), b.Session.JWT, b.Session.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]projectInfo)
for _, project := range page.Items {
username := ""
if project.Username != nil {
username = *project.Username
}
s.lastProjects[project.ID] = projectInfo{
Title: project.Title,
TelegramID: project.TelegramID,
Username: username,
Status: project.Status,
DefaultInviteType: project.PurchaseInviteTypeDefault,
}
}
if len(page.Items) == 0 {
text += "У вас нет проектов. Создайте проект и попробуйте снова.\n\n"
} else {
text += fmt.Sprintf("Проекты%s\n\n", ui.FormatPageInfo(s.ProjectPage, page.Pages))
buttons = append(buttons, ui.BuildGrid(
page.Items,
2,
addPurchaseProjectsPerPage,
page.Pages,
func(project backend.Project) (string, string) {
return project.Title, "project:" + project.ID
},
)...)
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(), b.Session.JWT, b.Session.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]creativeInfo)
for _, creative := range page.Items {
s.lastCreatives[creative.ID] = creativeInfo{
Title: creative.Name,
}
}
if len(page.Items) == 0 {
text += `Для создания закупа сначала нужно создать креатив.
Вернитесь назад и создайте креатив в разделе <b>Креативы</b>`
buttons = append(buttons, Row(
Button("🎨 Перейти к креативам", "go_to_creatives"),
))
} else {
text += fmt.Sprintf("Креативы%s\n\n", ui.FormatPageInfo(s.CreativePage, page.Pages))
buttons = append(buttons, ui.BuildGrid(
page.Items,
2,
addPurchaseCreativesPerPage,
page.Pages,
func(creative backend.Creative) (string, string) {
return creative.Name, "creative:" + creative.ID
},
)...)
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)
if s.ActivePicker == "" && s.ProjectTelegramID != 0 {
messageID := b.LastMessageID
updateProjectHeaderMedia(b, messageID, text, keyboard, s.ProjectTelegramID, s.ProjectTitle, s.ProjectUsername, s.ProjectStatus)
}
}
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 "go_to_creatives":
b.SetState(&Creatives{
CurrentPage: 0,
ProjectID: s.ProjectID,
ProjectTitle: s.ProjectTitle,
ProjectTelegramID: s.ProjectTelegramID,
ProjectUsername: s.ProjectUsername,
ProjectStatus: s.ProjectStatus,
BackState: s,
}, 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{
ProjectID: s.ProjectID,
ProjectTitle: s.ProjectTitle,
ProjectTelegramID: s.ProjectTelegramID,
ProjectUsername: s.ProjectUsername,
ProjectStatus: s.ProjectStatus,
ProjectDefaultLinkType: s.ProjectDefaultLinkType,
CreativeID: s.CreativeID,
CreativeTitle: s.CreativeTitle,
Channels: []PurchaseChannelInput{},
Duplicates: []string{},
ParsingErrors: []ParseError{},
BackState: s.BackState,
}, bot.EditMessage)
}
default:
if len(data) > 8 && data[:8] == "project:" {
projectID := data[8:]
if s.lastProjects != nil {
if info, ok := s.lastProjects[projectID]; ok {
s.ProjectTitle = info.Title
s.ProjectTelegramID = info.TelegramID
s.ProjectUsername = info.Username
s.ProjectStatus = info.Status
s.ProjectDefaultLinkType = info.DefaultInviteType
}
}
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 {
if info, ok := s.lastCreatives[creativeID]; ok {
s.CreativeTitle = info.Title
}
}
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 }
func (s *AddPurchase) Exit() {}