import { useQuery } from "@tanstack/react-query" import { createFileRoute, redirect } from "@tanstack/react-router" import type { Dashboard } from "@/components/Dashboard/DashboardView" import { PanelRail } from "@/components/Dashboard/PanelRail" import { PanelSurface } from "@/components/Dashboard/PanelSurface" import { dashboardQueryOptions, panelQueryOptions, } from "@/components/Dashboard/queries" import { LookProvider, useCanvasRoot, } from "@/components/Dashboard/ui/core/look" import { useFlowSocket } from "@/components/Flow/useFlowSocket" import { isLoggedIn } from "@/hooks/useAuth" import { useIsMobile } from "@/hooks/useMobile" import { cn } from "@/lib/utils" /** * What a paired device shows: the dashboards this panel was assigned. * * The same full-bleed surface as `/view/{name}`, with a rail down the left * when there is more than one to switch between — so a hallway tablet and a * workshop tablet can carry different sets without either dashboard knowing * anything about the other. * * Which one is open lives in the URL, so a panel that reboots comes back where * it was rather than at the first one. */ export const Route = createFileRoute("/panel/$id")({ component: PanelRoute, validateSearch: (search: Record): { d?: string } => typeof search.d === "string" ? { d: search.d } : {}, beforeLoad: async () => { // Unpaired, or a credential the server stopped honouring. Either way this // device needs a new code, not a login form it cannot type into. if (!isLoggedIn()) { throw redirect({ to: "/panel" }) } }, head: ({ params }) => ({ meta: [{ title: `${params.id} - Fluksio` }] }), }) function PanelRoute() { const { id } = Route.useParams() const { d } = Route.useSearch() useFlowSocket() const { data: panel } = useQuery(panelQueryOptions(id)) const dashboards = panel?.dashboards ?? [] // A name in the URL that this panel no longer carries falls back to the // first, which is what a dashboard removed from under a running panel does. const current = d && dashboards.includes(d) ? d : dashboards[0] const { data: dashboard } = useQuery({ ...dashboardQueryOptions(current ?? ""), enabled: Boolean(current), }) const stacked = useIsMobile() const rail = dashboards.length > 1 // The screen is the dashboard here, so its appearance covers the whole of // it — the rail and the letterbox around a scaled canvas included. This is // the surface these settings exist for: a panel in a room has no other way // to be told what to wear. const root = useCanvasRoot(dashboard as Dashboard | undefined) if (panel && dashboards.length === 0) { return (

No dashboards are assigned to this panel yet.

) } return (
{dashboard ? ( ({ to: "/panel/$id", params: { id }, search: { d: name }, })} /> ) : null } /> ) : null}
) }