From f8af8f95ac4ab2bdacc58cf2bf1e9073da8b11ae Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com> Date: Fri, 26 Apr 2024 14:03:01 -0700 Subject: [PATCH] Fix loading screen not showing when opening a budget file (#2663) * Fix app loading screen * Release note * Code review feedback --- .../desktop-client/src/components/App.tsx | 73 ++++++++++++------- .../src/components/AppBackground.tsx | 2 +- .../src/components/manager/BudgetList.jsx | 56 +++++++------- packages/loot-core/src/types/file.d.ts | 2 +- upcoming-release-notes/2663.md | 6 ++ 5 files changed, 82 insertions(+), 57 deletions(-) create mode 100644 upcoming-release-notes/2663.md diff --git a/packages/desktop-client/src/components/App.tsx b/packages/desktop-client/src/components/App.tsx index 692f1986c..fa06630dd 100644 --- a/packages/desktop-client/src/components/App.tsx +++ b/packages/desktop-client/src/components/App.tsx @@ -6,8 +6,15 @@ import { type FallbackProps, } from 'react-error-boundary'; import { HotkeysProvider } from 'react-hotkeys-hook'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; +import { + closeBudget, + loadBudget, + loadGlobalPrefs, + setAppState, + sync, +} from 'loot-core/client/actions'; import * as Platform from 'loot-core/src/client/platform'; import { type State } from 'loot-core/src/client/state-types'; import { @@ -15,7 +22,6 @@ import { send, } from 'loot-core/src/platform/client/fetch'; -import { useActions } from '../hooks/useActions'; import { useLocalPref } from '../hooks/useLocalPref'; import { installPolyfills } from '../polyfills'; import { ResponsiveProvider } from '../ResponsiveProvider'; @@ -38,37 +44,49 @@ type AppInnerProps = { function AppInner({ budgetId, cloudFileId }: AppInnerProps) { const [initializing, setInitializing] = useState(true); const { showBoundary: showErrorBoundary } = useErrorBoundary(); - const stateLoadingText = useSelector((state: State) => state.app.loadingText); - const [loadingText = stateLoadingText, setLoadingText] = useState< - string | null - >(null); - const { loadBudget, closeBudget, loadGlobalPrefs } = useActions(); + const loadingText = useSelector((state: State) => state.app.loadingText); + const dispatch = useDispatch(); async function init() { const socketName = await global.Actual.getServerSocket(); - setLoadingText('Initializing the connection to the local database...'); + dispatch( + setAppState({ + loadingText: 'Initializing the connection to the local database...', + }), + ); await initConnection(socketName); // Load any global prefs - setLoadingText('Loading global preferences...'); - await loadGlobalPrefs(); + dispatch( + setAppState({ + loadingText: 'Loading global preferences...', + }), + ); + await dispatch(loadGlobalPrefs()); // Open the last opened budget, if any - setLoadingText('Opening last budget...'); + dispatch( + setAppState({ + loadingText: 'Opening last budget...', + }), + ); const budgetId = await send('get-last-opened-backup'); if (budgetId) { - setLoadingText('Loading the last budget file...'); - await loadBudget(budgetId); + await dispatch(loadBudget(budgetId, 'Loading the last budget file...')); // Check to see if this file has been remotely deleted (but // don't block on this in case they are offline or something) - setLoadingText('Retrieving remote files...'); + dispatch( + setAppState({ + loadingText: 'Retrieving remote files...', + }), + ); send('get-remote-files').then(files => { if (files) { const remoteFile = files.find(f => f.fileId === cloudFileId); if (remoteFile && remoteFile.deleted) { - closeBudget(); + dispatch(closeBudget()); } } }); @@ -79,7 +97,11 @@ function AppInner({ budgetId, cloudFileId }: AppInnerProps) { async function initAll() { await Promise.all([installPolyfills(), init()]); setInitializing(false); - setLoadingText(null); + dispatch( + setAppState({ + loadingText: null, + }), + ); } initAll().catch(showErrorBoundary); @@ -91,18 +113,13 @@ function AppInner({ budgetId, cloudFileId }: AppInnerProps) { return ( <> - {initializing ? ( + {(initializing || !budgetId) && ( <AppBackground initializing={initializing} loadingText={loadingText} /> - ) : budgetId ? ( + )} + {budgetId ? ( <FinancesApp /> ) : ( - <> - <AppBackground - initializing={initializing} - loadingText={loadingText} - /> - <ManagementApp isLoading={loadingText != null} /> - </> + <ManagementApp isLoading={loadingText != null} /> )} <UpdateNotification /> @@ -123,10 +140,10 @@ function ErrorFallback({ error }: FallbackProps) { export function App() { const [budgetId] = useLocalPref('id'); const [cloudFileId] = useLocalPref('cloudFileId'); - const { sync } = useActions(); const [hiddenScrollbars, setHiddenScrollbars] = useState( hasHiddenScrollbars(), ); + const dispatch = useDispatch(); useEffect(() => { function checkScrollbars() { @@ -141,7 +158,7 @@ export function App() { if (!isSyncing) { console.debug('triggering sync because of visibility change'); isSyncing = true; - await sync(); + await dispatch(sync()); isSyncing = false; } } @@ -153,7 +170,7 @@ export function App() { window.removeEventListener('focus', checkScrollbars); window.removeEventListener('visibilitychange', onVisibilityChange); }; - }, [sync]); + }, [dispatch]); return ( <HotkeysProvider initiallyActiveScopes={['*']}> diff --git a/packages/desktop-client/src/components/AppBackground.tsx b/packages/desktop-client/src/components/AppBackground.tsx index daff02ad6..698581aec 100644 --- a/packages/desktop-client/src/components/AppBackground.tsx +++ b/packages/desktop-client/src/components/AppBackground.tsx @@ -22,7 +22,7 @@ export function AppBackground({ const transitions = useTransition(loadingText, { from: { opacity: 0, transform: 'translateY(-100px)' }, enter: { opacity: 1, transform: 'translateY(0)' }, - leave: { opacity: 0, transform: 'translateY(-100px)' }, + leave: { opacity: 0, transform: 'translateY(100px)' }, unique: true, }); diff --git a/packages/desktop-client/src/components/manager/BudgetList.jsx b/packages/desktop-client/src/components/manager/BudgetList.jsx index 4ca30a418..33cee3764 100644 --- a/packages/desktop-client/src/components/manager/BudgetList.jsx +++ b/packages/desktop-client/src/components/manager/BudgetList.jsx @@ -1,10 +1,16 @@ import React, { useState, useRef } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; -import * as actions from 'loot-core/src/client/actions'; +import { + createBudget, + downloadBudget, + getUserData, + loadAllFiles, + loadBudget, + pushModal, +} from 'loot-core/client/actions'; import { isNonProductionEnvironment } from 'loot-core/src/shared/environment'; -import { useActions } from '../../hooks/useActions'; import { AnimatedLoading } from '../../icons/AnimatedLoading'; import { SvgCloudCheck, @@ -13,6 +19,7 @@ import { SvgFileDouble, } from '../../icons/v1'; import { SvgCloudUnknown, SvgKey, SvgRefreshArrow } from '../../icons/v2'; +import { useResponsive } from '../../ResponsiveProvider'; import { styles, theme } from '../../style'; import { tokens } from '../../tokens'; import { Button } from '../common/Button'; @@ -247,22 +254,19 @@ function RefreshButton({ onRefresh }) { export function BudgetList() { const files = useSelector(state => state.budgets.allFiles || []); - - const { - getUserData, - loadAllFiles, - pushModal, - loadBudget, - createBudget, - downloadBudget, - } = useActions(); - + const dispatch = useDispatch(); const [creating, setCreating] = useState(false); + const { isNarrowWidth } = useResponsive(); + const narrowButtonStyle = isNarrowWidth + ? { + height: styles.mobileMinHeight, + } + : {}; const onCreate = ({ testMode } = {}) => { if (!creating) { setCreating(true); - createBudget({ testMode }); + dispatch(createBudget({ testMode })); } }; @@ -294,47 +298,45 @@ export function BudgetList() { > <RefreshButton onRefresh={() => { - getUserData(); - loadAllFiles(); + dispatch(getUserData()); + dispatch(loadAllFiles()); }} /> </View> </View> <BudgetTable files={files} - actions={actions} onSelect={file => { if (file.state === 'remote') { - downloadBudget(file.cloudFileId); + dispatch(downloadBudget(file.cloudFileId)); } else { - loadBudget(file.id); + dispatch(loadBudget(file.id, `Loading ${file.name}...`)); } }} - onDelete={file => pushModal('delete-budget', { file })} + onDelete={file => dispatch(pushModal('delete-budget', { file }))} /> <View style={{ flexDirection: 'row', justifyContent: 'flex-end', padding: 25, - paddingLeft: 5, + gap: 15, }} > <Button type="bare" style={{ - marginLeft: 10, + ...narrowButtonStyle, color: theme.pageTextLight, }} - onClick={e => { - e.preventDefault(); - pushModal('import'); + onClick={() => { + dispatch(pushModal('import')); }} > Import file </Button> - <Button type="primary" onClick={onCreate} style={{ marginLeft: 15 }}> + <Button type="primary" onClick={onCreate} style={narrowButtonStyle}> Create new file </Button> @@ -343,7 +345,7 @@ export function BudgetList() { type="primary" isSubmit={false} onClick={() => onCreate({ testMode: true })} - style={{ marginLeft: 15 }} + style={narrowButtonStyle} > Create test file </Button> diff --git a/packages/loot-core/src/types/file.d.ts b/packages/loot-core/src/types/file.d.ts index 30301b1fb..9302a7c76 100644 --- a/packages/loot-core/src/types/file.d.ts +++ b/packages/loot-core/src/types/file.d.ts @@ -30,7 +30,7 @@ export type RemoteFile = { cloudFileId: string; groupId: string; name: string; - enccryptKeyId?: string; + encryptKeyId?: string; hasKey: boolean; state: 'remote'; }; diff --git a/upcoming-release-notes/2663.md b/upcoming-release-notes/2663.md new file mode 100644 index 000000000..bd63ad395 --- /dev/null +++ b/upcoming-release-notes/2663.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [joel-jeremy] +--- + +Fix app loading screen not showing when opening a budget file. -- GitLab