Files
tgex-backend/tg_bot/screens/project_details.go
2026-01-20 13:40:24 +03:00

227 lines
6.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"
"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
confirmingLinkTypeChange bool // Флаг для двухшагового подтверждения смены типа ссылки
}
func (s *ProjectDetails) Enter(b *bot.Bot, mode bot.RenderMode) {
if s.Project == nil {
b.SendNew("❌ Проект не найден", Keyboard(
Row(Button("← Назад", "back_to_projects")),
))
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("<b>%s</b>\n\n", p.Title)
// Информация о канале
if p.Username != nil && *p.Username != "" {
text += fmt.Sprintf("▸ Telegram: @%s\n", *p.Username)
} else {
text += "▸ Telegram: <i>не привязан</i>\n"
}
// Статус проекта
var statusSymbol string
var 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 linkTypeButtonText string
if s.confirmingLinkTypeChange {
// Показываем подтверждение
var newType string
if s.Project.PurchaseInviteTypeDefault == "public" {
newType = "По заявке"
} else {
newType = "Свободное"
}
linkTypeButtonText = fmt.Sprintf("Изменить → %s", newType)
} else {
// Показываем текущий тип вступления
var currentType string
if s.Project.PurchaseInviteTypeDefault == "public" {
currentType = "Свободное"
} else {
currentType = "По заявке"
}
linkTypeButtonText = fmt.Sprintf("Вступление: %s", currentType)
}
buttons = append(buttons, Row(
Button(linkTypeButtonText, fmt.Sprintf("link_type:%s", s.Project.ID)),
))
// Нижний ряд: Назад и Архивировать
buttons = append(buttons, Row(
Button("← Назад", "back_to_projects"),
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_to_projects", data == "back":
s.confirmingLinkTypeChange = false // Сбрасываем флаг подтверждения
if s.BackState != nil {
s.transitionWithNewMessage(b, s.BackState)
}
case strings.HasPrefix(data, "creatives:"):
s.confirmingLinkTypeChange = false // Сбрасываем флаг подтверждения
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:"):
s.confirmingLinkTypeChange = false // Сбрасываем флаг подтверждения
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.confirmingLinkTypeChange = false // Сбрасываем флаг подтверждения
s.Enter(b, bot.EditMessage)
case strings.HasPrefix(data, "link_type:"):
if !s.confirmingLinkTypeChange {
// Первое нажатие - включаем режим подтверждения
s.confirmingLinkTypeChange = true
s.Enter(b, bot.EditMessage)
} else {
// Второе нажатие - меняем тип ссылки
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.confirmingLinkTypeChange = false
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
}