187 lines
5.3 KiB
Go
187 lines
5.3 KiB
Go
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 {
|
||
ProjectID string
|
||
PlacementID string
|
||
BackState bot.State
|
||
}
|
||
|
||
func (s *PlacementDetails) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||
s.renderDetails(b, mode)
|
||
}
|
||
|
||
func (s *PlacementDetails) renderDetails(b *bot.Bot, mode bot.RenderMode) {
|
||
placement, err := b.Backend.GetPlacement(context.Background(), b.Session.JWT, b.Session.WorkspaceID, s.ProjectID, s.PlacementID)
|
||
if err != nil {
|
||
log.Error().Err(err).Msg("Failed to get placement")
|
||
b.SendNew("❌ Не удалось загрузить размещение", Keyboard())
|
||
return
|
||
}
|
||
|
||
var placementPost *backend.PlacementPostOutput
|
||
if len(placement.PlacementPosts) > 0 {
|
||
placementPost = &placement.PlacementPosts[0]
|
||
}
|
||
|
||
text := "<b>Детали размещения</b>\n\n"
|
||
|
||
channelName := formatChannelName(placement.Channel)
|
||
text += fmt.Sprintf("• <b>Канал:</b> %s\n", channelName)
|
||
text += fmt.Sprintf("• <b>Статус:</b> %s\n", formatPlacementStatus(placement.Status))
|
||
text += fmt.Sprintf("• <b>Ссылка:</b> %s\n", formatInviteLinkType(placement.InviteLinkType))
|
||
|
||
if placement.Details != nil {
|
||
if placement.Details.PlacementType != nil {
|
||
text += fmt.Sprintf("• <b>Тип:</b> %s\n", formatPlacementType(*placement.Details.PlacementType))
|
||
}
|
||
if placement.Details.PlacementAt != nil && *placement.Details.PlacementAt != "" {
|
||
text += fmt.Sprintf("• <b>Дата размещения:</b> %s\n", formatDateTime(*placement.Details.PlacementAt))
|
||
}
|
||
if placement.Details.PaymentAt != nil && *placement.Details.PaymentAt != "" {
|
||
text += fmt.Sprintf("• <b>Дата оплаты:</b> %s\n", formatDateTime(*placement.Details.PaymentAt))
|
||
}
|
||
if placement.Details.Cost != nil {
|
||
text += fmt.Sprintf("• <b>Стоимость:</b> %s %.0f₽\n",
|
||
formatCostType(placement.Details.Cost.Type),
|
||
placement.Details.Cost.Value,
|
||
)
|
||
}
|
||
if placement.Details.CostBeforeBargain != nil {
|
||
text += fmt.Sprintf("• <b>До торга:</b> %.0f₽\n", *placement.Details.CostBeforeBargain)
|
||
}
|
||
if placement.Details.Format != nil && *placement.Details.Format != "" {
|
||
text += fmt.Sprintf("• <b>Формат:</b> %s\n", *placement.Details.Format)
|
||
}
|
||
if placement.Details.Comment != nil && *placement.Details.Comment != "" {
|
||
text += fmt.Sprintf("• <b>Комментарий:</b> %s\n", *placement.Details.Comment)
|
||
}
|
||
}
|
||
|
||
if placementPost != nil {
|
||
text += "\n<b>Пост</b>\n"
|
||
if placementPost.AdPostURL != nil && *placementPost.AdPostURL != "" {
|
||
text += fmt.Sprintf("• <b>Ссылка на пост:</b> %s\n", *placementPost.AdPostURL)
|
||
} else {
|
||
text += "• <b>Ссылка на пост:</b> не найдена\n"
|
||
}
|
||
text += fmt.Sprintf("• <b>Статус поста:</b> %s\n", formatPlacementPostStatus(placementPost.Status))
|
||
}
|
||
|
||
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 formatPlacementPostStatus(status string) string {
|
||
normalized := strings.TrimSpace(strings.ToLower(status))
|
||
switch normalized {
|
||
case "active":
|
||
return "Активен"
|
||
case "archived":
|
||
return "Архивирован"
|
||
default:
|
||
return status
|
||
}
|
||
}
|
||
|
||
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() {}
|