feat: opção de subir a campanha já ativa (no ar)

Antes tudo subia PAUSED por padrão. Agora o pipeline propaga um status
comum para campanha, conjunto e anúncio (os 3 precisam estar ACTIVE para
entregar). A rota aceita activate=true e o Preview ganha um toggle
"Iniciar a campanha já ativa" (default desmarcado = pausada para revisão).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcio Bevervanso 2026-06-16 12:47:18 -03:00
parent 6068f77b09
commit 349203b761
3 changed files with 60 additions and 17 deletions

View file

@ -242,10 +242,16 @@ export async function POST(req: Request) {
};
}
// Por padrão sobe PAUSED (revisar antes de ativar). Quando activate=true,
// os 3 níveis (campanha/conjunto/anúncio) sobem ACTIVE e já entram em
// análise/entrega na Meta.
const finalStatus = body.activate === true ? 'ACTIVE' : 'PAUSED';
const result = await createFullCampaign(mcpClient, {
campaign_name,
objective: finalObjective,
daily_budget: finalDailyBudget,
status: finalStatus,
bid_strategy: finalBidStrategy,
bid_amount: finalBidStrategy === 'LOWEST_COST_WITHOUT_CAP' ? undefined : finalBidAmount,
targeting: {

View file

@ -74,6 +74,9 @@ export default function CreateCampaignPage() {
// Estampar o preço/oferta no criativo gerado por IA (bom p/ low-ticket DR).
const [stampOffer, setStampOffer] = useState(false);
// Subir a campanha já ativa (no ar) em vez de pausada para revisão.
const [startActive, setStartActive] = useState(false);
const [uploadedImageBytes, setUploadedImageBytes] =
useState<string | null>(null);
@ -571,6 +574,9 @@ export default function CreateCampaignPage() {
cta:
copyVariations[selectedCopy]
.cta || 'LEARN_MORE',
// Sobe ACTIVE (no ar) ou PAUSED (revisar antes) nos 3 níveis.
activate: startActive,
}),
}
);
@ -1475,7 +1481,23 @@ export default function CreateCampaignPage() {
</div>
</div>
<div className="flex justify-between items-center glass-card-static p-4">
<div className="glass-card-static p-4 flex flex-col gap-4">
<label className="flex items-start gap-2.5 cursor-pointer select-none">
<input
type="checkbox"
checked={startActive}
onChange={(e) => setStartActive(e.target.checked)}
className="mt-0.5 h-4 w-4 accent-[var(--accent)]"
/>
<span className="text-xs text-white/70 leading-relaxed">
Iniciar a campanha <strong>ativa</strong> (no ar)
<span className="block text-white/40">
Marcado: campanha, conjunto e anúncio sobem ativos e entram em análise/entrega na Meta. Desmarcado: sobem <strong>pausados</strong> pra você revisar e dar play no Gerenciador.
</span>
</span>
</label>
<div className="flex justify-between items-center">
<button
type="button"
onClick={() => setStep('config')}
@ -1489,10 +1511,11 @@ export default function CreateCampaignPage() {
className="btn-primary flex items-center gap-2 px-8 py-3"
>
<Send size={16} />
Aprovar e Publicar na Meta
{startActive ? 'Publicar e Ativar na Meta' : 'Aprovar e Publicar (pausada)'}
</button>
</div>
</div>
</div>
)}
{/* DONE */}
@ -1505,7 +1528,9 @@ export default function CreateCampaignPage() {
Campanha no Ar!
</h2>
<p className="text-sm text-white/60 max-w-md mb-8">
Seus criativos, públicos e orçamentos foram enviados com sucesso para o seu Gerenciador de Anúncios. A campanha entrará em análise pela Meta em instantes.
{startActive
? 'Tudo enviado para o seu Gerenciador de Anúncios. A campanha subiu ATIVA e entra em análise da Meta agora — começa a entregar assim que for aprovada.'
: 'Tudo enviado para o seu Gerenciador de Anúncios. A campanha subiu PAUSADA — revise no Gerenciador e dê play quando quiser colocar no ar.'}
</p>
<div className="flex gap-4">
<button

View file

@ -585,6 +585,8 @@ export interface AddAdToAdSetParams {
description: string;
cta: string;
ad_account_id?: string;
// Status do ANÚNCIO criado (ACTIVE | PAUSED). Default PAUSED.
status?: string;
is_whatsapp?: boolean;
whatsapp_link?: string;
@ -739,6 +741,7 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
name: `${params.ad_name} — Ad`,
adset_id: params.adset_id,
creative_id: creativeId,
status: params.status,
ad_account_id: params.ad_account_id,
});
@ -775,6 +778,9 @@ export interface FullCampaignParams {
description: string;
cta: string;
ad_account_id?: string;
// Status aplicado a campanha, conjunto e anúncio (ACTIVE | PAUSED).
// Default PAUSED — para um anúncio entregar, os 3 níveis precisam estar ACTIVE.
status?: string;
bid_strategy?: string;
bid_amount?: number;
@ -790,10 +796,14 @@ export interface FullCampaignParams {
}
export async function createFullCampaign(client: Client, params: FullCampaignParams) {
// Status comum aos 3 níveis. Default PAUSED (revisar antes de ativar).
const status = params.status || 'PAUSED';
// Step 1: Campaign
const campaign = await createCampaign(client, {
name: params.campaign_name,
objective: params.objective,
status,
ad_account_id: params.ad_account_id,
});
@ -834,6 +844,7 @@ export async function createFullCampaign(client: Client, params: FullCampaignPar
destination_type: destinationType,
bid_strategy: params.bid_strategy,
bid_amount: params.bid_amount,
status,
ad_account_id: params.ad_account_id,
});
@ -856,6 +867,7 @@ export async function createFullCampaign(client: Client, params: FullCampaignPar
primary_text: params.primary_text,
description: params.description,
cta: params.cta,
status,
ad_account_id: params.ad_account_id,
is_whatsapp: params.is_whatsapp,
whatsapp_link: params.whatsapp_link,