- Updated kiosk stats API with expanded metrics - New components: company-tickets-card, gauge-chart, service-desk-card, ticket-leaders-card - Updated cycling-display, kpi-card, and ticker components - Added performance.css for kiosk optimizations - Added Wulf logo asset
173 lines
4.2 KiB
TypeScript
173 lines
4.2 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { CyclingDisplay } from '@/components/kiosk/cycling-display';
|
|
import { Ticker } from '@/components/kiosk/ticker';
|
|
import { SettingsPanel } from '@/components/kiosk/settings-panel';
|
|
import './performance.css';
|
|
|
|
interface TicketItem {
|
|
ticketNumber: string;
|
|
title: string;
|
|
companyName: string;
|
|
}
|
|
|
|
interface ResourceLeader {
|
|
resourceName: string;
|
|
ticketsClosed: number;
|
|
}
|
|
|
|
interface IssueType {
|
|
issueType: string;
|
|
subIssueType: string;
|
|
count: number;
|
|
}
|
|
|
|
interface KpiStats {
|
|
criticalTickets: number;
|
|
topCritical?: TicketItem[];
|
|
waitingTickets: number;
|
|
topWaiting?: TicketItem[];
|
|
staleTickets: number;
|
|
topStale?: TicketItem[];
|
|
overdueTickets: number;
|
|
topOverdue?: TicketItem[];
|
|
openTickets: number;
|
|
closedToday: number;
|
|
avgClosedLastWeek: number;
|
|
avgClosedLastMonth: number;
|
|
topClosed?: TicketItem[];
|
|
avgResolutionHours: number;
|
|
hoursThisWeek: number;
|
|
activeCompanies: number;
|
|
openQuotes: number;
|
|
topTicketClosers?: ResourceLeader[];
|
|
topManagedIssueTypes?: IssueType[];
|
|
nmsCoverage: number;
|
|
rmmCoverage: number;
|
|
serviceDeskManaged: number;
|
|
serviceDeskTM: number;
|
|
serviceDeskVendor: number;
|
|
hynesTickets: number;
|
|
seubertTickets: number;
|
|
universalTickets: number;
|
|
}
|
|
|
|
interface TickerActivity {
|
|
ticketNumber: string;
|
|
title: string;
|
|
priority: number;
|
|
statusLabel: string;
|
|
companyName: string;
|
|
}
|
|
|
|
export default function KioskPage() {
|
|
const [stats, setStats] = useState<KpiStats>({
|
|
criticalTickets: 0,
|
|
waitingTickets: 0,
|
|
staleTickets: 0,
|
|
overdueTickets: 0,
|
|
openTickets: 0,
|
|
closedToday: 0,
|
|
avgClosedLastWeek: 0,
|
|
avgClosedLastMonth: 0,
|
|
avgResolutionHours: 0,
|
|
hoursThisWeek: 0,
|
|
activeCompanies: 0,
|
|
openQuotes: 0,
|
|
nmsCoverage: 0,
|
|
rmmCoverage: 0,
|
|
serviceDeskManaged: 0,
|
|
serviceDeskTM: 0,
|
|
serviceDeskVendor: 0,
|
|
hynesTickets: 0,
|
|
seubertTickets: 0,
|
|
universalTickets: 0,
|
|
});
|
|
const [activities, setActivities] = useState<TickerActivity[]>([]);
|
|
const [cycleInterval, setCycleInterval] = useState(7);
|
|
const [tickerSpeed, setTickerSpeed] = useState(30);
|
|
|
|
useEffect(() => {
|
|
// Fetch settings from API
|
|
const fetchSettings = async () => {
|
|
try {
|
|
const res = await fetch('/api/kiosk/settings');
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data.cycle_interval) {
|
|
setCycleInterval(data.cycle_interval);
|
|
}
|
|
if (data.ticker_speed) {
|
|
setTickerSpeed(data.ticker_speed);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching kiosk settings:', error);
|
|
}
|
|
};
|
|
fetchSettings();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// Fetch initial data
|
|
fetchData();
|
|
|
|
// Set up auto-refresh every 60 seconds
|
|
const statsInterval = setInterval(fetchData, 60000);
|
|
|
|
return () => {
|
|
clearInterval(statsInterval);
|
|
};
|
|
}, []);
|
|
|
|
const fetchData = async () => {
|
|
try {
|
|
// Fetch stats
|
|
const statsRes = await fetch('/api/kiosk/stats');
|
|
if (statsRes.ok) {
|
|
const statsData = await statsRes.json();
|
|
setStats(statsData);
|
|
}
|
|
|
|
// Fetch activity feed
|
|
const activityRes = await fetch('/api/kiosk/activity');
|
|
if (activityRes.ok) {
|
|
const activityData = await activityRes.json();
|
|
setActivities(activityData.activities || []);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching kiosk data:', error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="h-screen w-screen bg-black text-white overflow-hidden flex flex-col">
|
|
{/* Settings Panel */}
|
|
<SettingsPanel
|
|
cycleInterval={cycleInterval}
|
|
onIntervalChange={setCycleInterval}
|
|
tickerSpeed={tickerSpeed}
|
|
onTickerSpeedChange={setTickerSpeed}
|
|
/>
|
|
|
|
{/* Main Content Area */}
|
|
<CyclingDisplay stats={stats} cycleInterval={cycleInterval} />
|
|
|
|
{/* Ticker */}
|
|
<Ticker activities={activities} speed={tickerSpeed} />
|
|
|
|
{/* Custom CSS for ticker animation */}
|
|
<style jsx global>{`
|
|
@keyframes ticker {
|
|
0% {
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
100% {
|
|
transform: translate3d(-50%, 0, 0);
|
|
}
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
}
|