43bbcece7a
Backend: adds JDBC session support, login/status/logout endpoints, and new DTOs (AuthResponse, ConnectionStatusResponse, LoginResult). Frontend replaces the Vite boilerplate with a Dashboard, ServiceCard, and ConnectModal backed by a typed API client. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
2.0 KiB
TypeScript
59 lines
2.0 KiB
TypeScript
import { useState, useEffect } from "react"
|
|
import { getStatuses, logout } from "../api/connections"
|
|
import type { ConnectionStatus } from "../types/connection"
|
|
import { ServiceCard } from "./ServiceCard"
|
|
import { ConnectModal } from "./ConnectModal"
|
|
import "./Dashboard.scss"
|
|
|
|
const SERVICES = [
|
|
{ serviceType: 'HOMEBOX', label: 'Homebox', icon: '📦' },
|
|
] as const
|
|
|
|
export function Dashboard() {
|
|
const [statuses, setStatuses] = useState<ConnectionStatus[]>([])
|
|
const [openModal, setOpenModal] = useState<string | null>(null)
|
|
|
|
const refresh = () => {
|
|
getStatuses().then(setStatuses).catch(() => { })
|
|
}
|
|
|
|
useEffect(() => { refresh() }, [])
|
|
|
|
const handleDisconnect = (serviceType: string) => {
|
|
logout(serviceType).then(refresh).catch(() => { })
|
|
}
|
|
|
|
const activeModal = SERVICES.find(s => s.serviceType === openModal)
|
|
|
|
return (
|
|
<div className="dashboard">
|
|
<div className="dashboard__header">
|
|
<h1 className="dashboard__title">Vaessl Dashboard</h1>
|
|
</div>
|
|
|
|
<p className="dashboard__section-label">Services</p>
|
|
<div className="dashboard__cards">
|
|
{SERVICES.map(({ serviceType, label, icon }) => (
|
|
<ServiceCard
|
|
key={serviceType}
|
|
serviceType={serviceType}
|
|
label={label}
|
|
icon={icon}
|
|
status={statuses.find(s => s.serviceType === serviceType) ?? null}
|
|
onConnect={() => setOpenModal(serviceType)}
|
|
onDisconnect={() => handleDisconnect(serviceType)}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{activeModal && (
|
|
<ConnectModal
|
|
serviceType={activeModal.serviceType}
|
|
label={activeModal.label}
|
|
onClose={() => setOpenModal(null)}
|
|
onSuccess={() => { setOpenModal(null); refresh() }}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
} |