diff --git a/src/config/buffered-bus.ts b/src/config/buffered-bus.ts new file mode 100644 index 0000000..a8fd1b8 --- /dev/null +++ b/src/config/buffered-bus.ts @@ -0,0 +1,43 @@ +type Listener = (payload: unknown) => void; + +class BufferedEventBus { + private listeners = new Map(); + private buffer = new Map(); + + on(event: string, listener: Listener) { + if (!this.listeners.has(event)) { + this.listeners.set(event, []); + } + this.listeners.get(event)!.push(listener); + + if (this.buffer.has(event)) { + for (const payload of this.buffer.get(event)!) { + listener(payload); + } + this.buffer.delete(event); + } + } + + off(event: string, listener: Listener) { + if (!this.listeners.has(event)) return; + this.listeners.set( + event, + this.listeners.get(event)!.filter((l) => l !== listener) + ); + } + + emit(event: string, payload: unknown) { + const ls = this.listeners.get(event); + if (!ls || ls.length === 0) { + if (!this.buffer.has(event)) this.buffer.set(event, []); + this.buffer.get(event)!.push(payload); + return; + } + + for (const listener of ls) { + listener(payload); + } + } +} + +export default new BufferedEventBus(); diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index 6133316..0e1f08f 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -16,6 +16,7 @@ import WorkspaceList from "@/components/WorkspaceList/WorkspaceList"; import { AnimatePresence, motion } from "motion/react"; import { socket } from "@/config/socket"; import { WorkspaceMembersModified } from "@/models/workspace"; +import bufferedBus from "@/config/buffered-bus"; export const Dashboard = () => { const navigate = useNavigate(); @@ -43,6 +44,10 @@ export const Dashboard = () => { socket?.off("workspace"); }; }, []); + useEffect(() => { + socket.on("provision", (msg) => bufferedBus.emit("internal.provision.message", msg)); + return () => void socket.off("provision"); + }, []); useEffect(() => { init(); diff --git a/src/pages/Status/Status.tsx b/src/pages/Status/Status.tsx index 4ed18da..558ce65 100644 --- a/src/pages/Status/Status.tsx +++ b/src/pages/Status/Status.tsx @@ -14,6 +14,7 @@ import Button from "@/components/common/Button/Button"; import RadialProgress from "@/components/common/RadialProgress/RadialProgress"; import { AnimatePresence, motion } from "motion/react"; import { openEnv } from "@/store/env"; +import bufferedBus from "@/config/buffered-bus"; export const Status = () => { const navigate = useNavigate(); @@ -21,7 +22,7 @@ export const Status = () => { const node = useRef(null); const bound = useRef<{ first: HTMLElement | null; last: HTMLElement | null }>(null); const location = useLocation(); - const workspaceName = location.state?.workspaceName as string; + const workspaceName = usePrevious(location.state?.workspaceName); const isNew = usePrevious(location.state?.isNew); const [provStatus, setProvStatus] = useState(null); const dispatch = useAppDispatch(); @@ -30,17 +31,20 @@ export const Status = () => { const [launchBusy, setLaunchBusy] = useState(false); useEffect(() => { - if (!workspaceName) navigate("/dashboard", { replace: true }); + if (!workspaceName) { + navigate("/dashboard", { replace: true }); + return; + } + + const handleProvisionMessage = (msg: unknown) => { + setProvStatus(msg as ProvisionPayload); + }; + bufferedBus.on("internal.provision.message", handleProvisionMessage); - socket.on("provision", (msg) => { - console.log(msg); - setProvStatus(msg); - }); return () => { - console.log("De-registering provision"); - socket.off("provision"); + bufferedBus.off("internal.provision.message", handleProvisionMessage); }; - }, []); + }, [navigate, workspaceName]); const trapFocus = useCallback((event: KeyboardEvent) => { if (event.key === "Tab") {