import {
Box,
Button,
config,
Dialog,
Icon,
IconButton,
Icons,
Menu,
MenuItem,
PopOut,
RectCords,
Spinner,
Text,
} from 'folds';
import { HttpApiEvent, HttpApiEventHandlerMap, MatrixClient } from 'matrix-js-sdk';
import FocusTrap from 'focus-trap-react';
import React, { MouseEventHandler, ReactNode, useCallback, useEffect, useState } from 'react';
import {
clearCacheAndReload,
initClient,
logoutClient,
startClient,
} from '../../../client/initMatrix';
import { getSecret } from '../../../client/state/auth';
import { SplashScreen } from '../../components/splash-screen';
import { CapabilitiesAndMediaConfigLoader } from '../../components/CapabilitiesAndMediaConfigLoader';
import { CapabilitiesProvider } from '../../hooks/useCapabilities';
import { MediaConfigProvider } from '../../hooks/useMediaConfig';
import { MatrixClientProvider } from '../../hooks/useMatrixClient';
import { SpecVersions } from './SpecVersions';
import Windows from '../../organisms/pw/Windows';
import Dialogs from '../../organisms/pw/Dialogs';
import ReusableContextMenu from '../../atoms/context-menu/ReusableContextMenu';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { useSyncState } from '../../hooks/useSyncState';
import { stopPropagation } from '../../utils/keyboard';
import { SyncStatus } from './SyncStatus';
function ClientRootLoading() {
return (
Heating up
);
}
function ClientRootOptions({ mx }: { mx: MatrixClient }) {
const [menuAnchor, setMenuAnchor] = useState();
const handleToggle: MouseEventHandler = (evt) => {
const cords = evt.currentTarget.getBoundingClientRect();
setMenuAnchor((currentState) => {
if (currentState) return undefined;
return cords;
});
};
return (
setMenuAnchor(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
escapeDeactivates: stopPropagation,
}}
>
}
/>
);
}
const useLogoutListener = (mx?: MatrixClient) => {
useEffect(() => {
const handleLogout: HttpApiEventHandlerMap[HttpApiEvent.SessionLoggedOut] = async () => {
mx?.stopClient();
await mx?.clearStores();
window.localStorage.clear();
window.location.reload();
};
mx?.on(HttpApiEvent.SessionLoggedOut, handleLogout);
return () => {
mx?.removeListener(HttpApiEvent.SessionLoggedOut, handleLogout);
};
}, [mx]);
};
type ClientRootProps = {
children: ReactNode;
};
export function ClientRoot({ children }: ClientRootProps) {
const [loading, setLoading] = useState(true);
const { baseUrl } = getSecret();
const [loadState, loadMatrix] = useAsyncCallback(
useCallback(() => initClient(getSecret() as any), [])
);
const mx = loadState.status === AsyncStatus.Success ? loadState.data : undefined;
const [startState, startMatrix] = useAsyncCallback(
useCallback((m) => startClient(m), [])
);
useLogoutListener(mx);
useEffect(() => {
if (loadState.status === AsyncStatus.Idle) {
loadMatrix();
}
}, [loadState, loadMatrix]);
useEffect(() => {
if (mx && !mx.clientRunning) {
startMatrix(mx);
}
}, [mx, startMatrix]);
useSyncState(
mx,
useCallback((state) => {
if (state === 'PREPARED') {
setLoading(false);
}
}, [])
);
return (
{mx && }
{loading && mx && }
{(loadState.status === AsyncStatus.Error || startState.status === AsyncStatus.Error) && (
)}
{loading || !mx ? (
) : (
{(capabilities, mediaConfig) => (
{children}
)}
)}
);
}