diff --git a/src/app/dashboard/create/page.tsx b/src/app/dashboard/create/page.tsx index 4ac0f55..6977146 100644 --- a/src/app/dashboard/create/page.tsx +++ b/src/app/dashboard/create/page.tsx @@ -459,10 +459,15 @@ export default function CreateCampaignPage() { campaign_name: form.campaign_name, link: form.link, pixel_id: form.pixel_id, + conversion_event: form.conversion_event, bid_strategy: form.bid_strategy, bid_amount: form.bid_amount, targeting_template: form.targeting_template, skin_id: skinId, + // Página/Instagram escolhidos — pra republicar do histórico no mesmo + // destino, em vez de cair na primeira página da conta. + page_id: selectedPageId || undefined, + instagram_actor_id: selectedInstagramAccount?.id || undefined, }, }); diff --git a/src/app/dashboard/history/page.tsx b/src/app/dashboard/history/page.tsx index 123c015..7525878 100644 --- a/src/app/dashboard/history/page.tsx +++ b/src/app/dashboard/history/page.tsx @@ -5,6 +5,7 @@ import { History, RefreshCw, CheckCircle, Clock, XCircle, ImageOff, ExternalLink import { Spinner } from '@/components/ui/Spinner'; import { ErrorBlock } from '@/components/ui/ErrorBlock'; import { parseApiError, type FriendlyError } from '@/lib/errors'; +import { TARGETING_TEMPLATES } from '@/lib/meta/targeting'; interface CopyVariation { headline: string; @@ -26,10 +27,13 @@ interface CampaignDraft { campaign_name?: string; link?: string; pixel_id?: string; + conversion_event?: string; bid_strategy?: string; bid_amount?: number; targeting_template?: string; skin_id?: string; + page_id?: string; + instagram_actor_id?: string; } | null; status: 'draft' | 'pending' | 'published' | 'active' | 'paused' | 'failed'; meta_campaign_id: string | null; @@ -105,6 +109,16 @@ export default function HistoryPage() { setRetryError((prev) => ({ ...prev, [draft.id]: '' })); setRetryErrorDetail((prev) => { const next = { ...prev }; delete next[draft.id]; return next; }); + // Reconstrói o público: o rascunho guarda só o id do template + // (ex: parents_kids); resolvemos pro objeto de targeting real. Se o + // rascunho tiver um targeting customizado salvo (sem template), usa ele. + const templateId = config.targeting_template || (draft.targeting?.template as string | undefined); + const resolvedTargeting = + (templateId && TARGETING_TEMPLATES.find((t) => t.id === templateId)?.targeting) || + (draft.targeting && !draft.targeting.template ? draft.targeting : undefined); + + const usesCap = config.bid_strategy === 'BID_CAP' || config.bid_strategy === 'COST_CAP'; + try { const res = await fetch('/api/campaigns/create', { method: 'POST', @@ -113,11 +127,15 @@ export default function HistoryPage() { campaign_name: config.campaign_name || draft.product, objective: draft.objective, daily_budget: Math.round((draft.budget_daily || 0) * 100), - bid_strategy: config.bid_strategy === 'BID_CAP' ? 'LOWEST_COST_WITH_BID_CAP' : undefined, - bid_amount: config.bid_strategy === 'BID_CAP' && config.bid_amount ? Math.round(config.bid_amount * 100) : undefined, - targeting: draft.targeting?.template ? undefined : draft.targeting, + // Token cru ('VOLUME' | 'COST_CAP' | 'BID_CAP') — a rota converte. + bid_strategy: config.bid_strategy, + bid_amount: usesCap && config.bid_amount ? Math.round(config.bid_amount * 100) : undefined, + targeting: resolvedTargeting, link, pixel_id: config.pixel_id, + conversion_event: config.conversion_event, + page_id: config.page_id, + instagram_actor_id: config.instagram_actor_id, image_urls: draft.image_urls, headline: copy.headline, primary_text: copy.primary_text,