Files
hanzo.ai/app/(app)/home/_workspace.tsx

57 lines
2.0 KiB
TypeScript

'use client'
// /home, as the app. The route's client half.
//
// The same shape as /chat and /board, because it is the same shell: the rail,
// the destination it is lit on, and one pane — and, as on /chat, the open room
// rides the address.
import { useEffect, useRef } from 'react'
import { Room } from '@hanzo/app/Room'
import { Home } from '@hanzo/app/Home'
import { useOpen, openRoom } from '@hanzo/app/open'
/**
* The open room rides the address, both directions, so a reload keeps your
* place and a link opens the same room.
*
* ONE effect owns the URL, the way `/chat` carries `?thread=`. On arrival the
* param opens the room — Home then resolves the key against the org's rooms,
* which answer only a validated principal, so a shared link degrades to "not
* here" rather than leaking anything. The open room mirrors back out: pressing
* a room in the rail writes its key, and leaving it strips the param. The
* mirror is idempotent, so the mount open re-runs the effect, finds the param
* it just read, and writes nothing.
*/
export default function HomeRoom() {
const { room } = useOpen()
const seeded = useRef(false)
useEffect(() => {
const isDesktop = typeof window !== 'undefined' && Boolean((window as unknown as { __TAURI__?: unknown; __TAURI_INTERNALS__?: unknown }).__TAURI__ || (window as unknown as { __TAURI__?: unknown; __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__)
if (isDesktop) {
window.location.replace('/chat')
return
}
const url = new URL(window.location.href)
if (!seeded.current) {
seeded.current = true
const asked = url.searchParams.get('room')
if (asked) {
openRoom(asked)
return
}
}
const has = url.searchParams.get('room')
if ((room ?? null) === (has ?? null)) return
if (room) url.searchParams.set('room', room)
else url.searchParams.delete('room')
window.history.replaceState(null, '', `${url.pathname}${url.search}${url.hash}`)
}, [room])
return (
<Room mode="home">
<Home />
</Room>
)
}