Include paid ad channels with spend in CRM % a cliente table.
Google (and other channels with ads but no CRM-sourced leads) now appear with 0 leads so investment and CAC stay visible. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -123,19 +123,42 @@ export default function CrmDashboard({
|
||||
return m;
|
||||
}, [attribution]);
|
||||
|
||||
const paidChannels = channelRows.filter((r) =>
|
||||
['meta', 'google'].includes(r.channel)
|
||||
// Include paid channels that have ad spend/ventas even with 0 CRM leads
|
||||
// (e.g. Google Ads spend but no leads sourced as "google" in Clientify).
|
||||
const channelRowsWithAds: CrmChannelStats[] = useMemo(() => {
|
||||
const byCh = new Map(channelRows.map((r) => [r.channel, r]));
|
||||
for (const r of attribution) {
|
||||
if (r.spend <= 0 && r.ventas <= 0) continue;
|
||||
if (byCh.has(r.channel)) continue;
|
||||
byCh.set(r.channel, {
|
||||
channel: r.channel,
|
||||
leads: 0,
|
||||
cliente: 0,
|
||||
enOportunidad: 0,
|
||||
leadFrio: 0,
|
||||
leadPerdido: 0,
|
||||
other: 0,
|
||||
clienteRate: 0,
|
||||
});
|
||||
}
|
||||
const all = [...byCh.values()];
|
||||
const paid = all
|
||||
.filter((r) => ['meta', 'google'].includes(r.channel))
|
||||
.sort((a, b) => {
|
||||
const sa = cacByChannel.get(a.channel)?.spend || 0;
|
||||
const sb = cacByChannel.get(b.channel)?.spend || 0;
|
||||
return sb - sa || b.leads - a.leads;
|
||||
});
|
||||
const other = all
|
||||
.filter((r) => !['meta', 'google'].includes(r.channel))
|
||||
.sort((a, b) => b.cliente - a.cliente || b.leads - a.leads);
|
||||
return [...paid, ...other];
|
||||
}, [channelRows, attribution, cacByChannel]);
|
||||
|
||||
const leadMax = Math.max(
|
||||
1,
|
||||
...channelRowsWithAds.map((r) => r.leads)
|
||||
);
|
||||
const otherChannels = channelRows.filter(
|
||||
(r) => !['meta', 'google'].includes(r.channel)
|
||||
);
|
||||
// Channels with ads spend / ventas but maybe no CRM lead row in this lens
|
||||
const extraCacChannels = attribution.filter(
|
||||
(r) =>
|
||||
(r.spend > 0 || r.ventas > 0) &&
|
||||
!channelRows.some((c) => c.channel === r.channel)
|
||||
);
|
||||
const leadMax = Math.max(1, ...channelRows.map((r) => r.leads));
|
||||
const statusMax = Math.max(1, ...statusRows.map((r) => r.count));
|
||||
|
||||
return (
|
||||
@@ -330,9 +353,9 @@ export default function CrmDashboard({
|
||||
hint="Estado ganado en el CRM. Ads spend y CAC del periodo son referencia."
|
||||
/>
|
||||
<Surface padded={false}>
|
||||
{!channelRows.length && !extraCacChannels.length ? (
|
||||
{!channelRowsWithAds.length ? (
|
||||
<p className="text-sm text-gray-500 py-10 text-center">
|
||||
Sin leads en esta lente/periodo.
|
||||
Sin leads ni gasto ads en esta lente/periodo.
|
||||
</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
@@ -350,7 +373,7 @@ export default function CrmDashboard({
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{[...paidChannels, ...otherChannels].map((row) => {
|
||||
{channelRowsWithAds.map((row) => {
|
||||
const cacRow = cacByChannel.get(row.channel);
|
||||
return (
|
||||
<tr
|
||||
@@ -375,7 +398,9 @@ export default function CrmDashboard({
|
||||
row.clienteRate
|
||||
)}`}
|
||||
>
|
||||
{row.clienteRate.toFixed(1)}%
|
||||
{row.leads > 0
|
||||
? `${row.clienteRate.toFixed(1)}%`
|
||||
: '—'}
|
||||
</td>
|
||||
<td className="py-3 pr-4 tabular-nums text-gray-700">
|
||||
{cacRow && cacRow.spend > 0
|
||||
|
||||
Reference in New Issue
Block a user