Files
remotelink-docker/app/(dashboard)/dashboard/sessions/page.tsx
2026-04-10 15:36:33 -07:00

107 lines
4.5 KiB
TypeScript

import { auth } from '@/auth'
import { db } from '@/lib/db'
import { sessions } from '@/lib/db/schema'
import { eq, desc } from 'drizzle-orm'
import { Card, CardContent } from '@/components/ui/card'
import { History, Clock, Monitor, CheckCircle2, Circle, Link2 } from 'lucide-react'
import { format, formatDistanceToNow } from 'date-fns'
function formatDuration(seconds: number | null) {
if (!seconds) return '-'
const h = Math.floor(seconds / 3600)
const m = Math.floor((seconds % 3600) / 60)
const s = seconds % 60
if (h > 0) return `${h}h ${m}m`
if (m > 0) return `${m}m ${s}s`
return `${s}s`
}
export default async function SessionsPage() {
const session = await auth()
const sessionList = await db
.select()
.from(sessions)
.where(eq(sessions.viewerUserId, session!.user.id))
.orderBy(desc(sessions.startedAt))
.limit(50)
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold">Session History</h2>
<p className="text-muted-foreground">View your remote connection history</p>
</div>
{sessionList.length > 0 ? (
<div className="space-y-3">
{sessionList.map((s) => (
<Card key={s.id} className="border-border/50">
<CardContent className="py-4">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className={`flex h-10 w-10 items-center justify-center rounded-lg ${s.endedAt ? 'bg-muted text-muted-foreground' : 'bg-green-500/10 text-green-500'}`}>
<Monitor className="h-5 w-5" />
</div>
<div>
<div className="flex items-center gap-2">
<p className="font-medium">{s.machineName || 'Unknown Machine'}</p>
{s.endedAt
? <CheckCircle2 className="h-4 w-4 text-muted-foreground" />
: <Circle className="h-4 w-4 text-green-500" />}
</div>
<div className="flex items-center gap-3 text-sm text-muted-foreground">
<span className="flex items-center gap-1">
<Link2 className="h-3 w-3" />
{s.connectionType === 'session_code' ? 'Session Code' : 'Direct'}
</span>
{s.sessionCode && (
<span className="font-mono text-xs">{s.sessionCode}</span>
)}
</div>
</div>
</div>
<div className="flex flex-wrap items-center gap-4 sm:gap-6 text-sm pl-14 sm:pl-0">
<div>
<p className="text-muted-foreground text-xs">Started</p>
<p className="font-medium">{format(new Date(s.startedAt), 'MMM d, h:mm a')}</p>
</div>
<div>
<p className="text-muted-foreground text-xs">Duration</p>
<p className="font-medium flex items-center gap-1">
<Clock className="h-3 w-3" />
{s.endedAt ? formatDuration(s.durationSeconds) : 'Active'}
</p>
</div>
<div>
<p className="text-muted-foreground text-xs">Status</p>
<p className={`font-medium ${s.endedAt ? 'text-muted-foreground' : 'text-green-500'}`}>
{s.endedAt ? 'Completed' : 'Active'}
</p>
</div>
</div>
</div>
{s.notes && (
<div className="mt-3 pt-3 border-t border-border/50 pl-14">
<p className="text-sm text-muted-foreground">{s.notes}</p>
</div>
)}
</CardContent>
</Card>
))}
</div>
) : (
<Card className="border-border/50">
<CardContent className="flex flex-col items-center justify-center py-16">
<History className="h-12 w-12 text-muted-foreground/30 mb-4" />
<h3 className="text-lg font-semibold mb-2">No sessions yet</h3>
<p className="text-muted-foreground text-center max-w-sm text-balance">
Your remote session history will appear here once you start connecting to machines.
</p>
</CardContent>
</Card>
)}
</div>
)
}