Skip to content

Commit ad39874

Browse files
authored
Merge pull request #202 from sillsdev/TT-7061
TT-7061 going offline
2 parents 83a18b2 + 1887c3c commit ad39874

File tree

7 files changed

+287
-161
lines changed

7 files changed

+287
-161
lines changed

src/renderer/src/components/App/AppHead.tsx

Lines changed: 38 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
22
import { useGetGlobal, useGlobal } from '../../context/useGlobal';
3-
import { useLocation, useParams } from 'react-router-dom';
3+
import { useLocation } from 'react-router-dom';
44
import { IState, IViewModeStrings } from '../../model';
55
import { shallowEqual, useSelector } from 'react-redux';
66
import {
77
AppBar,
8-
Toolbar,
9-
Typography,
10-
IconButton,
118
LinearProgress,
12-
Tooltip,
139
Box,
1410
} from '@mui/material';
15-
import HomeIcon from '@mui/icons-material/Home';
16-
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
17-
import TableViewIcon from '@mui/icons-material/TableView';
18-
import { API_CONFIG, isElectron } from '../../../api-variable';
11+
import { isElectron } from '../../../api-variable';
1912
import { TokenContext } from '../../context/TokenProvider';
2013
import { UnsavedContext } from '../../context/UnsavedContext';
21-
import HelpMenu from '../HelpMenu';
22-
import UserMenu from '../UserMenu';
23-
import { GrowingSpacer } from '../../control';
2414
import {
2515
resetData,
2616
exitElectronApp,
@@ -36,70 +26,18 @@ import {
3626
useMobile,
3727
} from '../../utils';
3828
import { withBucket } from '../../hoc/withBucket';
39-
import { usePlan } from '../../crud';
4029
import Busy from '../Busy';
4130
import ProjectDownloadAlert from '../ProjectDownloadAlert';
4231
import { useSnackBar } from '../../hoc/SnackBar';
4332
import PolicyDialog from '../PolicyDialog';
4433
import JSONAPISource from '@orbit/jsonapi';
4534
import { viewModeSelector } from '../../selector';
46-
import { useHome } from '../../utils/useHome';
47-
import { ApmLogo } from '../../control/ApmLogo';
48-
import { OrgHead } from './OrgHead';
49-
import { HeadStatus } from './HeadStatus';
50-
import MobileDetailTitle from './MobileDetailTitle';
35+
import { DesktopToolbar } from './DesktopToolbar';
36+
import { MobileToolbar } from './MobileToolbar';
5137

5238
const twoIcon = { minWidth: `calc(${48 * 2}px)` } as React.CSSProperties;
5339
const threeIcon = { minWidth: `calc(${48 * 3}px)` } as React.CSSProperties;
5440

55-
interface INameProps {
56-
switchTo: boolean;
57-
}
58-
59-
const ProjectName = ({ switchTo }: INameProps) => {
60-
const ctx = useContext(UnsavedContext);
61-
const { checkSavedFn } = ctx.state;
62-
const { getPlanName } = usePlan();
63-
const [plan] = useGlobal('plan'); //verified this is not used in a function 2/18/25
64-
const { prjId } = useParams();
65-
const navigate = useMyNavigate();
66-
const { goHome } = useHome();
67-
const t: IViewModeStrings = useSelector(viewModeSelector, shallowEqual);
68-
69-
const handleHome = () => {
70-
localStorage.removeItem(LocalKey.plan);
71-
localStorage.removeItem('mode');
72-
goHome();
73-
};
74-
75-
const handleAudioProject = () => {
76-
navigate(`/plan/${prjId}/0`);
77-
};
78-
79-
const checkSavedAndGoAP = () => checkSavedFn(() => handleAudioProject());
80-
const checkSavedAndGoHome = () => checkSavedFn(() => handleHome());
81-
82-
return (
83-
<>
84-
<Tooltip title={t.home}>
85-
<IconButton id="home" onClick={checkSavedAndGoHome}>
86-
<HomeIcon />
87-
</IconButton>
88-
</Tooltip>
89-
{plan && switchTo && (
90-
<Tooltip title={t.audioProject}>
91-
<IconButton id="project" onClick={checkSavedAndGoAP}>
92-
<TableViewIcon />
93-
</IconButton>
94-
</Tooltip>
95-
)}
96-
<Typography variant="h6" noWrap>
97-
{getPlanName(plan)}
98-
</Typography>
99-
</>
100-
);
101-
};
102-
10341
type ResetRequests = () => Promise<void>;
10442

10543
interface IProps {
@@ -282,12 +220,6 @@ export const AppHead = (props: IProps) => {
282220
return undefined;
283221
};
284222

285-
const handleTeamNav = () => {
286-
checkSavedFn(() => navigate('/team'));
287-
};
288-
289-
const handlePlanNav = () => checkSavedFn(() => navigate(planUrl || '/team'));
290-
291223
useEffect(() => {
292224
window.addEventListener('beforeunload', handleUnload);
293225
if (!user) {
@@ -348,7 +280,9 @@ export const AppHead = (props: IProps) => {
348280
if (view === 'Terms') navigate('/terms');
349281
if (view === 'Privacy') navigate('/privacy');
350282

351-
return !isMobileView && !isMobileWidth ? (
283+
const isMobile = isMobileView || isMobileWidth;
284+
285+
return (
352286
<AppBar
353287
position="fixed"
354288
sx={{ width: '100%', display: 'flex' }}
@@ -363,95 +297,41 @@ export const AppHead = (props: IProps) => {
363297
{(!busy && !saving && !dataChangeCount) || complete !== 0 || (
364298
<LinearProgress id="busy" variant="indeterminate" />
365299
)}
366-
<Toolbar>
367-
{!home && orgRole && (
368-
<>
369-
<ProjectName switchTo={switchTo ?? false} />
370-
<GrowingSpacer />
371-
<Typography variant="h6">
372-
{switchTo ? tv.work : tv.audioProject}
373-
</Typography>
374-
<GrowingSpacer />
375-
</>
376-
)}
377-
{home && <span style={cssVars}>{'\u00A0'}</span>}
378-
<GrowingSpacer />
379-
{(pathname === '/' || pathname.startsWith('/access')) && (
380-
<>
381-
<Typography variant="h6" noWrap>
382-
{API_CONFIG.productName}
383-
</Typography>
384-
<GrowingSpacer />
385-
</>
386-
)}
387-
{'\u00A0'}
388-
<HeadStatus
300+
301+
{isMobile ? (
302+
<MobileToolbar
303+
isDetail={isDetail}
304+
planUrl={planUrl}
305+
navigate={navigate}
306+
isMobileWidth={isMobileWidth}
389307
handleMenu={handleMenu}
390-
onVersion={setVersion}
391-
onLatestVersion={setLatestVersion}
392-
onUpdateTipOpen={setUpdateTipOpen}
393-
/>
394-
<HelpMenu
395-
online={!isOffline}
396-
sx={updateTipOpen && isElectron ? { top: '40px' } : {}}
308+
setVersion={setVersion}
309+
setLatestVersion={setLatestVersion}
310+
setUpdateTipOpen={setUpdateTipOpen}
311+
isOffline={isOffline}
312+
updateTipOpen={updateTipOpen}
313+
pathname={pathname}
314+
handleUserMenu={handleUserMenu}
397315
/>
398-
{pathname !== '/' && !pathname.startsWith('/access') && (
399-
<UserMenu action={handleUserMenu} />
400-
)}
401-
</Toolbar>
402-
{!importexportBusy || <Busy />}
403-
{downloadAlert && <ProjectDownloadAlert cb={downDone} />}
404-
<PolicyDialog
405-
isOpen={Boolean(showTerms)}
406-
content={showTerms}
407-
onClose={handleTermsClose}
408-
/>
409-
</>
410-
</AppBar>
411-
) : (
412-
<AppBar
413-
position="fixed"
414-
sx={{ width: '100%', display: 'flex' }}
415-
color="inherit"
416-
>
417-
<>
418-
<Toolbar>
419-
{!isDetail ? (
420-
<IconButton onClick={handleTeamNav} sx={{ p: 0 }}>
421-
<ApmLogo sx={{ width: '24px', height: '24px' }} />
422-
</IconButton>
423-
) : (
424-
<IconButton onClick={handlePlanNav}>
425-
<ArrowBackIcon sx={{ width: '24px', height: '24px' }} />
426-
</IconButton>
427-
)}
428-
{isDetail ? <MobileDetailTitle /> : <OrgHead />}
429-
<GrowingSpacer />
430-
{!isMobileWidth && (
431-
<HeadStatus
432-
handleMenu={handleMenu}
433-
onVersion={setVersion}
434-
onLatestVersion={setLatestVersion}
435-
onUpdateTipOpen={setUpdateTipOpen}
436-
/>
437-
)}
438-
<HelpMenu
439-
online={!isOffline}
440-
sx={updateTipOpen && isElectron ? { top: '40px' } : {}}
316+
) : (
317+
<DesktopToolbar
318+
switchTo={switchTo}
319+
home={home}
320+
orgRole={orgRole}
321+
cssVars={cssVars}
322+
pathname={pathname}
323+
handleMenu={handleMenu}
324+
setVersion={setVersion}
325+
setLatestVersion={setLatestVersion}
326+
setUpdateTipOpen={setUpdateTipOpen}
327+
isOffline={isOffline}
328+
updateTipOpen={updateTipOpen}
329+
handleUserMenu={handleUserMenu}
330+
tv={tv}
441331
/>
442-
{pathname !== '/' && !pathname.startsWith('/access') && (
443-
<UserMenu action={handleUserMenu} small={true} />
444-
)}
445-
</Toolbar>
446-
{complete === 0 || complete === 100 || (
447-
<Box sx={{ width: '100%' }}>
448-
<LinearProgress id="prog" variant="determinate" value={complete} />
449-
</Box>
450332
)}
451-
{(!busy && !saving && !dataChangeCount) || complete !== 0 || (
452-
<LinearProgress id="busy" variant="indeterminate" />
453-
)}
454-
{!importexportBusy || <Busy />}
333+
{importexportBusy && !downloadAlert && <Busy />}
334+
{downloadAlert && <ProjectDownloadAlert cb={downDone} />}
455335
<PolicyDialog
456336
isOpen={Boolean(showTerms)}
457337
content={showTerms}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import React, { useContext } from 'react';
2+
import { useGlobal } from '../../context/useGlobal';
3+
import { useParams } from 'react-router-dom';
4+
import { IViewModeStrings, RoleNames } from '../../model';
5+
import { shallowEqual, useSelector } from 'react-redux';
6+
import { Toolbar, Typography, IconButton, Tooltip } from '@mui/material';
7+
import HomeIcon from '@mui/icons-material/Home';
8+
import TableViewIcon from '@mui/icons-material/TableView';
9+
import { API_CONFIG, isElectron } from '../../../api-variable';
10+
import { UnsavedContext } from '../../context/UnsavedContext';
11+
import HelpMenu from '../HelpMenu';
12+
import UserMenu from '../UserMenu';
13+
import { GrowingSpacer } from '../../control';
14+
import { LocalKey, useMyNavigate } from '../../utils';
15+
import { usePlan } from '../../crud';
16+
import { viewModeSelector } from '../../selector';
17+
import { useHome } from '../../utils/useHome';
18+
import { HeadStatus } from './HeadStatus';
19+
import { type DownloadAlertReason } from './AppHead';
20+
21+
interface INameProps {
22+
switchTo: boolean;
23+
}
24+
25+
const ProjectName = ({ switchTo }: INameProps) => {
26+
const ctx = useContext(UnsavedContext);
27+
const { checkSavedFn } = ctx.state;
28+
const { getPlanName } = usePlan();
29+
const [plan] = useGlobal('plan'); //verified this is not used in a function 2/18/25
30+
const { prjId } = useParams();
31+
const navigate = useMyNavigate();
32+
const { goHome } = useHome();
33+
const t: IViewModeStrings = useSelector(viewModeSelector, shallowEqual);
34+
35+
const handleHome = () => {
36+
localStorage.removeItem(LocalKey.plan);
37+
localStorage.removeItem('mode');
38+
goHome();
39+
};
40+
41+
const handleAudioProject = () => {
42+
navigate(`/plan/${prjId}/0`);
43+
};
44+
45+
const checkSavedAndGoAP = () => checkSavedFn(() => handleAudioProject());
46+
const checkSavedAndGoHome = () => checkSavedFn(() => handleHome());
47+
48+
return (
49+
<>
50+
<Tooltip title={t.home}>
51+
<IconButton id="home" onClick={checkSavedAndGoHome}>
52+
<HomeIcon />
53+
</IconButton>
54+
</Tooltip>
55+
{plan && switchTo && (
56+
<Tooltip title={t.audioProject}>
57+
<IconButton id="project" onClick={checkSavedAndGoAP}>
58+
<TableViewIcon />
59+
</IconButton>
60+
</Tooltip>
61+
)}
62+
<Typography variant="h6" noWrap>
63+
{getPlanName(plan)}
64+
</Typography>
65+
</>
66+
);
67+
};
68+
69+
export interface DesktopToolbarProps {
70+
switchTo?: boolean;
71+
home: boolean;
72+
orgRole: RoleNames | undefined;
73+
cssVars: React.CSSProperties;
74+
pathname: string;
75+
handleMenu: (what: string, reason?: DownloadAlertReason | null) => void;
76+
setVersion: (version: string) => void;
77+
setLatestVersion: (version: string) => void;
78+
setUpdateTipOpen: (open: boolean) => void;
79+
isOffline: boolean;
80+
updateTipOpen: boolean;
81+
handleUserMenu: (what: string) => void;
82+
tv: IViewModeStrings;
83+
}
84+
85+
export const DesktopToolbar = ({
86+
switchTo,
87+
home,
88+
orgRole,
89+
cssVars,
90+
pathname,
91+
handleMenu,
92+
setVersion,
93+
setLatestVersion,
94+
setUpdateTipOpen,
95+
isOffline,
96+
updateTipOpen,
97+
handleUserMenu,
98+
tv,
99+
}: DesktopToolbarProps) => {
100+
return (
101+
<Toolbar>
102+
{!home && orgRole && (
103+
<>
104+
<ProjectName switchTo={switchTo ?? false} />
105+
<GrowingSpacer />
106+
<Typography variant="h6">
107+
{switchTo ? tv.work : tv.audioProject}
108+
</Typography>
109+
<GrowingSpacer />
110+
</>
111+
)}
112+
{home && <span style={cssVars}>{'\u00A0'}</span>}
113+
<GrowingSpacer />
114+
{(pathname === '/' || pathname.startsWith('/access')) && (
115+
<>
116+
<Typography variant="h6" noWrap>
117+
{API_CONFIG.productName}
118+
</Typography>
119+
<GrowingSpacer />
120+
</>
121+
)}
122+
{'\u00A0'}
123+
<HeadStatus
124+
handleMenu={handleMenu}
125+
onVersion={setVersion}
126+
onLatestVersion={setLatestVersion}
127+
onUpdateTipOpen={setUpdateTipOpen}
128+
/>
129+
<HelpMenu
130+
online={!isOffline}
131+
sx={updateTipOpen && isElectron ? { top: '40px' } : {}}
132+
/>
133+
{pathname !== '/' && !pathname.startsWith('/access') && (
134+
<UserMenu action={handleUserMenu} />
135+
)}
136+
</Toolbar>
137+
);
138+
};

0 commit comments

Comments
 (0)