feat(portal): connect estrategia to live targets RPC and enrich chat assistant with multi-RPC routing
This commit is contained in:
@@ -4,12 +4,57 @@ import { Target, CheckCircle2, TrendingUp } from 'lucide-react';
|
||||
export const revalidate = 0;
|
||||
|
||||
export default async function EstrategiaPage() {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://supabase.4ventures.es';
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '';
|
||||
|
||||
const now = new Date();
|
||||
const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01`;
|
||||
|
||||
let targetData: any = {
|
||||
revenue_target: 10000,
|
||||
revenue_actual: 0,
|
||||
revenue_achievement_pct: 0,
|
||||
leads_target: 20,
|
||||
leads_actual: 0,
|
||||
clients_target: 4,
|
||||
clients_actual: 0
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(`${supabaseUrl}/rest/v1/rpc/targets_vs_actual`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
apikey: serviceKey,
|
||||
Authorization: `Bearer ${serviceKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ p_month: currentMonth }),
|
||||
cache: 'no-store'
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
targetData = data[0];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error fetching targets_vs_actual:', e);
|
||||
}
|
||||
|
||||
const revenuePct = Math.min(100, Math.round(targetData.revenue_achievement_pct || 0));
|
||||
const leadsPct = targetData.leads_target > 0
|
||||
? Math.min(100, Math.round((Number(targetData.leads_actual) / Number(targetData.leads_target)) * 100))
|
||||
: 0;
|
||||
const clientsPct = targetData.clients_target > 0
|
||||
? Math.min(100, Math.round((Number(targetData.clients_actual) / Number(targetData.clients_target)) * 100))
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold tracking-tight text-white">Estrategia de Crecimiento & Objetivos</h2>
|
||||
<p className="text-sm text-gray-400 mt-1">
|
||||
Monitoreo mensual de metas de facturación, captación de leads y posicionamiento.
|
||||
Monitoreo mensual en tiempo real de metas fijadas frente al rendimiento real consolidado en Supabase.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -19,11 +64,15 @@ export default async function EstrategiaPage() {
|
||||
<h3 className="font-semibold text-white text-base">Objetivo de Facturación</h3>
|
||||
<Target className="w-5 h-5 text-brand-500" />
|
||||
</div>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">50.000 €</p>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">
|
||||
{Number(targetData.revenue_actual || 0).toLocaleString('es-ES', { minimumFractionDigits: 2 })} €
|
||||
</p>
|
||||
<div className="w-full bg-gray-800 rounded-full h-2 mb-2">
|
||||
<div className="bg-brand-500 h-2 rounded-full w-[65%]"></div>
|
||||
<div className="bg-brand-500 h-2 rounded-full" style={{ width: `${revenuePct}%` }}></div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400">65% completado este mes</p>
|
||||
<p className="text-xs text-gray-400">
|
||||
Meta: {Number(targetData.revenue_target || 0).toLocaleString('es-ES')} € ({revenuePct}% completado)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#111827] border border-gray-800 rounded-xl p-6">
|
||||
@@ -31,23 +80,27 @@ export default async function EstrategiaPage() {
|
||||
<h3 className="font-semibold text-white text-base">Meta de Leads Cualificados</h3>
|
||||
<TrendingUp className="w-5 h-5 text-blue-400" />
|
||||
</div>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">150</p>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">{targetData.leads_actual || 0}</p>
|
||||
<div className="w-full bg-gray-800 rounded-full h-2 mb-2">
|
||||
<div className="bg-blue-400 h-2 rounded-full w-[82%]"></div>
|
||||
<div className="bg-blue-400 h-2 rounded-full" style={{ width: `${leadsPct}%` }}></div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400">123 leads registrados (82%)</p>
|
||||
<p className="text-xs text-gray-400">
|
||||
{targetData.leads_actual || 0} de {targetData.leads_target || 0} leads captados ({leadsPct}%)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#111827] border border-gray-800 rounded-xl p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-semibold text-white text-base">Nuevos Clientes</h3>
|
||||
<h3 className="font-semibold text-white text-base">Nuevos Clientes (Won)</h3>
|
||||
<CheckCircle2 className="w-5 h-5 text-emerald-400" />
|
||||
</div>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">12</p>
|
||||
<p className="text-3xl font-extrabold text-white mb-2">{targetData.clients_actual || 0}</p>
|
||||
<div className="w-full bg-gray-800 rounded-full h-2 mb-2">
|
||||
<div className="bg-emerald-400 h-2 rounded-full w-[75%]"></div>
|
||||
<div className="bg-emerald-400 h-2 rounded-full" style={{ width: `${clientsPct}%` }}></div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400">9 cerrados ganados (75%)</p>
|
||||
<p className="text-xs text-gray-400">
|
||||
{targetData.clients_actual || 0} de {targetData.clients_target || 0} clientes ganados ({clientsPct}%)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user