57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
/**
|
|
* WorkspaceKeepAlive
|
|
*
|
|
* Renders the WorkspacePage permanently at the MainLayout level so it
|
|
* survives route changes. Visibility is toggled via CSS `display`
|
|
* instead of mount / unmount, preserving messages, SSE connections,
|
|
* files, and all other workspace state.
|
|
*
|
|
* Persistence is scoped per `(mandateId, instanceId)` — switching to a
|
|
* different mandate or instance via the navigator unmounts the previous
|
|
* page and mounts a fresh one (otherwise stale state from tenant A
|
|
* leaks into tenant B).
|
|
*/
|
|
|
|
import React, { useRef } from 'react';
|
|
import { useLocation } from 'react-router-dom';
|
|
import { WorkspacePage } from './WorkspacePage';
|
|
|
|
const _WORKSPACE_ROUTE_RE = /\/mandates\/([^/]+)\/workspace\/([^/]+)/;
|
|
|
|
interface WorkspaceKeepAliveProps {
|
|
isVisible: boolean;
|
|
}
|
|
|
|
export const WorkspaceKeepAlive: React.FC<WorkspaceKeepAliveProps> = ({ isVisible }) => {
|
|
const location = useLocation();
|
|
const cachedMandateIdRef = useRef<string>('');
|
|
const cachedInstanceIdRef = useRef<string>('');
|
|
|
|
const match = location.pathname.match(_WORKSPACE_ROUTE_RE);
|
|
if (match?.[1] && match?.[2]) {
|
|
cachedMandateIdRef.current = match[1];
|
|
cachedInstanceIdRef.current = match[2];
|
|
}
|
|
|
|
const mandateId = cachedMandateIdRef.current;
|
|
const instanceId = cachedInstanceIdRef.current;
|
|
if (!instanceId) return null;
|
|
const scopeKey = `${mandateId}:${instanceId}`;
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
display: isVisible ? 'flex' : 'none',
|
|
flexDirection: 'column',
|
|
position: 'absolute',
|
|
top: 'var(--mobile-topbar-height, 0px)',
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<WorkspacePage key={scopeKey} persistentInstanceId={instanceId} />
|
|
</div>
|
|
);
|
|
};
|