feat: purchase-plans global update

This commit is contained in:
ivannoskov
2026-02-02 21:01:11 +03:00
parent f9c334ba22
commit 735077e707
11 changed files with 2575 additions and 534 deletions

View File

@@ -0,0 +1,148 @@
import type { PlacementStatus, PlacementPostStatus, CostType, PlacementType, InviteLinkType } from "@/lib/types/api";
export interface ColumnConfig {
id: string;
label: string;
group: string;
editable: boolean;
width?: string;
required?: boolean;
}
export const COLUMN_GROUPS = [
{ id: "basic", label: "Основная информация" },
{ id: "content", label: "Контент" },
{ id: "finance", label: "Финансы" },
{ id: "dates", label: "Даты и время" },
{ id: "metrics", label: "Метрики" },
{ id: "calculated", label: "Расчетные показатели" },
{ id: "technical", label: "Технические детали" },
] as const;
export const ALL_COLUMNS: ColumnConfig[] = [
// Basic
{ id: "checkbox", label: "", group: "basic", editable: false, required: true },
{ id: "number", label: "№", group: "basic", editable: false, required: true },
{ id: "status_deal", label: "Статус сделки", group: "basic", editable: true },
{ id: "status_post", label: "Статус поста", group: "basic", editable: true },
// Content
{ id: "creative", label: "Креатив", group: "content", editable: true },
{ id: "invite_link", label: "Пригласительная ссылка", group: "content", editable: false },
{ id: "post_link", label: "Ссылка на пост", group: "content", editable: false },
// Finance
{ id: "cost", label: "Стоимость", group: "finance", editable: true },
{ id: "cost_before", label: "Стоимость до торга", group: "finance", editable: true },
{ id: "cost_format", label: "Формат оплаты", group: "finance", editable: true },
{ id: "placement_type", label: "Тип закупа", group: "finance", editable: true },
{ id: "discount", label: "% скидки", group: "finance", editable: false },
{ id: "payment_date", label: "Дата оплаты", group: "finance", editable: true },
// Dates
{ id: "planned_date", label: "Плановая дата", group: "dates", editable: true },
{ id: "actual_date", label: "Фактическая дата", group: "dates", editable: false },
{ id: "format", label: "Плановый формат", group: "dates", editable: true },
{ id: "time_top", label: "Время в топе", group: "dates", editable: false },
{ id: "time_in_feed", label: "Время в ленте", group: "dates", editable: false },
{ id: "link_created", label: "Дата ссылки", group: "dates", editable: false },
{ id: "post_deleted", label: "Дата удаления", group: "dates", editable: false },
// Metrics
{ id: "subscriptions", label: "Всего подписок", group: "metrics", editable: false },
{ id: "views", label: "Просмотры", group: "metrics", editable: false },
// Calculated
{ id: "cpf", label: "CPF", group: "calculated", editable: false },
{ id: "cpm", label: "CPM", group: "calculated", editable: false },
{ id: "conversion_24h", label: "Конверсия 24ч", group: "calculated", editable: false },
{ id: "conversion_48h", label: "Конверсия 48ч", group: "calculated", editable: false },
{ id: "conversion_total", label: "Конверсия общ.", group: "calculated", editable: false },
{ id: "total_unsubs", label: "Всего отписок", group: "calculated", editable: false },
{ id: "unsub_percent", label: "% отписок", group: "calculated", editable: false },
{ id: "total_active", label: "Итого подписок", group: "calculated", editable: false },
// Technical
{ id: "invite_type", label: "Тип ссылки", group: "technical", editable: true },
{ id: "comment", label: "Комментарий", group: "technical", editable: true },
] as const;
// Default visible columns
export const DEFAULT_VISIBLE_COLUMNS = new Set([
"checkbox",
"number",
"status_deal",
"status_post",
"creative",
"invite_link",
"cost",
"cost_before",
"cost_format",
"planned_date",
"format",
"subscriptions",
"views",
"cpf",
"cpm",
"comment",
]);
// Status lists
export const PLACEMENT_DEAL_STATUSES: PlacementStatus[] = [
"Без статуса",
"Написать",
"Ждём ответа",
"Согласование условий",
"Оплатить",
"Оплачено",
"Отмена",
"Не подходит цена",
"Неактуально",
"Не отвечает",
];
export const PLACEMENT_POST_STATUSES: PlacementPostStatus[] = [
"Без статуса",
"Отправить пост",
"Согласование поста",
"Ожидание отложки",
"Запланирован",
"Пост вышел",
"Размещение отработало - пост удалён",
"Размещение отработало - пост не удалён",
"Проверить - пост удалён раньше срока",
"Проверить - пост не вышел",
"Размещение отработало",
];
export const COST_FORMATS: CostType[] = ["fixed", "cpm"];
export const PLACEMENT_TYPES: PlacementType[] = ["self_promo", "standard"];
export const INVITE_TYPES: InviteLinkType[] = ["public", "approval"];
// Manual post statuses (user can select before post is published)
export const MANUAL_POST_STATUSES: Set<PlacementPostStatus> = new Set([
"Без статуса",
"Отправить пост",
"Согласование поста",
"Ожидание отложки",
"Запланирован",
]);
// Automatic post statuses (set by backend)
export const AUTOMATIC_POST_STATUSES: Set<PlacementPostStatus> = new Set([
"Пост вышел",
"Размещение отработало - пост удалён",
"Размещение отработало - пост не удалён",
"Проверить - пост удалён раньше срока",
"Проверить - пост не вышел",
"Размещение отработало",
]);
// Helper functions
export const canEditPostStatus = (currentStatus: PlacementPostStatus): boolean => {
return MANUAL_POST_STATUSES.has(currentStatus);
};
export const isAutomaticPostStatus = (status: PlacementPostStatus): boolean => {
return AUTOMATIC_POST_STATUSES.has(status);
};