package screens import ( "context" "fmt" "strings" "github.com/NicoNex/echotron/v3" "github.com/TelegramExchange/tgex-backend/tg_bot/backend" "github.com/TelegramExchange/tgex-backend/tg_bot/bot" "github.com/rs/zerolog/log" ) type ProjectDetails struct { Project *backend.Project BackState bot.State } func (s *ProjectDetails) Enter(b *bot.Bot, mode bot.RenderMode) { if s.Project == nil { b.SendNew("❌ Проект не найден", Keyboard( Row(Button("← Назад", "back")), )) return } text := s.formatProjectDetails() keyboard := s.buildKeyboard() b.Render(text, keyboard, mode) messageID := b.LastMessageID username := usernameFromProject(s.Project) status := statusFromProject(s.Project) updateProjectHeaderMedia(b, messageID, text, keyboard, s.Project.TelegramID, s.Project.Title, username, status) } func (s *ProjectDetails) formatProjectDetails() string { p := s.Project text := fmt.Sprintf("%s\n\n", p.Title) if p.Username != nil && *p.Username != "" { text += fmt.Sprintf("▸ Tg username: @%s\n", *p.Username) } else { text += "▸ Tg username: не привязан\n" } // Статус проекта var statusSymbol, statusText string switch p.Status { case "active": statusSymbol, statusText = "●", "Активный" case "inactive": statusSymbol, statusText = "○", "Неактивен" case "archived": statusSymbol, statusText = "■", "Архивный" case "paused": statusSymbol, statusText = "◐", "Приостановлен" default: statusSymbol, statusText = "○", p.Status } text += fmt.Sprintf("▸ Статус: %s %s\n", statusSymbol, statusText) text += "\nУправление проектом" return text } func (s *ProjectDetails) buildKeyboard() echotron.InlineKeyboardMarkup { var buttons [][]echotron.InlineKeyboardButton buttons = append(buttons, Row( Button("Креативы", fmt.Sprintf("creatives:%s", s.Project.ID)), Button("Размещения", fmt.Sprintf("placements:%s", s.Project.ID)), )) // Второй ряд: Тип вступления по умолчанию для закупов var currentType string if s.Project.PurchaseInviteTypeDefault == "public" { currentType = "открытая" } else { currentType = "с заявками" } buttons = append(buttons, Row( Button(fmt.Sprintf("Ссылка: %s", currentType), fmt.Sprintf("link_type:%s", s.Project.ID)), )) // Нижний ряд: Назад и Архивировать buttons = append(buttons, Row( Button("← Назад", "back"), Button("≡ Архивировать", fmt.Sprintf("archive:%s", s.Project.ID)), )) return Keyboard(buttons...) } func (s *ProjectDetails) HandleCallback(b *bot.Bot, u *echotron.Update) { if u.CallbackQuery == nil || u.CallbackQuery.Data == "" { return } data := u.CallbackQuery.Data switch { case data == "back": if s.BackState != nil { s.transitionWithNewMessage(b, s.BackState) } case strings.HasPrefix(data, "creatives:"): b.SetState(&Creatives{ ProjectID: s.Project.ID, ProjectTitle: s.Project.Title, ProjectTelegramID: s.Project.TelegramID, ProjectUsername: usernameFromProject(s.Project), ProjectStatus: statusFromProject(s.Project), BackState: s, }, bot.EditMessage) case strings.HasPrefix(data, "placements:"): b.SetState(&Placements{ ProjectID: s.Project.ID, ProjectTitle: s.Project.Title, ProjectTelegramID: s.Project.TelegramID, ProjectUsername: usernameFromProject(s.Project), ProjectStatus: statusFromProject(s.Project), BackState: s, }, bot.EditMessage) case data == "back_to_project": s.Enter(b, bot.EditMessage) case strings.HasPrefix(data, "link_type:"): var newType string if s.Project.PurchaseInviteTypeDefault == "public" { newType = "approval" } else { newType = "public" } updatedProject, err := b.Backend.UpdateProjectInviteLinkType(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.Project.ID, newType) if err != nil { b.SendNew(fmt.Sprintf("❌ Ошибка при изменении типа ссылки: %v", err), Keyboard( Row(Button("← Назад", "back_to_project")), )) return } s.Project = updatedProject s.Enter(b, bot.EditMessage) default: // Для остальных кнопок показываем заглушку b.Edit(fmt.Sprintf("🚧 Функция в разработке\n\nCallback: %s", data), Keyboard( Row(Button("← Назад", "back_to_project")), )) } return } func (s *ProjectDetails) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *ProjectDetails) Handle(_ *bot.Bot, _ *echotron.Update) { return } func (s *ProjectDetails) Exit() {} func (s *ProjectDetails) transitionWithNewMessage(b *bot.Bot, next bot.State) { if b.LastMessageID != 0 { if _, err := b.DeleteMessage(b.ChatID, b.LastMessageID); err != nil { log.Error().Err(err).Msg("DeleteMessage failed") } else { b.LastMessageID = 0 } } b.SetState(next, bot.NewMessage) } func usernameFromProject(p *backend.Project) string { if p == nil || p.Username == nil { return "" } return *p.Username } func statusFromProject(p *backend.Project) string { if p == nil { return "" } return p.Status }