2022-10-28 13:17:40 -07:00
|
|
|
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
|
|
/* eslint-disable jsx-a11y/anchor-has-content */
|
|
|
|
|
2022-01-23 10:21:45 -08:00
|
|
|
import {
|
|
|
|
useCallback,
|
|
|
|
useEffect,
|
2022-02-07 13:12:26 -08:00
|
|
|
useMemo,
|
2022-10-28 13:17:40 -07:00
|
|
|
useRef,
|
2022-01-23 10:21:45 -08:00
|
|
|
} from 'react';
|
2021-03-22 14:29:03 -07:00
|
|
|
import {
|
|
|
|
useLocation,
|
2022-01-25 12:18:04 -08:00
|
|
|
useNavigate,
|
2022-01-09 14:33:38 -08:00
|
|
|
Link,
|
|
|
|
generatePath,
|
2022-01-25 12:18:04 -08:00
|
|
|
useMatch,
|
2022-01-09 14:33:38 -08:00
|
|
|
} from 'react-router-dom';
|
2021-03-22 14:29:03 -07:00
|
|
|
import {
|
|
|
|
Layout,
|
|
|
|
Space,
|
|
|
|
Button,
|
|
|
|
Row,
|
|
|
|
Col,
|
|
|
|
Tooltip,
|
|
|
|
Grid,
|
|
|
|
Menu,
|
|
|
|
Dropdown,
|
|
|
|
Typography,
|
|
|
|
Radio,
|
|
|
|
} from 'antd';
|
|
|
|
import {
|
|
|
|
UserOutlined,
|
|
|
|
CloudUploadOutlined,
|
|
|
|
CloudDownloadOutlined,
|
|
|
|
SettingOutlined,
|
|
|
|
LoginOutlined,
|
|
|
|
LineChartOutlined,
|
|
|
|
SlidersOutlined,
|
|
|
|
FileZipOutlined,
|
|
|
|
DesktopOutlined,
|
|
|
|
DownOutlined,
|
|
|
|
SearchOutlined,
|
2021-03-22 15:24:39 -07:00
|
|
|
ToolOutlined,
|
|
|
|
FundOutlined,
|
2021-12-25 14:32:07 -08:00
|
|
|
UserAddOutlined,
|
|
|
|
LogoutOutlined,
|
2022-01-16 09:32:55 -08:00
|
|
|
InfoCircleOutlined,
|
2022-01-24 13:59:21 -08:00
|
|
|
CarOutlined,
|
2022-10-28 13:17:40 -07:00
|
|
|
FileTextOutlined,
|
|
|
|
FileExcelOutlined,
|
2021-03-22 14:29:03 -07:00
|
|
|
} from '@ant-design/icons';
|
2022-01-23 10:21:45 -08:00
|
|
|
import { useKBar } from 'kbar';
|
2021-03-22 14:29:03 -07:00
|
|
|
import store from '../store';
|
2022-03-12 03:00:13 -08:00
|
|
|
import { isMac } from '../utils/env';
|
|
|
|
import { isToggleSidebar } from '../utils/keyboard/shortcuts';
|
2021-03-22 14:29:03 -07:00
|
|
|
import { Routes } from '../routes';
|
2021-12-25 14:32:07 -08:00
|
|
|
import { useAuth } from '../contexts/AuthContext';
|
2022-10-17 13:28:33 -07:00
|
|
|
import { logOutSuccessful } from '../pages/auth/notifications';
|
2022-10-19 14:24:45 -07:00
|
|
|
import { TuneDataState } from '../types/state';
|
2022-10-28 13:17:40 -07:00
|
|
|
import { removeFilenameSuffix } from '../pocketbase';
|
|
|
|
import useServerStorage from '../hooks/useServerStorage';
|
2021-03-22 14:29:03 -07:00
|
|
|
|
|
|
|
const { Header } = Layout;
|
|
|
|
const { useBreakpoint } = Grid;
|
2022-10-28 13:17:40 -07:00
|
|
|
|
|
|
|
const logsExtensionsIcons: { [key: string]: any } = {
|
|
|
|
'mlg': <FileZipOutlined />,
|
|
|
|
'msl': <FileTextOutlined />,
|
|
|
|
'csv': <FileExcelOutlined />,
|
|
|
|
};
|
2021-03-22 14:29:03 -07:00
|
|
|
|
2022-10-19 14:24:45 -07:00
|
|
|
const TopBar = ({
|
|
|
|
tuneData,
|
|
|
|
}: {
|
|
|
|
tuneData: TuneDataState | null;
|
|
|
|
}) => {
|
2022-07-17 13:15:06 -07:00
|
|
|
const { xs, sm, lg } = useBreakpoint();
|
2021-03-22 14:29:03 -07:00
|
|
|
const { pathname } = useLocation();
|
2021-12-25 14:32:07 -08:00
|
|
|
const { currentUser, logout } = useAuth();
|
2022-01-25 12:18:04 -08:00
|
|
|
const navigate = useNavigate();
|
2022-01-23 10:21:45 -08:00
|
|
|
const { query } = useKBar();
|
2022-10-19 14:24:45 -07:00
|
|
|
const buildTuneUrl = useCallback((route: string) => tuneData?.tuneId ? generatePath(route, { tuneId: tuneData.tuneId }) : null, [tuneData?.tuneId]);
|
2022-02-13 14:14:28 -08:00
|
|
|
const hubPathMatch = useMatch(Routes.HUB);
|
2022-01-25 12:18:04 -08:00
|
|
|
const tuneRootMatch = useMatch(`${Routes.TUNE_ROOT}/*`);
|
|
|
|
const tuneTuneMatch = useMatch(`${Routes.TUNE_TUNE}/*`);
|
2022-10-18 12:40:53 -07:00
|
|
|
const tuneLogMatch = useMatch(`${Routes.TUNE_LOGS}/*`);
|
2022-10-19 05:47:47 -07:00
|
|
|
const toothLogMatch = useMatch(`${Routes.TUNE_DIAGNOSE}/*`);
|
2022-01-25 12:18:04 -08:00
|
|
|
const tabMatch = useMatch(`${Routes.TUNE_TAB}/*`);
|
|
|
|
const uploadMatch = useMatch(Routes.UPLOAD);
|
2022-02-13 14:14:28 -08:00
|
|
|
const hubMatch = useMatch(Routes.HUB);
|
2022-10-28 13:17:40 -07:00
|
|
|
const { downloadFile } = useServerStorage();
|
|
|
|
const downloadAnchorRef = useRef<HTMLAnchorElement | null>(null);
|
2022-10-17 13:28:33 -07:00
|
|
|
const logoutClick = useCallback(() => {
|
|
|
|
logout();
|
|
|
|
logOutSuccessful();
|
|
|
|
navigate(Routes.HUB);
|
2022-02-13 14:14:28 -08:00
|
|
|
}, [logout, navigate]);
|
2021-03-22 14:29:03 -07:00
|
|
|
|
2022-01-23 10:21:45 -08:00
|
|
|
const toggleCommandPalette = useCallback(() => query.toggle(), [query]);
|
|
|
|
|
|
|
|
const handleGlobalKeyboard = useCallback((e: KeyboardEvent) => {
|
2021-03-22 14:29:03 -07:00
|
|
|
if (isToggleSidebar(e)) {
|
|
|
|
e.preventDefault();
|
|
|
|
store.dispatch({ type: 'ui/toggleSidebar' });
|
|
|
|
}
|
2022-03-12 03:00:13 -08:00
|
|
|
}, []);
|
2022-01-23 10:21:45 -08:00
|
|
|
|
2022-10-28 13:17:40 -07:00
|
|
|
const downloadLogsItems = {
|
|
|
|
label: 'Logs',
|
|
|
|
icon: <LineChartOutlined />,
|
|
|
|
key: 'logs',
|
|
|
|
children: (tuneData?.logFiles || []).map((filename) => ({
|
|
|
|
key: filename,
|
|
|
|
label: removeFilenameSuffix(filename),
|
|
|
|
icon: logsExtensionsIcons[filename.slice(-3)],
|
|
|
|
onClick: () => downloadFile(tuneData!.id, filename, downloadAnchorRef.current!),
|
|
|
|
})),
|
|
|
|
};
|
|
|
|
|
|
|
|
const downloadToothLogsItems = {
|
|
|
|
label: 'Tooth logs',
|
|
|
|
icon: <SettingOutlined />,
|
|
|
|
key: 'toothLogs',
|
|
|
|
children: (tuneData?.toothLogFiles || []).map((filename) => ({
|
|
|
|
key: filename,
|
|
|
|
label: removeFilenameSuffix(filename),
|
|
|
|
icon: logsExtensionsIcons[filename.slice(-3)],
|
|
|
|
onClick: () => downloadFile(tuneData!.id, filename, downloadAnchorRef.current!),
|
|
|
|
})),
|
|
|
|
};
|
|
|
|
|
|
|
|
const downloadItems = [
|
|
|
|
{
|
|
|
|
label: 'Tune',
|
|
|
|
icon: <SlidersOutlined />,
|
|
|
|
key: 'tune',
|
|
|
|
children: [
|
|
|
|
{
|
|
|
|
label: 'Download',
|
|
|
|
icon: <FileTextOutlined />,
|
|
|
|
key: 'download',
|
|
|
|
onClick: () => downloadFile(tuneData!.id, tuneData!.tuneFile, downloadAnchorRef.current!),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Open in app',
|
|
|
|
icon: <DesktopOutlined />,
|
|
|
|
key: 'open',
|
2022-10-28 13:48:57 -07:00
|
|
|
disabled: true,
|
2022-10-28 13:17:40 -07:00
|
|
|
onClick: () => window.open(`hypertuner://hypertuner.cloud/t/${tuneData!.tuneId}`, '_blank'),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
(tuneData?.logFiles || []).length > 0 ? { ...downloadLogsItems } : null,
|
|
|
|
(tuneData?.toothLogFiles || []).length > 0 ? { ...downloadToothLogsItems } : null,
|
|
|
|
];
|
|
|
|
|
2021-03-22 14:29:03 -07:00
|
|
|
useEffect(() => {
|
|
|
|
document.addEventListener('keydown', handleGlobalKeyboard);
|
|
|
|
|
|
|
|
return () => document.removeEventListener('keydown', handleGlobalKeyboard);
|
2022-04-02 08:26:11 -07:00
|
|
|
}, [currentUser, handleGlobalKeyboard]);
|
2021-03-22 14:29:03 -07:00
|
|
|
|
2022-02-07 13:12:26 -08:00
|
|
|
const tabs = useMemo(() => (
|
2022-02-13 14:14:28 -08:00
|
|
|
<Col span={16} md={16} sm={16}>
|
2022-01-09 14:33:38 -08:00
|
|
|
<Radio.Group
|
|
|
|
key={pathname}
|
2022-10-19 05:47:47 -07:00
|
|
|
defaultValue={tuneLogMatch?.pathnameBase || toothLogMatch?.pathnameBase || tuneTuneMatch?.pathnameBase || tabMatch?.pathname || tuneRootMatch?.pathname || hubPathMatch?.pathname}
|
2022-01-09 14:33:38 -08:00
|
|
|
optionType="button"
|
|
|
|
buttonStyle="solid"
|
2022-01-25 12:18:04 -08:00
|
|
|
onChange={(e) => navigate(e.target.value)}
|
2022-01-09 14:33:38 -08:00
|
|
|
>
|
2022-02-13 14:14:28 -08:00
|
|
|
<Radio.Button value={buildTuneUrl(Routes.HUB)}>
|
2022-01-24 13:59:21 -08:00
|
|
|
<Space>
|
|
|
|
<CarOutlined />
|
|
|
|
{lg && 'Hub'}
|
|
|
|
</Space>
|
|
|
|
</Radio.Button>
|
2022-01-16 09:32:55 -08:00
|
|
|
<Radio.Button value={buildTuneUrl(Routes.TUNE_ROOT)}>
|
|
|
|
<Space>
|
|
|
|
<InfoCircleOutlined />
|
2022-01-24 13:59:21 -08:00
|
|
|
{lg && 'Info'}
|
2022-01-16 09:32:55 -08:00
|
|
|
</Space>
|
|
|
|
</Radio.Button>
|
2022-01-09 14:33:38 -08:00
|
|
|
<Radio.Button value={buildTuneUrl(Routes.TUNE_TUNE)}>
|
|
|
|
<Space>
|
|
|
|
<ToolOutlined />
|
2022-01-24 13:59:21 -08:00
|
|
|
{lg && 'Tune'}
|
2022-01-09 14:33:38 -08:00
|
|
|
</Space>
|
|
|
|
</Radio.Button>
|
2022-10-19 14:24:45 -07:00
|
|
|
<Radio.Button value={buildTuneUrl(Routes.TUNE_LOGS)} disabled={(tuneData?.logFiles || []).length === 0}>
|
2022-01-09 14:33:38 -08:00
|
|
|
<Space>
|
|
|
|
<FundOutlined />
|
2022-01-24 13:59:21 -08:00
|
|
|
{lg && 'Logs'}
|
2022-01-09 14:33:38 -08:00
|
|
|
</Space>
|
|
|
|
</Radio.Button>
|
2022-10-19 14:24:45 -07:00
|
|
|
<Radio.Button value={buildTuneUrl(Routes.TUNE_DIAGNOSE)} disabled={(tuneData?.toothLogFiles || []).length === 0}>
|
2022-01-09 14:33:38 -08:00
|
|
|
<Space>
|
|
|
|
<SettingOutlined />
|
2022-01-24 13:59:21 -08:00
|
|
|
{lg && 'Diagnose'}
|
2022-01-09 14:33:38 -08:00
|
|
|
</Space>
|
|
|
|
</Radio.Button>
|
|
|
|
</Radio.Group>
|
|
|
|
</Col>
|
2022-10-19 14:24:45 -07:00
|
|
|
), [pathname, tuneLogMatch?.pathnameBase, toothLogMatch?.pathnameBase, tuneTuneMatch?.pathnameBase, tabMatch?.pathname, tuneRootMatch?.pathname, hubPathMatch?.pathname, buildTuneUrl, lg, tuneData?.logFiles, tuneData?.toothLogFiles, navigate]);
|
2022-01-09 14:33:38 -08:00
|
|
|
|
2022-10-19 14:24:45 -07:00
|
|
|
const rightMenuColProps = tuneData?.tuneId ? {
|
2022-02-07 13:12:26 -08:00
|
|
|
span: 8,
|
2022-01-23 10:21:45 -08:00
|
|
|
md: 8,
|
|
|
|
sm: 8,
|
|
|
|
} : {
|
|
|
|
span: 14,
|
|
|
|
md: 10,
|
|
|
|
sm: 8,
|
|
|
|
};
|
|
|
|
|
2022-02-07 13:12:26 -08:00
|
|
|
const downloadButton = useMemo(() => {
|
|
|
|
const list = [];
|
|
|
|
|
|
|
|
if (lg) {
|
2022-02-07 13:31:26 -08:00
|
|
|
list.push(<span key="download-text">Download</span>);
|
2022-02-07 13:12:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sm) {
|
2022-02-07 13:31:26 -08:00
|
|
|
list.push(<DownOutlined key="download-icon" />);
|
2022-02-07 13:12:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return list.length ? list : null;
|
|
|
|
}, [lg, sm]);
|
|
|
|
|
2022-10-29 10:48:21 -07:00
|
|
|
const userAuthMenuItems = useMemo(() => currentUser ? [{
|
2022-07-17 11:55:10 -07:00
|
|
|
key: 'profile',
|
|
|
|
icon: <UserOutlined />,
|
|
|
|
label: 'Profile',
|
|
|
|
onClick: () => navigate(Routes.PROFILE),
|
|
|
|
}, {
|
|
|
|
key: 'logout',
|
|
|
|
icon: <LogoutOutlined />,
|
|
|
|
label: 'Logout',
|
|
|
|
onClick: logoutClick,
|
|
|
|
}] : [{
|
|
|
|
key: 'login',
|
|
|
|
icon: <LoginOutlined />,
|
|
|
|
label: 'Login',
|
|
|
|
onClick: () => navigate(Routes.LOGIN),
|
|
|
|
}, {
|
|
|
|
key: 'sign-up',
|
|
|
|
icon: <UserAddOutlined />,
|
|
|
|
label: 'Sign Up',
|
|
|
|
onClick: () => navigate(Routes.SIGN_UP),
|
|
|
|
}], [currentUser, logoutClick, navigate]);
|
|
|
|
|
2022-10-29 10:48:21 -07:00
|
|
|
const userMenuItems = [
|
|
|
|
...userAuthMenuItems,
|
|
|
|
{
|
|
|
|
key: 'divider',
|
|
|
|
type: 'divider',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'about',
|
|
|
|
icon: <InfoCircleOutlined />,
|
|
|
|
label: 'About',
|
|
|
|
onClick: () => navigate(Routes.ABOUT),
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2021-03-22 14:29:03 -07:00
|
|
|
return (
|
2022-10-17 13:28:33 -07:00
|
|
|
<Header className="app-top-bar" style={xs ? { padding: '0 5px' } : {}}>
|
2021-03-22 14:29:03 -07:00
|
|
|
<Row>
|
2022-10-19 14:24:45 -07:00
|
|
|
{tuneData?.tuneId ? tabs : (
|
2022-02-13 14:14:28 -08:00
|
|
|
<Col span={10} md={14} sm={16}>
|
|
|
|
<Link to={Routes.HUB}>
|
|
|
|
<Button icon={<CarOutlined />} type={hubMatch ? 'primary' : 'default'}>Hub</Button>
|
|
|
|
</Link>
|
|
|
|
</Col>
|
|
|
|
)}
|
2022-01-23 10:21:45 -08:00
|
|
|
<Col {...rightMenuColProps} style={{ textAlign: 'right' }}>
|
2021-12-13 13:53:59 -08:00
|
|
|
<Space>
|
2022-01-23 10:21:45 -08:00
|
|
|
{sm && <Tooltip title={
|
2022-03-12 03:00:13 -08:00
|
|
|
<>
|
|
|
|
<Typography.Text keyboard>{isMac ? '⌘' : 'CTRL'}</Typography.Text>
|
|
|
|
<Typography.Text keyboard>K</Typography.Text>
|
|
|
|
</>
|
2021-03-22 14:29:03 -07:00
|
|
|
}>
|
2022-01-23 10:21:45 -08:00
|
|
|
<Button icon={<SearchOutlined />} onClick={toggleCommandPalette} />
|
2022-01-16 09:53:36 -08:00
|
|
|
</Tooltip>}
|
2022-01-02 13:25:52 -08:00
|
|
|
<Link to={Routes.UPLOAD}>
|
2022-01-25 12:18:04 -08:00
|
|
|
<Button icon={<CloudUploadOutlined />} type={uploadMatch ? 'primary' : 'default'}>
|
2022-01-02 13:25:52 -08:00
|
|
|
{lg && 'Upload'}
|
|
|
|
</Button>
|
|
|
|
</Link>
|
2022-10-28 13:17:40 -07:00
|
|
|
{tuneData?.tuneId && <Dropdown
|
2022-01-02 13:25:52 -08:00
|
|
|
overlay={
|
2022-10-28 13:17:40 -07:00
|
|
|
<Menu triggerSubMenuAction="click" items={downloadItems} />
|
2022-01-02 13:25:52 -08:00
|
|
|
}
|
2022-04-02 08:26:11 -07:00
|
|
|
placement="bottom"
|
2021-03-23 12:36:06 -07:00
|
|
|
trigger={['click']}
|
2021-03-22 14:29:03 -07:00
|
|
|
>
|
2022-01-02 13:25:52 -08:00
|
|
|
<Button icon={<CloudDownloadOutlined />}>
|
2022-02-07 13:12:26 -08:00
|
|
|
{downloadButton}
|
2021-03-22 14:29:03 -07:00
|
|
|
</Button>
|
2022-10-28 13:17:40 -07:00
|
|
|
</Dropdown>}
|
2021-03-22 14:29:03 -07:00
|
|
|
<Dropdown
|
2022-07-17 11:55:10 -07:00
|
|
|
overlay={<Menu items={userMenuItems} />}
|
|
|
|
placement="bottomRight"
|
2021-03-23 12:36:06 -07:00
|
|
|
trigger={['click']}
|
2021-03-22 14:29:03 -07:00
|
|
|
>
|
|
|
|
<Button icon={<UserOutlined />}>
|
2022-01-16 09:53:36 -08:00
|
|
|
{sm && <DownOutlined />}
|
2021-03-22 14:29:03 -07:00
|
|
|
</Button>
|
|
|
|
</Dropdown>
|
2022-10-28 13:17:40 -07:00
|
|
|
{/* dummy anchor for file download */}
|
|
|
|
<a ref={downloadAnchorRef} style={{ display: 'none' }} />
|
2021-03-22 14:29:03 -07:00
|
|
|
</Space>
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
</Header>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default TopBar;
|