import { useEffect, useMemo } from 'react' import { getRouteApi } from '@tanstack/react-router' import { Alert } from '@/components/ui/Alert' import { GardenCanvas } from '@/editor/GardenCanvas' import { useEditorStore } from '@/editor/store' import type { EditorGarden } from '@/editor/types' import { toEditorObject } from '@/lib/objects' import { toEditorPlanting } from '@/lib/plantings' import { usePublicGarden } from '@/lib/publicGarden' import { usePageTitle } from '@/lib/usePageTitle' const routeApi = getRouteApi('/g/$token') /** * The public, read-only garden view behind a share token. Rendered on the * unauthenticated `/g/$token` route (no auth guard), so a logged-out visitor * never hits /login or OIDC. Reuses GardenCanvas with canEdit=false — pan/zoom * to explore, but no editing chrome. */ export function PublicGardenPage() { const { token } = routeApi.useParams() const full = usePublicGarden(token) usePageTitle(full.data?.garden.name ?? 'Shared garden') // Start from a clean canvas: if a logged-in user reaches here from their own // editor, stale focus/selection state would otherwise dim or highlight things. useEffect(() => { useEditorStore.getState().resetTransient() }, [token]) const objects = useMemo(() => full.data?.objects.map(toEditorObject) ?? [], [full.data?.objects]) const plantings = useMemo(() => full.data?.plantings.map(toEditorPlanting) ?? [], [full.data?.plantings]) const plants = useMemo(() => full.data?.plants ?? [], [full.data?.plants]) const plantsById = useMemo(() => new Map(plants.map((p) => [p.id, p])), [plants]) if (full.isPending) return

Loading garden…

if (full.isError) return (
This shared link isn’t available. The owner may have turned it off or changed it.
) const g = full.data.garden const garden: EditorGarden = { id: g.id, name: g.name, widthCm: g.widthCm, heightCm: g.heightCm, unitPref: g.unitPref, gridSizeCm: g.gridSizeCm, snapToGrid: g.snapToGrid, } return (

{garden.name}

👁 Shared · read-only
) }