Skip to content

Commit

Permalink
Move sync actions to appSlice
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-jeremy committed Jan 17, 2025
1 parent 3b05855 commit be406ae
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 103 deletions.
3 changes: 1 addition & 2 deletions packages/desktop-client/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ import {
loadBudget,
loadGlobalPrefs,
signOut,
sync,
} from 'loot-core/client/actions';
import { setAppState } from 'loot-core/client/app/appSlice';
import { setAppState, sync } from 'loot-core/client/app/appSlice';
import { SpreadsheetProvider } from 'loot-core/client/SpreadsheetProvider';
import * as Platform from 'loot-core/src/client/platform';
import {
Expand Down
3 changes: 2 additions & 1 deletion packages/desktop-client/src/components/FinancesApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
useHref,
} from 'react-router-dom';

import { addNotification, sync } from 'loot-core/client/actions';
import { addNotification } from 'loot-core/client/actions';
import { sync } from 'loot-core/client/app/appSlice';
import * as undo from 'loot-core/src/platform/client/undo';

import { ProtectedRoute } from '../auth/ProtectedRoute';
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop-client/src/components/Titlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Routes, Route, useLocation } from 'react-router-dom';

import { css } from '@emotion/css';

import { sync } from 'loot-core/client/actions';
import { sync } from 'loot-core/client/app/appSlice';
import * as Platform from 'loot-core/src/client/platform';
import * as queries from 'loot-core/src/client/queries';
import { listen } from 'loot-core/src/platform/client/fetch';
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/accounts/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
openAccountCloseModal,
pushModal,
replaceModal,
syncAndDownload,
} from 'loot-core/client/actions';
import { syncAndDownload } from 'loot-core/client/app/appSlice';
import {
createPayee,
initiallyLoadPayees,
Expand Down Expand Up @@ -624,7 +624,7 @@ class AccountInternal extends PureComponent<
const account = this.props.accounts.find(acct => acct.id === accountId);

await this.props.dispatch(
syncAndDownload(account ? account.id : undefined),
syncAndDownload({ accountId: account ? account.id : undefined }),
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
collapseModals,
openAccountCloseModal,
pushModal,
syncAndDownload,
} from 'loot-core/client/actions';
import { syncAndDownload } from 'loot-core/client/app/appSlice';
import {
accountSchedulesQuery,
SchedulesProvider,
Expand Down Expand Up @@ -258,7 +258,7 @@ function TransactionListWithPreviews({

const onRefresh = useCallback(() => {
if (accountId) {
dispatch(syncAndDownload(accountId));
dispatch(syncAndDownload({ accountId }));
}
}, [accountId, dispatch]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next';

import { css } from '@emotion/css';

import { replaceModal, syncAndDownload } from 'loot-core/src/client/actions';
import { syncAndDownload } from 'loot-core/client/app/appSlice';
import { replaceModal } from 'loot-core/src/client/actions';
import * as queries from 'loot-core/src/client/queries';
import { type AccountEntity } from 'loot-core/types/models';

Expand Down Expand Up @@ -323,7 +324,7 @@ export function Accounts() {
}, [dispatch]);

const onSync = useCallback(async () => {
dispatch(syncAndDownload());
dispatch(syncAndDownload({}));
}, [dispatch]);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// @ts-strict-ignore
import React, { useCallback, useEffect, useState } from 'react';

import { collapseModals, pushModal, sync } from 'loot-core/client/actions';
import { collapseModals, pushModal } from 'loot-core/client/actions';
import { sync } from 'loot-core/client/app/appSlice';
import {
applyBudgetAction,
createCategory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { useTranslation, Trans } from 'react-i18next';

import { css } from '@emotion/css';

import { loadAllFiles, loadGlobalPrefs, sync } from 'loot-core/client/actions';
import { loadAllFiles, loadGlobalPrefs } from 'loot-core/client/actions';
import { sync } from 'loot-core/client/app/appSlice';
import { send } from 'loot-core/src/platform/client/fetch';
import { getCreateKeyError } from 'loot-core/src/shared/errors';

Expand Down
2 changes: 1 addition & 1 deletion packages/desktop-client/src/components/settings/Reset.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { Trans } from 'react-i18next';

import { resetSync } from 'loot-core/client/actions';
import { resetSync } from 'loot-core/client/app/appSlice';
import { send } from 'loot-core/src/platform/client/fetch';

import { useMetadataPref } from '../../hooks/useMetadataPref';
Expand Down
1 change: 0 additions & 1 deletion packages/loot-core/src/client/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ export * from './notifications';
export * from './prefs';
export * from './budgets';
export * from './backups';
export * from './sync';
export * from './user';
82 changes: 0 additions & 82 deletions packages/loot-core/src/client/actions/sync.ts

This file was deleted.

94 changes: 92 additions & 2 deletions packages/loot-core/src/client/app/appSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';

import { send } from '../../platform/client/fetch';
import { getUploadError } from '../../shared/errors';
import { type AccountEntity } from '../../types/models';
import { syncAccounts } from '../accounts/accountsSlice';
import { loadPrefs, pushModal } from '../actions';
import { createAppAsyncThunk } from '../redux';

const sliceName = 'app';
Expand All @@ -24,9 +29,91 @@ const initialState: AppState = {

export const updateApp = createAppAsyncThunk(
`${sliceName}/updateApp`,
async (_, thunkApi) => {
async (_, { dispatch }) => {
await global.Actual.applyAppUpdate();
thunkApi.dispatch(setAppState({ updateInfo: null }));
dispatch(setAppState({ updateInfo: null }));
},
);

export const resetSync = createAppAsyncThunk(
`${sliceName}/resetSync`,
async (_, { dispatch }) => {
const { error } = await send('sync-reset');

if (error) {
alert(getUploadError(error));

if (
(error.reason === 'encrypt-failure' &&
(error.meta as { isMissingKey?: boolean }).isMissingKey) ||
error.reason === 'file-has-new-key'
) {
dispatch(
pushModal('fix-encryption-key', {
onSuccess: () => {
// TODO: There won't be a loading indicator for this
dispatch(resetSync());
},
}),
);
} else if (error.reason === 'encrypt-failure') {
dispatch(pushModal('create-encryption-key', { recreate: true }));
}
} else {
await dispatch(sync());
}
},
);

export const sync = createAppAsyncThunk(
`${sliceName}/sync`,
async (_, { dispatch, getState }) => {
const prefs = getState().prefs.local;
if (prefs && prefs.id) {
const result = await send('sync');
if ('error' in result) {
return { error: result.error };
}

// Update the prefs
await dispatch(loadPrefs());
}

return {};
},
);

type SyncAndDownloadPayload = {
accountId?: AccountEntity['id'] | string;
};

export const syncAndDownload = createAppAsyncThunk(
`${sliceName}/syncAndDownload`,
async ({ accountId }: SyncAndDownloadPayload, { dispatch }) => {
// It is *critical* that we sync first because of transaction
// reconciliation. We want to get all transactions that other
// clients have already made, so that imported transactions can be
// reconciled against them. Otherwise, two clients will each add
// new transactions from the bank and create duplicate ones.
const syncState = await dispatch(sync()).unwrap();
if (syncState.error) {
return { error: syncState.error };
}

const hasDownloaded = await dispatch(syncAccounts({ id: accountId }));

if (hasDownloaded) {
// Sync again afterwards if new transactions were created
const syncState = await dispatch(sync()).unwrap();
if (syncState.error) {
return { error: syncState.error };
}

// `hasDownloaded` is already true, we know there has been
// updates
return true;
}
return { hasUpdated: hasDownloaded };
},
);

Expand All @@ -50,6 +137,9 @@ export const { name, reducer, getInitialState } = appSlice;
export const actions = {
...appSlice.actions,
updateApp,
resetSync,
sync,
syncAndDownload,
};

export const { setAppState } = actions;
15 changes: 10 additions & 5 deletions packages/loot-core/src/client/shared-listeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import {
closeAndDownloadBudget,
loadPrefs,
pushModal,
resetSync,
signOut,
sync,
uploadBudget,
} from './actions';
import { resetSync, sync } from './app/appSlice';
import { getAccounts, getCategories, getPayees } from './queries/queriesSlice';
import type { Notification } from './state-types/notifications';
import { type AppStore } from './store';
Expand Down Expand Up @@ -82,7 +81,9 @@ export function listenForSyncEvent(store: AppStore) {
id: 'reset-sync',
button: {
title: t('Reset sync'),
action: () => store.dispatch(resetSync()),
action: () => {
store.dispatch(resetSync());
},
},
};
} else {
Expand Down Expand Up @@ -131,7 +132,9 @@ export function listenForSyncEvent(store: AppStore) {
id: 'old-file',
button: {
title: t('Reset sync'),
action: () => store.dispatch(resetSync()),
action: () => {
store.dispatch(resetSync());
},
},
};
break;
Expand Down Expand Up @@ -197,7 +200,9 @@ export function listenForSyncEvent(store: AppStore) {
id: 'upload-file',
button: {
title: t('Upload'),
action: () => store.dispatch(resetSync()),
action: () => {
store.dispatch(resetSync());
},
},
};
break;
Expand Down

0 comments on commit be406ae

Please sign in to comment.