import axios from "axios"; class MetaAdsService { constructor() { this.client = axios.create({ baseURL: "/api/meta-ads", headers: { "Content-Type": "application/json", }, }); } // metaAdsService.js processMetrics(campaign) { const insights = campaign.insights?.data?.[0] || {}; const spend = parseFloat(insights.spend || 0); const impressions = parseInt(insights.impressions || 0); const clicks = parseInt(insights.clicks || 0); const reach = parseInt(insights.reach || 0); const cpc = parseFloat(insights.cpc || 0); const ctr = parseFloat(insights.ctr || 0); const cpm = parseFloat(insights.cpm || 0); const frequency = parseFloat(insights.frequency || 0); // Purchase value and total purchases const purchaseValue = (insights.action_values || []) .filter(({ action_type }) => action_type === "purchase") .reduce((sum, { value }) => sum + parseFloat(value || 0), 0); const totalPurchases = (insights.actions || []) .filter(({ action_type }) => action_type === "purchase") .reduce((sum, { value }) => sum + parseInt(value || 0), 0); // Aggregate unique actions const actionMap = new Map(); (insights.actions || []).forEach(({ action_type, value }) => { const currentValue = actionMap.get(action_type) || 0; actionMap.set(action_type, currentValue + parseInt(value || 0)); }); const actions = Array.from(actionMap.entries()).map( ([action_type, value]) => ({ action_type, value, }) ); // Map of cost per action const costPerActionMap = new Map(); (insights.cost_per_action_type || []).forEach(({ action_type, value }) => { costPerActionMap.set(action_type, parseFloat(value || 0)); }); // Total post engagements const totalPostEngagements = actionMap.get("post_engagement") || 0; return { spend, impressions, clicks, reach, frequency, ctr, cpm, cpc, actions, costPerActionMap, // Include cost per action map purchaseValue, totalPurchases, totalPostEngagements, // Include total post engagements }; } getObjectiveAction(campaignObjective) { const objectiveMap = { OUTCOME_AWARENESS: { action_type: "impressions", label: "Impressions" }, OUTCOME_ENGAGEMENT: { action_type: "post_engagement", label: "Post Engagements", }, OUTCOME_TRAFFIC: { action_type: "link_click", label: "Link Clicks" }, OUTCOME_LEADS: { action_type: "lead", label: "Leads" }, OUTCOME_SALES: { action_type: "purchase", label: "Purchases" }, MESSAGES: { action_type: "messages", label: "Messages" }, // Add other objectives as needed }; return ( objectiveMap[campaignObjective] || { action_type: "link_click", label: "Link Clicks", } ); } calculateBudget(campaign) { if (campaign.daily_budget) { return { value: campaign.daily_budget / 100, type: "day" }; } if (campaign.lifetime_budget) { return { value: campaign.lifetime_budget / 100, type: "lifetime" }; } const adsets = campaign.adsets?.data || []; const dailyTotal = adsets.reduce( (sum, adset) => sum + (adset.daily_budget || 0), 0 ); const lifetimeTotal = adsets.reduce( (sum, adset) => sum + (adset.lifetime_budget || 0), 0 ); if (dailyTotal > 0) return { value: dailyTotal / 100, type: "day" }; if (lifetimeTotal > 0) return { value: lifetimeTotal / 100, type: "lifetime" }; return { value: 0, type: "day" }; } processCampaignData(campaign) { const metrics = this.processMetrics(campaign); const budget = this.calculateBudget(campaign); const { action_type, label } = this.getObjectiveAction(campaign.objective); // Get cost per result from costPerActionMap const costPerResult = metrics.costPerActionMap.get(action_type) || 0; return { id: campaign.id, name: campaign.name, status: campaign.status, objective: label, // User-friendly objective label objectiveActionType: action_type, // Action type for metrics budget: budget.value, budgetType: budget.type, metrics: { ...metrics, costPerResult, }, }; } async getCampaigns({ since, until }) { try { const response = await this.client.get("/campaigns", { params: { since, until }, }); return response.data.map((campaign) => this.processCampaignData(campaign) ); } catch (error) { console.error( "Error fetching campaigns:", error.response?.data || error.message ); throw error; } } async getAccountInsights({ since, until }) { try { const response = await this.client.get("/account_insights", { params: { since, until }, }); return response.data; // This will be an object with reach and other fields } catch (error) { console.error( "Error fetching account insights:", error.response?.data || error.message ); throw error; } } } export const metaAdsService = new MetaAdsService();