import {
DesktopWindows as DesktopWindowsIcon,
PowerSettingsNewOutlined as PowerSettingsNewOutlinedIcon,
} from '@mui/icons-material';
import {
Box,
IconButton as MUIIconButton,
IconButtonProps as MUIIconButtonProps,
} from '@mui/material';
import { FC, ReactNode, useEffect, useMemo, useState } from 'react';
import {
BORDER_RADIUS,
GREY,
UNSELECTED,
} from '../../lib/consts/DEFAULT_THEME';
import api from '../../lib/api';
import FlexBox from '../FlexBox';
import IconButton, { IconButtonProps } from '../IconButton';
import { InnerPanel, InnerPanelHeader, Panel, PanelHeader } from '../Panels';
import ServerMenu from '../ServerMenu';
import Spinner from '../Spinner';
import { BodyText, HeaderText } from '../Text';
import { elapsed, last, now } from '../../lib/time';
type PreviewOptionalProps = {
externalPreview?: string;
externalTimestamp?: number;
headerEndAdornment?: ReactNode;
hrefPreview?: string;
isExternalLoading?: boolean;
isExternalPreviewStale?: boolean;
isFetchPreview?: boolean;
isShowControls?: boolean;
isUseInnerPanel?: boolean;
onClickConnectButton?: IconButtonProps['onClick'];
onClickPreview?: MUIIconButtonProps['onClick'];
serverName?: string;
serverState?: string;
};
type PreviewProps = PreviewOptionalProps & {
serverUUID: string;
};
const PREVIEW_DEFAULT_PROPS: Required<
Omit<
PreviewOptionalProps,
'hrefPreview' | 'onClickConnectButton' | 'onClickPreview'
>
> &
Pick<
PreviewOptionalProps,
'hrefPreview' | 'onClickConnectButton' | 'onClickPreview'
> = {
externalPreview: '',
externalTimestamp: 0,
headerEndAdornment: null,
hrefPreview: undefined,
isExternalLoading: false,
isExternalPreviewStale: false,
isFetchPreview: true,
isShowControls: true,
isUseInnerPanel: false,
onClickConnectButton: undefined,
onClickPreview: undefined,
serverName: '',
serverState: '',
};
const PreviewPanel: FC<{ isUseInnerPanel: boolean }> = ({
children,
isUseInnerPanel,
}) =>
isUseInnerPanel ? (
{children}
) : (
{children}
);
const PreviewPanelHeader: FC<{
isUseInnerPanel: boolean;
text: string | undefined;
}> = ({ children, isUseInnerPanel, text }) =>
isUseInnerPanel ? (
{text ? : <>>}
{children}
) : (
{text ? : <>>}
{children}
);
const Preview: FC = ({
externalPreview = PREVIEW_DEFAULT_PROPS.externalPreview,
externalTimestamp = PREVIEW_DEFAULT_PROPS.externalTimestamp,
headerEndAdornment,
hrefPreview,
isExternalLoading = PREVIEW_DEFAULT_PROPS.isExternalLoading,
isExternalPreviewStale = PREVIEW_DEFAULT_PROPS.isExternalPreviewStale,
isFetchPreview = PREVIEW_DEFAULT_PROPS.isFetchPreview,
isShowControls = PREVIEW_DEFAULT_PROPS.isShowControls,
isUseInnerPanel = PREVIEW_DEFAULT_PROPS.isUseInnerPanel,
onClickPreview: previewClickHandler,
serverName = PREVIEW_DEFAULT_PROPS.serverName,
serverState = PREVIEW_DEFAULT_PROPS.serverState,
serverUUID,
onClickConnectButton: connectButtonClickHandle = previewClickHandler,
}) => {
const [isPreviewLoading, setIsPreviewLoading] = useState(true);
const [isPreviewStale, setIsPreviewStale] = useState(false);
const [preview, setPreview] = useState('');
const [previewTimstamp, setPreviewTimestamp] = useState(0);
const nao = now();
const previewButtonContent = useMemo(
() =>
serverState === 'running' ? (
<>
{isPreviewStale &&
((sst: number) => {
const { unit, value } = elapsed(nao - sst);
return (
Updated ~{value} {unit} ago
);
})(previewTimstamp)}
>
) : (
),
[
isPreviewStale,
isUseInnerPanel,
nao,
preview,
previewTimstamp,
serverState,
],
);
const iconButton = useMemo(() => {
if (isPreviewLoading) {
return ;
}
const disabled = !preview;
const sx: MUIIconButtonProps['sx'] = {
borderRadius: BORDER_RADIUS,
color: GREY,
padding: 0,
};
if (hrefPreview) {
return (
{previewButtonContent}
);
}
return (
{previewButtonContent}
);
}, [
hrefPreview,
isPreviewLoading,
preview,
previewButtonContent,
previewClickHandler,
]);
useEffect(() => {
if (isFetchPreview) {
(async () => {
try {
const { data } = await api.get<{
screenshot: string;
timestamp: number;
}>(`/server/${serverUUID}?ss=1`);
const { screenshot, timestamp } = data;
setPreview(screenshot);
setPreviewTimestamp(timestamp);
setIsPreviewStale(!last(timestamp, 300));
} catch {
setIsPreviewStale(true);
} finally {
setIsPreviewLoading(false);
}
})();
} else if (!isExternalLoading) {
setPreview(externalPreview);
setPreviewTimestamp(externalTimestamp);
setIsPreviewStale(isExternalPreviewStale);
setIsPreviewLoading(false);
}
}, [
externalPreview,
externalTimestamp,
isExternalLoading,
isExternalPreviewStale,
isFetchPreview,
serverUUID,
]);
return (
{headerEndAdornment}
:first-child': { flexGrow: 1 } }}>
{/* Box wrapper below is required to keep external preview size sane. */}
{iconButton}
{isShowControls && preview && (
)}
);
};
Preview.defaultProps = PREVIEW_DEFAULT_PROPS;
export default Preview;