// The editor on a project of server F (F5.3b): the shared document over // /sync and the room over /sim, both signed in by the cookie F set at // /__auth. Until the document is there, a word that it is coming; when F // refuses or lets go — of the document or the room — a word why, instead of // the editor. Who only reads gets the editor locked (Editor's readOnly). // The others in the project are shown in the editor and told to whoever // embeds it (`onPeople`: the dashboard's header, over the bridge). import { useEffect, useMemo, useState } from 'react'; import { peopleOf, type PresenceUser } from './presence.js'; import { usePresence } from './usePresence.js'; import { Editor } from '../Editor.js'; import { CATALOGS, useLanguage, useTranslate } from '../i18n/i18n.js'; import type { SimHostFactory } from '../simulation/useSimulation.js'; import { RemoteSimHost, simUrl } from './remoteSimHost.js'; import { connectSharedDoc, type SharedDocState } from './sharedDoc.js'; type Ready = Extract; /** The editor on the ready document, with the others in the project. */ function ReadyEditor({ state, createSimHost, onPeople }: { readonly state: Ready; readonly createSimHost: SimHostFactory; readonly onPeople: ((people: readonly PresenceUser[]) => void) | undefined }) { const presence = usePresence(state.awareness, state.you); const key = JSON.stringify(peopleOf(presence.peers, state.you.id)); useEffect(() => onPeople?.(JSON.parse(key) as PresenceUser[]), [key, onPeople]); return ; } export interface SharedProjectProps { /** F's address. */ readonly server: string; readonly project: string; /** The others in the project, each time they change. */ readonly onPeople?: (people: readonly PresenceUser[]) => void; } export function SharedProject({ server, project, onPeople }: SharedProjectProps) { const t = useTranslate(); const language = useLanguage(); const [state, setState] = useState({ kind: 'connecting' }); /** F ended the room for this page: the editor goes as when the document is let go. */ const [roomEnd, setRoomEnd] = useState(null); useEffect(() => connectSharedDoc({ server, project, onState: setState }), [server, project]); const createSimHost = useMemo( () => () => { const host = new RemoteSimHost(simUrl(server, project)); host.onEnd((end) => setRoomEnd(end.reason)); return host; }, [server, project], ); const ended = roomEnd ?? (state.kind === 'refused' || state.kind === 'closed' ? state.reason : null); if (ended !== null) { const key = `remote.${ended}`; return (

{key in CATALOGS[language] ? t(key) : t('remote.refused', { reason: ended })}

); } if (state.kind !== 'ready') return (

{t('remote.connecting')}

); return ; }