import { useState, useEffect, ReactNode } from 'react'
import { invoke } from '@tauri-apps/api/core'
import { useAppContext } from '@/contexts/useAppContext'
import { Icon, IconName } from '@/components/icons'
interface LocalReport {
game_id: string
unlocker: string
worked: boolean
}
interface SystemInfo {
os_name: string
cpu_model: string
cpu_cores: number
gpu_name: string
}
interface StatChipProps {
label: string
value: ReactNode
icon: IconName | string
variant?: string
}
const StatChip = ({ label, value, icon, variant }: StatChipProps) => (
{value}
{label}
)
/**
* Overview page - the default landing view. Leads with the two library
* totals as hero numbers, then a Native/Proton composition bar for the
* Steam library, then secondary stats as compact chips, plus app info.
*/
const OverviewPage = () => {
const { games, epicGames, epicLoading, loadEpicGames, activityFeed } = useAppContext()
const [localReports, setLocalReports] = useState([])
const [systemInfo, setSystemInfo] = useState(null)
useEffect(() => {
invoke('get_local_reports')
.then(setLocalReports)
.catch(() => setLocalReports([]))
}, [])
useEffect(() => {
invoke('get_system_info')
.then(setSystemInfo)
.catch(() => setSystemInfo(null))
}, [])
// Overview is the default landing page, so kick off the Epic scan here too
// otherwise the Epic count would show 0 until the user visits that tab.
useEffect(() => {
if (epicGames.length === 0 && !epicLoading) {
loadEpicGames()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const nativeCount = games.filter((g) => g.native).length
const protonCount = games.length - nativeCount
const creamCount = games.filter((g) => g.cream_installed).length
const smokeCount = games.filter((g) => g.smoke_installed).length
const nativePct = games.length ? (nativeCount / games.length) * 100 : 0
const protonPct = games.length ? (protonCount / games.length) * 100 : 0
return (
Overview
{games.length}
Steam Games
{epicLoading ? '—' : epicGames.length}
Epic Games
{games.length > 0 && (
Steam Library Composition
Native
{nativeCount}
Proton
{protonCount}
)}
Recent Activity
{activityFeed.length === 0 ? (
Nothing yet this session - install or uninstall something and it'll show up here.
) : (
{activityFeed.map((item) => (
-
{item.message}
{new Date(item.timestamp).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
})}
))}
)}
System
{systemInfo ? (
Operating System
{systemInfo.os_name}
Processor
{systemInfo.cpu_model}
{systemInfo.cpu_cores} threads
Graphics
{systemInfo.gpu_name}
) : (
Reading system info...
)}
)
}
export default OverviewPage