package screens import ( "context" "fmt" "strings" "example.com/m/bot" "example.com/m/ui" "github.com/NicoNex/echotron/v3" "github.com/rs/zerolog/log" ) type SelectWorkspace struct { ChannelID string BackState bot.State CurrentPage int } const msgChooseWorkspace = ` 📁 Выбор workspace для канала В какой workspace добавить канал? ` const msgSuccessChooseWorkspace = ` ✅ Канал успешно добавлен! 📊 Проект ID: %s 📝 Название: %s 🏷 Статус: %s ` func (s *SelectWorkspace) Enter(b *bot.Bot, mode bot.RenderMode) { workspaces, err := b.Backend.GetWorkspaces(context.Background(), b.Session.JWT) if err != nil { b.SendNew("❌ Не удалось загрузить список workspace'ов", Keyboard()) return } if len(workspaces) == 0 { kb := Keyboard(Row(Button("Главное меню", "back"))) b.SendNew("У вас пока нет workspace'ов", kb) return } // Создаем кнопки для всех workspace'ов var allButtons []echotron.InlineKeyboardButton for _, ws := range workspaces { allButtons = append(allButtons, Button(ws.Name, fmt.Sprintf("select_workspace:%s", ws.ID))) } // Используем компонент пагинации для автоматической раскладки const workspacesPerPage = 6 var buttons [][]echotron.InlineKeyboardButton // Раскладываем workspace'ы в grid (2 в ряд) с пагинацией elementRows := ui.BuildElementRows(ui.ElementLayoutConfig{ CurrentPage: s.CurrentPage, ItemsPerPage: workspacesPerPage, ItemsPerRow: 2, }, allButtons) buttons = append(buttons, elementRows...) // Добавляем навигацию (стрелки появятся только если страниц > 1) if navRow := ui.BuildNavigationRow(ui.PaginationConfig{ CurrentPage: s.CurrentPage, TotalItems: len(allButtons), ItemsPerPage: workspacesPerPage, }); navRow != nil { buttons = append(buttons, navRow) } // Кнопка отмены buttons = append(buttons, Row(Button("Отмена", "cancel"))) kb := Keyboard(buttons...) b.Render(msgChooseWorkspace, kb, mode) } func (s *SelectWorkspace) 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 == "cancel", data == "back": if s.BackState != nil { b.SetState(s.BackState, bot.NewMessage) } case strings.HasPrefix(data, "select_workspace:"): parts := strings.Split(data, ":") if len(parts) != 2 { log.Error().Str("callback_data", data).Msg("Invalid callback data format") return } workspaceID := parts[1] project, err := b.Backend.AttachChannelToWorkspace( context.Background(), s.ChannelID, workspaceID, b.ChatID, ) if err != nil { b.Edit("❌ Не удалось добавить канал в workspace", Keyboard( Row(Button("← Назад", "back_to_select")), )) return } successText := fmt.Sprintf(msgSuccessChooseWorkspace, project.ID, project.Title, project.Status) kb := Keyboard( Row(Button("Мои проекты", "my_projects")), Row(Button("Главное меню", "main_menu")), ) b.Edit(successText, kb) case data == "back_to_select": s.Enter(b, bot.EditMessage) case data == "my_projects": b.SetState(&MyProjects{}, bot.NewMessage) case data == "main_menu": b.SetState(&MainMenu{}, bot.NewMessage) default: s.Enter(b, bot.NewMessage) } return } func (s *SelectWorkspace) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *SelectWorkspace) Handle(_ *bot.Bot, _ *echotron.Update) { return } func (s *SelectWorkspace) Exit() {}