165 lines
5.3 KiB
TypeScript
165 lines
5.3 KiB
TypeScript
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import { Card } from "@/components/ui/card";
|
|
import { formatDistanceToNow, format } from "date-fns";
|
|
import { Clock, Calendar, Radio, Star } from "lucide-react";
|
|
const ratings = {
|
|
"-1": "INA",
|
|
"0": "SUS",
|
|
"1": "OBS",
|
|
"2": "S1",
|
|
"3": "S2",
|
|
"4": "S3",
|
|
"5": "C1",
|
|
"6": "C2",
|
|
"7": "C3",
|
|
"8": "I1",
|
|
"9": "I2",
|
|
"10": "I3",
|
|
"11": "SUP",
|
|
"12": "ADM",
|
|
}
|
|
interface ControllerProfileProps {
|
|
sessions: any[];
|
|
loading: boolean;
|
|
}
|
|
|
|
export function ControllerProfile({ sessions, loading }: ControllerProfileProps) {
|
|
if (loading) {
|
|
return <LoadingSkeleton />;
|
|
}
|
|
|
|
const totalTime = sessions.reduce((acc, session) => {
|
|
const duration = new Date(session.lastSeen).getTime() - new Date(session.logonTime).getTime();
|
|
return acc + duration;
|
|
}, 0);
|
|
|
|
const totalHours = Math.floor(totalTime / (1000 * 60 * 60));
|
|
const totalMinutes = Math.floor((totalTime % (1000 * 60 * 60)) / (1000 * 60));
|
|
|
|
// Get unique positions
|
|
const positions = [...new Set(sessions.map(s => s.facilityType))];
|
|
|
|
return (
|
|
<div className="space-y-6 p-6">
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
|
{[
|
|
{
|
|
icon: <Clock className="h-5 w-5 text-blue-500" />,
|
|
title: "Total Time",
|
|
value: `${totalHours}h ${totalMinutes}m`,
|
|
},
|
|
{
|
|
icon: <Calendar className="h-5 w-5 text-blue-500" />,
|
|
title: "Total Sessions",
|
|
value: sessions.length,
|
|
},
|
|
{
|
|
icon: <Radio className="h-5 w-5 text-blue-500" />,
|
|
title: "Positions",
|
|
value: (
|
|
<div className="flex flex-wrap gap-2">
|
|
{positions.map(position => (
|
|
<span
|
|
key={position}
|
|
className="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900 dark:text-blue-200"
|
|
>
|
|
{position}
|
|
</span>
|
|
))}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
icon: <Star className="h-5 w-5 text-blue-500" aria-hidden="true" />,
|
|
title: "Highest Rating",
|
|
value: sessions[0].rating || "N/A",
|
|
},
|
|
].map(({ icon, title, value }, i) => (
|
|
<Card key={i} className="p-6 h-full flex flex-col justify-between">
|
|
<div className="flex items-center gap-3 mb-4">
|
|
{icon}
|
|
<h3 className="text-lg font-semibold">{title}</h3>
|
|
</div>
|
|
<p className="text-3xl font-bold">{value}</p>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<h3 className="text-lg font-semibold mb-4">Session History</h3>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Date</TableHead>
|
|
<TableHead>Callsign</TableHead>
|
|
<TableHead>Position</TableHead>
|
|
<TableHead>Airport</TableHead>
|
|
<TableHead>Frequency</TableHead>
|
|
<TableHead>Duration</TableHead>
|
|
<TableHead>Rating</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{sessions.map((session) => (
|
|
<TableRow key={`${session.callsign}-${session.lastSeen}`}>
|
|
<TableCell>
|
|
{format(new Date(session.logonTime), "MMM d, yyyy")}
|
|
</TableCell>
|
|
<TableCell>{session.callsign}</TableCell>
|
|
<TableCell>{session.facilityType}</TableCell>
|
|
<TableCell>{session.airport}</TableCell>
|
|
<TableCell>{session.frequency}</TableCell>
|
|
<TableCell>
|
|
{formatSessionDuration(session.logonTime, session.lastSeen)}
|
|
</TableCell>
|
|
<TableCell>{session.rating}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function formatSessionDuration(start: string, end: string) {
|
|
const duration = new Date(end).getTime() - new Date(start).getTime();
|
|
const hours = Math.floor(duration / (1000 * 60 * 60));
|
|
const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60));
|
|
return `${hours}h ${minutes}m`;
|
|
}
|
|
|
|
function LoadingSkeleton() {
|
|
return (
|
|
<div className="space-y-6 p-6">
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
|
<Skeleton className="h-[140px] rounded-lg" />
|
|
<Skeleton className="h-[140px] rounded-lg" />
|
|
<Skeleton className="h-[140px] rounded-lg" />
|
|
<Skeleton className="h-[140px] rounded-lg" />
|
|
</div>
|
|
<div className="space-y-3 mt-8">
|
|
<Skeleton className="h-8 w-[200px]" />
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
<div key={i} className="flex gap-4">
|
|
<Skeleton className="h-4 w-[120px]" />
|
|
<Skeleton className="h-4 w-[120px]" />
|
|
<Skeleton className="h-4 w-[100px]" />
|
|
<Skeleton className="h-4 w-[80px]" />
|
|
<Skeleton className="h-4 w-[100px]" />
|
|
<Skeleton className="h-4 w-[100px]" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|