package screens import ( "context" "fmt" "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/rs/zerolog/log" ) type PlacementDetails struct { WorkspaceID string ProjectID string PlacementID string BackState bot.State } func (s *PlacementDetails) Enter(b *bot.Bot, mode bot.RenderMode) { jwt := b.Session.JWT if jwt == "" { log.Error().Msg("JWT is empty in session") b.SendNew("❌ Ошибка авторизации. Попробуйте /start", Keyboard()) return } s.renderDetails(b, mode, jwt) } func (s *PlacementDetails) renderDetails(b *bot.Bot, mode bot.RenderMode, jwt string) { placement, err := b.Backend.GetPlacement( context.Background(), jwt, s.WorkspaceID, s.ProjectID, s.PlacementID, ) if err != nil { log.Error().Err(err).Msg("Failed to get placement") b.SendNew("❌ Не удалось загрузить размещение", Keyboard()) return } text := "Детали размещения\n\n" channelName := formatChannelName(placement.Channel) text += fmt.Sprintf("• Канал: %s\n", channelName) text += fmt.Sprintf("• Статус: %s\n", formatPlacementStatus(placement.Status)) text += fmt.Sprintf("• Ссылка: %s\n", formatInviteLinkType(placement.InviteLinkType)) if placement.Details != nil { if placement.Details.PlacementType != nil { text += fmt.Sprintf("• Тип: %s\n", formatPlacementType(*placement.Details.PlacementType)) } if placement.Details.PlacementAt != nil && *placement.Details.PlacementAt != "" { text += fmt.Sprintf("• Дата размещения: %s\n", formatDateTime(*placement.Details.PlacementAt)) } if placement.Details.PaymentAt != nil && *placement.Details.PaymentAt != "" { text += fmt.Sprintf("• Дата оплаты: %s\n", formatDateTime(*placement.Details.PaymentAt)) } if placement.Details.Cost != nil { text += fmt.Sprintf("• Стоимость: %s %.0f₽\n", formatCostType(placement.Details.Cost.Type), placement.Details.Cost.Value, ) } if placement.Details.CostBeforeBargain != nil { text += fmt.Sprintf("• До торга: %.0f₽\n", *placement.Details.CostBeforeBargain) } if placement.Details.Format != nil && *placement.Details.Format != "" { text += fmt.Sprintf("• Формат: %s\n", *placement.Details.Format) } if placement.Details.Comment != nil && *placement.Details.Comment != "" { text += fmt.Sprintf("• Комментарий: %s\n", *placement.Details.Comment) } } keyboard := Keyboard(Row(Button("← Назад", "back"))) b.Render(text, keyboard, mode) } func formatChannelName(channel backend.Channel) string { if channel.Title != nil && *channel.Title != "" { return *channel.Title } if channel.Username != nil && *channel.Username != "" { return "@" + *channel.Username } return "Без названия" } func formatInviteLinkType(value string) string { if value == "approval" { return "с одобрением" } return "публичная" } func formatPlacementStatus(status string) string { normalized := strings.TrimSpace(strings.ToLower(status)) switch normalized { case "planned": return "Планируется" case "approved": return "Согласовано" case "rejected": return "Отклонено" case "in_progress": return "В работе" case "completed": return "Размещено" default: return status } } func formatPlacementType(value string) string { normalized := strings.TrimSpace(strings.ToLower(value)) switch normalized { case "self_promo": return "Самопиар" case "standard": return "Стандарт" default: return value } } func formatCostType(value string) string { switch strings.TrimSpace(strings.ToLower(value)) { case "cpm": return "СРМ" default: return "Фикс" } } func formatDateTime(value string) string { if value == "" { return value } if parsed, err := time.Parse(time.RFC3339, value); err == nil { return parsed.Format("02.01.2006 15:04") } if parsed, err := time.Parse(time.RFC3339Nano, value); err == nil { return parsed.Format("02.01.2006 15:04") } return value } func (s *PlacementDetails) HandleCallback(b *bot.Bot, u *echotron.Update) { if u.CallbackQuery == nil || u.CallbackQuery.Data == "" { return } switch u.CallbackQuery.Data { case "back": if s.BackState != nil { b.SetState(s.BackState, bot.EditMessage) } default: s.Enter(b, bot.NewMessage) } } func (s *PlacementDetails) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return } func (s *PlacementDetails) Handle(_ *bot.Bot, _ *echotron.Update) { return } func (s *PlacementDetails) Exit() {}