import { apiClient, ensureCsrfCookie } from './client'; /** * API-модуль клиентской Telegram-рекламы «по своей базе» (план §Сессия 3, задача 3.2). * * Эндпоинты под [auth:sanctum, tenant], префикс /api/telegram. GET'ы не требуют * CSRF-cookie, мутации (POST) — требуют. * * 🔴 Отличие от СМС-близнеца: создание (create) и запуск (launch) РАЗДЕЛЕНЫ. * create возвращает ЧЕРНОВИК со сметой и числом кандидатов; launch переводит его * в очередь и запускает робота кабинета МТС (в песочнице — только черновик). */ /** Способ выбора аудитории: свежие сделки за период / своя база / свой список. */ export type TelegramAudienceKind = 'deals' | 'base' | 'list'; /** Кампания клиентской Telegram-рекламы (строка списка, POST-ответ и часть GET .../{id}). */ export interface TelegramCampaign { id: number; status: string; status_reason?: string | null; ad_text: string; ad_link: string; media_path: string | null; /** Документ модератору, приложённый при пересдаче отклонённой кампании (задача 3.6). */ moderator_file_path?: string | null; ord_category: string; budget_cap_rub: string; audience_kind: TelegramAudienceKind; audience_params: Record | null; planned_count: number; matched_count: number | null; estimated_cost_rub: string; actual_cost_rub: string | null; /** null = авто-кампания (накопитель), иначе id создавшего менеджера. */ created_by?: number | null; created_at?: string; } /** Ответ GET /api/telegram/campaigns — список кампаний тенанта + режим + баланс. */ export interface TelegramIndex { campaigns: TelegramCampaign[]; sandbox: boolean; balance_rub: string; frozen_rub: string; } /** Тело POST /api/telegram/campaigns — создание черновика кампании. */ export interface TelegramCreatePayload { ad_text: string; ad_link: string; audience_kind: TelegramAudienceKind; budget_cap_rub: string; audience_days?: number; ord_category?: string; phones?: string[]; } /** GET /api/telegram/campaigns — список кампаний тенанта + режим + баланс. */ export async function fetchTelegram(): Promise { const { data } = await apiClient.get('/api/telegram/campaigns'); return data; } /** POST /api/telegram/campaigns — создать ЧЕРНОВИК кампании (деньги/робот не трогаются). */ export async function createTelegram(payload: TelegramCreatePayload): Promise { await ensureCsrfCookie(); const { data } = await apiClient.post('/api/telegram/campaigns', payload); return data; } /** GET /api/telegram/campaigns/{id} — детали кампании. */ export async function fetchTelegramCampaign(id: number): Promise<{ campaign: TelegramCampaign }> { const { data } = await apiClient.get<{ campaign: TelegramCampaign }>(`/api/telegram/campaigns/${id}`); return data; } /** POST /api/telegram/campaigns/{id}/launch — запустить черновик (draft → queued + робот). */ export async function launchTelegram(id: number): Promise { await ensureCsrfCookie(); const { data } = await apiClient.post(`/api/telegram/campaigns/${id}/launch`); return data; } /** Тело POST /api/telegram/campaigns/{id}/resubmit — правки + опц. документ модератору. */ export interface TelegramResubmitPayload { ad_text: string; ad_link: string; ord_category?: string; /** Лицензия/договор для модератора МТС (png/jpg/pdf ≤10 МБ). */ moderator_file?: File | null; } /** * POST /api/telegram/campaigns/{id}/resubmit — пересдать ОТКЛОНЁННУЮ кампанию * (rejected → queued). Отправляем multipart, т.к. можно приложить документ модератору. */ export async function resubmitTelegram(id: number, payload: TelegramResubmitPayload): Promise { await ensureCsrfCookie(); const form = new FormData(); form.append('ad_text', payload.ad_text); form.append('ad_link', payload.ad_link); if (payload.ord_category) { form.append('ord_category', payload.ord_category); } if (payload.moderator_file) { form.append('moderator_file', payload.moderator_file); } const { data } = await apiClient.post(`/api/telegram/campaigns/${id}/resubmit`, form); return data; } /** * POST /api/telegram/campaigns/{id}/media — приложить картинку/видео к ЧЕРНОВИКУ * объявления (png/jpg/gif или mp4, ≤50 МБ). Робот отдаёт файл кабинету МТС при запуске. */ export async function uploadTelegramMedia(id: number, file: File): Promise { await ensureCsrfCookie(); const form = new FormData(); form.append('media', file); const { data } = await apiClient.post(`/api/telegram/campaigns/${id}/media`, form); return data; } /** * Правило авто-рекламы Telegram (план §Этап 5, задача 5.4). Одно на тенанта: клиент * из кабинета включает авто, задаёт объявление, порог пачки, бюджет и дневной лимит. */ export interface TelegramAutoRule { enabled: boolean; ad_text: string; ad_link: string; ord_category: string; budget_cap_rub: string; daily_limit_rub: string; /** Сколько кандидатов накопить перед отправкой пачки; null → порог по умолчанию (367). */ batch_threshold: number | null; } /** GET /api/telegram/auto-rule — правило авто-рекламы тенанта (или дефолты). */ export async function fetchAutoRule(): Promise { const { data } = await apiClient.get('/api/telegram/auto-rule'); return data; } /** PUT /api/telegram/auto-rule — сохранить правило авто-рекламы. */ export async function saveAutoRule(payload: TelegramAutoRule): Promise { await ensureCsrfCookie(); const { data } = await apiClient.put('/api/telegram/auto-rule', payload); return data; }