diag: revelar o motivo de a customização por posicionamento falhar
As 3 imagens sobem, mas a Meta recusa montar o criativo com elas e o app cai pra 1 imagem silenciosamente. Agora o erro real da Meta é logado ([Placement]) e devolvido na resposta (placement_error), aparecendo na tela final — pra diagnosticar e corrigir a estrutura do asset_feed_spec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
adc6580848
commit
8ebbe079ec
2 changed files with 35 additions and 2 deletions
|
|
@ -77,6 +77,9 @@ export default function CreateCampaignPage() {
|
||||||
// Subir a campanha já ativa (no ar) em vez de pausada para revisão.
|
// Subir a campanha já ativa (no ar) em vez de pausada para revisão.
|
||||||
const [startActive, setStartActive] = useState(false);
|
const [startActive, setStartActive] = useState(false);
|
||||||
|
|
||||||
|
// Diagnóstico: motivo de a customização por posicionamento ter caído pra 1 imagem.
|
||||||
|
const [placementNote, setPlacementNote] = useState<string | null>(null);
|
||||||
|
|
||||||
const [uploadedImageBytes, setUploadedImageBytes] =
|
const [uploadedImageBytes, setUploadedImageBytes] =
|
||||||
useState<string | null>(null);
|
useState<string | null>(null);
|
||||||
|
|
||||||
|
|
@ -608,6 +611,12 @@ export default function CreateCampaignPage() {
|
||||||
approved_at: new Date().toISOString(),
|
approved_at: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setPlacementNote(
|
||||||
|
data.data?.placements_dropped
|
||||||
|
? data.data?.placement_error || 'A Meta recusou a customização por posicionamento; subiu com 1 imagem.'
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
setStep('done');
|
setStep('done');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Debug] Publish error:', err);
|
console.error('[Debug] Publish error:', err);
|
||||||
|
|
@ -1537,6 +1546,15 @@ export default function CreateCampaignPage() {
|
||||||
? '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 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.'}
|
: '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>
|
</p>
|
||||||
|
|
||||||
|
{placementNote && (
|
||||||
|
<div className="max-w-md mb-8 -mt-4 text-left rounded-lg border border-amber-500/30 bg-amber-500/10 p-3">
|
||||||
|
<p className="text-xs text-amber-300/90 leading-relaxed">
|
||||||
|
<span className="font-semibold">Subiu com 1 imagem</span> (a Meta recusou usar as 3 por posicionamento). Motivo retornado pela Meta:
|
||||||
|
</p>
|
||||||
|
<p className="mt-1 text-[11px] text-white/60 break-words font-mono">{placementNote}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -713,13 +713,18 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let placementError: string | undefined;
|
||||||
|
|
||||||
if (wantPlacements) {
|
if (wantPlacements) {
|
||||||
try {
|
try {
|
||||||
// 1) Melhor caso: imagem específica por posicionamento, com IG.
|
// 1) Melhor caso: imagem específica por posicionamento, com IG.
|
||||||
creative = await buildCreative(params.instagram_actor_id, true);
|
creative = await buildCreative(params.instagram_actor_id, true);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// 2) Customização por posicionamento falhou (ex: conflito com a
|
// 2) Customização por posicionamento falhou (ex: conflito com a
|
||||||
// identidade de IG) → cai pra imagem única mantendo o Instagram.
|
// identidade de IG) → cai pra imagem única mantendo o Instagram.
|
||||||
|
// Guardamos o motivo pra diagnóstico (sai no log e na resposta).
|
||||||
|
placementError = err instanceof Error ? err.message : String(err);
|
||||||
|
console.warn('[Placement] Customização por posicionamento falhou, usando imagem única:', placementError);
|
||||||
placementsDropped = true;
|
placementsDropped = true;
|
||||||
creative = await buildSingleWithIgFallback();
|
creative = await buildSingleWithIgFallback();
|
||||||
}
|
}
|
||||||
|
|
@ -751,6 +756,7 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
|
||||||
ad_id: adId,
|
ad_id: adId,
|
||||||
instagram_dropped: instagramDropped,
|
instagram_dropped: instagramDropped,
|
||||||
placements_dropped: placementsDropped,
|
placements_dropped: placementsDropped,
|
||||||
|
placement_error: placementError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -850,7 +856,13 @@ export async function createFullCampaign(client: Client, params: FullCampaignPar
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 3-5: Image Upload + Ad Creative + Ad (pipeline compartilhado)
|
// Steps 3-5: Image Upload + Ad Creative + Ad (pipeline compartilhado)
|
||||||
const { creative_id: creativeId, ad_id: adId } = await addAdToAdSet(client, {
|
const {
|
||||||
|
creative_id: creativeId,
|
||||||
|
ad_id: adId,
|
||||||
|
instagram_dropped: instagramDropped,
|
||||||
|
placements_dropped: placementsDropped,
|
||||||
|
placement_error: placementError,
|
||||||
|
} = await addAdToAdSet(client, {
|
||||||
adset_id: adSetId,
|
adset_id: adSetId,
|
||||||
ad_name: params.campaign_name,
|
ad_name: params.campaign_name,
|
||||||
page_id: params.page_id,
|
page_id: params.page_id,
|
||||||
|
|
@ -880,5 +892,8 @@ export async function createFullCampaign(client: Client, params: FullCampaignPar
|
||||||
bid_strategy: params.bid_strategy,
|
bid_strategy: params.bid_strategy,
|
||||||
bid_amount: params.bid_amount,
|
bid_amount: params.bid_amount,
|
||||||
is_whatsapp: params.is_whatsapp || false,
|
is_whatsapp: params.is_whatsapp || false,
|
||||||
|
instagram_dropped: instagramDropped,
|
||||||
|
placements_dropped: placementsDropped,
|
||||||
|
placement_error: placementError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue