Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions app/Http/Controllers/PostProxyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,18 @@ public function operationState($area): JsonResponse
$data = $response->json();
return response()->json($data);
}
public function operationQueueState($area): JsonResponse
public function operationPromState($area): JsonResponse
{
$response = Http::get("http://10.57.251.181:3014/operacion/{$area}");
$response = Http::get("http://10.57.251.181:3015/tiempo-respuesta/{$area}");
if (!$response->successful()) {
return response()->json(['error' => 'No se pudo obtener los datos'], 500);
}
$data = $response->json();
return response()->json($data);
}
public function operationAgentSatus($area): JsonResponse
{
$response = Http::get("http://10.57.251.181:3016/operacion/{$area}");
if (!$response->successful()) {
return response()->json(['error' => 'No se pudo obtener los datos'], 500);
}
Expand Down
53 changes: 53 additions & 0 deletions resources/js/components/queuesAgentsModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// ModalColasAgent.jsx
import React from 'react';
import {
Glasses,
} from 'lucide-react';
function ModalColasAgent({ titulo = "Agentes", usuarios = [], tipo }) {
const estadoColorMap = {
disponibles: 'bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-300',
ocupados: 'bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-300',
en_pausa: 'bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-300',
};

const badgeClass = `text-xs font-semibold px-3 py-1 rounded-full ${estadoColorMap[tipo] ?? ''}`;
return (
<div className="p-6 max-h-[70vh] overflow-y-auto">
<h2 className="text-lg font-semibold mb-4 text-gray-800 dark:text-white flex items-center gap-2">
<Glasses/> {titulo} ({usuarios.length})
</h2>

{usuarios.length === 0 ? (
<p className="text-sm text-gray-500 dark:text-gray-400">
No hay agentes en este estado.
</p>
) : (
<ul className="divide-y divide-gray-200 dark:divide-gray-700">
{usuarios.map((agente, idx) => (
<li key={idx} className="py-3">
<div className="flex justify-between items-start">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">
👤 {agente.usuario}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
Extensión: <strong>{agente.extension}</strong>
</p>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Colas asignadas:{" "}
<span className="font-semibold">{agente.colas.join(", ")}</span>
</p>
</div>
<span className={badgeClass}>
{agente.estado}
</span>
</div>
</li>
))}
</ul>
)}
</div>
);
}

export default ModalColasAgent;
32 changes: 32 additions & 0 deletions resources/js/components/utils/formatTime.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export default function TiempoFormateado({ tiempo }) {
if (tiempo === undefined || tiempo === null || tiempo === '') {
return <span className="">–</span>;
}

let horas = 0;
let minutos = 0;
let segundos = 0;

if (typeof tiempo === 'string' && tiempo.includes(':')) {
const partes = tiempo.split(':');
horas = parseInt(partes[0], 10);
minutos = parseInt(partes[1], 10);
segundos = parseFloat(partes[2]);
} else if (!isNaN(tiempo)) {
const totalSegundos = parseFloat(tiempo);
horas = Math.floor(totalSegundos / 3600);
minutos = Math.floor((totalSegundos % 3600) / 60);
segundos = Math.floor(totalSegundos % 60);
} else {
return <span className="">–</span>;
}

let resultado = '';
if (horas > 0) {
resultado = `${horas}:${String(minutos).padStart(2, '0')}:${String(segundos).padStart(2, '0')}`;
} else {
resultado = `${minutos}:${String(segundos).padStart(2, '0')}`;
}

return <span className="">{resultado}</span>;
}
8 changes: 5 additions & 3 deletions resources/js/components/welcome/agentRankingWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DiscordLoader from '@/components/discordloader';
import { useLoadStatus } from "../context/loadContext";
import { Link, usePage } from "@inertiajs/react";
import { themeByProject } from '../utils/theme';

import TiempoFormateado from '@/components/utils/formatTime';

const getMedal = (rank) => {
switch (rank) {
Expand Down Expand Up @@ -34,6 +34,8 @@ export default function AgentRankingWidget() {
.map((agente, index) => ({ ...agente, rank: index + 1 }));

setAgentes(ordenados);
console.log(ordenados);

} else {
console.warn("La respuesta no contiene un array de datos:", res.data);
}
Expand All @@ -49,7 +51,7 @@ export default function AgentRankingWidget() {
}, []);

return (
<div className="p-6 flex flex-col justify-between">
<div className="p-0 sm:p-6 flex flex-col justify-between">
{loading || !allLoaded ? ( // ⛳ doble condición: hasta que TODOS estén listos
<DiscordLoader />
) : (
Expand All @@ -72,7 +74,7 @@ export default function AgentRankingWidget() {
<div>
<p className="font-medium text-gray-900 dark:text-white">{agente.agente}</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
Directas: {agente.directas}, Transferidas: {agente.transferidas}
promedio: <TiempoFormateado tiempo={agente?.promedio_duracion}/>,<br/> Total en llamadas: <TiempoFormateado tiempo={agente?.total_duracion}/>
</p>
</div>
</div>
Expand Down
10 changes: 6 additions & 4 deletions resources/js/components/welcome/callPerOperationChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useEffect, useState } from 'react';
import DiscordLoader from '@/components/discordloader';
import axios from "axios";
import { useLoadStatus } from "../context/loadContext";
import { themeByProject } from "../utils/theme";
import { themeByProject, getChartColors } from '../utils/theme';
ChartJS.register(
CategoryScale,
LinearScale,
Expand Down Expand Up @@ -63,6 +63,8 @@ export default function CallsPerOperationChart() {
const theme = themeByProject[proyecto];
const [loading, setLoading] = useState(true);
const { allLoaded, markLoaded } = useLoadStatus();
const chartColors = getChartColors(proyecto);

const [callData, setCallData] = useState({
Soporte: 0,
Tramites: 0,
Expand Down Expand Up @@ -111,16 +113,16 @@ export default function CallsPerOperationChart() {
callData.Movil,
callData.Pruebas
],
backgroundColor: 'rgba(168, 85, 247, 0.6)',
borderColor: 'rgba(147, 51, 234, 1)',
backgroundColor: chartColors.fill,
borderColor: chartColors.border,
borderWidth: 1,
borderRadius: 10,
},
],
};

return (
<div className="absolute inset-0 p-6 flex flex-col justify-between ">
<div className="px-4 py-3 sm:px-6 sm:py-4 flex flex-col justify-between h-full">
{!allLoaded ? (
<DiscordLoader />
) : (
Expand Down
15 changes: 15 additions & 0 deletions resources/js/hooks/useOperationModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useState } from 'react';

export default function useOperationModal() {
const [modal, setModal] = useState({ show: false, tipo: null });

const showModal = (tipo) => {
setModal({ show: true, tipo });
};

const hideModal = () => {
setModal({ show: false, tipo: null });
};

return { modal, showModal, hideModal };
}
46 changes: 24 additions & 22 deletions resources/js/pages/agentState.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,33 @@ export default function TableAgents() {
<div className="xl:col-span-2 rounded-2xl shadow-lg border border-gray-100 dark:border-gray-800 p-6 flex flex-col">
<h2 className="text-xl font-semibold text-indigo-700 dark:text-indigo-300 mb-4">Tabla de Ranking</h2>
<div className="flex-1">
{/* <LoadProvider total={1}>
<LoadProvider total={1}>
<AgentRankingWidget />
</LoadProvider> */}
</div>
</div>
<div className=" from-purple-100 via-white to-indigo-100 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 rounded-2xl shadow-lg border border-gray-100 dark:border-gray-800 p-6 flex flex-col justify-between">
<h3 className="text-lg font-bold text-purple-700 dark:text-purple-300 mb-2">Resumen del Día</h3>
<ul className="space-y-3 text-base text-gray-700 dark:text-gray-200">
<li>
<span className="font-bold text-indigo-600">124</span> llamadas atendidas
<span className="block text-xs text-gray-500 dark:text-gray-400">Excelente desempeño general.</span>
</li>
<li>
<span className="font-bold text-green-600">32</span> llamadas en espera
<span className="block text-xs text-gray-500 dark:text-gray-400">Revisar horarios de mayor demanda.</span>
</li>
<li>
<span className="font-bold text-red-600">18</span> llamadas perdidas
<span className="block text-xs text-gray-500 dark:text-gray-400">Oportunidad de mejora en atención.</span>
</li>
</ul>
<div className="mt-6 text-xs text-gray-400 dark:text-gray-500">
Última actualización: hace 5 minutos.
</LoadProvider>
</div>
</div>
<div className="from-purple-100 via-white to-indigo-100 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 rounded-2xl shadow-lg border border-gray-100 dark:border-gray-800 p-6 flex flex-col justify-between">
<h3 className="text-lg font-bold text-purple-700 dark:text-purple-300 mb-2">Estadísticas Curiosas</h3>

<ul className="space-y-3 text-base text-gray-700 dark:text-gray-200">
<li>
🏆 <span className="font-bold text-indigo-600">luisa611</span> fue el agente más rápido
<span className="block text-xs text-gray-500 dark:text-gray-400">Promedio de duración: 2:31</span>
</li>
<li>
🧱 <span className="font-bold text-green-600">baguirre39</span> trabajó sin pausas por 3h 10m
<span className="block text-xs text-gray-500 dark:text-gray-400">Resistencia comprobada 💪</span>
</li>
<li>
🎯 <span className="font-bold text-pink-600">sramoss1</span> recibió 12 transferencias
<span className="block text-xs text-gray-500 dark:text-gray-400">¡Más apoyo recibido!</span>
</li>
</ul>

<div className="mt-6 text-xs text-gray-400 dark:text-gray-500">
Última actualización: hace 5 minutos.
</div>
</div>
</div>

<div className=" rounded-2xl shadow-lg border border-gray-100 dark:border-gray-800 p-8 mt-8">
Expand Down
Loading
Loading