package screens import ( "context" "strings" "time" "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 projectsPerPage = 6 const projectsPerRow = 2 type MyProjects struct { CurrentPage int BackState bot.State OpenPlacements bool cancel context.CancelFunc lastProjectCount int } const msgNoProjects = ` Мои проекты У вас пока нет подключенных каналов. Что дает подключение канала: ▸ Управление типом приглашений (публичные/с одобрением) ▸ Автоматическая отправка креативов в канал ▸ Интеграция с планом закупов ▸ Статистика и аналитика подписчиков ▸ Настройка уведомлений Начните с добавления первого проекта ` const msgProjects = ` Мои проекты Управление вашими Telegram-каналами. Выберите канал ` func (s *MyProjects) Enter(b *bot.Bot, mode bot.RenderMode) { s.renderProjects(b, mode) s.startPolling(b) } func (s *MyProjects) renderProjects(b *bot.Bot, mode bot.RenderMode) { page, err := b.Backend.GetProjects(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.CurrentPage+1, projectsPerPage) if err != nil { b.SendNew("❌ Не удалось загрузить проекты", refreshKeyboard) return } s.lastProjectCount = page.Total var kbRows [][]echotron.InlineKeyboardButton grid := ui.BuildGrid(page.Items, projectsPerRow, projectsPerPage, page.Pages, func(project backend.Project) (string, string) { return project.Title, "project:" + project.ID }, ) kbRows = append(kbRows, grid...) if navRow := ui.BuildNavigationRow(ui.PaginationConfig{ CurrentPage: s.CurrentPage, TotalPages: page.Pages, MiddleButtons: Row(Button("+ Добавить", "add_project")), }); navRow != nil { kbRows = append(kbRows, navRow) } kbRows = append(kbRows, Row(Button("← Назад", "main_menu"), Button("≡ Архив", "archive"))) keyboard := Keyboard(kbRows...) text := msgProjects if len(page.Items) == 0 { text = msgNoProjects } b.Render(text, keyboard, mode) } func (s *MyProjects) HandleCallback(b *bot.Bot, u *echotron.Update) { if u.CallbackQuery == nil || u.CallbackQuery.Data == "" { return } data := u.CallbackQuery.Data switch { case data == "prev": if s.CurrentPage > 0 { s.CurrentPage-- } s.Enter(b, bot.EditMessage) case data == "next": s.CurrentPage++ s.Enter(b, bot.EditMessage) case data == "main_menu": b.SetState(&MainMenu{}, bot.EditMessage) case data == "archive": b.Edit("Эта функция в разработке", Keyboard(Row(Button("← Назад", "in_dev")))) case data == "add_project": b.SetState(&AddProject{BackState: &MyProjects{}}, bot.EditMessage) case strings.HasPrefix(data, "project:"): projectID, ok := strings.CutPrefix(data, "project:") if !ok || projectID == "" { return } project, err := b.Backend.GetProject(context.Background(), b.Session.JWT, b.Session.WorkspaceID, projectID) if err != nil { log.Error().Err(err).Str("project_id", projectID).Msg("Failed to get project") return } if s.OpenPlacements { b.SetState(&Placements{ ProjectID: project.ID, ProjectTitle: project.Title, BackState: &MyProjects{OpenPlacements: true}, }, bot.EditMessage) } else { b.SetState(&ProjectDetails{ Project: project, BackState: &MyProjects{}, }, bot.EditMessage) } default: s.Enter(b, bot.EditMessage) } return } func (s *MyProjects) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *MyProjects) Handle(_ *bot.Bot, _ *echotron.Update) { return } func (s *MyProjects) Exit() { if s.cancel != nil { log.Info().Msg("MyProjects: cancelling polling goroutine") s.cancel() } } func (s *MyProjects) startPolling(b *bot.Bot) { if s.cancel != nil { s.cancel() } ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute) s.cancel = cancel go s.pollProjects(ctx, b) } func (s *MyProjects) pollProjects(ctx context.Context, b *bot.Bot) { interval := 3 * time.Second timeToSlow := time.Now().Add(30 * time.Second) timer := time.NewTimer(interval) defer timer.Stop() for { select { case <-ctx.Done(): return case <-timer.C: if time.Now().After(timeToSlow) { interval = 10 * time.Second } page, err := b.Backend.GetProjects(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.CurrentPage+1, projectsPerPage) if err == nil && page.Total != s.lastProjectCount { s.lastProjectCount = page.Total s.renderProjects(b, bot.EditMessage) } timer.Reset(interval) } } }