import React, { useState, useEffect } from 'react';
const MarketingCalculator = () => {
// Начальные значения параметров
const [budget, setBudget] = useState(6400);
const [cpm, setCpm] = useState(7);
const [ctr, setCtr] = useState(0.9);
const [siteConversion, setSiteConversion] = useState(10);
const [leadQualificationRate, setLeadQualificationRate] = useState(17);
const [salesConversion, setSalesConversion] = useState(20);
const [averageSaleValue, setAverageSaleValue] = useState(100);
const [profitMargin, setProfitMargin] = useState(30);
const [contractorCost, setContractorCost] = useState(0);
// LTV множитель
const [ltvMultiplier, setLtvMultiplier] = useState(3);
// Активные этапы воронки
const [activeStages, setActiveStages] = useState({
impressions: true,
clicks: true,
leads: true,
qualifiedLeads: true,
customers: true,
ltv: true
});
// Для анализа чувствительности
const [showSensitivityAnalysis, setShowSensitivityAnalysis] = useState(false);
const [sensitivityParameter, setSensitivityParameter] = useState('ctr');
// Расчетные показатели
const [results, setResults] = useState({
impressions: 0,
clicks: 0,
leads: 0,
qualifiedLeads: 0,
customers: 0,
revenue: 0,
profit: 0,
revenueLtv: 0,
profitLtv: 0,
cpc: 0,
cpl: 0,
cpql: 0,
cpa: 0,
roi: 0,
roas: 0,
ltv: 0
});
// Расчет всех показателей
useEffect(() => {
const impressions = Math.round(budget * 1000 / cpm);
const clicks = Math.round(impressions * ctr / 100);
const leads = Math.round(clicks * siteConversion / 100);
const qualifiedLeads = Math.round(leads * leadQualificationRate / 100);
const customers = Math.round(qualifiedLeads * salesConversion / 100);
const ltv = averageSaleValue * ltvMultiplier;
const revenue = customers * averageSaleValue;
const totalCost = budget + contractorCost;
const profit = revenue * profitMargin / 100 - totalCost;
const revenueLtv = customers * ltv;
const profitLtv = revenueLtv * profitMargin / 100 - totalCost;
const cpc = budget / clicks || 0;
const cpl = budget / leads || 0;
const cpql = budget / qualifiedLeads || 0;
const cpa = budget / customers || 0;
const roi = (profit / totalCost) * 100 || 0;
const roas = (revenue / totalCost) * 100 || 0;
setResults({
impressions,
clicks,
leads,
qualifiedLeads,
customers,
revenue,
profit,
revenueLtv,
profitLtv,
cpc: cpc.toFixed(2),
cpl: cpl.toFixed(2),
cpql: cpql.toFixed(2),
cpa: cpa.toFixed(2),
roi: roi.toFixed(2),
roas: roas.toFixed(2),
ltv: ltv.toFixed(2)
});
}, [budget, cpm, ctr, siteConversion, leadQualificationRate, salesConversion, averageSaleValue, profitMargin, ltvMultiplier, contractorCost]);
// Данные для customer journey map
const getJourneyStages = () => {
const stages = [];
if (activeStages.impressions) {
stages.push({
id: 'impressions',
name: 'Показы',
value: results.impressions,
description: 'Первый контакт',
kpi: `CPM: $${cpm}`
});
}
if (activeStages.clicks) {
stages.push({
id: 'clicks',
name: 'Клики',
value: results.clicks,
description: 'Проявление интереса',
kpi: `CPC: $${results.cpc}`
});
}
if (activeStages.leads) {
stages.push({
id: 'leads',
name: 'Лиды',
value: results.leads,
description: 'Сбор контактов',
kpi: `CPL: $${results.cpl}`
});
}
if (activeStages.qualifiedLeads) {
stages.push({
id: 'qualifiedLeads',
name: 'Квал. лиды',
value: results.qualifiedLeads,
description: 'Оценка качества',
kpi: `CPQL: $${results.cpql}`
});
}
if (activeStages.customers) {
stages.push({
id: 'customers',
name: 'Клиенты',
value: results.customers,
description: 'Совершение покупки',
kpi: `CPA: $${results.cpa}`
});
}
return stages;
};
// Получение данных о конверсии между этапами
const getConversionRates = () => {
const rates = [];
const stages = getJourneyStages();
for (let i = 0; i < stages.length - 1; i++) {
let rate = 0;
if (stages[i].id === 'impressions' && stages[i+1].id === 'clicks') {
rate = ctr;
} else if (stages[i].id === 'clicks' && stages[i+1].id === 'leads') {
rate = siteConversion;
} else if (stages[i].id === 'leads' && stages[i+1].id === 'qualifiedLeads') {
rate = leadQualificationRate;
} else if (stages[i].id === 'qualifiedLeads' && stages[i+1].id === 'customers') {
rate = salesConversion;
} else if (stages[i].id === 'leads' && stages[i+1].id === 'customers') {
// Если квал. лиды пропущены
const combinedRate = (leadQualificationRate * salesConversion) / 100;
rate = combinedRate;
}
rates.push(rate);
}
return rates;
};
// Форматирование чисел для отображения
const formatNumber = (num) => {
return new Intl.NumberFormat('ru-RU').format(num);
};
// Расчет анализа чувствительности
const calculateSensitivityAnalysis = () => {
const variations = [];
let baseValue = 0;
let min = 0;
let max = 0;
let step = 0;
// Установка диапазонов и шагов для разных параметров
switch(sensitivityParameter) {
case 'ctr':
baseValue = ctr;
min = Math.max(baseValue * 0.5, 0.1);
max = baseValue * 2;
break;
case 'cpm':
baseValue = cpm;
min = Math.max(baseValue * 0.5, 1);
max = baseValue * 2;
break;
case 'siteConversion':
baseValue = siteConversion;
min = Math.max(baseValue * 0.5, 1);
max = Math.min(baseValue * 2, 100);
break;
case 'leadQualificationRate':
baseValue = leadQualificationRate;
min = Math.max(baseValue * 0.5, 1);
max = Math.min(baseValue * 2, 100);
break;
case 'salesConversion':
baseValue = salesConversion;
min = Math.max(baseValue * 0.5, 1);
max = Math.min(baseValue * 2, 100);
break;
default:
return [];
}
step = (max - min) / 5;
// Создание вариаций значения параметра
for (let i = 0; i <= 5; i++) {
const value = Number((min + step * i).toFixed(2));
variations.push(value);
}
// Расчет результатов для каждой вариации
return variations.map(value => {
// Клонирование текущих значений
let tempCtr = ctr;
let tempCpm = cpm;
let tempSiteConversion = siteConversion;
let tempLeadQualificationRate = leadQualificationRate;
let tempSalesConversion = salesConversion;
// Установка текущего варианта
switch(sensitivityParameter) {
case 'ctr':
tempCtr = value;
break;
case 'cpm':
tempCpm = value;
break;
case 'siteConversion':
tempSiteConversion = value;
break;
case 'leadQualificationRate':
tempLeadQualificationRate = value;
break;
case 'salesConversion':
tempSalesConversion = value;
break;
default:
break;
}
// Расчет новых значений для текущей вариации
const impressions = Math.round(budget * 1000 / tempCpm);
const clicks = Math.round(impressions * tempCtr / 100);
const leads = Math.round(clicks * tempSiteConversion / 100);
const qualifiedLeads = Math.round(leads * tempLeadQualificationRate / 100);
const customers = Math.round(qualifiedLeads * tempSalesConversion / 100);
const revenue = customers * averageSaleValue;
const profit = revenue * profitMargin / 100 - budget;
const roi = (profit / budget) * 100 || 0;
return {
value: value,
customers,
revenue,
profit,
roi: parseFloat(roi.toFixed(2))
};
});
};
// Переключение активных этапов воронки
const toggleStage = (stage) => {
setActiveStages(prev => ({
...prev,
[stage]: !prev[stage]
}));
};
return (
{/* Левая колонка - выбор этапов и параметры */}
{/* Выбор этапов воронки */}
{/* Параметры кампании - с двумя столбцами */}
Параметры кампании
{/* Левый столбец параметров - Показатели эффективности */}
{/* Правый столбец параметров - Финансовые параметры */}
{/* Правая колонка - результаты */}
Финансовый результат
{activeStages.customers && (
Выручка
${formatNumber(Math.round(results.revenue))}
)}
{activeStages.customers && activeStages.ltv && (
Выручка (LTV)
${formatNumber(Math.round(results.revenueLtv))}
)}
{activeStages.customers && (
Прибыль
${formatNumber(Math.round(results.profit))}
)}
{activeStages.customers && activeStages.ltv && (
Прибыль (LTV)
${formatNumber(Math.round(results.profitLtv))}
)}
{activeStages.customers && (
)}
{activeStages.customers && (
)}
{activeStages.customers && activeStages.ltv && (
ROI (LTV)
{(results.profitLtv / budget * 100).toFixed(2)}%
)}
{/* Customer Journey Map / Анализ чувствительности */}
{showSensitivityAnalysis ? 'Анализ чувствительности' : 'Customer Journey Map'}
{showSensitivityAnalysis && (
)}
{/* Содержимое в зависимости от выбранного представления */}
{showSensitivityAnalysis ? (
График показывает, как изменение параметра "{
sensitivityParameter === 'ctr' ? 'CTR (%)' :
sensitivityParameter === 'cpm' ? 'CPM ($)' :
sensitivityParameter === 'siteConversion' ? 'Конверсия сайта (%)' :
sensitivityParameter === 'leadQualificationRate' ? 'Квалификация лидов (%)' :
'Конверсия продаж (%)'
}" влияет на ключевые показатели.
{/* Таблица результатов анализа чувствительности */}
{
sensitivityParameter === 'ctr' ? 'CTR (%)' :
sensitivityParameter === 'cpm' ? 'CPM ($)' :
sensitivityParameter === 'siteConversion' ? 'Конверсия сайта (%)' :
sensitivityParameter === 'leadQualificationRate' ? 'Квалификация лидов (%)' :
'Конверсия продаж (%)'
} | Клиенты | Выручка ($) | Прибыль ($) | ROI (%) |
{calculateSensitivityAnalysis().map((result, index) => (
{result.value} | {formatNumber(result.customers)} | ${formatNumber(Math.round(result.revenue))} |
${formatNumber(Math.round(result.profit))}
|
{result.roi}%
|
))}
) : (
{/* Journey Steps */}
{getJourneyStages().map((stage, index) => (
{stage.name}
{formatNumber(stage.value)}
{stage.description}
))}
{/* Conversion rates between steps */}
{getJourneyStages().length > 1 && (
{getConversionRates().map((rate, index) => (
Конверсия
{rate.toFixed(1)}%
))}
)}
{/* Line connecting all steps */}
{getJourneyStages().length > 1 && (
)}
{/* KPIs for each stage */}
{getJourneyStages().map((stage) => (
))}
)}
);
};
export default MarketingCalculator;