-
Matiss Janis Aboltins authoredMatiss Janis Aboltins authored
ManagementApp.jsx 6.23 KiB
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { Navigate, BrowserRouter, Route, Routes } from 'react-router-dom';
import { useActions } from '../../hooks/useActions';
import { theme } from '../../style';
import { tokens } from '../../tokens';
import { ExposeNavigate } from '../../util/router-tools';
import { Text } from '../common/Text';
import { View } from '../common/View';
import { LoggedInUser } from '../LoggedInUser';
import { Notifications } from '../Notifications';
import { useServerVersion } from '../ServerContext';
import { BudgetList } from './BudgetList';
import { ConfigServer } from './ConfigServer';
import { Modals } from './Modals';
import { ServerURL } from './ServerURL';
import { Bootstrap } from './subscribe/Bootstrap';
import { ChangePassword } from './subscribe/ChangePassword';
import { Error } from './subscribe/Error';
import { Login } from './subscribe/Login';
import { WelcomeScreen } from './WelcomeScreen';
function Version() {
const version = useServerVersion();
return (
<Text
style={{
color: theme.pageTextSubdued,
':hover': { color: theme.pageText },
margin: 15,
marginLeft: 17,
[`@media (min-width: ${tokens.breakpoint_small})`]: {
position: 'absolute',
bottom: 0,
right: 0,
marginLeft: 15,
marginRight: 17,
zIndex: 5001,
},
}}
>
{`App: v${window.Actual?.ACTUAL_VERSION} | Server: ${version}`}
</Text>
);
}
export function ManagementApp({ isLoading }) {
const files = useSelector(state => state.budgets.allFiles);
const userData = useSelector(state => state.user.data);
const managerHasInitialized = useSelector(
state => state.app.managerHasInitialized,
);
const { setAppState, getUserData, loadAllFiles } = useActions();
// runs on mount only
useEffect(() => {
// An action may have been triggered from outside, and we don't
// want to override its loading message so we only show the
// initial loader if there isn't already a message
// Remember: this component is remounted every time the user
// closes a budget. That's why we keep `managerHasInitialized` in
// redux so that it persists across renders. This will show the
// loading spinner on first run, but never again since we'll have
// a cached list of files and can show them
if (!managerHasInitialized) {
if (!isLoading) {
setAppState({ loadingText: '' });
}
}
async function fetchData() {
const userData = await getUserData();
if (userData) {
await loadAllFiles();
}
// TODO: There is a race condition here. The user could perform an
// action that starts loading in between where `isLoading`
// was captured and this would clear it. We really only want to
// ever clear the initial loading screen, so we need a "loading
// id" of some kind.
setAppState({
managerHasInitialized: true,
...(!isLoading ? { loadingText: null } : null),
});
}
fetchData();
}, []);
if (!managerHasInitialized) {
return null;
}
if (isLoading) {
return null;
}
return (
<BrowserRouter>
<ExposeNavigate />
<View style={{ height: '100%', color: theme.pageText }}>
<View
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: 40,
WebkitAppRegion: 'drag',
}}
/>
<View
style={{
position: 'absolute',
bottom: 40,
right: 15,
}}
>
<Notifications
style={{
position: 'relative',
left: 'initial',
right: 'initial',
}}
/>
</View>
{managerHasInitialized && (
<View
style={{
alignItems: 'center',
bottom: 0,
justifyContent: 'center',
left: 0,
padding: 20,
position: 'absolute',
right: 0,
top: 0,
}}
>
{userData && files ? (
<>
<Routes>
<Route path="/config-server" element={<ConfigServer />} />
<Route path="/change-password" element={<ChangePassword />} />
{files && files.length > 0 ? (
<Route path="/" element={<BudgetList />} />
) : (
<Route path="/" element={<WelcomeScreen />} />
)}
{/* Redirect all other pages to this route */}
<Route path="/*" element={<Navigate to="/" />} />
</Routes>
<View
style={{
position: 'absolute',
top: 0,
right: 0,
padding: '6px 10px',
zIndex: 4000,
}}
>
<Routes>
<Route path="/config-server" element={null} />
<Route
path="/*"
element={
<LoggedInUser
hideIfNoServer
style={{ padding: '4px 7px' }}
/>
}
/>
</Routes>
</View>
</>
) : (
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/error" element={<Error />} />
<Route path="/config-server" element={<ConfigServer />} />
<Route path="/bootstrap" element={<Bootstrap />} />
{/* Redirect all other pages to this route */}
<Route
path="/*"
element={<Navigate to="/bootstrap" replace />}
/>
</Routes>
)}
</View>
)}
<Routes>
<Route path="/config-server" element={null} />
<Route path="/*" element={<ServerURL />} />
</Routes>
<Version />
</View>
<Modals />
</BrowserRouter>
);
}