package screens
import (
"fmt"
"strconv"
"strings"
"time"
"example.com/m/bot"
"github.com/NicoNex/echotron/v3"
)
type PurchaseOptionalDetails struct {
WorkspaceID string
ProjectID string
ProjectTitle string
CreativeID string
CreativeTitle string
Channels []PurchaseChannelInput
PlacementDateTime *time.Time
PaymentDate *time.Time
CostType string
CostValue *float64
CostBeforeBargain *float64
PurchaseType string
Format string
Comment string
InputMode string
BackState bot.State
}
func (s *PurchaseOptionalDetails) Enter(b *bot.Bot, mode bot.RenderMode) {
if s.InputMode != "" {
s.renderInputPrompt(b, mode)
return
}
text := "… › Создание › Дополнительно\n\n"
text += "Страница создания закупа и необязательные составляющие"
text += "\n\n"
text += s.formatOptionalSummary()
var rows [][]echotron.InlineKeyboardButton
rows = append(rows, bot.Row(
s.placementButton(),
s.costButton(),
))
rows = append(rows, bot.Row(
s.paymentButton(),
s.typeButton(),
))
rows = append(rows, bot.Row(
s.costBeforeButton(),
s.formatButton(),
))
rows = append(rows, bot.Row(
s.commentButton(),
))
if row := s.costBeforeDeleteRow(); row != nil {
rows = append(rows, row)
}
if row := s.commentDeleteRow(); row != nil {
rows = append(rows, row)
}
rows = append(rows, bot.Row(bot.Button("Назад", "back"), bot.Button("Далее", "next")))
keyboard := bot.Keyboard(rows...)
b.Render(text, keyboard, mode)
}
func (s *PurchaseOptionalDetails) HandleCallback(b *bot.Bot, u *echotron.Update) {
if u.CallbackQuery == nil || u.CallbackQuery.Data == "" {
return
}
switch u.CallbackQuery.Data {
case "opt_datetime":
b.SetState(NewDateTimePicker(DateTimePickerConfig{
Title: "Дата и время размещения",
Key: "placement_datetime",
IncludeTime: true,
Selected: s.PlacementDateTime,
BackState: s,
}), bot.EditMessage)
case "opt_payment_date":
b.SetState(NewDateTimePicker(DateTimePickerConfig{
Title: "Дата оплаты",
Key: "payment_date",
IncludeTime: true,
Selected: s.PaymentDate,
BackState: s,
}), bot.EditMessage)
case "opt_cost":
s.InputMode = "cost_select"
s.Enter(b, bot.EditMessage)
case "opt_type":
s.InputMode = "type"
s.Enter(b, bot.EditMessage)
case "opt_format":
s.InputMode = "format_select"
s.Enter(b, bot.EditMessage)
case "opt_comment":
s.InputMode = "comment"
s.Enter(b, bot.EditMessage)
case "delete_comment":
s.Comment = ""
s.Enter(b, bot.EditMessage)
case "format_custom":
s.InputMode = "format_custom"
s.Enter(b, bot.EditMessage)
case "cost_type_toggle":
if s.costTypeLabel() == "СРМ" {
s.CostType = "fixed"
} else {
s.CostType = "cpm"
}
s.Enter(b, bot.EditMessage)
case "cost_value":
s.InputMode = "cost_value"
s.Enter(b, bot.EditMessage)
case "cost_before":
s.InputMode = "cost_before"
s.Enter(b, bot.EditMessage)
case "delete_cost_before":
s.CostBeforeBargain = nil
s.Enter(b, bot.EditMessage)
case "back_to_optional":
s.InputMode = ""
s.Enter(b, bot.EditMessage)
case "back":
b.SetState(&SelectChannelsForPurchase{
WorkspaceID: s.WorkspaceID,
ProjectID: s.ProjectID,
ProjectTitle: s.ProjectTitle,
CreativeID: s.CreativeID,
CreativeTitle: s.CreativeTitle,
Channels: s.Channels,
BackState: s.BackState,
}, bot.EditMessage)
default:
if strings.HasPrefix(u.CallbackQuery.Data, "format:") {
value := strings.TrimPrefix(u.CallbackQuery.Data, "format:")
s.Format = value
s.InputMode = ""
s.Enter(b, bot.EditMessage)
return
}
s.Enter(b, bot.EditMessage)
}
}
func (s *PurchaseOptionalDetails) HandleMessage(b *bot.Bot, u *echotron.Update) {
if s.InputMode == "" || u.Message == nil || u.Message.Text == "" {
return
}
text := strings.TrimSpace(u.Message.Text)
if text == "" {
return
}
switch s.InputMode {
case "type":
s.PurchaseType = text
case "format_custom":
s.Format = text
case "comment":
s.Comment = text
case "cost_value":
value, err := strconv.ParseFloat(strings.ReplaceAll(text, ",", "."), 64)
if err != nil {
s.renderInputPrompt(b, bot.EditMessage)
return
}
s.CostValue = &value
case "cost_before":
value, err := strconv.ParseFloat(strings.ReplaceAll(text, ",", "."), 64)
if err != nil {
s.renderInputPrompt(b, bot.EditMessage)
return
}
s.CostBeforeBargain = &value
}
s.InputMode = ""
s.Enter(b, bot.NewMessage)
}
func (s *PurchaseOptionalDetails) Handle(_ *bot.Bot, _ *echotron.Update) { return }
func (s *PurchaseOptionalDetails) SetDateTimeSelection(key string, value time.Time) {
switch key {
case "placement_datetime":
s.PlacementDateTime = &value
case "payment_date":
s.PaymentDate = &value
}
}
func (s *PurchaseOptionalDetails) formatOptionalSummary() string {
lines := []string{
fmt.Sprintf("Дата размещения: %s", s.formatDateTime(s.PlacementDateTime)),
fmt.Sprintf("Дата оплаты: %s", s.formatDateTime(s.PaymentDate)),
fmt.Sprintf("Стоимость: %s", s.formatCostValue()),
fmt.Sprintf("Стоимость до торга: %s", s.formatCostBefore()),
fmt.Sprintf("Тип закупа: %s", s.formatText(s.PurchaseType)),
fmt.Sprintf("Формат: %s", s.formatText(s.Format)),
fmt.Sprintf("Комментарий: %s", s.formatText(s.Comment)),
}
return strings.Join(lines, "\n")
}
func (s *PurchaseOptionalDetails) formatDateTime(value *time.Time) string {
if value == nil {
return "—"
}
local := value.In(mskLocation)
return fmt.Sprintf("%s %02d %s %s", weekdayName(local.Weekday()), local.Day(), monthShort(local.Month()), local.Format("15:04"))
}
func (s *PurchaseOptionalDetails) formatText(value string) string {
if value == "" {
return "—"
}
return value
}
func (s *PurchaseOptionalDetails) formatCostValue() string {
if s.CostValue == nil {
return "—"
}
return fmt.Sprintf("%s %.0f₽", s.costTypeLabel(), *s.CostValue)
}
func (s *PurchaseOptionalDetails) formatCostBefore() string {
if s.CostBeforeBargain == nil {
return "—"
}
return fmt.Sprintf("%.0f₽", *s.CostBeforeBargain)
}
func (s *PurchaseOptionalDetails) costTypeLabel() string {
if s.CostType == "cpm" {
return "СРМ"
}
return "Фикс"
}
func (s *PurchaseOptionalDetails) placementButton() echotron.InlineKeyboardButton {
if s.PlacementDateTime == nil {
return bot.Button("+ Дата размещения", "opt_datetime")
}
return bot.Button("✎ Дата размещения", "opt_datetime")
}
func (s *PurchaseOptionalDetails) paymentButton() echotron.InlineKeyboardButton {
if s.PaymentDate == nil {
return bot.Button("+ Дата оплаты", "opt_payment_date")
}
return bot.Button("✎ Дата оплаты", "opt_payment_date")
}
func (s *PurchaseOptionalDetails) costButton() echotron.InlineKeyboardButton {
if s.CostValue == nil {
return bot.Button("+ Стоимость", "opt_cost")
}
return bot.Button("✎ Стоимость", "opt_cost")
}
func (s *PurchaseOptionalDetails) costBeforeButton() echotron.InlineKeyboardButton {
if s.CostBeforeBargain == nil {
return bot.Button("+ До торга", "cost_before")
}
return bot.Button("✎ До торга", "cost_before")
}
func (s *PurchaseOptionalDetails) typeButton() echotron.InlineKeyboardButton {
if s.PurchaseType == "" {
return bot.Button("+ Тип", "opt_type")
}
return bot.Button("✎ Тип", "opt_type")
}
func (s *PurchaseOptionalDetails) formatButton() echotron.InlineKeyboardButton {
if s.Format == "" {
return bot.Button("+ Формат", "opt_format")
}
return bot.Button("✎ Формат", "opt_format")
}
func (s *PurchaseOptionalDetails) commentButton() echotron.InlineKeyboardButton {
if s.Comment == "" {
return bot.Button("+ Комментарий", "opt_comment")
}
return bot.Button("✎ Комментарий", "opt_comment")
}
func (s *PurchaseOptionalDetails) commentDeleteRow() []echotron.InlineKeyboardButton {
if s.Comment == "" {
return nil
}
return bot.Row(bot.Button("⌫ Удалить комментарий", "delete_comment"))
}
func (s *PurchaseOptionalDetails) costBeforeDeleteRow() []echotron.InlineKeyboardButton {
if s.CostBeforeBargain == nil {
return nil
}
return bot.Row(bot.Button("⌫ Удалить до торга", "delete_cost_before"))
}
func (s *PurchaseOptionalDetails) renderInputPrompt(b *bot.Bot, mode bot.RenderMode) {
text := "… › Создание › Дополнительно\n\n"
switch s.InputMode {
case "type":
text += "Введите тип закупа\n\nНапример: вп или стандарт"
case "cost_select":
text = "Страница ввода стоимости\n\n"
text += "Ставка СРМ / Фикс цена (по умолчанию фикс)\n\n"
keyboard := bot.Keyboard(
bot.Row(bot.Button(fmt.Sprintf("Тип: %s", s.costTypeLabel()), "cost_type_toggle")),
bot.Row(bot.Button(fmt.Sprintf("Стоимость: %s", s.formatCostValue()), "cost_value")),
bot.Row(bot.Button("Назад", "back_to_optional")),
)
if mode == bot.EditMessage {
b.Edit(text, keyboard)
} else {
b.SendNew(text, keyboard)
}
return
case "cost_value":
text += "Ввод стоимости (СРМ / фикс)\n\nНапример: 15000"
case "cost_before":
text += "Ввод стоимости до торга\n\nНапример: 20000"
case "format_select":
text = "Страница ввода формата размещения\n\n"
text += "Выберите формат\n\n"
keyboard := bot.Keyboard(
bot.Row(
bot.Button("1 / 24", "format:1 / 24"),
bot.Button("1/48", "format:1/48"),
bot.Button("1 / 72", "format:1 / 72"),
),
bot.Row(
bot.Button("1 / (7 дней)", "format:1 / (7 дней)"),
bot.Button("1 / (30 дней)", "format:1 / (30 дней)"),
bot.Button("1 / (без удаления)", "format:1 / (без удаления)"),
),
bot.Row(
bot.Button("2 / 24", "format:2 / 24"),
bot.Button("2/48", "format:2/48"),
bot.Button("2/72", "format:2/72"),
),
bot.Row(
bot.Button("Назад", "back_to_optional"),
bot.Button("Свой формат", "format_custom"),
),
)
if mode == bot.EditMessage {
b.Edit(text, keyboard)
} else {
b.SendNew(text, keyboard)
}
return
case "format_custom":
text += "Введите формат\n\nНапример: пост"
case "comment":
text += "Введите комментарий"
default:
s.InputMode = ""
s.Enter(b, mode)
return
}
keyboard := bot.Keyboard(
bot.Row(bot.Button("← Назад", "back_to_optional")),
)
if mode == bot.EditMessage {
b.Edit(text, keyboard)
} else {
b.SendNew(text, keyboard)
}
}