diff --git a/.eslintrc.js b/.eslintrc.js
index d0eadff98ccc0cc50e6effa0df36827a2b4eafaa..1c9425aa7a9f4b2757af57fe78070cfb3ed9910d 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -239,7 +239,27 @@ module.exports = {
         './packages/api/app/**/*',
         './packages/crdt/**/*',
         './packages/desktop-client/src/*',
-        // './packages/desktop-client/src/components/**/*',
+        // './packages/desktop-client/src/components/*',
+        './packages/desktop-client/src/components/accounts/**/*',
+        './packages/desktop-client/src/components/autocomplete/**/*',
+        './packages/desktop-client/src/components/budget/**/*',
+        './packages/desktop-client/src/components/common/**/*',
+        './packages/desktop-client/src/components/filters/**/*',
+        './packages/desktop-client/src/components/gocardless/**/*',
+        './packages/desktop-client/src/components/manager/**/*',
+        './packages/desktop-client/src/components/mobile/**/*',
+        './packages/desktop-client/src/components/modals/**/*',
+        // './packages/desktop-client/src/components/payees/**/*',
+        // './packages/desktop-client/src/components/reports/**/*',
+        // './packages/desktop-client/src/components/responsive/**/*',
+        // './packages/desktop-client/src/components/rules/**/*',
+        // './packages/desktop-client/src/components/schedules/**/*',
+        // './packages/desktop-client/src/components/select/**/*',
+        // './packages/desktop-client/src/components/settings/**/*',
+        // './packages/desktop-client/src/components/sidebar/**/*',
+        // './packages/desktop-client/src/components/spreadsheet/**/*',
+        // './packages/desktop-client/src/components/transactions/**/*',
+        // './packages/desktop-client/src/components/util/**/*',
         './packages/desktop-client/src/hooks/**/*',
         './packages/desktop-client/src/icons/**/*',
         './packages/desktop-client/src/style/**/*',
diff --git a/packages/desktop-client/src/components/accounts/Account.js b/packages/desktop-client/src/components/accounts/Account.js
index 8e047c7abb45c622daf1db884d780c4923b56c6d..37871916290bf0265a8e2829883c9247962bc02f 100644
--- a/packages/desktop-client/src/components/accounts/Account.js
+++ b/packages/desktop-client/src/components/accounts/Account.js
@@ -89,11 +89,11 @@ function AllTransactions({
   children,
 }) {
   const { id: accountId } = account;
-  let scheduleData = useCachedSchedules();
+  const scheduleData = useCachedSchedules();
 
   transactions ??= [];
 
-  let schedules = useMemo(
+  const schedules = useMemo(
     () =>
       scheduleData
         ? scheduleData.schedules.filter(
@@ -107,7 +107,7 @@ function AllTransactions({
     [scheduleData],
   );
 
-  let prependTransactions = useMemo(() => {
+  const prependTransactions = useMemo(() => {
     return schedules.map(schedule => ({
       id: `preview/${schedule.id}`,
       payee: schedule._payee,
@@ -130,16 +130,16 @@ function AllTransactions({
       : 0;
   }, [showBalances, balances, transactions]);
 
-  let prependBalances = useMemo(() => {
+  const prependBalances = useMemo(() => {
     if (!showBalances) {
       return null;
     }
 
     // Reverse so we can calculate from earliest upcoming schedule.
-    let scheduledBalances = [...prependTransactions]
+    const scheduledBalances = [...prependTransactions]
       .reverse()
       .map(scheduledTransaction => {
-        let amount =
+        const amount =
           (scheduledTransaction._inverse ? -1 : 1) *
           getScheduledAmount(scheduledTransaction.amount);
         return {
@@ -150,7 +150,7 @@ function AllTransactions({
     return groupById(scheduledBalances);
   }, [showBalances, prependTransactions, runningBalance]);
 
-  let allTransactions = useMemo(() => {
+  const allTransactions = useMemo(() => {
     // Don't prepend scheduled transactions if we are filtering
     if (!filtered && prependTransactions.length > 0) {
       return prependTransactions.concat(transactions);
@@ -158,7 +158,7 @@ function AllTransactions({
     return transactions;
   }, [filtered, prependTransactions, transactions]);
 
-  let allBalances = useMemo(() => {
+  const allBalances = useMemo(() => {
     // Don't prepend scheduled transactions if we are filtering
     if (!filtered && prependBalances && balances) {
       return { ...prependBalances, ...balances };
@@ -217,7 +217,7 @@ class AccountInternal extends PureComponent {
   }
 
   async componentDidMount() {
-    let maybeRefetch = tables => {
+    const maybeRefetch = tables => {
       if (
         tables.includes('transactions') ||
         tables.includes('category_mapping') ||
@@ -227,7 +227,7 @@ class AccountInternal extends PureComponent {
       }
     };
 
-    let onUndo = async ({ tables, messages, undoTag }) => {
+    const onUndo = async ({ tables, messages, undoTag }) => {
       await maybeRefetch(tables);
 
       // If all the messages are dealing with transactions, find the
@@ -239,7 +239,7 @@ class AccountInternal extends PureComponent {
         messages.every(msg => msg.dataset === 'transactions') &&
         !messages.find(msg => msg.column === 'tombstone')
       ) {
-        let focusableMsgs = messages.filter(
+        const focusableMsgs = messages.filter(
           msg =>
             msg.dataset === 'transactions' && !(msg.column === 'tombstone'),
         );
@@ -265,7 +265,7 @@ class AccountInternal extends PureComponent {
       this.props.setLastUndoState(null);
     };
 
-    let unlistens = [listen('undo-event', onUndo)];
+    const unlistens = [listen('undo-event', onUndo)];
 
     this.unlisten = () => {
       unlistens.forEach(unlisten => unlisten());
@@ -317,7 +317,7 @@ class AccountInternal extends PureComponent {
   }
 
   fetchAllIds = async () => {
-    let { data } = await runQuery(this.paged.getQuery().select('id'));
+    const { data } = await runQuery(this.paged.getQuery().select('id'));
     // Remember, this is the `grouped` split type so we need to deal
     // with the `subtransactions` property
     return data.reduce((arr, t) => {
@@ -332,7 +332,7 @@ class AccountInternal extends PureComponent {
   };
 
   fetchTransactions = () => {
-    let query = this.makeRootQuery();
+    const query = this.makeRootQuery();
     this.rootQuery = this.currentQuery = query;
     this.updateQuery(query);
 
@@ -342,8 +342,8 @@ class AccountInternal extends PureComponent {
   };
 
   makeRootQuery = () => {
-    let locationState = this.props.location.state;
-    let accountId = this.props.accountId;
+    const locationState = this.props.location.state;
+    const accountId = this.props.accountId;
 
     if (locationState && locationState.filter) {
       return q('transactions')
@@ -488,12 +488,12 @@ class AccountInternal extends PureComponent {
   };
 
   onExport = async accountName => {
-    let exportedTransactions = await send('transactions-export-query', {
+    const exportedTransactions = await send('transactions-export-query', {
       query: this.currentQuery.serialize(),
     });
-    let normalizedName =
+    const normalizedName =
       accountName && accountName.replace(/[()]/g, '').replace(/\s+/g, '-');
-    let filename = `${normalizedName || 'transactions'}.csv`;
+    const filename = `${normalizedName || 'transactions'}.csv`;
 
     window.Actual.saveFile(
       exportedTransactions,
@@ -523,8 +523,10 @@ class AccountInternal extends PureComponent {
   };
 
   canCalculateBalance = () => {
-    let accountId = this.props.accountId;
-    let account = this.props.accounts.find(account => account.id === accountId);
+    const accountId = this.props.accountId;
+    const account = this.props.accounts.find(
+      account => account.id === accountId,
+    );
     return (
       account &&
       this.state.search === '' &&
@@ -540,7 +542,7 @@ class AccountInternal extends PureComponent {
       return null;
     }
 
-    let { data } = await runQuery(
+    const { data } = await runQuery(
       this.paged
         .getQuery()
         .options({ splits: 'none' })
@@ -570,8 +572,8 @@ class AccountInternal extends PureComponent {
   };
 
   onToggleExtraBalances = () => {
-    let { accountId, showExtraBalances } = this.props;
-    let key = 'show-extra-balances-' + accountId || 'all-accounts';
+    const { accountId, showExtraBalances } = this.props;
+    const key = 'show-extra-balances-' + accountId || 'all-accounts';
 
     this.props.savePrefs({ [key]: !showExtraBalances });
   };
@@ -622,7 +624,7 @@ class AccountInternal extends PureComponent {
         break;
       case 'remove-sorting': {
         this.setState({ sort: [] }, () => {
-          let filters = this.state.filters;
+          const filters = this.state.filters;
           if (filters.length > 0) {
             this.applyFilters([...filters]);
           } else {
@@ -648,7 +650,7 @@ class AccountInternal extends PureComponent {
   };
 
   getAccountTitle(account, id) {
-    let { filterName } = this.props.location.state || {};
+    const { filterName } = this.props.location.state || {};
 
     if (filterName) {
       return filterName;
@@ -686,7 +688,7 @@ class AccountInternal extends PureComponent {
   };
 
   onCreatePayee = name => {
-    let trimmed = name.trim();
+    const trimmed = name.trim();
     if (trimmed !== '') {
       return this.props.createPayee(name);
     }
@@ -696,9 +698,9 @@ class AccountInternal extends PureComponent {
   lockTransactions = async () => {
     this.setState({ workingHard: true });
 
-    let { accountId } = this.props;
+    const { accountId } = this.props;
 
-    let { data } = await runQuery(
+    const { data } = await runQuery(
       q('transactions')
         .filter({ cleared: true, reconciled: false, account: accountId })
         .select('*')
@@ -706,10 +708,10 @@ class AccountInternal extends PureComponent {
     );
     let transactions = ungroupTransactions(data);
 
-    let changes = { updated: [] };
+    const changes = { updated: [] };
 
     transactions.forEach(trans => {
-      let { diff } = updateTransaction(transactions, {
+      const { diff } = updateTransaction(transactions, {
         ...trans,
         reconciled: true,
       });
@@ -730,16 +732,16 @@ class AccountInternal extends PureComponent {
   };
 
   onDoneReconciling = async () => {
-    let { accountId } = this.props;
-    let { reconcileAmount } = this.state;
+    const { accountId } = this.props;
+    const { reconcileAmount } = this.state;
 
-    let { data } = await runQuery(
+    const { data } = await runQuery(
       q('transactions')
         .filter({ cleared: true, account: accountId })
         .select('*')
         .options({ splits: 'grouped' }),
     );
-    let transactions = ungroupTransactions(data);
+    const transactions = ungroupTransactions(data);
 
     let cleared = 0;
 
@@ -749,7 +751,7 @@ class AccountInternal extends PureComponent {
       }
     });
 
-    let targetDiff = reconcileAmount - cleared;
+    const targetDiff = reconcileAmount - cleared;
 
     if (targetDiff === 0) {
       await this.lockTransactions();
@@ -792,10 +794,10 @@ class AccountInternal extends PureComponent {
   };
 
   onBatchEdit = async (name, ids) => {
-    let onChange = async (name, value) => {
+    const onChange = async (name, value) => {
       this.setState({ workingHard: true });
 
-      let { data } = await runQuery(
+      const { data } = await runQuery(
         q('transactions')
           .filter({ id: { $oneof: ids } })
           .select('*')
@@ -803,7 +805,7 @@ class AccountInternal extends PureComponent {
       );
       let transactions = ungroupTransactions(data);
 
-      let changes = { deleted: [], updated: [] };
+      const changes = { deleted: [], updated: [] };
 
       // Cleared is a special case right now
       if (name === 'cleared') {
@@ -826,7 +828,7 @@ class AccountInternal extends PureComponent {
           return;
         }
 
-        let transaction = {
+        const transaction = {
           ...trans,
           [name]: value,
         };
@@ -835,7 +837,7 @@ class AccountInternal extends PureComponent {
           transaction.reconciled = false;
         }
 
-        let { diff } = updateTransaction(transactions, transaction);
+        const { diff } = updateTransaction(transactions, transaction);
 
         // TODO: We need to keep an updated list of transactions so
         // the logic in `updateTransaction`, particularly about
@@ -863,13 +865,13 @@ class AccountInternal extends PureComponent {
     };
 
     if (name === 'amount' || name === 'payee' || name === 'account') {
-      let { data } = await runQuery(
+      const { data } = await runQuery(
         q('transactions')
           .filter({ id: { $oneof: ids }, reconciled: true })
           .select('*')
           .options({ splits: 'grouped' }),
       );
-      let transactions = ungroupTransactions(data);
+      const transactions = ungroupTransactions(data);
 
       if (transactions.length > 0) {
         this.props.pushModal('confirm-transaction-edit', {
@@ -892,17 +894,17 @@ class AccountInternal extends PureComponent {
   };
 
   onBatchDuplicate = async ids => {
-    let onConfirmDuplicate = async ids => {
+    const onConfirmDuplicate = async ids => {
       this.setState({ workingHard: true });
 
-      let { data } = await runQuery(
+      const { data } = await runQuery(
         q('transactions')
           .filter({ id: { $oneof: ids } })
           .select('*')
           .options({ splits: 'grouped' }),
       );
 
-      let changes = {
+      const changes = {
         added: data
           .reduce((newTransactions, trans) => {
             return newTransactions.concat(
@@ -925,10 +927,10 @@ class AccountInternal extends PureComponent {
   };
 
   onBatchDelete = async ids => {
-    let onConfirmDelete = async ids => {
+    const onConfirmDelete = async ids => {
       this.setState({ workingHard: true });
 
-      let { data } = await runQuery(
+      const { data } = await runQuery(
         q('transactions')
           .filter({ id: { $oneof: ids } })
           .select('*')
@@ -936,11 +938,11 @@ class AccountInternal extends PureComponent {
       );
       let transactions = ungroupTransactions(data);
 
-      let idSet = new Set(ids);
-      let changes = { deleted: [], updated: [] };
+      const idSet = new Set(ids);
+      const changes = { deleted: [], updated: [] };
 
       transactions.forEach(trans => {
-        let parentId = trans.parent_id;
+        const parentId = trans.parent_id;
 
         // First, check if we're actually deleting this transaction by
         // checking `idSet`. Then, we don't need to do anything if it's
@@ -949,7 +951,7 @@ class AccountInternal extends PureComponent {
           return;
         }
 
-        let { diff } = deleteTransaction(transactions, trans.id);
+        const { diff } = deleteTransaction(transactions, trans.id);
 
         // TODO: We need to keep an updated list of transactions so
         // the logic in `updateTransaction`, particularly about
@@ -977,13 +979,13 @@ class AccountInternal extends PureComponent {
   };
 
   checkForReconciledTransactions = async (ids, confirmReason, onConfirm) => {
-    let { data } = await runQuery(
+    const { data } = await runQuery(
       q('transactions')
         .filter({ id: { $oneof: ids }, reconciled: true })
         .select('*')
         .options({ splits: 'grouped' }),
     );
-    let transactions = ungroupTransactions(data);
+    const transactions = ungroupTransactions(data);
     if (transactions.length > 0) {
       this.props.pushModal('confirm-transaction-edit', {
         onConfirm: () => {
@@ -1005,14 +1007,14 @@ class AccountInternal extends PureComponent {
   };
 
   onCreateRule = async ids => {
-    let { data } = await runQuery(
+    const { data } = await runQuery(
       q('transactions')
         .filter({ id: { $oneof: ids } })
         .select('*')
         .options({ splits: 'grouped' }),
     );
-    let transactions = ungroupTransactions(data);
-    let payeeCondition = transactions[0].imported_payee
+    const transactions = ungroupTransactions(data);
+    const payeeCondition = transactions[0].imported_payee
       ? {
           field: 'imported_payee',
           op: 'is',
@@ -1026,7 +1028,7 @@ class AccountInternal extends PureComponent {
           type: 'id',
         };
 
-    let rule = {
+    const rule = {
       stage: null,
       conditionsOp: 'and',
       conditions: [payeeCondition],
@@ -1054,7 +1056,7 @@ class AccountInternal extends PureComponent {
 
   onReloadSavedFilter = (savedFilter, item) => {
     if (item === 'reload') {
-      let [getFilter] = this.props.filtersList.filter(
+      const [getFilter] = this.props.filtersList.filter(
         f => f.id === this.state.filterId.id,
       );
       this.setState({ conditionsOp: getFilter.conditionsOp });
@@ -1136,15 +1138,15 @@ class AccountInternal extends PureComponent {
   onScheduleAction = async (name, ids) => {
     switch (name) {
       case 'post-transaction':
-        for (let id of ids) {
-          let parts = id.split('/');
+        for (const id of ids) {
+          const parts = id.split('/');
           await send('schedule/post-transaction', { id: parts[1] });
         }
         this.refetchTransactions();
         break;
       case 'skip':
-        for (let id of ids) {
-          let parts = id.split('/');
+        for (const id of ids) {
+          const parts = id.split('/');
           await send('schedule/skip-next-date', { id: parts[1] });
         }
         break;
@@ -1154,10 +1156,10 @@ class AccountInternal extends PureComponent {
 
   applyFilters = async conditions => {
     if (conditions.length > 0) {
-      let customFilters = conditions
+      const customFilters = conditions
         .filter(cond => !!cond.customName)
         .map(f => f.filter);
-      let { filters } = await send('make-filters-from-conditions', {
+      const { filters } = await send('make-filters-from-conditions', {
         conditions: conditions.filter(cond => !cond.customName),
       });
       const conditionsOpKey = this.state.conditionsOp === 'or' ? '$or' : '$and';
@@ -1187,13 +1189,13 @@ class AccountInternal extends PureComponent {
   };
 
   applySort = (field, ascDesc, prevField, prevAscDesc) => {
-    let filters = this.state.filters;
-    let sortField = getField(!field ? this.state.sort.field : field);
-    let sortAscDesc = !ascDesc ? this.state.sort.ascDesc : ascDesc;
-    let sortPrevField = getField(
+    const filters = this.state.filters;
+    const sortField = getField(!field ? this.state.sort.field : field);
+    const sortAscDesc = !ascDesc ? this.state.sort.ascDesc : ascDesc;
+    const sortPrevField = getField(
       !prevField ? this.state.sort.prevField : prevField,
     );
-    let sortPrevAscDesc = !prevField
+    const sortPrevAscDesc = !prevField
       ? this.state.sort.prevAscDesc
       : prevAscDesc;
 
@@ -1263,7 +1265,7 @@ class AccountInternal extends PureComponent {
   };
 
   render() {
-    let {
+    const {
       accounts,
       categoryGroups,
       payees,
@@ -1277,7 +1279,7 @@ class AccountInternal extends PureComponent {
       accountId,
       categoryId,
     } = this.props;
-    let {
+    const {
       transactions,
       loading,
       workingHard,
@@ -1290,7 +1292,7 @@ class AccountInternal extends PureComponent {
       showCleared,
     } = this.state;
 
-    let account = accounts.find(account => account.id === accountId);
+    const account = accounts.find(account => account.id === accountId);
     const accountName = this.getAccountTitle(account, accountId);
 
     if (!accountName && !loading) {
@@ -1299,19 +1301,19 @@ class AccountInternal extends PureComponent {
       return <Navigate to="/accounts" replace />;
     }
 
-    let category = categoryGroups
+    const category = categoryGroups
       .flatMap(g => g.categories)
       .find(category => category.id === categoryId);
 
-    let showEmptyMessage = !loading && !accountId && accounts.length === 0;
+    const showEmptyMessage = !loading && !accountId && accounts.length === 0;
 
-    let isNameEditable =
+    const isNameEditable =
       accountId &&
       accountId !== 'budgeted' &&
       accountId !== 'offbudget' &&
       accountId !== 'uncategorized';
 
-    let balanceQuery = this.getBalanceQuery(account, accountId);
+    const balanceQuery = this.getBalanceQuery(account, accountId);
 
     return (
       <AllTransactions
@@ -1459,8 +1461,8 @@ class AccountInternal extends PureComponent {
 }
 
 function AccountHack(props) {
-  let { dispatch: splitsExpandedDispatch } = useSplitsExpanded();
-  let match = useMatch(props.location.pathname);
+  const { dispatch: splitsExpandedDispatch } = useSplitsExpanded();
+  const match = useMatch(props.location.pathname);
 
   return (
     <AccountInternal
@@ -1472,11 +1474,11 @@ function AccountHack(props) {
 }
 
 export default function Account() {
-  let params = useParams();
-  let location = useLocation();
+  const params = useParams();
+  const location = useLocation();
 
-  let { grouped: categoryGroups } = useCategories();
-  let state = useSelector(state => ({
+  const { grouped: categoryGroups } = useCategories();
+  const state = useSelector(state => ({
     newTransactions: state.queries.newTransactions,
     matchedTransactions: state.queries.matchedTransactions,
     accounts: state.queries.accounts,
@@ -1494,14 +1496,14 @@ export default function Account() {
     lastUndoState: state.app.lastUndoState,
   }));
 
-  let dispatch = useDispatch();
-  let filtersList = useFilters();
-  let actionCreators = useMemo(
+  const dispatch = useDispatch();
+  const filtersList = useFilters();
+  const actionCreators = useMemo(
     () => bindActionCreators(actions, dispatch),
     [dispatch],
   );
 
-  let transform = useMemo(() => {
+  const transform = useMemo(() => {
     let filterByAccount = queries.getAccountFilter(params.id, '_account');
     let filterByPayee = queries.getAccountFilter(
       params.id,
diff --git a/packages/desktop-client/src/components/accounts/AccountSyncCheck.js b/packages/desktop-client/src/components/accounts/AccountSyncCheck.js
index c6e2e4e440b31233947c6bb0906d9acb24708531..d7d3597b71db3b600f99dcdaf7c9c1c6544b32d9 100644
--- a/packages/desktop-client/src/components/accounts/AccountSyncCheck.js
+++ b/packages/desktop-client/src/components/accounts/AccountSyncCheck.js
@@ -49,24 +49,24 @@ function getErrorMessage(type, code) {
 }
 
 export default function AccountSyncCheck() {
-  let accounts = useSelector(state => state.queries.accounts);
-  let failedAccounts = useSelector(state => state.account.failedAccounts);
-  let { unlinkAccount, pushModal } = useActions();
+  const accounts = useSelector(state => state.queries.accounts);
+  const failedAccounts = useSelector(state => state.account.failedAccounts);
+  const { unlinkAccount, pushModal } = useActions();
 
-  let { id } = useParams();
-  let [open, setOpen] = useState(false);
+  const { id } = useParams();
+  const [open, setOpen] = useState(false);
   if (!failedAccounts) {
     return null;
   }
 
-  let error = failedAccounts.get(id);
+  const error = failedAccounts.get(id);
   if (!error) {
     return null;
   }
 
-  let account = accounts.find(account => account.id === id);
-  let { type, code } = error;
-  let showAuth =
+  const account = accounts.find(account => account.id === id);
+  const { type, code } = error;
+  const showAuth =
     (type === 'ITEM_ERROR' && code === 'ITEM_LOGIN_REQUIRED') ||
     (type === 'INVALID_INPUT' && code === 'INVALID_ACCESS_TOKEN');
 
diff --git a/packages/desktop-client/src/components/accounts/Balance.js b/packages/desktop-client/src/components/accounts/Balance.js
index c3710c2c9a3f83158c0f89685c3b83f0f988868e..8383b055c3960c5fedb5baea07993a5db76c88b8 100644
--- a/packages/desktop-client/src/components/accounts/Balance.js
+++ b/packages/desktop-client/src/components/accounts/Balance.js
@@ -40,9 +40,9 @@ function DetailedBalance({ name, balance, isExactBalance = true }) {
 }
 
 function SelectedBalance({ selectedItems, account }) {
-  let name = `selected-balance-${[...selectedItems].join('-')}`;
+  const name = `selected-balance-${[...selectedItems].join('-')}`;
 
-  let rows = useSheetValue({
+  const rows = useSheetValue({
     name,
     query: q('transactions')
       .filter({
@@ -51,9 +51,9 @@ function SelectedBalance({ selectedItems, account }) {
       })
       .select('id'),
   });
-  let ids = new Set((rows || []).map(r => r.id));
+  const ids = new Set((rows || []).map(r => r.id));
 
-  let finalIds = [...selectedItems].filter(id => !ids.has(id));
+  const finalIds = [...selectedItems].filter(id => !ids.has(id));
   let balance = useSheetValue({
     name: name + '-sum',
     query: q('transactions')
@@ -63,14 +63,14 @@ function SelectedBalance({ selectedItems, account }) {
   });
 
   let scheduleBalance = null;
-  let scheduleData = useCachedSchedules();
-  let schedules = scheduleData ? scheduleData.schedules : [];
-  let previewIds = [...selectedItems]
+  const scheduleData = useCachedSchedules();
+  const schedules = scheduleData ? scheduleData.schedules : [];
+  const previewIds = [...selectedItems]
     .filter(id => isPreviewId(id))
     .map(id => id.slice(8));
   let isExactBalance = true;
 
-  for (let s of schedules) {
+  for (const s of schedules) {
     if (previewIds.includes(s.id)) {
       // If a schedule is `between X and Y` then we calculate the average
       if (s._amountOp === 'isbetween') {
@@ -105,11 +105,11 @@ function SelectedBalance({ selectedItems, account }) {
 }
 
 function MoreBalances({ balanceQuery }) {
-  let cleared = useSheetValue({
+  const cleared = useSheetValue({
     name: balanceQuery.name + '-cleared',
     query: balanceQuery.query.filter({ cleared: true }),
   });
-  let uncleared = useSheetValue({
+  const uncleared = useSheetValue({
     name: balanceQuery.name + '-uncleared',
     query: balanceQuery.query.filter({ cleared: false }),
   });
@@ -128,7 +128,7 @@ export function Balances({
   onToggleExtraBalances,
   account,
 }) {
-  let selectedItems = useSelectedItems();
+  const selectedItems = useSelectedItems();
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/accounts/Header.js b/packages/desktop-client/src/components/accounts/Header.js
index ab40a636894f96cd0179a82138a764d42bfbc873..6e3992583e910d7f4de3526059d8c38978f0a1fe 100644
--- a/packages/desktop-client/src/components/accounts/Header.js
+++ b/packages/desktop-client/src/components/accounts/Header.js
@@ -78,9 +78,9 @@ export function AccountHeader({
   onDeleteFilter,
   onScheduleAction,
 }) {
-  let [menuOpen, setMenuOpen] = useState(false);
-  let searchInput = useRef(null);
-  let splitsExpanded = useSplitsExpanded();
+  const [menuOpen, setMenuOpen] = useState(false);
+  const searchInput = useRef(null);
+  const splitsExpanded = useSplitsExpanded();
 
   let canSync = account && account.account_id;
   if (!account) {
@@ -359,7 +359,7 @@ function AccountMenu({
   onReconcile,
   onMenuSelect,
 }) {
-  let [tooltip, setTooltip] = useState('default');
+  const [tooltip, setTooltip] = useState('default');
   const syncServerStatus = useSyncServerStatus();
 
   return tooltip === 'reconcile' ? (
diff --git a/packages/desktop-client/src/components/accounts/MobileAccount.js b/packages/desktop-client/src/components/accounts/MobileAccount.js
index 794c59a4c0cce0c21a37512ca4b413e30ee0d45e..837764310ba71cae908705375a90f5a35a4aa073 100644
--- a/packages/desktop-client/src/components/accounts/MobileAccount.js
+++ b/packages/desktop-client/src/components/accounts/MobileAccount.js
@@ -41,13 +41,13 @@ const getSchedulesTransform = memoizeOne((id, hasSearch) => {
 });
 
 function PreviewTransactions({ accountId, children }) {
-  let scheduleData = useCachedSchedules();
+  const scheduleData = useCachedSchedules();
 
   if (scheduleData == null) {
     return children(null);
   }
 
-  let schedules = scheduleData.schedules.filter(
+  const schedules = scheduleData.schedules.filter(
     s =>
       !s.completed &&
       ['due', 'upcoming', 'missed'].includes(scheduleData.statuses.get(s.id)),
@@ -76,15 +76,15 @@ export default function Account(props) {
   const [searchText, setSearchText] = useState('');
   const [currentQuery, setCurrentQuery] = useState();
 
-  let state = useSelector(state => ({
+  const state = useSelector(state => ({
     payees: state.queries.payees,
     newTransactions: state.queries.newTransactions,
     prefs: state.prefs.local,
     dateFormat: state.prefs.local.dateFormat || 'MM/dd/yyyy',
   }));
 
-  let dispatch = useDispatch();
-  let actionCreators = useMemo(
+  const dispatch = useDispatch();
+  const actionCreators = useMemo(
     () => bindActionCreators(actions, dispatch),
     [dispatch],
   );
@@ -106,7 +106,7 @@ export default function Account(props) {
   };
 
   const fetchTransactions = async () => {
-    let query = makeRootQuery();
+    const query = makeRootQuery();
     setCurrentQuery(query);
     updateQuery(query);
   };
@@ -189,9 +189,9 @@ export default function Account(props) {
     }
   };
 
-  let balance = queries.accountBalance(account);
-  let numberFormat = state.prefs.numberFormat || 'comma-dot';
-  let hideFraction = state.prefs.hideFraction || false;
+  const balance = queries.accountBalance(account);
+  const numberFormat = state.prefs.numberFormat || 'comma-dot';
+  const hideFraction = state.prefs.hideFraction || false;
 
   return (
     <SchedulesProvider
diff --git a/packages/desktop-client/src/components/accounts/MobileAccountDetails.js b/packages/desktop-client/src/components/accounts/MobileAccountDetails.js
index b20832df9fda9153e0197bfe4a71bd3a67a7045d..c2a250d2b1220800581d305ab6646e01c16c2a7c 100644
--- a/packages/desktop-client/src/components/accounts/MobileAccountDetails.js
+++ b/packages/desktop-client/src/components/accounts/MobileAccountDetails.js
@@ -75,7 +75,7 @@ export default function AccountDetails({
   onSelectTransaction,
   pushModal,
 }) {
-  let allTransactions = useMemo(() => {
+  const allTransactions = useMemo(() => {
     return prependTransactions.concat(transactions);
   }, [prependTransactions, transactions]);
 
diff --git a/packages/desktop-client/src/components/accounts/MobileAccounts.js b/packages/desktop-client/src/components/accounts/MobileAccounts.js
index 2df04b5ac84a135ba812de2aeef1d8e9ff062b3a..ac71f9231e08295d72f3c81f95fc103ac24b60fe 100644
--- a/packages/desktop-client/src/components/accounts/MobileAccounts.js
+++ b/packages/desktop-client/src/components/accounts/MobileAccounts.js
@@ -216,18 +216,18 @@ function AccountList({
 }
 
 export default function Accounts() {
-  let accounts = useSelector(state => state.queries.accounts);
-  let newTransactions = useSelector(state => state.queries.newTransactions);
-  let updatedAccounts = useSelector(state => state.queries.updatedAccounts);
-  let numberFormat = useSelector(
+  const accounts = useSelector(state => state.queries.accounts);
+  const newTransactions = useSelector(state => state.queries.newTransactions);
+  const updatedAccounts = useSelector(state => state.queries.updatedAccounts);
+  const numberFormat = useSelector(
     state => state.prefs.local.numberFormat || 'comma-dot',
   );
-  let hideFraction = useSelector(
+  const hideFraction = useSelector(
     state => state.prefs.local.hideFraction || false,
   );
 
   const { list: categories } = useCategories();
-  let { getAccounts, replaceModal, syncAndDownload } = useActions();
+  const { getAccounts, replaceModal, syncAndDownload } = useActions();
 
   const transactions = useState({});
   const navigate = useNavigate();
diff --git a/packages/desktop-client/src/components/accounts/Reconcile.js b/packages/desktop-client/src/components/accounts/Reconcile.js
index 762a728f884b1bff44cb52f6ce86d762a9a4c6d5..d01ad8ef3f24f1eecb5b354ebe7e59c3b48e21ec 100644
--- a/packages/desktop-client/src/components/accounts/Reconcile.js
+++ b/packages/desktop-client/src/components/accounts/Reconcile.js
@@ -20,13 +20,13 @@ export function ReconcilingMessage({
   onDone,
   onCreateTransaction,
 }) {
-  let cleared = useSheetValue({
+  const cleared = useSheetValue({
     name: balanceQuery.name + '-cleared',
     value: 0,
     query: balanceQuery.query.filter({ cleared: true }),
   });
-  let format = useFormat();
-  let targetDiff = targetBalance - cleared;
+  const format = useFormat();
+  const targetDiff = targetBalance - cleared;
 
   return (
     <View
@@ -96,18 +96,18 @@ export function ReconcilingMessage({
 }
 
 export function ReconcileTooltip({ account, onReconcile, onClose }) {
-  let balanceQuery = queries.accountBalance(account);
-  let clearedBalance = useSheetValue({
+  const balanceQuery = queries.accountBalance(account);
+  const clearedBalance = useSheetValue({
     name: balanceQuery.name + '-cleared',
     value: null,
     query: balanceQuery.query.filter({ cleared: true }),
   });
-  let format = useFormat();
+  const format = useFormat();
 
   function onSubmit(e) {
     e.preventDefault();
-    let input = e.target.elements[0];
-    let amount = currencyToInteger(input.value);
+    const input = e.target.elements[0];
+    const amount = currencyToInteger(input.value);
     if (amount != null) {
       onReconcile(amount == null ? clearedBalance : amount);
       onClose();
diff --git a/packages/desktop-client/src/components/autocomplete/Autocomplete.tsx b/packages/desktop-client/src/components/autocomplete/Autocomplete.tsx
index 16491a6fd2c1a24a33f93aee1c9d60f02bb8ff95..5c413b01d55a0d0c83b7df7d0d4df6fc75b617ad 100644
--- a/packages/desktop-client/src/components/autocomplete/Autocomplete.tsx
+++ b/packages/desktop-client/src/components/autocomplete/Autocomplete.tsx
@@ -24,7 +24,7 @@ const inst: { lastChangeType? } = {};
 
 function findItem(strict, suggestions, value) {
   if (strict) {
-    let idx = suggestions.findIndex(item => item.id === value);
+    const idx = suggestions.findIndex(item => item.id === value);
     return idx === -1 ? null : suggestions[idx];
   }
 
@@ -70,7 +70,7 @@ function fireUpdate(onUpdate, strict, suggestions, index, value) {
   } else {
     if (index == null) {
       // If passing in a value directly, validate the id
-      let sug = suggestions.find(sug => sug.id === value);
+      const sug = suggestions.find(sug => sug.id === value);
       if (sug) {
         selected = sug.id;
       }
@@ -90,7 +90,7 @@ function defaultRenderItems(items, getItemProps, highlightedIndex) {
   return (
     <div>
       {items.map((item, index) => {
-        let name = getItemName(item);
+        const name = getItemName(item);
         return (
           <div
             {...getItemProps({ item })}
@@ -222,7 +222,7 @@ function SingleAutocomplete({
 
   function resetState(newValue) {
     const val = newValue === undefined ? initialValue : newValue;
-    let selectedItem = findItem(strict, suggestions, val);
+    const selectedItem = findItem(strict, suggestions, val);
 
     setSelectedItem(selectedItem);
     setValue(selectedItem ? getItemName(selectedItem) : '');
@@ -311,10 +311,10 @@ function SingleAutocomplete({
 
           setHighlightedIndex(null);
         } else {
-          let defaultGetHighlightedIndex = filteredSuggestions => {
+          const defaultGetHighlightedIndex = filteredSuggestions => {
             return highlightFirst && filteredSuggestions.length ? 0 : null;
           };
-          let highlightedIndex = (
+          const highlightedIndex = (
             getHighlightedIndex || defaultGetHighlightedIndex
           )(filteredSuggestions);
           // @ts-expect-error Types say there is no type
@@ -415,7 +415,7 @@ function SingleAutocomplete({
 
                   // If not using table behavior, reset the input on blur. Tables
                   // handle saving the value on blur.
-                  let value = selectedItem ? getItemId(selectedItem) : null;
+                  const value = selectedItem ? getItemId(selectedItem) : null;
 
                   resetState(value);
                 } else {
@@ -423,7 +423,7 @@ function SingleAutocomplete({
                 }
               },
               onKeyDown: (e: KeyboardEvent<HTMLInputElement>) => {
-                let { onKeyDown } = inputProps || {};
+                const { onKeyDown } = inputProps || {};
 
                 // If the dropdown is open, an item is highlighted, and the user
                 // pressed enter, always capture that and handle it ourselves
@@ -561,15 +561,15 @@ function MultiAutocomplete({
   strict,
   ...props
 }: MultiAutocompleteProps) {
-  let [focused, setFocused] = useState(false);
-  let lastSelectedItems = useRef<unknown[]>();
+  const [focused, setFocused] = useState(false);
+  const lastSelectedItems = useRef<unknown[]>();
 
   useEffect(() => {
     lastSelectedItems.current = selectedItems;
   });
 
   function onRemoveItem(id) {
-    let items = selectedItems.filter(i => i !== id);
+    const items = selectedItems.filter(i => i !== id);
     onSelect(items);
   }
 
diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
index 59c71f81c17530ca9c902632c9ba83fdd764a010..b8c07ba36dbf1c8038418d4f2563814524ffc3ec 100644
--- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
+++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
@@ -117,7 +117,7 @@ export default function CategoryAutocomplete({
   renderCategoryItem,
   ...props
 }: CategoryAutocompleteProps) {
-  let categorySuggestions: Array<
+  const categorySuggestions: Array<
     CategoryEntity & { group?: CategoryGroupEntity }
   > = useMemo(
     () =>
diff --git a/packages/desktop-client/src/components/autocomplete/PayeeAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/PayeeAutocomplete.tsx
index 740cd93eb435401e74cb873ae6a9b5f5609c87c2..6ed812c7b02b4280294fd25390c690f1ba186eba 100644
--- a/packages/desktop-client/src/components/autocomplete/PayeeAutocomplete.tsx
+++ b/packages/desktop-client/src/components/autocomplete/PayeeAutocomplete.tsx
@@ -68,7 +68,7 @@ function PayeeList({
   renderPayeeItem = defaultRenderPayeeItem,
   footer,
 }) {
-  let isFiltered = items.filtered;
+  const isFiltered = items.filtered;
   let createNew = null;
   items = [...items];
 
@@ -76,12 +76,12 @@ function PayeeList({
   // with the value of the input so it always shows whatever the user
   // entered
   if (items[0].id === 'new') {
-    let [first, ...rest] = items;
+    const [first, ...rest] = items;
     createNew = first;
     items = rest;
   }
 
-  let offset = createNew ? 1 : 0;
+  const offset = createNew ? 1 : 0;
   let lastType = null;
 
   return (
@@ -102,14 +102,14 @@ function PayeeList({
           })}
 
         {items.map((item, idx) => {
-          let type = item.transfer_acct ? 'account' : 'payee';
+          const type = item.transfer_acct ? 'account' : 'payee';
           let title;
           if (type === 'payee' && lastType !== type) {
             title = 'Payees';
           } else if (type === 'account' && lastType !== type) {
             title = 'Transfer To/From';
           }
-          let showMoreMessage = idx === items.length - 1 && isFiltered;
+          const showMoreMessage = idx === items.length - 1 && isFiltered;
           lastType = type;
 
           return (
@@ -185,20 +185,20 @@ export default function PayeeAutocomplete({
   payees,
   ...props
 }: PayeeAutocompleteProps) {
-  let cachedPayees = useCachedPayees();
+  const cachedPayees = useCachedPayees();
   if (!payees) {
     payees = cachedPayees;
   }
 
-  let cachedAccounts = useCachedAccounts();
+  const cachedAccounts = useCachedAccounts();
   if (!accounts) {
     accounts = cachedAccounts;
   }
 
-  let [focusTransferPayees, setFocusTransferPayees] = useState(false);
-  let [rawPayee, setRawPayee] = useState('');
-  let hasPayeeInput = !!rawPayee;
-  let payeeSuggestions = useMemo(() => {
+  const [focusTransferPayees, setFocusTransferPayees] = useState(false);
+  const [rawPayee, setRawPayee] = useState('');
+  const hasPayeeInput = !!rawPayee;
+  const payeeSuggestions = useMemo(() => {
     const suggestions = getPayeeSuggestions(
       payees,
       focusTransferPayees,
@@ -211,13 +211,13 @@ export default function PayeeAutocomplete({
     return [{ id: 'new', name: '' }, ...suggestions];
   }, [payees, focusTransferPayees, accounts, hasPayeeInput]);
 
-  let dispatch = useDispatch();
+  const dispatch = useDispatch();
 
   async function handleSelect(value, rawInputValue) {
     if (tableBehavior) {
       onSelect?.(makeNew(value, rawInputValue));
     } else {
-      let create = () => dispatch(createPayee(rawInputValue));
+      const create = () => dispatch(createPayee(rawInputValue));
 
       if (Array.isArray(value)) {
         value = await Promise.all(value.map(v => (v === 'new' ? create() : v)));
@@ -279,10 +279,10 @@ export default function PayeeAutocomplete({
         });
 
         filtered.sort((p1, p2) => {
-          let r1 = p1.name.toLowerCase().startsWith(value.toLowerCase());
-          let r2 = p2.name.toLowerCase().startsWith(value.toLowerCase());
-          let r1exact = p1.name.toLowerCase() === value.toLowerCase();
-          let r2exact = p2.name.toLowerCase() === value.toLowerCase();
+          const r1 = p1.name.toLowerCase().startsWith(value.toLowerCase());
+          const r2 = p2.name.toLowerCase().startsWith(value.toLowerCase());
+          const r1exact = p1.name.toLowerCase() === value.toLowerCase();
+          const r2exact = p2.name.toLowerCase() === value.toLowerCase();
 
           // (maniacal laughter) mwahaHAHAHAHAH
           if (p1.id === 'new') {
@@ -306,7 +306,7 @@ export default function PayeeAutocomplete({
           }
         });
 
-        let isf = filtered.length > 100;
+        const isf = filtered.length > 100;
         filtered = filtered.slice(0, 100);
         filtered.filtered = isf;
 
diff --git a/packages/desktop-client/src/components/autocomplete/SavedFilterAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/SavedFilterAutocomplete.tsx
index 347db0826391fdccce284fbf9fe709e6039d2875..a2800b8564609ec7c2460201f7cf777ca355f635 100644
--- a/packages/desktop-client/src/components/autocomplete/SavedFilterAutocomplete.tsx
+++ b/packages/desktop-client/src/components/autocomplete/SavedFilterAutocomplete.tsx
@@ -63,7 +63,7 @@ export default function SavedFilterAutocomplete({
   embedded,
   ...props
 }: SavedFilterAutocompleteProps) {
-  let filters = useFilters() || [];
+  const filters = useFilters() || [];
 
   return (
     <Autocomplete
diff --git a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
index f0c29ee5283295541b9da738e21a786a062dd7a5..7b09d547d9a5dcf7c05801fe2293d65aa2c0d621 100644
--- a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
+++ b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
@@ -29,11 +29,11 @@ export default function BalanceWithCarryover({
   balanceStyle,
   carryoverStyle,
 }: BalanceWithCarryoverProps) {
-  let carryoverValue = useSheetValue(carryover);
-  let balanceValue = useSheetValue(balance);
-  let goalValue = useSheetValue(goal);
-  let budgetedValue = useSheetValue(budgeted);
-  let isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
+  const carryoverValue = useSheetValue(carryover);
+  const balanceValue = useSheetValue(balance);
+  const goalValue = useSheetValue(goal);
+  const budgetedValue = useSheetValue(budgeted);
+  const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
   return (
     <View style={style}>
       <CellValue
diff --git a/packages/desktop-client/src/components/budget/BudgetCategories.js b/packages/desktop-client/src/components/budget/BudgetCategories.js
index 9f6d2286f5d9c46614e6d8394d51b3cf593ca8d4..e4788008c161499e93963211903c5935da832776 100644
--- a/packages/desktop-client/src/components/budget/BudgetCategories.js
+++ b/packages/desktop-client/src/components/budget/BudgetCategories.js
@@ -39,8 +39,8 @@ const BudgetCategories = memo(
     onShowNewGroup,
     onHideNewGroup,
   }) => {
-    let items = useMemo(() => {
-      let [expenseGroups, incomeGroup] = separateGroups(categoryGroups);
+    const items = useMemo(() => {
+      const [expenseGroups, incomeGroup] = separateGroups(categoryGroups);
 
       let items = Array.prototype.concat.apply(
         [],
@@ -53,7 +53,7 @@ const BudgetCategories = memo(
             cat => showHiddenCategories || !cat.hidden,
           );
 
-          let items = [{ type: 'expense-group', value: { ...group } }];
+          const items = [{ type: 'expense-group', value: { ...group } }];
 
           if (newCategoryForGroup === group.id) {
             items.push({ type: 'new-category' });
@@ -103,13 +103,13 @@ const BudgetCategories = memo(
       showHiddenCategories,
     ]);
 
-    let [dragState, setDragState] = useState(null);
-    let [savedCollapsed, setSavedCollapsed] = useState(null);
+    const [dragState, setDragState] = useState(null);
+    const [savedCollapsed, setSavedCollapsed] = useState(null);
 
     // TODO: If we turn this into a reducer, we could probably memoize
     // each item in the list for better perf
     function onDragChange(newDragState) {
-      let { state } = newDragState;
+      const { state } = newDragState;
 
       if (state === 'start-preview') {
         setDragState({
@@ -283,7 +283,7 @@ const BudgetCategories = memo(
               throw new Error('Unknown item type: ' + item.type);
           }
 
-          let pos =
+          const pos =
             idx === 0 ? 'first' : idx === items.length - 1 ? 'last' : null;
 
           return (
diff --git a/packages/desktop-client/src/components/budget/BudgetMonthCountContext.tsx b/packages/desktop-client/src/components/budget/BudgetMonthCountContext.tsx
index 4a825f4ec20eee4932bd2a5c4b785a60ae2b57ed..a69e40fb69f9b619275dc3b256550277e054bb88 100644
--- a/packages/desktop-client/src/components/budget/BudgetMonthCountContext.tsx
+++ b/packages/desktop-client/src/components/budget/BudgetMonthCountContext.tsx
@@ -12,7 +12,8 @@ type BudgetMonthCountContextValue = {
   setDisplayMax: Dispatch<SetStateAction<number>>;
 };
 
-let BudgetMonthCountContext = createContext<BudgetMonthCountContextValue>(null);
+const BudgetMonthCountContext =
+  createContext<BudgetMonthCountContextValue>(null);
 
 type BudgetMonthCountProviderProps = {
   children: ReactNode;
@@ -21,7 +22,7 @@ type BudgetMonthCountProviderProps = {
 export function BudgetMonthCountProvider({
   children,
 }: BudgetMonthCountProviderProps) {
-  let [displayMax, setDisplayMax] = useState(1);
+  const [displayMax, setDisplayMax] = useState(1);
 
   return (
     <BudgetMonthCountContext.Provider value={{ displayMax, setDisplayMax }}>
diff --git a/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx b/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx
index c5f3576c70bc2e84f65d69b9db962a47d98171d2..919793bc3f6bc8e98a56bec19114c6cf1e6aabb3 100644
--- a/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx
+++ b/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx
@@ -17,8 +17,8 @@ type BudgetPageHeaderProps = {
 const BudgetPageHeader = memo<BudgetPageHeaderProps>(
   ({ startMonth, onMonthSelect, numMonths, monthBounds }) => {
     function getValidMonth(month) {
-      let start = monthBounds.start;
-      let end = monthUtils.subMonths(monthBounds.end, numMonths - 1);
+      const start = monthBounds.start;
+      const end = monthUtils.subMonths(monthBounds.end, numMonths - 1);
 
       if (month < start) {
         return start;
diff --git a/packages/desktop-client/src/components/budget/BudgetSummaries.tsx b/packages/desktop-client/src/components/budget/BudgetSummaries.tsx
index 11dc77f5bc2f3cbbb6d21918f7773c321554d083..1367005cc11accf736f6c759c0d2bbc047afc5fe 100644
--- a/packages/desktop-client/src/components/budget/BudgetSummaries.tsx
+++ b/packages/desktop-client/src/components/budget/BudgetSummaries.tsx
@@ -25,37 +25,37 @@ type BudgetSummariesProps = {
 export default function BudgetSummaries({
   SummaryComponent,
 }: BudgetSummariesProps) {
-  let { months } = useContext(MonthsContext);
+  const { months } = useContext(MonthsContext);
 
-  let [widthState, setWidthState] = useState(0);
-  let [styles, spring] = useSpring(() => ({
+  const [widthState, setWidthState] = useState(0);
+  const [styles, spring] = useSpring(() => ({
     x: 0,
     config: { mass: 3, tension: 600, friction: 80 },
   }));
 
-  let containerRef = useResizeObserver(
+  const containerRef = useResizeObserver(
     useCallback(rect => {
       setWidthState(rect.width);
     }, []),
   );
 
-  let prevMonth0 = useRef(months[0]);
-  let allMonths = [...months];
+  const prevMonth0 = useRef(months[0]);
+  const allMonths = [...months];
   allMonths.unshift(subMonths(months[0], 1));
   allMonths.push(addMonths(months[months.length - 1], 1));
-  let monthWidth = widthState / months.length;
+  const monthWidth = widthState / months.length;
 
   useLayoutEffect(() => {
-    let prevMonth = prevMonth0.current;
-    let reversed = prevMonth > months[0];
-    let offsetX = monthWidth;
+    const prevMonth = prevMonth0.current;
+    const reversed = prevMonth > months[0];
+    const offsetX = monthWidth;
     let from = reversed ? -offsetX * 2 : 0;
 
     if (prevMonth !== allMonths[0] && prevMonth !== allMonths[2]) {
       from = -offsetX;
     }
 
-    let to = -offsetX;
+    const to = -offsetX;
     spring.start({ from: { x: from }, x: to });
   }, [months[0]]);
 
diff --git a/packages/desktop-client/src/components/budget/BudgetTable.js b/packages/desktop-client/src/components/budget/BudgetTable.js
index 46568a288471ee67f4c1051fcb7626d9d0cf2361..1059c0633fd91b88e9cc47a3998e7b627dfeb902 100644
--- a/packages/desktop-client/src/components/budget/BudgetTable.js
+++ b/packages/desktop-client/src/components/budget/BudgetTable.js
@@ -33,16 +33,20 @@ class BudgetTable extends Component {
   };
 
   onReorderCategory = (id, dropPos, targetId) => {
-    let { categoryGroups } = this.props;
+    const { categoryGroups } = this.props;
 
-    let isGroup = !!categoryGroups.find(g => g.id === targetId);
+    const isGroup = !!categoryGroups.find(g => g.id === targetId);
 
     if (isGroup) {
-      let { targetId: groupId } = findSortUp(categoryGroups, dropPos, targetId);
-      let group = categoryGroups.find(g => g.id === groupId);
+      const { targetId: groupId } = findSortUp(
+        categoryGroups,
+        dropPos,
+        targetId,
+      );
+      const group = categoryGroups.find(g => g.id === groupId);
 
       if (group) {
-        let { categories } = group;
+        const { categories } = group;
         this.props.onReorderCategory({
           id,
           groupId: group.id,
@@ -55,7 +59,7 @@ class BudgetTable extends Component {
     } else {
       let targetGroup;
 
-      for (let group of categoryGroups) {
+      for (const group of categoryGroups) {
         if (group.categories.find(cat => cat.id === targetId)) {
           targetGroup = group;
           break;
@@ -71,7 +75,7 @@ class BudgetTable extends Component {
   };
 
   onReorderGroup = (id, dropPos, targetId) => {
-    let { categoryGroups } = this.props;
+    const { categoryGroups } = this.props;
 
     this.props.onReorderGroup({
       id,
@@ -80,8 +84,8 @@ class BudgetTable extends Component {
   };
 
   moveVertically = dir => {
-    let { editing } = this.state;
-    let { type, categoryGroups, collapsed } = this.props;
+    const { editing } = this.state;
+    const { type, categoryGroups, collapsed } = this.props;
 
     const flattened = categoryGroups.reduce((all, group) => {
       if (collapsed.includes(group.id)) {
@@ -151,12 +155,12 @@ class BudgetTable extends Component {
   };
 
   collapseAllCategories = () => {
-    let { setCollapsed, categoryGroups } = this.props;
+    const { setCollapsed, categoryGroups } = this.props;
     setCollapsed(categoryGroups.map(g => g.id));
   };
 
   render() {
-    let {
+    const {
       type,
       categoryGroups,
       prewarmStartMonth,
@@ -177,7 +181,7 @@ class BudgetTable extends Component {
       onShowNewGroup,
       onHideNewGroup,
     } = this.props;
-    let { editing, draggingState, showHiddenCategories } = this.state;
+    const { editing, draggingState, showHiddenCategories } = this.state;
 
     return (
       <View
diff --git a/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx
index 51ab9df276161b04bbba6ef545d3ca2cf95ef245..961f2ee146bab47ea8392f922e97b8b1bdfa13d2 100644
--- a/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx
+++ b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx
@@ -10,7 +10,7 @@ import BudgetPageHeader from './BudgetPageHeader';
 import BudgetTable from './BudgetTable';
 
 function getNumPossibleMonths(width: number) {
-  let estimatedTableWidth = width - 200;
+  const estimatedTableWidth = width - 200;
 
   if (estimatedTableWidth < 500) {
     return 1;
@@ -51,13 +51,13 @@ const DynamicBudgetTableInner = forwardRef<
     },
     ref,
   ) => {
-    let prefs = useSelector(state => state.prefs.local);
-    let { setDisplayMax } = useBudgetMonthCount();
-    let actions = useActions();
+    const prefs = useSelector(state => state.prefs.local);
+    const { setDisplayMax } = useBudgetMonthCount();
+    const actions = useActions();
 
-    let numPossible = getNumPossibleMonths(width);
-    let numMonths = Math.min(numPossible, maxMonths);
-    let maxWidth = 200 + 500 * numMonths;
+    const numPossible = getNumPossibleMonths(width);
+    const numMonths = Math.min(numPossible, maxMonths);
+    const maxWidth = 200 + 500 * numMonths;
 
     useEffect(() => {
       setDisplayMax(numPossible);
diff --git a/packages/desktop-client/src/components/budget/ExpenseCategory.tsx b/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
index af20de7e5418ffd69df4292a77672f0f91d5387a..cc1313966870b8ac437a22f5be55b3ad4d225a86 100644
--- a/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
+++ b/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
@@ -52,14 +52,14 @@ function ExpenseCategory({
     dragging = true;
   }
 
-  let { dragRef } = useDraggable({
+  const { dragRef } = useDraggable({
     type: 'category',
     onDragChange,
     item: cat,
     canDrag: editingCell === null,
   });
 
-  let { dropRef, dropPos } = useDroppable({
+  const { dropRef, dropPos } = useDroppable({
     types: 'category',
     id: cat.id,
     onDrop: onReorder,
diff --git a/packages/desktop-client/src/components/budget/ExpenseGroup.tsx b/packages/desktop-client/src/components/budget/ExpenseGroup.tsx
index 6104e012545305bf4cf070fcd8c0bb75efa351bd..7c1bfd8983f6d601e246de455aedd0e475ea3193 100644
--- a/packages/desktop-client/src/components/budget/ExpenseGroup.tsx
+++ b/packages/desktop-client/src/components/budget/ExpenseGroup.tsx
@@ -48,22 +48,22 @@ function ExpenseGroup({
   onToggleCollapse,
   onShowNewCategory,
 }: ExpenseGroupProps) {
-  let dragging = dragState && dragState.item === group;
+  const dragging = dragState && dragState.item === group;
 
-  let { dragRef } = useDraggable({
+  const { dragRef } = useDraggable({
     type: 'group',
     onDragChange,
     item: group,
     canDrag: editingCell === null,
   });
 
-  let { dropRef, dropPos } = useDroppable({
+  const { dropRef, dropPos } = useDroppable({
     types: 'group',
     id: group.id,
     onDrop: onReorderGroup,
   });
 
-  let { dropRef: catDropRef, dropPos: catDropPos } = useDroppable({
+  const { dropRef: catDropRef, dropPos: catDropPos } = useDroppable({
     types: 'category',
     id: group.id,
     onDrop: onReorderCategory,
diff --git a/packages/desktop-client/src/components/budget/IncomeCategory.tsx b/packages/desktop-client/src/components/budget/IncomeCategory.tsx
index 110da55231e56d6a2ca57e7a90858cd874411954..0d5625186da77a50cc60a493767d1db7b2da95c0 100644
--- a/packages/desktop-client/src/components/budget/IncomeCategory.tsx
+++ b/packages/desktop-client/src/components/budget/IncomeCategory.tsx
@@ -43,14 +43,14 @@ function IncomeCategory({
   onReorder,
   onShowActivity,
 }: IncomeCategoryProps) {
-  let { dragRef } = useDraggable({
+  const { dragRef } = useDraggable({
     type: 'income-category',
     onDragChange,
     item: cat,
     canDrag: editingCell === null,
   });
 
-  let { dropRef, dropPos } = useDroppable({
+  const { dropRef, dropPos } = useDroppable({
     types: 'income-category',
     id: cat.id,
     onDrop: onReorder,
diff --git a/packages/desktop-client/src/components/budget/MobileBudget.js b/packages/desktop-client/src/components/budget/MobileBudget.js
index 4f9e1601c18eb62310b2c539f0232059e8cc5067..8c3e7327c65db14682d8dbb9fd47739ff7656d7c 100644
--- a/packages/desktop-client/src/components/budget/MobileBudget.js
+++ b/packages/desktop-client/src/components/budget/MobileBudget.js
@@ -41,7 +41,7 @@ class Budget extends Component {
   }
 
   async loadCategories() {
-    let result = await this.props.getCategories();
+    const result = await this.props.getCategories();
     this.setState({ categoryGroups: result.grouped });
   }
 
@@ -63,7 +63,7 @@ class Budget extends Component {
 
     this.setState({ initialized: true });
 
-    let unlisten = listen('sync-event', ({ type, tables }) => {
+    const unlisten = listen('sync-event', ({ type, tables }) => {
       if (
         type === 'success' &&
         (tables.includes('categories') ||
@@ -145,14 +145,14 @@ class Budget extends Component {
   };
 
   onDeleteGroup = async groupId => {
-    let group = this.state.categoryGroups?.find(g => g.id === groupId);
+    const group = this.state.categoryGroups?.find(g => g.id === groupId);
 
     if (!group) {
       return;
     }
 
     let mustTransfer = false;
-    for (let category of group.categories) {
+    for (const category of group.categories) {
       if (await send('must-category-transfer', { id: category.id })) {
         mustTransfer = true;
         break;
@@ -210,21 +210,22 @@ class Budget extends Component {
   };
 
   onReorderCategory = (id, { inGroup, aroundCategory }) => {
-    let { categoryGroups } = this.state;
+    const { categoryGroups } = this.state;
     let groupId, targetId;
 
     if (inGroup) {
       groupId = inGroup;
     } else if (aroundCategory) {
-      let { id: catId, position } = aroundCategory;
+      const { id: originalCatId, position } = aroundCategory;
 
-      let group = categoryGroups.find(group =>
+      let catId = originalCatId;
+      const group = categoryGroups.find(group =>
         group.categories.find(cat => cat.id === catId),
       );
 
       if (position === 'bottom') {
-        let { categories } = group;
-        let idx = categories.findIndex(cat => cat.id === catId);
+        const { categories } = group;
+        const idx = categories.findIndex(cat => cat.id === catId);
         catId = idx < categories.length - 1 ? categories[idx + 1].id : null;
       }
 
@@ -240,10 +241,10 @@ class Budget extends Component {
   };
 
   onReorderGroup = (id, targetId, position) => {
-    let { categoryGroups } = this.state;
+    const { categoryGroups } = this.state;
 
     if (position === 'bottom') {
-      let idx = categoryGroups.findIndex(group => group.id === targetId);
+      const idx = categoryGroups.findIndex(group => group.id === targetId);
       targetId =
         idx < categoryGroups.length - 1 ? categoryGroups[idx + 1].id : null;
     }
@@ -266,23 +267,23 @@ class Budget extends Component {
   };
 
   onPrevMonth = async () => {
-    let { spreadsheet, budgetType } = this.props;
-    let month = monthUtils.subMonths(this.state.currentMonth, 1);
+    const { spreadsheet, budgetType } = this.props;
+    const month = monthUtils.subMonths(this.state.currentMonth, 1);
     await prewarmMonth(budgetType, spreadsheet, month);
     this.setState({ currentMonth: month, initialized: true });
   };
 
   onNextMonth = async () => {
-    let { spreadsheet, budgetType } = this.props;
-    let month = monthUtils.addMonths(this.state.currentMonth, 1);
+    const { spreadsheet, budgetType } = this.props;
+    const month = monthUtils.addMonths(this.state.currentMonth, 1);
     await prewarmMonth(budgetType, spreadsheet, month);
     this.setState({ currentMonth: month, initialized: true });
   };
 
   onOpenActionSheet = () => {
-    let { budgetType } = this.props;
+    const { budgetType } = this.props;
 
-    let options = [
+    const options = [
       'Edit Categories',
       'Copy last month’s budget',
       'Set budgets to zero',
@@ -352,8 +353,8 @@ class Budget extends Component {
       applyBudgetAction,
       pushModal,
     } = this.props;
-    let numberFormat = prefs.numberFormat || 'comma-dot';
-    let hideFraction = prefs.hideFraction || false;
+    const numberFormat = prefs.numberFormat || 'comma-dot';
+    const hideFraction = prefs.hideFraction || false;
 
     if (!categoryGroups || !initialized) {
       return (
@@ -414,14 +415,14 @@ class Budget extends Component {
 }
 
 export default function BudgetWrapper() {
-  let { list: categories, grouped: categoryGroups } = useCategories();
-  let budgetType = useSelector(
+  const { list: categories, grouped: categoryGroups } = useCategories();
+  const budgetType = useSelector(
     state => state.prefs.local.budgetType || 'rollover',
   );
-  let prefs = useSelector(state => state.prefs.local);
+  const prefs = useSelector(state => state.prefs.local);
 
-  let actions = useActions();
-  let spreadsheet = useSpreadsheet();
+  const actions = useActions();
+  const spreadsheet = useSpreadsheet();
   useSetThemeColor(theme.mobileViewTheme);
   return (
     <Budget
diff --git a/packages/desktop-client/src/components/budget/MobileBudgetTable.js b/packages/desktop-client/src/components/budget/MobileBudgetTable.js
index 0190840d57839279ade9fc5bd00649909c58b059..4f8e81107c107377589bf384108759ae42632065 100644
--- a/packages/desktop-client/src/components/budget/MobileBudgetTable.js
+++ b/packages/desktop-client/src/components/budget/MobileBudgetTable.js
@@ -40,7 +40,7 @@ import RolloverBudgetBalanceTooltip from './rollover/BalanceTooltip';
 import { makeAmountGrey } from './util';
 
 function ToBudget({ toBudget, onClick }) {
-  let amount = useSheetValue(toBudget);
+  const amount = useSheetValue(toBudget);
   return (
     <Button
       type="bare"
@@ -70,12 +70,12 @@ function ToBudget({ toBudget, onClick }) {
 }
 
 function Saved({ projected, onClick }) {
-  let binding = projected
+  const binding = projected
     ? reportBudget.totalBudgetedSaved
     : reportBudget.totalSaved;
 
-  let saved = useSheetValue(binding) || 0;
-  let isNegative = saved < 0;
+  const saved = useSheetValue(binding) || 0;
+  const isNegative = saved < 0;
 
   return (
     <Button
@@ -135,7 +135,7 @@ function BudgetCell({
   onEdit,
   isEditing,
 }) {
-  let sheetValue = useSheetValue(binding);
+  const sheetValue = useSheetValue(binding);
 
   function updateBudgetAmount(amount) {
     onBudgetAction?.(month, 'budget-amount', {
@@ -255,14 +255,14 @@ const ExpenseCategory = memo(function ExpenseCategory({
   show3Cols,
   showBudgetedCol,
 }) {
-  let opacity = blank ? 0 : 1;
-  let showEditables = editMode || isEditing;
+  const opacity = blank ? 0 : 1;
+  const showEditables = editMode || isEditing;
 
-  let [categoryName, setCategoryName] = useState(category.name);
-  let [isHidden, setIsHidden] = useState(category.hidden);
+  const [categoryName, setCategoryName] = useState(category.name);
+  const [isHidden, setIsHidden] = useState(category.hidden);
 
-  let tooltip = useTooltip();
-  let balanceTooltip = useTooltip();
+  const tooltip = useTooltip();
+  const balanceTooltip = useTooltip();
 
   useEffect(() => {
     if (isBudgetActionMenuOpen) {
@@ -276,7 +276,7 @@ const ExpenseCategory = memo(function ExpenseCategory({
     }
   }, [isEditing, tooltip]);
 
-  let onSubmit = () => {
+  const onSubmit = () => {
     if (categoryName) {
       onSave?.({
         ...category,
@@ -288,7 +288,7 @@ const ExpenseCategory = memo(function ExpenseCategory({
     onEdit?.(null);
   };
 
-  let onMenuSelect = type => {
+  const onMenuSelect = type => {
     onEdit?.(null);
     switch (type) {
       case 'toggle-visibility':
@@ -306,10 +306,10 @@ const ExpenseCategory = memo(function ExpenseCategory({
     }
   };
 
-  let listItemRef = useRef();
-  let inputRef = useRef();
+  const listItemRef = useRef();
+  const inputRef = useRef();
 
-  let _onBudgetAction = (monthIndex, action, arg) => {
+  const _onBudgetAction = (monthIndex, action, arg) => {
     onBudgetAction?.(
       monthUtils.getMonthFromIndex(monthUtils.getYear(month), monthIndex),
       action,
@@ -317,7 +317,7 @@ const ExpenseCategory = memo(function ExpenseCategory({
     );
   };
 
-  let content = (
+  const content = (
     <ListItem
       style={{
         backgroundColor: isEditingBudget
@@ -555,13 +555,13 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({
   show3Cols,
   showBudgetedCol,
 }) {
-  let opacity = blank ? 0 : 1;
-  let showEditables = editMode || isEditing;
+  const opacity = blank ? 0 : 1;
+  const showEditables = editMode || isEditing;
 
-  let [groupName, setGroupName] = useState(group.name);
-  let [isHidden, setIsHidden] = useState(group.hidden);
+  const [groupName, setGroupName] = useState(group.name);
+  const [isHidden, setIsHidden] = useState(group.hidden);
 
-  let tooltip = useTooltip();
+  const tooltip = useTooltip();
 
   useEffect(() => {
     if (!isEditing && tooltip.isOpen) {
@@ -569,7 +569,7 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({
     }
   }, [isEditing]);
 
-  let onSubmit = () => {
+  const onSubmit = () => {
     if (groupName) {
       onSave?.({
         ...group,
@@ -581,7 +581,7 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({
     onEdit?.(null);
   };
 
-  let onMenuSelect = type => {
+  const onMenuSelect = type => {
     onEdit?.(null);
     switch (type) {
       case 'add-category':
@@ -602,10 +602,10 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({
     }
   };
 
-  let listItemRef = useRef();
-  let inputRef = useRef();
+  const listItemRef = useRef();
+  const inputRef = useRef();
 
-  let content = (
+  const content = (
     <ListItem
       style={{
         flexDirection: 'row',
@@ -811,11 +811,11 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({
   isEditing,
   onEdit,
 }) {
-  let [groupName, setGroupName] = useState(group.name);
-  let [isHidden, setIsHidden] = useState(group.hidden);
-  let showEditables = editMode || isEditing;
+  const [groupName, setGroupName] = useState(group.name);
+  const [isHidden, setIsHidden] = useState(group.hidden);
+  const showEditables = editMode || isEditing;
 
-  let tooltip = useTooltip();
+  const tooltip = useTooltip();
 
   useEffect(() => {
     if (!isEditing && tooltip.isOpen) {
@@ -823,7 +823,7 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({
     }
   }, [isEditing]);
 
-  let onSubmit = () => {
+  const onSubmit = () => {
     if (groupName) {
       onSave?.({
         ...group,
@@ -835,7 +835,7 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({
     onEdit?.(null);
   };
 
-  let onMenuSelect = type => {
+  const onMenuSelect = type => {
     onEdit?.(null);
     switch (type) {
       case 'add-category':
@@ -856,8 +856,8 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({
     }
   };
 
-  let listItemRef = useRef();
-  let inputRef = useRef();
+  const listItemRef = useRef();
+  const inputRef = useRef();
 
   return (
     <ListItem
@@ -1019,11 +1019,11 @@ const IncomeCategory = memo(function IncomeCategory({
   isEditingBudget,
   onEditBudget,
 }) {
-  let [categoryName, setCategoryName] = useState(category.name);
-  let [isHidden, setIsHidden] = useState(category.hidden);
-  let showEditables = editMode || isEditing;
+  const [categoryName, setCategoryName] = useState(category.name);
+  const [isHidden, setIsHidden] = useState(category.hidden);
+  const showEditables = editMode || isEditing;
 
-  let tooltip = useTooltip();
+  const tooltip = useTooltip();
 
   useEffect(() => {
     if (!isEditing && tooltip.isOpen) {
@@ -1031,7 +1031,7 @@ const IncomeCategory = memo(function IncomeCategory({
     }
   }, [isEditing]);
 
-  let onSubmit = () => {
+  const onSubmit = () => {
     if (categoryName) {
       onSave?.({
         ...category,
@@ -1043,7 +1043,7 @@ const IncomeCategory = memo(function IncomeCategory({
     onEdit?.(null);
   };
 
-  let onMenuSelect = type => {
+  const onMenuSelect = type => {
     onEdit?.(null);
     switch (type) {
       case 'toggle-visibility':
@@ -1061,8 +1061,8 @@ const IncomeCategory = memo(function IncomeCategory({
     }
   };
 
-  let listItemRef = useRef();
-  let inputRef = useRef();
+  const listItemRef = useRef();
+  const inputRef = useRef();
 
   return (
     <ListItem
@@ -1694,7 +1694,7 @@ export function BudgetTable(props) {
   const show3Cols = width >= 360;
 
   // let editMode = false; // neuter editMode -- sorry, not rewriting drag-n-drop right now
-  let format = useFormat();
+  const format = useFormat();
 
   const mobileShowBudgetedColPref = useSelector(state => {
     return state.prefs?.local?.toggleMobileDisplayPref || true;
@@ -1704,7 +1704,7 @@ export function BudgetTable(props) {
     return state.prefs?.local?.['budget.showHiddenCategories'] || false;
   });
 
-  let [showBudgetedCol, setShowBudgetedCol] = useState(
+  const [showBudgetedCol, setShowBudgetedCol] = useState(
     !mobileShowBudgetedColPref &&
       !document.cookie.match(/mobileShowBudgetedColPref=true/),
   );
@@ -1716,7 +1716,7 @@ export function BudgetTable(props) {
     }
   }
 
-  let buttonStyle = {
+  const buttonStyle = {
     padding: 0,
     backgroundColor: 'transparent',
     borderRadius: 'unset',
@@ -1995,10 +1995,10 @@ function BudgetMenu({
   onToggleHiddenCategories,
   onSwitchBudgetType,
 }) {
-  let tooltip = useTooltip();
-  let isReportBudgetEnabled = useFeatureFlag('reportBudget');
+  const tooltip = useTooltip();
+  const isReportBudgetEnabled = useFeatureFlag('reportBudget');
 
-  let onMenuSelect = name => {
+  const onMenuSelect = name => {
     tooltip.close();
     switch (name) {
       case 'edit-mode':
@@ -2062,10 +2062,10 @@ function BudgetMenu({
 }
 
 function MonthSelector({ month, monthBounds, onPrevMonth, onNextMonth }) {
-  let prevEnabled = month > monthBounds.start;
-  let nextEnabled = month < monthUtils.subMonths(monthBounds.end, 1);
+  const prevEnabled = month > monthBounds.start;
+  const nextEnabled = month < monthUtils.subMonths(monthBounds.end, 1);
 
-  let arrowButtonStyle = {
+  const arrowButtonStyle = {
     padding: 10,
     margin: 2,
   };
diff --git a/packages/desktop-client/src/components/budget/MonthCountSelector.tsx b/packages/desktop-client/src/components/budget/MonthCountSelector.tsx
index 8a325e18f23ded9d3883de6db5641ff6d2224592..c3509bc20bca535a1e5d35aaa2e6f2bb0d67b3d8 100644
--- a/packages/desktop-client/src/components/budget/MonthCountSelector.tsx
+++ b/packages/desktop-client/src/components/budget/MonthCountSelector.tsx
@@ -29,7 +29,7 @@ export function MonthCountSelector({
   maxMonths,
   onChange,
 }: MonthCountSelectorProps) {
-  let { displayMax } = useBudgetMonthCount();
+  const { displayMax } = useBudgetMonthCount();
 
   // It doesn't make sense to show anything if we can only fit one
   // month
@@ -37,7 +37,7 @@ export function MonthCountSelector({
     return null;
   }
 
-  let calendars = [];
+  const calendars = [];
   for (let i = 1; i <= displayMax; i++) {
     calendars.push(
       <Calendar
diff --git a/packages/desktop-client/src/components/budget/MonthPicker.tsx b/packages/desktop-client/src/components/budget/MonthPicker.tsx
index 7ee9c2206c1864fbc52ac63cee0fe09f4b18c202..b80e8e740eeb3f1e4ec2ab22ebd91fde25856f43 100644
--- a/packages/desktop-client/src/components/budget/MonthPicker.tsx
+++ b/packages/desktop-client/src/components/budget/MonthPicker.tsx
@@ -57,7 +57,7 @@ export const MonthPicker = ({
     );
   });
 
-  let yearHeadersShown = [];
+  const yearHeadersShown = [];
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/budget/MonthsContext.tsx b/packages/desktop-client/src/components/budget/MonthsContext.tsx
index 3292929dfdfc7025459033f2dd9704b319d80688..bca1acfe315c3f75a78f1102532d8f1533b4b747 100644
--- a/packages/desktop-client/src/components/budget/MonthsContext.tsx
+++ b/packages/desktop-client/src/components/budget/MonthsContext.tsx
@@ -23,7 +23,7 @@ type MonthsContextProps = {
   type: string;
 };
 
-export let MonthsContext = createContext<MonthsContextProps>(null);
+export const MonthsContext = createContext<MonthsContextProps>(null);
 
 type MonthsProviderProps = {
   startMonth: string | undefined;
@@ -40,9 +40,9 @@ export function MonthsProvider({
   type,
   children,
 }: MonthsProviderProps) {
-  let endMonth = monthUtils.addMonths(startMonth, numMonths - 1);
-  let bounds = getValidMonthBounds(monthBounds, startMonth, endMonth);
-  let months = monthUtils.rangeInclusive(bounds.start, bounds.end);
+  const endMonth = monthUtils.addMonths(startMonth, numMonths - 1);
+  const bounds = getValidMonthBounds(monthBounds, startMonth, endMonth);
+  const months = monthUtils.rangeInclusive(bounds.start, bounds.end);
 
   return (
     <MonthsContext.Provider value={{ months, type }}>
diff --git a/packages/desktop-client/src/components/budget/RenderMonths.tsx b/packages/desktop-client/src/components/budget/RenderMonths.tsx
index 362ebafcec4946cb66e312c4288eb4349e58b1c3..649734d97550cd75dc256b2b6f83011642b2e285 100644
--- a/packages/desktop-client/src/components/budget/RenderMonths.tsx
+++ b/packages/desktop-client/src/components/budget/RenderMonths.tsx
@@ -25,10 +25,10 @@ function RenderMonths({
   args,
   style,
 }: RenderMonthsProps) {
-  let { months } = useContext(MonthsContext);
+  const { months } = useContext(MonthsContext);
 
   return months.map((month, index) => {
-    let editing = editingIndex === index;
+    const editing = editingIndex === index;
 
     return (
       <NamespaceContext.Provider
diff --git a/packages/desktop-client/src/components/budget/index.tsx b/packages/desktop-client/src/components/budget/index.tsx
index d72b15de959b8a205e75e5d883e40ea69efb1d3f..db90edc081706b31a876dbec7059798050d5be41 100644
--- a/packages/desktop-client/src/components/budget/index.tsx
+++ b/packages/desktop-client/src/components/budget/index.tsx
@@ -122,17 +122,17 @@ function Budget(props: BudgetProps) {
   );
 
   async function loadCategories() {
-    let result = await props.getCategories();
+    const result = await props.getCategories();
     setCategoryGroups(result.grouped);
   }
 
   useEffect(() => {
-    let { titlebar, budgetType } = props;
+    const { titlebar, budgetType } = props;
 
     async function run() {
       loadCategories();
 
-      let { start, end } = await send('get-budget-bounds');
+      const { start, end } = await send('get-budget-bounds');
       setBounds({ start, end });
 
       await prewarmAllMonths(
@@ -147,7 +147,7 @@ function Budget(props: BudgetProps) {
 
     run();
 
-    let unlistens = [
+    const unlistens = [
       listen('sync-event', ({ type, tables }) => {
         if (
           type === 'success' &&
@@ -255,7 +255,7 @@ function Budget(props: BudgetProps) {
   };
 
   const onSaveCategory = async category => {
-    let exists =
+    const exists =
       (await props.getCategories()).grouped
         .filter(g => g.id === category.cat_group)[0]
         .categories.filter(
@@ -270,7 +270,7 @@ function Budget(props: BudgetProps) {
     }
 
     if (category.id === 'new') {
-      let id = await props.createCategory(
+      const id = await props.createCategory(
         category.name,
         category.cat_group,
         category.is_income,
@@ -313,7 +313,7 @@ function Budget(props: BudgetProps) {
 
   const onSaveGroup = async group => {
     if (group.id === 'new') {
-      let id = await props.createGroup(group.name);
+      const id = await props.createGroup(group.name);
       setIsAddingGroup(false);
       setCategoryGroups(state =>
         addGroup(state, {
@@ -330,10 +330,10 @@ function Budget(props: BudgetProps) {
   };
 
   const onDeleteGroup = async id => {
-    let group = categoryGroups.find(g => g.id === id);
+    const group = categoryGroups.find(g => g.id === id);
 
     let mustTransfer = false;
-    for (let category of group.categories) {
+    for (const category of group.categories) {
       if (await send('must-category-transfer', { id: category.id })) {
         mustTransfer = true;
         break;
@@ -377,9 +377,9 @@ function Budget(props: BudgetProps) {
   };
 
   const onReorderCategory = async sortInfo => {
-    let cats = await props.getCategories();
-    let moveCandidate = cats.list.filter(c => c.id === sortInfo.id)[0];
-    let exists =
+    const cats = await props.getCategories();
+    const moveCandidate = cats.list.filter(c => c.id === sortInfo.id)[0];
+    const exists =
       cats.grouped
         .filter(g => g.id === sortInfo.groupId)[0]
         .categories.filter(
@@ -406,7 +406,7 @@ function Budget(props: BudgetProps) {
   };
 
   const onToggleCollapse = () => {
-    let collapsed = !summaryCollapsed;
+    const collapsed = !summaryCollapsed;
     setSummaryCollapsed(collapsed);
     props.savePrefs({ 'budget.summaryCollapsed': collapsed });
   };
@@ -427,14 +427,14 @@ function Budget(props: BudgetProps) {
     }
   };
 
-  let {
-    maxMonths,
+  const {
+    maxMonths: originalMaxMonths,
     budgetType: type,
     reportComponents,
     rolloverComponents,
   } = props;
 
-  maxMonths = maxMonths || 1;
+  const maxMonths = originalMaxMonths || 1;
 
   if (!initialized || !categoryGroups) {
     return null;
@@ -532,27 +532,29 @@ const RolloverBudgetSummary = memo<{ month: string }>(props => {
 });
 
 export default function BudgetWrapper(props) {
-  let startMonth = useSelector(state => state.prefs.local['budget.startMonth']);
-  let collapsedPrefs = useSelector(
+  const startMonth = useSelector(
+    state => state.prefs.local['budget.startMonth'],
+  );
+  const collapsedPrefs = useSelector(
     state => state.prefs.local['budget.collapsed'],
   );
-  let summaryCollapsed = useSelector(
+  const summaryCollapsed = useSelector(
     state => state.prefs.local['budget.summaryCollapsed'],
   );
-  let budgetType = useSelector(
+  const budgetType = useSelector(
     state => state.prefs.local.budgetType || 'rollover',
   );
-  let maxMonths = useSelector(state => state.prefs.global.maxMonths);
-  let { grouped: categoryGroups } = useCategories();
+  const maxMonths = useSelector(state => state.prefs.global.maxMonths);
+  const { grouped: categoryGroups } = useCategories();
 
-  let actions = useActions();
-  let spreadsheet = useSpreadsheet();
-  let titlebar = useContext(TitlebarContext);
-  let location = useLocation();
-  let match = useMatch(location.pathname);
-  let navigate = useNavigate();
+  const actions = useActions();
+  const spreadsheet = useSpreadsheet();
+  const titlebar = useContext(TitlebarContext);
+  const location = useLocation();
+  const match = useMatch(location.pathname);
+  const navigate = useNavigate();
 
-  let reportComponents = useMemo<ReportComponents>(
+  const reportComponents = useMemo<ReportComponents>(
     () => ({
       SummaryComponent: report.BudgetSummary,
       ExpenseCategoryComponent: report.ExpenseCategoryMonth,
@@ -565,7 +567,7 @@ export default function BudgetWrapper(props) {
     [report],
   );
 
-  let rolloverComponents = useMemo<RolloverComponents>(
+  const rolloverComponents = useMemo<RolloverComponents>(
     () => ({
       SummaryComponent: RolloverBudgetSummary,
       ExpenseCategoryComponent: rollover.ExpenseCategoryMonth,
diff --git a/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx b/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
index 4d34915a5e39adfcf7a0ccae58e181a18784f16d..c1c297518a821cec0b8ab7f448a02351788f705a 100644
--- a/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
@@ -22,9 +22,9 @@ export default function BalanceTooltip({
   onClose,
   ...tooltipProps
 }: BalanceTooltipProps) {
-  let carryover = useSheetValue(reportBudget.catCarryover(categoryId));
+  const carryover = useSheetValue(reportBudget.catCarryover(categoryId));
 
-  let _onClose = () => {
+  const _onClose = () => {
     tooltip.close();
     onClose?.();
   };
diff --git a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
index 1d3d03bb8d36852be59295736b06adda39f0db68..ed38d3bab9d7aae8a0624f6aa9d4e07d7ed4d896 100644
--- a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
+++ b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
@@ -20,7 +20,7 @@ import { makeAmountGrey } from '../util';
 
 import BalanceTooltip from './BalanceTooltip';
 
-let headerLabelStyle: CSSProperties = {
+const headerLabelStyle: CSSProperties = {
   flex: 1,
   padding: '0 5px',
   textAlign: 'right',
@@ -91,7 +91,7 @@ type GroupMonthProps = {
   group: { id: string; is_income: boolean };
 };
 export const GroupMonth = memo(function GroupMonth({ group }: GroupMonthProps) {
-  let { id } = group;
+  const { id } = group;
 
   return (
     <View style={{ flex: 1, flexDirection: 'row' }}>
@@ -156,7 +156,7 @@ export const CategoryMonth = memo(function CategoryMonth({
   onBudgetAction,
   onShowActivity,
 }: CategoryMonthProps) {
-  let balanceTooltip = useTooltip();
+  const balanceTooltip = useTooltip();
   const [menuOpen, setMenuOpen] = useState(false);
   const [hover, setHover] = useState(false);
   const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
diff --git a/packages/desktop-client/src/components/budget/report/ReportContext.tsx b/packages/desktop-client/src/components/budget/report/ReportContext.tsx
index 3f746cfd5b0a0d0b48b782c96139b0247b3d0b1f..e38b4da869fbf76bcabe887e994bc87d3a2c55f6 100644
--- a/packages/desktop-client/src/components/budget/report/ReportContext.tsx
+++ b/packages/desktop-client/src/components/budget/report/ReportContext.tsx
@@ -2,7 +2,7 @@ import React, { type ReactNode, createContext, useContext } from 'react';
 
 import * as monthUtils from 'loot-core/src/shared/months';
 
-let Context = createContext(null);
+const Context = createContext(null);
 
 type ReportProviderProps = {
   summaryCollapsed: boolean;
@@ -16,7 +16,7 @@ export function ReportProvider({
   onToggleSummaryCollapse,
   children,
 }: ReportProviderProps) {
-  let currentMonth = monthUtils.currentMonth();
+  const currentMonth = monthUtils.currentMonth();
 
   return (
     <Context.Provider
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
index d1f726a7ed5e1caf478fe9cca8629895ce5fb133..58e18d32a0a8441416b9b3af4fd600ccae436079 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
@@ -26,7 +26,7 @@ type BudgetSummaryProps = {
   month?: string;
 };
 export default function BudgetSummary({ month }: BudgetSummaryProps) {
-  let {
+  const {
     currentMonth,
     summaryCollapsed: collapsed,
     onBudgetAction,
@@ -35,7 +35,7 @@ export default function BudgetSummary({ month }: BudgetSummaryProps) {
 
   const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
 
-  let [menuOpen, setMenuOpen] = useState(false);
+  const [menuOpen, setMenuOpen] = useState(false);
   function onMenuOpen() {
     setMenuOpen(true);
   }
@@ -44,7 +44,7 @@ export default function BudgetSummary({ month }: BudgetSummaryProps) {
     setMenuOpen(false);
   }
 
-  let ExpandOrCollapseIcon = collapsed ? ArrowButtonDown1 : ArrowButtonUp1;
+  const ExpandOrCollapseIcon = collapsed ? ArrowButtonDown1 : ArrowButtonUp1;
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
index 5f5120cdeb0e5ecbbf655aac307a5bef24c85b11..4613c95760681d240c4a93d4362badc8fa2ff60a 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx
@@ -13,7 +13,7 @@ type ExpenseProgressProps = {
 };
 export function ExpenseProgress({ current, target }: ExpenseProgressProps) {
   let totalSpent = useSheetValue(current) || 0;
-  let totalBudgeted = useSheetValue(target) || 0;
+  const totalBudgeted = useSheetValue(target) || 0;
 
   // Reverse total spent, and also set a bottom boundary of 0 (in case
   // income goes into an expense category and it's "positive", don't
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/IncomeProgress.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/IncomeProgress.tsx
index 7a13d213d5a25aeb8e752ea30718fc1e63a8efc8..33f731711e70936a45156570ee9831ac5a06dad8 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/IncomeProgress.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/IncomeProgress.tsx
@@ -16,7 +16,7 @@ export default function IncomeProgress({
   target,
 }: IncomeProgressProps) {
   let totalIncome = useSheetValue(current) || 0;
-  let totalBudgeted = useSheetValue(target) || 0;
+  const totalBudgeted = useSheetValue(target) || 0;
 
   let over = false;
 
@@ -25,7 +25,7 @@ export default function IncomeProgress({
     totalIncome = -totalIncome;
   }
 
-  let frac = fraction(totalIncome, totalBudgeted);
+  const frac = fraction(totalIncome, totalBudgeted);
 
   return (
     <PieProgress
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/PieProgress.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/PieProgress.tsx
index 32cba3df5cbfb35ddc7dcd440c09bf1d4c85d1a8..7f655168f0e7225da4f9dcd32e597c8cd05b9fac 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/PieProgress.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/PieProgress.tsx
@@ -12,10 +12,10 @@ export default function PieProgress({
   color,
   backgroundColor,
 }: PieProgressProps) {
-  let radius = 4;
-  let circum = 2 * Math.PI * radius;
-  let dash = progress * circum;
-  let gap = circum;
+  const radius = 4;
+  const circum = 2 * Math.PI * radius;
+  const dash = progress * circum;
+  const gap = circum;
 
   return (
     <svg viewBox="0 0 20 20" style={style}>
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
index 8c8768e3e729a374a7eac7d3808e5bb396615529..80fbf1b74ace6a95a1a219925d426aa3501dc270 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
@@ -20,11 +20,11 @@ type SavedProps = {
   style?: CSSProperties;
 };
 export default function Saved({ projected, style }: SavedProps) {
-  let budgetedSaved = useSheetValue(reportBudget.totalBudgetedSaved) || 0;
-  let totalSaved = useSheetValue(reportBudget.totalSaved) || 0;
-  let format = useFormat();
-  let saved = projected ? budgetedSaved : totalSaved;
-  let isNegative = saved < 0;
+  const budgetedSaved = useSheetValue(reportBudget.totalBudgetedSaved) || 0;
+  const totalSaved = useSheetValue(reportBudget.totalSaved) || 0;
+  const format = useFormat();
+  const saved = projected ? budgetedSaved : totalSaved;
+  const isNegative = saved < 0;
 
   return (
     <View style={{ alignItems: 'center', fontSize: 14, ...style }}>
@@ -39,7 +39,7 @@ export default function Saved({ projected, style }: SavedProps) {
       <HoverTarget
         renderContent={() => {
           if (!projected) {
-            let diff = totalSaved - budgetedSaved;
+            const diff = totalSaved - budgetedSaved;
             return (
               <Tooltip
                 position="bottom-center"
diff --git a/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx
index cf959c9a9459b9ee166bd5f9a5a3a49d62922e36..6df17d977bc25ef2749b299c4da668a90ee27815 100644
--- a/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/BalanceTooltip.tsx
@@ -24,11 +24,11 @@ export default function BalanceTooltip({
   onClose,
   ...tooltipProps
 }: BalanceTooltipProps) {
-  let carryover = useSheetValue(rolloverBudget.catCarryover(categoryId));
-  let balance = useSheetValue(rolloverBudget.catBalance(categoryId));
-  let [menu, setMenu] = useState('menu');
+  const carryover = useSheetValue(rolloverBudget.catCarryover(categoryId));
+  const balance = useSheetValue(rolloverBudget.catBalance(categoryId));
+  const [menu, setMenu] = useState('menu');
 
-  let _onClose = () => {
+  const _onClose = () => {
     tooltip.close();
     onClose?.();
   };
diff --git a/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx
index 9e24fcaf6828d43119fa079fc9d9f15305c62c5d..2605e5df23b460f49f8a3f4bb1a02be59751be76 100644
--- a/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/CoverTooltip.tsx
@@ -22,7 +22,7 @@ export default function CoverTooltip({
   categoryGroups = addToBeBudgetedGroup(
     categoryGroups.filter(g => !g.is_income),
   );
-  let [category, setCategory] = useState(null);
+  const [category, setCategory] = useState(null);
 
   function submit() {
     if (category) {
diff --git a/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx b/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
index 747770a7d869756ade95d099386e117666e2d35f..e34a1322d2f6875dc6abaf4013a4edb07ea780f8 100644
--- a/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/RolloverComponents.tsx
@@ -20,7 +20,7 @@ import { makeAmountGrey } from '../util';
 
 import BalanceTooltip from './BalanceTooltip';
 
-let headerLabelStyle: CSSProperties = {
+const headerLabelStyle: CSSProperties = {
   flex: 1,
   padding: '0 5px',
   textAlign: 'right',
@@ -89,7 +89,7 @@ type ExpenseGroupMonthProps = {
 export const ExpenseGroupMonth = memo(function ExpenseGroupMonth({
   group,
 }: ExpenseGroupMonthProps) {
-  let { id } = group;
+  const { id } = group;
 
   return (
     <View style={{ flex: 1, flexDirection: 'row' }}>
@@ -152,7 +152,7 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
   onBudgetAction,
   onShowActivity,
 }: ExpenseCategoryMonthProps) {
-  let balanceTooltip = useTooltip();
+  const balanceTooltip = useTooltip();
   const [menuOpen, setMenuOpen] = useState(false);
   const [hover, setHover] = useState(false);
   const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
diff --git a/packages/desktop-client/src/components/budget/rollover/RolloverContext.tsx b/packages/desktop-client/src/components/budget/rollover/RolloverContext.tsx
index 7006ae78ee8498d939d9703df2376b4448a1e899..3d825c834e251a7fef00e07f7dc70f22e7d8b3ac 100644
--- a/packages/desktop-client/src/components/budget/rollover/RolloverContext.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/RolloverContext.tsx
@@ -2,7 +2,7 @@ import React, { type ReactNode, createContext, useContext } from 'react';
 
 import * as monthUtils from 'loot-core/src/shared/months';
 
-let Context = createContext(null);
+const Context = createContext(null);
 
 type RolloverContextProps = {
   categoryGroups: unknown[];
@@ -18,7 +18,7 @@ export function RolloverContext({
   onToggleSummaryCollapse,
   children,
 }: RolloverContextProps) {
-  let currentMonth = monthUtils.currentMonth();
+  const currentMonth = monthUtils.currentMonth();
 
   return (
     <Context.Provider
diff --git a/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx b/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx
index 4aa10527c9e90831158afa8b11b441decb7ac80d..5e7c382165bfc71156dde24f5bb84fb6aa88f17e 100644
--- a/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/TransferTooltip.tsx
@@ -34,8 +34,8 @@ export default function TransferTooltip({
   position = 'bottom-right',
   ...props
 }: TransferTooltipProps) {
-  let spreadsheet = useSpreadsheet();
-  let sheetName = useContext(NamespaceContext);
+  const spreadsheet = useSpreadsheet();
+  const sheetName = useContext(NamespaceContext);
   let { grouped: categoryGroups } = useCategories();
 
   categoryGroups = categoryGroups.filter(g => !g.is_income);
@@ -43,8 +43,8 @@ export default function TransferTooltip({
     categoryGroups = addToBeBudgetedGroup(categoryGroups);
   }
 
-  let [amount, setAmount] = useState(null);
-  let [category, setCategory] = useState(null);
+  const [amount, setAmount] = useState(null);
+  const [category, setCategory] = useState(null);
 
   useEffect(() => {
     (async () => {
@@ -58,7 +58,7 @@ export default function TransferTooltip({
   }, []);
 
   function submit() {
-    let parsedAmount = evalArithmetic(amount, null);
+    const parsedAmount = evalArithmetic(amount, null);
     if (parsedAmount && category) {
       onSubmit(amountToInteger(parsedAmount), category);
       onClose();
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
index 5cbf8f573430560bcde050b888d4d761f871314a..0a5c73b9c7afdb15af4cd8ac980f9acde1bb1441 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
@@ -27,14 +27,14 @@ export default function BudgetSummary({
   month,
   isGoalTemplatesEnabled,
 }: BudgetSummaryProps) {
-  let {
+  const {
     currentMonth,
     summaryCollapsed: collapsed,
     onBudgetAction,
     onToggleSummaryCollapse,
   } = useRollover();
 
-  let [menuOpen, setMenuOpen] = useState(false);
+  const [menuOpen, setMenuOpen] = useState(false);
   function onMenuOpen(e) {
     setMenuOpen(true);
   }
@@ -43,9 +43,9 @@ export default function BudgetSummary({
     setMenuOpen(false);
   }
 
-  let prevMonthName = monthUtils.format(monthUtils.prevMonth(month), 'MMM');
+  const prevMonthName = monthUtils.format(monthUtils.prevMonth(month), 'MMM');
 
-  let ExpandOrCollapseIcon = collapsed ? ArrowButtonDown1 : ArrowButtonUp1;
+  const ExpandOrCollapseIcon = collapsed ? ArrowButtonDown1 : ArrowButtonUp1;
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
index e024e322d928c0bc80a5ae64b52604bb89b18f82..184456c76936b26a76b3c0c293d52676ffdfe882 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudget.tsx
@@ -43,16 +43,16 @@ export default function ToBudget({
   holdTooltipProps,
   transferTooltipProps,
 }: ToBudgetProps) {
-  let [menuOpen, setMenuOpen] = useState(null);
-  let sheetName = useSheetName(rolloverBudget.toBudget);
-  let sheetValue = useSheetValue({
+  const [menuOpen, setMenuOpen] = useState(null);
+  const sheetName = useSheetName(rolloverBudget.toBudget);
+  const sheetValue = useSheetValue({
     name: rolloverBudget.toBudget,
     value: 0,
   });
-  let format = useFormat();
-  let availableValue = parseInt(sheetValue);
-  let num = isNaN(availableValue) ? 0 : availableValue;
-  let isNegative = num < 0;
+  const format = useFormat();
+  const availableValue = parseInt(sheetValue);
+  const num = isNaN(availableValue) ? 0 : availableValue;
+  const isNegative = num < 0;
 
   return (
     <View style={{ alignItems: 'center', ...style }}>
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
index 0805b8bacf020db7e8894aa39b8a3d1d79af070a..20a5fd4b9cfa07b80af169ce5825012d6b5d6e8c 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
@@ -75,7 +75,7 @@ export default function TotalsList({ prevMonthName, style }: TotalsListProps) {
           binding={rolloverBudget.lastMonthOverspent}
           type="financial"
           formatter={value => {
-            let v = format(value, 'financial');
+            const v = format(value, 'financial');
             return value > 0 ? '+' + v : value === 0 ? '-' + v : v;
           }}
           style={{ fontWeight: 600, ...styles.tnum }}
@@ -85,7 +85,7 @@ export default function TotalsList({ prevMonthName, style }: TotalsListProps) {
           binding={rolloverBudget.totalBudgeted}
           type="financial"
           formatter={value => {
-            let v = format(value, 'financial');
+            const v = format(value, 'financial');
             return value > 0 ? '+' + v : value === 0 ? '-' + v : v;
           }}
           style={{ fontWeight: 600, ...styles.tnum }}
@@ -95,8 +95,8 @@ export default function TotalsList({ prevMonthName, style }: TotalsListProps) {
           binding={rolloverBudget.forNextMonth}
           type="financial"
           formatter={value => {
-            let n = parseInt(value) || 0;
-            let v = format(Math.abs(n), 'financial');
+            const n = parseInt(value) || 0;
+            const v = format(Math.abs(n), 'financial');
             return n >= 0 ? '-' + v : '+' + v;
           }}
           style={{ fontWeight: 600, ...styles.tnum }}
diff --git a/packages/desktop-client/src/components/budget/util.ts b/packages/desktop-client/src/components/budget/util.ts
index 6e9f7dd1427d70f757885e9435256f4291c821e6..b1e7d7d5c2496169d8597b5b77032aff3ec6fc93 100644
--- a/packages/desktop-client/src/components/budget/util.ts
+++ b/packages/desktop-client/src/components/budget/util.ts
@@ -85,13 +85,13 @@ export function findSortDown(
   if (pos === 'top') {
     return { targetId };
   } else {
-    let idx = arr.findIndex(item => item.id === targetId);
+    const idx = arr.findIndex(item => item.id === targetId);
 
     if (idx === -1) {
       throw new Error('findSort: item not found: ' + targetId);
     }
 
-    let newIdx = idx + 1;
+    const newIdx = idx + 1;
     if (newIdx < arr.length - 1) {
       return { targetId: arr[newIdx].id };
     } else {
@@ -109,13 +109,13 @@ export function findSortUp(
   if (pos === 'bottom') {
     return { targetId };
   } else {
-    let idx = arr.findIndex(item => item.id === targetId);
+    const idx = arr.findIndex(item => item.id === targetId);
 
     if (idx === -1) {
       throw new Error('findSort: item not found: ' + targetId);
     }
 
-    let newIdx = idx - 1;
+    const newIdx = idx - 1;
     if (newIdx >= 0) {
       return { targetId: arr[newIdx].id };
     } else {
@@ -134,12 +134,12 @@ export async function prewarmMonth(
   spreadsheet: ReturnType<typeof useSpreadsheet>,
   month: string,
 ) {
-  let method: keyof Handlers =
+  const method: keyof Handlers =
     budgetType === 'report' ? 'report-budget-month' : 'rollover-budget-month';
 
-  let values = await send(method, { month });
+  const values = await send(method, { month });
 
-  for (let value of values) {
+  for (const value of values) {
     spreadsheet.prewarmCache(value.name, value);
   }
 }
@@ -150,14 +150,14 @@ export async function prewarmAllMonths(
   bounds: { start: string; end: string },
   startMonth: string,
 ) {
-  let numMonths = 3;
+  const numMonths = 3;
 
   bounds = getValidMonthBounds(
     bounds,
     monthUtils.subMonths(startMonth, 1),
     monthUtils.addMonths(startMonth, numMonths + 1),
   );
-  let months = monthUtils.rangeInclusive(bounds.start, bounds.end);
+  const months = monthUtils.rangeInclusive(bounds.start, bounds.end);
 
   await Promise.all(
     months.map(month => prewarmMonth(budgetType, spreadsheet, month)),
diff --git a/packages/desktop-client/src/components/common/AnchorLink.tsx b/packages/desktop-client/src/components/common/AnchorLink.tsx
index c1ea47493855dc828a1350cd0aaa7749bd0aeca2..2cc6ba3fd013e2538a100f43e32aa19e2ccec5f6 100644
--- a/packages/desktop-client/src/components/common/AnchorLink.tsx
+++ b/packages/desktop-client/src/components/common/AnchorLink.tsx
@@ -18,7 +18,7 @@ export default function AnchorLink({
   activeStyle,
   children,
 }: AnchorLinkProps) {
-  let match = useMatch({ path: to });
+  const match = useMatch({ path: to });
 
   return (
     <NavLink
diff --git a/packages/desktop-client/src/components/common/Button.tsx b/packages/desktop-client/src/components/common/Button.tsx
index a421059aed94ca0f5c8b61e4af046888f45465c0..f99e0adec7efde55c7975ad831a1f5b3f9c136ef 100644
--- a/packages/desktop-client/src/components/common/Button.tsx
+++ b/packages/desktop-client/src/components/common/Button.tsx
@@ -149,7 +149,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
     },
     ref,
   ) => {
-    let typeWithDisabled = disabled ? type + 'Disabled' : type;
+    const typeWithDisabled = disabled ? type + 'Disabled' : type;
 
     hoveredStyle = {
       ...(type !== 'bare' && styles.shadow),
@@ -163,8 +163,8 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
       ...activeStyle,
     };
 
-    let Component = as;
-    let buttonStyle = {
+    const Component = as;
+    const buttonStyle = {
       alignItems: 'center',
       justifyContent: 'center',
       flexShrink: 0,
@@ -211,7 +211,7 @@ export const ButtonWithLoading = forwardRef<
   HTMLButtonElement,
   ButtonWithLoadingProps
 >((props, ref) => {
-  let { loading, children, ...buttonProps } = props;
+  const { loading, children, ...buttonProps } = props;
   return (
     <Button
       {...buttonProps}
diff --git a/packages/desktop-client/src/components/common/ExternalLink.tsx b/packages/desktop-client/src/components/common/ExternalLink.tsx
index 6c37ea5825a06a5f06556fad36fc0bf05b3db217..f31d240c9b540386cc0716d6888f8921f7612ca7 100644
--- a/packages/desktop-client/src/components/common/ExternalLink.tsx
+++ b/packages/desktop-client/src/components/common/ExternalLink.tsx
@@ -2,7 +2,7 @@ import React, { type ReactNode, forwardRef } from 'react';
 
 import { theme } from '../../style';
 
-let externalLinkColors = {
+const externalLinkColors = {
   purple: theme.pageTextPositive,
   blue: theme.pageTextLink,
   muted: 'inherit',
diff --git a/packages/desktop-client/src/components/common/HoverTarget.tsx b/packages/desktop-client/src/components/common/HoverTarget.tsx
index bbaa27b87d45cd5564e353f5561a198e671c6b7d..097ad9c013da88a58a776801239f477675d7b78e 100644
--- a/packages/desktop-client/src/components/common/HoverTarget.tsx
+++ b/packages/desktop-client/src/components/common/HoverTarget.tsx
@@ -19,7 +19,7 @@ export default function HoverTarget({
   renderContent,
   disabled,
 }: HoverTargetProps) {
-  let [hovered, setHovered] = useState(false);
+  const [hovered, setHovered] = useState(false);
 
   const onPointerEnter = useCallback(() => {
     if (!disabled) {
diff --git a/packages/desktop-client/src/components/common/InitialFocus.tsx b/packages/desktop-client/src/components/common/InitialFocus.tsx
index 7c6ad0a651ecee514a4bfe08dfdfb9da1ee53c00..6f88cbb60f0a8cef7bf7decd0635590214b553a2 100644
--- a/packages/desktop-client/src/components/common/InitialFocus.tsx
+++ b/packages/desktop-client/src/components/common/InitialFocus.tsx
@@ -11,7 +11,7 @@ type InitialFocusProps = {
 };
 
 export default function InitialFocus({ children }: InitialFocusProps) {
-  let node = useRef(null);
+  const node = useRef(null);
 
   useEffect(() => {
     if (node.current && !global.IS_DESIGN_MODE) {
diff --git a/packages/desktop-client/src/components/common/Input.tsx b/packages/desktop-client/src/components/common/Input.tsx
index d5284251426266b3118ffded1a80f53705055e30..6a4e6eaf96596ab705e29c0c003f012235eb54d7 100644
--- a/packages/desktop-client/src/components/common/Input.tsx
+++ b/packages/desktop-client/src/components/common/Input.tsx
@@ -37,7 +37,7 @@ export default function Input({
   focused,
   ...nativeProps
 }: InputProps) {
-  let ref = useRef();
+  const ref = useRef();
   useProperFocus(ref, focused);
 
   return (
diff --git a/packages/desktop-client/src/components/common/InputWithContent.tsx b/packages/desktop-client/src/components/common/InputWithContent.tsx
index 6321a7d857ce098521c0bf44a09bdf012ae5fc85..24b357342a8272b8c2182543e5dd8ed693e3e858 100644
--- a/packages/desktop-client/src/components/common/InputWithContent.tsx
+++ b/packages/desktop-client/src/components/common/InputWithContent.tsx
@@ -22,7 +22,7 @@ export default function InputWithContent({
   getStyle,
   ...props
 }: InputWithContentProps) {
-  let [focused, setFocused] = useState(props.focused);
+  const [focused, setFocused] = useState(props.focused);
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/common/Menu.tsx b/packages/desktop-client/src/components/common/Menu.tsx
index be4382405f3ac76196eef93bcc9671d067025f19..1d0258cd77e7e294700571aa34e657bae252cff5 100644
--- a/packages/desktop-client/src/components/common/Menu.tsx
+++ b/packages/desktop-client/src/components/common/Menu.tsx
@@ -46,21 +46,21 @@ export default function Menu({
   items: allItems,
   onMenuSelect,
 }: MenuProps) {
-  let elRef = useRef(null);
-  let items = allItems.filter(x => x);
-  let [hoveredIndex, setHoveredIndex] = useState(null);
+  const elRef = useRef(null);
+  const items = allItems.filter(x => x);
+  const [hoveredIndex, setHoveredIndex] = useState(null);
 
   useEffect(() => {
     const el = elRef.current;
     el.focus();
 
-    let onKeyDown = e => {
-      let filteredItems = items.filter(
+    const onKeyDown = e => {
+      const filteredItems = items.filter(
         item => item && item !== Menu.line && item.type !== Menu.label,
       );
-      let currentIndex = filteredItems.indexOf(items[hoveredIndex]);
+      const currentIndex = filteredItems.indexOf(items[hoveredIndex]);
 
-      let transformIndex = idx => items.indexOf(filteredItems[idx]);
+      const transformIndex = idx => items.indexOf(filteredItems[idx]);
 
       switch (e.key) {
         case 'ArrowUp':
@@ -131,7 +131,7 @@ export default function Menu({
           );
         }
 
-        let lastItem = items[idx - 1];
+        const lastItem = items[idx - 1];
 
         return (
           <View
diff --git a/packages/desktop-client/src/components/common/Modal.tsx b/packages/desktop-client/src/components/common/Modal.tsx
index a03bdd004b35176fd5c2e174a70c1c8c33121ff4..3eac7bf303b9a90598562bff9e4f8907b84458d4 100644
--- a/packages/desktop-client/src/components/common/Modal.tsx
+++ b/packages/desktop-client/src/components/common/Modal.tsx
@@ -64,7 +64,7 @@ const Modal = ({
     // This deactivates any key handlers in the "app" scope. Ideally
     // each modal would have a name so they could each have their own
     // key handlers, but we'll do that later
-    let prevScope = hotkeys.getScope();
+    const prevScope = hotkeys.getScope();
     hotkeys.setScope('modal');
     return () => hotkeys.setScope(prevScope);
   }, []);
@@ -243,9 +243,9 @@ const ModalContent = ({
   stackIndex,
   children,
 }: ModalContentProps) => {
-  let contentRef = useRef(null);
-  let mounted = useRef(false);
-  let rotateFactor = useRef(Math.random() * 10 - 5);
+  const contentRef = useRef(null);
+  const mounted = useRef(false);
+  const rotateFactor = useRef(Math.random() * 10 - 5);
 
   useLayoutEffect(() => {
     if (contentRef.current == null) {
@@ -319,11 +319,11 @@ export const ModalButtons = ({
   focusButton = false,
   children,
 }: ModalButtonsProps) => {
-  let containerRef = useRef(null);
+  const containerRef = useRef(null);
 
   useEffect(() => {
     if (focusButton && containerRef.current) {
-      let button = containerRef.current.querySelector(
+      const button = containerRef.current.querySelector(
         'button:not([data-hidden])',
       );
 
diff --git a/packages/desktop-client/src/components/common/Stack.tsx b/packages/desktop-client/src/components/common/Stack.tsx
index a59cf5a9fc374894e1ecec3a9493fc56da855e53..1a3df4f0f1daea5358af4e43f763758c940ede37 100644
--- a/packages/desktop-client/src/components/common/Stack.tsx
+++ b/packages/desktop-client/src/components/common/Stack.tsx
@@ -66,7 +66,7 @@ const Stack = forwardRef<HTMLDivElement, StackProps>(
         {...props}
       >
         {validChildren.map(({ key, child }, index) => {
-          let isLastChild = validChildren.length === index + 1;
+          const isLastChild = validChildren.length === index + 1;
 
           let marginProp;
           if (isHorizontal) {
diff --git a/packages/desktop-client/src/components/filters/FiltersMenu.js b/packages/desktop-client/src/components/filters/FiltersMenu.js
index 2c1b6d58e637a3fa90f31f0645113ab0e739fea6..16034382cca23eb8ca7ffb5fae76ed6dbcc91812 100644
--- a/packages/desktop-client/src/components/filters/FiltersMenu.js
+++ b/packages/desktop-client/src/components/filters/FiltersMenu.js
@@ -40,7 +40,7 @@ import CompactFiltersButton from './CompactFiltersButton';
 import FiltersButton from './FiltersButton';
 import { CondOpMenu } from './SavedFilters';
 
-let filterFields = [
+const filterFields = [
   'date',
   'account',
   'payee',
@@ -119,7 +119,7 @@ function OpButton({ op, selected, style, onClick }) {
 function updateFilterReducer(state, action) {
   switch (action.type) {
     case 'set-op': {
-      let type = FIELD_TYPES.get(state.field);
+      const type = FIELD_TYPES.get(state.field);
       let value = state.value;
       if (
         (type === 'id' || type === 'string') &&
@@ -135,7 +135,7 @@ function updateFilterReducer(state, action) {
       return { ...state, op: action.op, value };
     }
     case 'set-value': {
-      let { value } = makeValue(action.value, {
+      const { value } = makeValue(action.value, {
         type: FIELD_TYPES.get(state.field),
       });
       return { ...state, value };
@@ -153,9 +153,10 @@ function ConfigureField({
   dispatch,
   onApply,
 }) {
-  let [subfield, setSubfield] = useState(initialSubfield);
-  let inputRef = useRef();
-  let prevOp = useRef(null);
+  const [subfield, setSubfield] = useState(initialSubfield);
+  const inputRef = useRef();
+  const prevOp = useRef(null);
+
   useEffect(() => {
     if (prevOp.current !== op && inputRef.current) {
       inputRef.current.focus();
@@ -163,7 +164,7 @@ function ConfigureField({
     prevOp.current = op;
   }, [op]);
 
-  let type = FIELD_TYPES.get(field);
+  const type = FIELD_TYPES.get(field);
   let ops = TYPE_INFO[type].ops.filter(op => op !== 'isbetween');
 
   // Month and year fields are quite hacky right now! Figure out how
@@ -337,23 +338,23 @@ function ConfigureField({
 }
 
 export function FilterButton({ onApply, compact, hover }) {
-  let filters = useFilters();
+  const filters = useFilters();
 
-  let { dateFormat } = useSelector(state => {
+  const { dateFormat } = useSelector(state => {
     return {
       dateFormat: state.prefs.local.dateFormat || 'MM/dd/yyyy',
     };
   });
 
-  let [state, dispatch] = useReducer(
+  const [state, dispatch] = useReducer(
     (state, action) => {
       switch (action.type) {
         case 'select-field':
           return { ...state, fieldsOpen: true, condOpen: false };
         case 'configure': {
-          let { field } = deserializeField(action.field);
-          let type = FIELD_TYPES.get(field);
-          let ops = TYPE_INFO[type].ops;
+          const { field } = deserializeField(action.field);
+          const type = FIELD_TYPES.get(field);
+          const ops = TYPE_INFO[type].ops;
           return {
             ...state,
             fieldsOpen: false,
@@ -377,7 +378,7 @@ export function FilterButton({ onApply, compact, hover }) {
 
     if (cond.type === 'date' && cond.options) {
       if (cond.options.month) {
-        let date = parseDate(
+        const date = parseDate(
           cond.value,
           getMonthYearFormat(dateFormat),
           new Date(),
@@ -389,7 +390,7 @@ export function FilterButton({ onApply, compact, hover }) {
           return;
         }
       } else if (cond.options.year) {
-        let date = parseDate(cond.value, 'yyyy', new Date());
+        const date = parseDate(cond.value, 'yyyy', new Date());
         if (isDateValid(date)) {
           cond.value = formatDate(date, 'yyyy');
         } else {
@@ -399,17 +400,17 @@ export function FilterButton({ onApply, compact, hover }) {
       }
     }
 
-    let { error } =
+    const { error } =
       cond.field !== 'saved' &&
       (await send('rule-validate', {
         conditions: [cond],
         actions: [],
       }));
 
-    let saved = filters.find(f => cond.value === f.id);
+    const saved = filters.find(f => cond.value === f.id);
 
     if (error && error.conditionErrors.length > 0) {
-      let field = titleFirst(mapField(cond.field));
+      const field = titleFirst(mapField(cond.field));
       alert(field + ': ' + getFieldError(error.conditionErrors[0]));
     } else {
       onApply(saved ? saved : cond);
@@ -477,7 +478,7 @@ export function FilterButton({ onApply, compact, hover }) {
 }
 
 function FilterEditor({ field, op, value, options, onSave, onClose }) {
-  let [state, dispatch] = useReducer(
+  const [state, dispatch] = useReducer(
     (state, action) => {
       switch (action.type) {
         case 'close':
@@ -518,9 +519,10 @@ function FilterExpression({
   onChange,
   onDelete,
 }) {
-  let [editing, setEditing] = useState(false);
+  const [editing, setEditing] = useState(false);
+
+  const field = subfieldFromFilter({ field: originalField, value });
 
-  let field = subfieldFromFilter({ field: originalField, value });
   return (
     <View
       style={{
diff --git a/packages/desktop-client/src/components/filters/SavedFilters.js b/packages/desktop-client/src/components/filters/SavedFilters.js
index 31f88898f25fb11cd7f9b2454c735d8844245613..fce9af440cdcb6f316da7bcb9fe46606f48f51ce 100644
--- a/packages/desktop-client/src/components/filters/SavedFilters.js
+++ b/packages/desktop-client/src/components/filters/SavedFilters.js
@@ -67,7 +67,7 @@ function NameFilter({
   onAddUpdate,
   err,
 }) {
-  let inputRef = useRef();
+  const inputRef = useRef();
 
   useEffect(() => {
     if (inputRef.current) {
@@ -130,13 +130,13 @@ function SavedFilterMenuButton({
   onReloadSavedFilter,
   filtersList,
 }) {
-  let [nameOpen, setNameOpen] = useState(false);
-  let [adding, setAdding] = useState(false);
-  let [menuOpen, setMenuOpen] = useState(false);
-  let [err, setErr] = useState(null);
-  let [menuItem, setMenuItem] = useState(null);
-  let [name, setName] = useState(filterId.name);
-  let id = filterId.id;
+  const [nameOpen, setNameOpen] = useState(false);
+  const [adding, setAdding] = useState(false);
+  const [menuOpen, setMenuOpen] = useState(false);
+  const [err, setErr] = useState(null);
+  const [menuItem, setMenuItem] = useState(null);
+  const [name, setName] = useState(filterId.name);
+  const id = filterId.id;
   let res;
   let savedFilter;
 
diff --git a/packages/desktop-client/src/components/manager/BudgetList.js b/packages/desktop-client/src/components/manager/BudgetList.js
index 0f57c29f954266d28fac6acae4e86af69b96eced..0d702504f3816d5e069355d81e33bb2d2eed9d48 100644
--- a/packages/desktop-client/src/components/manager/BudgetList.js
+++ b/packages/desktop-client/src/components/manager/BudgetList.js
@@ -51,13 +51,13 @@ function FileMenu({ onDelete, onClose }) {
     }
   }
 
-  let items = [{ name: 'delete', text: 'Delete' }];
+  const items = [{ name: 'delete', text: 'Delete' }];
 
   return <Menu onMenuSelect={onMenuSelect} items={items} />;
 }
 
 function DetailButton({ state, onDelete }) {
-  let [menuOpen, setMenuOpen] = useState(false);
+  const [menuOpen, setMenuOpen] = useState(false);
 
   return (
     <View>
@@ -137,7 +137,7 @@ function FileState({ file }) {
 }
 
 function File({ file, onSelect, onDelete }) {
-  let selecting = useRef(false);
+  const selecting = useRef(false);
 
   async function _onSelect(file) {
     // Never allow selecting the file while uploading/downloading, and
@@ -223,7 +223,7 @@ function BudgetTable({ files, onSelect, onDelete }) {
 }
 
 function RefreshButton({ onRefresh }) {
-  let [loading, setLoading] = useState(false);
+  const [loading, setLoading] = useState(false);
 
   async function _onRefresh() {
     setLoading(true);
@@ -231,7 +231,7 @@ function RefreshButton({ onRefresh }) {
     setLoading(false);
   }
 
-  let Icon = loading ? Loading : RefreshArrow;
+  const Icon = loading ? Loading : RefreshArrow;
 
   return (
     <Button
@@ -246,9 +246,9 @@ function RefreshButton({ onRefresh }) {
 }
 
 export default function BudgetList() {
-  let files = useSelector(state => state.budgets.allFiles || []);
+  const files = useSelector(state => state.budgets.allFiles || []);
 
-  let {
+  const {
     getUserData,
     loadAllFiles,
     pushModal,
diff --git a/packages/desktop-client/src/components/manager/ConfigServer.tsx b/packages/desktop-client/src/components/manager/ConfigServer.tsx
index cda664eb51aa85228679e1678cc29c7232bb001d..20cf42356f7ac6e677070540da8cdfaeae390891 100644
--- a/packages/desktop-client/src/components/manager/ConfigServer.tsx
+++ b/packages/desktop-client/src/components/manager/ConfigServer.tsx
@@ -19,16 +19,16 @@ import { Title } from './subscribe/common';
 
 export default function ConfigServer() {
   useSetThemeColor(theme.mobileConfigServerViewTheme);
-  let { createBudget, signOut, loggedIn } = useActions();
-  let navigate = useNavigate();
-  let [url, setUrl] = useState('');
-  let currentUrl = useServerURL();
-  let setServerUrl = useSetServerURL();
+  const { createBudget, signOut, loggedIn } = useActions();
+  const navigate = useNavigate();
+  const [url, setUrl] = useState('');
+  const currentUrl = useServerURL();
+  const setServerUrl = useSetServerURL();
   useEffect(() => {
     setUrl(currentUrl);
   }, [currentUrl]);
-  let [loading, setLoading] = useState(false);
-  let [error, setError] = useState<string | null>(null);
+  const [loading, setLoading] = useState(false);
+  const [error, setError] = useState<string | null>(null);
 
   function getErrorMessage(error: string) {
     switch (error) {
@@ -46,14 +46,14 @@ export default function ConfigServer() {
 
     setError(null);
     setLoading(true);
-    let { error } = await setServerUrl(url);
+    const { error } = await setServerUrl(url);
 
     if (
       ['network-failure', 'get-server-failure'].includes(error) &&
       !url.startsWith('http://') &&
       !url.startsWith('https://')
     ) {
-      let { error } = await setServerUrl('https://' + url);
+      const { error } = await setServerUrl('https://' + url);
       if (error) {
         setUrl('https://' + url);
         setError(error);
diff --git a/packages/desktop-client/src/components/manager/DeleteFile.js b/packages/desktop-client/src/components/manager/DeleteFile.js
index 28eb1dc3fa5c432e1fa253828a297555bdee5e78..a801fa346afad02637c9d9211b1b3fcaec98edd5 100644
--- a/packages/desktop-client/src/components/manager/DeleteFile.js
+++ b/packages/desktop-client/src/components/manager/DeleteFile.js
@@ -7,7 +7,7 @@ import Text from '../common/Text';
 import View from '../common/View';
 
 export default function DeleteMenu({ modalProps, actions, file }) {
-  let [loadingState, setLoadingState] = useState(null);
+  const [loadingState, setLoadingState] = useState(null);
 
   async function onDeleteCloud() {
     setLoadingState('cloud');
@@ -28,7 +28,7 @@ export default function DeleteMenu({ modalProps, actions, file }) {
   // If the state is "broken" that means it was created by another
   // user. The current user should be able to delete the local file,
   // but not the remote one
-  let isRemote = file.cloudFileId && file.state !== 'broken';
+  const isRemote = file.cloudFileId && file.state !== 'broken';
 
   return (
     <Modal
diff --git a/packages/desktop-client/src/components/manager/Import.tsx b/packages/desktop-client/src/components/manager/Import.tsx
index 23854fe2c1783e7beabf9efbe75a3c86be4470d3..823a565cdf094afcc7b1654410e5d631f1a69deb 100644
--- a/packages/desktop-client/src/components/manager/Import.tsx
+++ b/packages/desktop-client/src/components/manager/Import.tsx
@@ -41,7 +41,7 @@ function Import({ modalProps, actions }: ImportProps) {
     }
   }
 
-  let itemStyle = {
+  const itemStyle = {
     padding: 10,
     border: '1px solid ' + theme.tableBorder,
     borderRadius: 6,
diff --git a/packages/desktop-client/src/components/manager/ManagementApp.js b/packages/desktop-client/src/components/manager/ManagementApp.js
index 3e61c09b76042ff8e5219e69c58b15a9cf3e612e..d72cf414103a299796b920891bf2c8931b143f5c 100644
--- a/packages/desktop-client/src/components/manager/ManagementApp.js
+++ b/packages/desktop-client/src/components/manager/ManagementApp.js
@@ -48,13 +48,13 @@ function Version() {
 }
 
 export default function ManagementApp({ isLoading }) {
-  let files = useSelector(state => state.budgets.allFiles);
-  let userData = useSelector(state => state.user.data);
-  let managerHasInitialized = useSelector(
+  const files = useSelector(state => state.budgets.allFiles);
+  const userData = useSelector(state => state.user.data);
+  const managerHasInitialized = useSelector(
     state => state.app.managerHasInitialized,
   );
 
-  let { setAppState, getUserData, loadAllFiles } = useActions();
+  const { setAppState, getUserData, loadAllFiles } = useActions();
 
   // runs on mount only
   useEffect(() => {
@@ -74,7 +74,7 @@ export default function ManagementApp({ isLoading }) {
     }
 
     async function fetchData() {
-      let userData = await getUserData();
+      const userData = await getUserData();
       if (userData) {
         await loadAllFiles();
       }
diff --git a/packages/desktop-client/src/components/manager/Modals.js b/packages/desktop-client/src/components/manager/Modals.js
index fa6451658677fe85eb610eaad6f42c3c4b29792f..cc7637a332cfcd8e3f73d83fc55367a44d3a0797 100644
--- a/packages/desktop-client/src/components/manager/Modals.js
+++ b/packages/desktop-client/src/components/manager/Modals.js
@@ -14,11 +14,11 @@ import ImportYNAB4 from './ImportYNAB4';
 import ImportYNAB5 from './ImportYNAB5';
 
 export default function Modals() {
-  let modalStack = useSelector(state => state.modals.modalStack);
-  let isHidden = useSelector(state => state.modals.isHidden);
-  let actions = useActions();
+  const modalStack = useSelector(state => state.modals.modalStack);
+  const isHidden = useSelector(state => state.modals.isHidden);
+  const actions = useActions();
 
-  let stack = modalStack.map(({ name, options = {} }, idx) => {
+  const stack = modalStack.map(({ name, options = {} }, idx) => {
     const modalProps = {
       onClose: actions.popModal,
       onPush: actions.pushModal,
diff --git a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
index 5f05c5cf5d179628a0fe0fabccf48259733e3c52..89f45cf1074285c13bb2a26447614a74314f1350 100644
--- a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
+++ b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx
@@ -9,7 +9,7 @@ import Text from '../common/Text';
 import View from '../common/View';
 
 export default function WelcomeScreen() {
-  let { createBudget, pushModal } = useActions();
+  const { createBudget, pushModal } = useActions();
 
   return (
     <View
diff --git a/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx b/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx
index 0de5a81dfe849e5c2900afb14a8834d2525cefcf..479833542a39f69da8b352c6f3c9875e8c51c023 100644
--- a/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx
@@ -16,10 +16,10 @@ import { useBootstrapped, Title } from './common';
 import { ConfirmPasswordForm } from './ConfirmPasswordForm';
 
 export default function Bootstrap() {
-  let dispatch = useDispatch();
-  let [error, setError] = useState(null);
+  const dispatch = useDispatch();
+  const [error, setError] = useState(null);
 
-  let { checked } = useBootstrapped();
+  const { checked } = useBootstrapped();
 
   function getErrorMessage(error) {
     switch (error) {
@@ -36,7 +36,7 @@ export default function Bootstrap() {
 
   async function onSetPassword(password) {
     setError(null);
-    let { error } = await send('subscribe-bootstrap', { password });
+    const { error } = await send('subscribe-bootstrap', { password });
 
     if (error) {
       setError(error);
diff --git a/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx b/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx
index 68adb49b8d4f7121e988d1e187e0d0b82bc6105c..3988553ad6cfcb3728e7ca1502d10ba4e4c493fc 100644
--- a/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx
@@ -12,9 +12,9 @@ import { Title } from './common';
 import { ConfirmPasswordForm } from './ConfirmPasswordForm';
 
 export default function ChangePassword() {
-  let navigate = useNavigate();
-  let [error, setError] = useState(null);
-  let [msg, setMessage] = useState(null);
+  const navigate = useNavigate();
+  const [error, setError] = useState(null);
+  const [msg, setMessage] = useState(null);
 
   function getErrorMessage(error) {
     switch (error) {
@@ -31,7 +31,7 @@ export default function ChangePassword() {
 
   async function onSetPassword(password) {
     setError(null);
-    let { error } = await send('subscribe-change-password', { password });
+    const { error } = await send('subscribe-change-password', { password });
 
     if (error) {
       setError(error);
diff --git a/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx b/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx
index b0d5b3622ffd09742adcf51a8d0b94d2421eb527..32ab5ca8a1256b9830ccbe1f694cde84665f1065 100644
--- a/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx
@@ -5,10 +5,10 @@ import { BigInput } from '../../common/Input';
 import View from '../../common/View';
 
 export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) {
-  let [password1, setPassword1] = useState('');
-  let [password2, setPassword2] = useState('');
-  let [showPassword, setShowPassword] = useState(false);
-  let [loading, setLoading] = useState(false);
+  const [password1, setPassword1] = useState('');
+  const [password2, setPassword2] = useState('');
+  const [showPassword, setShowPassword] = useState(false);
+  const [loading, setLoading] = useState(false);
 
   async function onSubmit(e) {
     e.preventDefault();
diff --git a/packages/desktop-client/src/components/manager/subscribe/Error.tsx b/packages/desktop-client/src/components/manager/subscribe/Error.tsx
index 30429f89fd2f448f6841e7d7f7065b48d8590af1..a26ff87c66bfb134301dffff638ce3eb1b55e363 100644
--- a/packages/desktop-client/src/components/manager/subscribe/Error.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/Error.tsx
@@ -17,9 +17,9 @@ function getErrorMessage(reason) {
 }
 
 export default function Error() {
-  let navigate = useNavigate();
-  let location = useLocation();
-  let { error } = (location.state || {}) as { error? };
+  const navigate = useNavigate();
+  const location = useLocation();
+  const { error } = (location.state || {}) as { error? };
 
   function onTryAgain() {
     navigate('/');
diff --git a/packages/desktop-client/src/components/manager/subscribe/Login.tsx b/packages/desktop-client/src/components/manager/subscribe/Login.tsx
index 600c809661cc646bd508d72e9c7a94878635e8c9..3ed5cef99a53b0195d9f379aeb227a322e022c3b 100644
--- a/packages/desktop-client/src/components/manager/subscribe/Login.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/Login.tsx
@@ -14,12 +14,12 @@ import View from '../../common/View';
 import { useBootstrapped, Title } from './common';
 
 export default function Login() {
-  let dispatch = useDispatch();
-  let [password, setPassword] = useState('');
-  let [loading, setLoading] = useState(false);
-  let [error, setError] = useState(null);
+  const dispatch = useDispatch();
+  const [password, setPassword] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [error, setError] = useState(null);
 
-  let { checked } = useBootstrapped();
+  const { checked } = useBootstrapped();
 
   function getErrorMessage(error) {
     switch (error) {
@@ -40,7 +40,7 @@ export default function Login() {
 
     setError(null);
     setLoading(true);
-    let { error } = await send('subscribe-sign-in', { password });
+    const { error } = await send('subscribe-sign-in', { password });
     setLoading(false);
 
     if (error) {
diff --git a/packages/desktop-client/src/components/manager/subscribe/common.tsx b/packages/desktop-client/src/components/manager/subscribe/common.tsx
index 9cc46ca8a6673bb357c613b6ce4599bae7b963bd..cb328c9608bb748ba0ac13a275a232bdf6980ab2 100644
--- a/packages/desktop-client/src/components/manager/subscribe/common.tsx
+++ b/packages/desktop-client/src/components/manager/subscribe/common.tsx
@@ -17,14 +17,14 @@ import { useSetServerURL } from '../../ServerContext';
 // they will also potentially redirect to other pages which do *not*
 // do any checks.
 export function useBootstrapped() {
-  let [checked, setChecked] = useState(false);
-  let navigate = useNavigate();
-  let location = useLocation();
-  let setServerURL = useSetServerURL();
+  const [checked, setChecked] = useState(false);
+  const navigate = useNavigate();
+  const location = useLocation();
+  const setServerURL = useSetServerURL();
 
   useEffect(() => {
     async function run() {
-      let ensure = url => {
+      const ensure = url => {
         if (location.pathname !== url) {
           navigate(url);
         } else {
@@ -32,12 +32,12 @@ export function useBootstrapped() {
         }
       };
 
-      let url = await send('get-server-url');
-      let bootstrapped = await send('get-did-bootstrap');
+      const url = await send('get-server-url');
+      const bootstrapped = await send('get-did-bootstrap');
       if (url == null && !bootstrapped) {
         // A server hasn't been specified yet
-        let serverURL = window.location.origin;
-        let result = await send('subscribe-needs-bootstrap', {
+        const serverURL = window.location.origin;
+        const result = await send('subscribe-needs-bootstrap', {
           url: serverURL,
         });
         if ('error' in result || !result.hasServer) {
@@ -54,7 +54,7 @@ export function useBootstrapped() {
           ensure('/bootstrap');
         }
       } else {
-        let result = await send('subscribe-needs-bootstrap');
+        const result = await send('subscribe-needs-bootstrap');
         if ('error' in result) {
           navigate('/error', { state: { error: result.error } });
         } else if (result.bootstrapped) {
diff --git a/packages/desktop-client/src/components/mobile/MobileAmountInput.js b/packages/desktop-client/src/components/mobile/MobileAmountInput.js
index a1c6895a5f88e73b481a39d6bd0d64624f5ef04d..4155bffab6afd235df165f144c9e4af1b20e680f 100644
--- a/packages/desktop-client/src/components/mobile/MobileAmountInput.js
+++ b/packages/desktop-client/src/components/mobile/MobileAmountInput.js
@@ -132,7 +132,7 @@ class AmountInput extends PureComponent {
   };
 
   onChangeText = text => {
-    let { onChange } = this.props;
+    const { onChange } = this.props;
 
     this.setState({ text });
     onChange(text);
@@ -142,7 +142,7 @@ class AmountInput extends PureComponent {
     const { style, textStyle } = this.props;
     const { editing, value, text } = this.state;
 
-    let input = (
+    const input = (
       <input
         type="text"
         ref={el => (this.input = el)}
diff --git a/packages/desktop-client/src/components/modals/CloseAccount.tsx b/packages/desktop-client/src/components/modals/CloseAccount.tsx
index 48f63a61ff7cb5968180c2e122eb926e52e72ffe..2b58b0852d3fa00b18cede442c5d73a5c4bd9e28 100644
--- a/packages/desktop-client/src/components/modals/CloseAccount.tsx
+++ b/packages/desktop-client/src/components/modals/CloseAccount.tsx
@@ -51,12 +51,12 @@ function CloseAccount({
   actions,
   modalProps,
 }: CloseAccountProps) {
-  let [loading, setLoading] = useState(false);
-  let [transfer, setTransfer] = useState('');
-  let [category, setCategory] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [transfer, setTransfer] = useState('');
+  const [category, setCategory] = useState('');
 
-  let [transferError, setTransferError] = useState(false);
-  let [categoryError, setCategoryError] = useState(false);
+  const [transferError, setTransferError] = useState(false);
+  const [categoryError, setCategoryError] = useState(false);
 
   return (
     <Modal
@@ -84,10 +84,10 @@ function CloseAccount({
             onSubmit={event => {
               event.preventDefault();
 
-              let transferError = balance !== 0 && transfer === '';
+              const transferError = balance !== 0 && transfer === '';
               setTransferError(transferError);
 
-              let categoryError =
+              const categoryError =
                 needsCategory(account, transfer, accounts) && category === '';
               setCategoryError(categoryError);
 
diff --git a/packages/desktop-client/src/components/modals/CreateEncryptionKey.tsx b/packages/desktop-client/src/components/modals/CreateEncryptionKey.tsx
index 33c8f94f07884262e4842e3ce5b73183b6e95fc2..8a18eff5f7a279c7fa5763fe9e81592a85ddbd6a 100644
--- a/packages/desktop-client/src/components/modals/CreateEncryptionKey.tsx
+++ b/packages/desktop-client/src/components/modals/CreateEncryptionKey.tsx
@@ -30,19 +30,19 @@ export default function CreateEncryptionKey({
   actions,
   options = {},
 }: CreateEncryptionKeyProps) {
-  let [password, setPassword] = useState('');
-  let [loading, setLoading] = useState(false);
-  let [error, setError] = useState('');
-  let [showPassword, setShowPassword] = useState(false);
+  const [password, setPassword] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [error, setError] = useState('');
+  const [showPassword, setShowPassword] = useState(false);
 
-  let isRecreating = options.recreate;
+  const isRecreating = options.recreate;
 
   async function onCreateKey() {
     if (password !== '' && !loading) {
       setLoading(true);
       setError(null);
 
-      let res = await send('key-make', { password });
+      const res = await send('key-make', { password });
       if (res.error) {
         setLoading(null);
         setError(getCreateKeyError(res.error));
diff --git a/packages/desktop-client/src/components/modals/CreateLocalAccount.tsx b/packages/desktop-client/src/components/modals/CreateLocalAccount.tsx
index 62d208cb39c175d807909ae04a7a23210620ade6..5f5cc59e6ff0680e860684c2eab4ad494d66d4b1 100644
--- a/packages/desktop-client/src/components/modals/CreateLocalAccount.tsx
+++ b/packages/desktop-client/src/components/modals/CreateLocalAccount.tsx
@@ -23,15 +23,15 @@ type CreateLocalAccountProps = {
 };
 
 function CreateLocalAccount({ modalProps, actions }: CreateLocalAccountProps) {
-  let navigate = useNavigate();
-  let [name, setName] = useState('');
-  let [offbudget, setOffbudget] = useState(false);
-  let [balance, setBalance] = useState('0');
+  const navigate = useNavigate();
+  const [name, setName] = useState('');
+  const [offbudget, setOffbudget] = useState(false);
+  const [balance, setBalance] = useState('0');
 
-  let [nameError, setNameError] = useState(false);
-  let [balanceError, setBalanceError] = useState(false);
+  const [nameError, setNameError] = useState(false);
+  const [balanceError, setBalanceError] = useState(false);
 
-  let validateBalance = balance => !isNaN(parseFloat(balance));
+  const validateBalance = balance => !isNaN(parseFloat(balance));
 
   return (
     <Modal title="Create Local Account" {...modalProps}>
@@ -41,15 +41,15 @@ function CreateLocalAccount({ modalProps, actions }: CreateLocalAccountProps) {
             onSubmit={async event => {
               event.preventDefault();
 
-              let nameError = !name;
+              const nameError = !name;
               setNameError(nameError);
 
-              let balanceError = !validateBalance(balance);
+              const balanceError = !validateBalance(balance);
               setBalanceError(balanceError);
 
               if (!nameError && !balanceError) {
                 actions.closeModal();
-                let id = await actions.createAccount(
+                const id = await actions.createAccount(
                   name,
                   toRelaxedNumber(balance),
                   offbudget,
@@ -65,7 +65,7 @@ function CreateLocalAccount({ modalProps, actions }: CreateLocalAccountProps) {
                   value={name}
                   onChange={event => setName(event.target.value)}
                   onBlur={event => {
-                    let name = event.target.value.trim();
+                    const name = event.target.value.trim();
                     setName(name);
                     if (name && nameError) {
                       setNameError(false);
@@ -139,7 +139,7 @@ function CreateLocalAccount({ modalProps, actions }: CreateLocalAccountProps) {
                 value={balance}
                 onChange={event => setBalance(event.target.value)}
                 onBlur={event => {
-                  let balance = event.target.value.trim();
+                  const balance = event.target.value.trim();
                   setBalance(balance);
                   if (validateBalance(balance) && balanceError) {
                     setBalanceError(false);
diff --git a/packages/desktop-client/src/components/modals/EditField.js b/packages/desktop-client/src/components/modals/EditField.js
index e5a3dd365b96dbcec9dd95a68a6def078e993a1b..853c85534be0d036401939dd6dc36c63ba7c8b5b 100644
--- a/packages/desktop-client/src/components/modals/EditField.js
+++ b/packages/desktop-client/src/components/modals/EditField.js
@@ -35,14 +35,14 @@ function CreatePayeeIcon(props) {
 }
 
 export default function EditField({ modalProps, name, onSubmit }) {
-  let dateFormat = useSelector(
+  const dateFormat = useSelector(
     state => state.prefs.local.dateFormat || 'MM/dd/yyyy',
   );
-  let { grouped: categoryGroups } = useCategories();
-  let accounts = useSelector(state => state.queries.accounts);
-  let payees = useSelector(state => state.queries.payees);
+  const { grouped: categoryGroups } = useCategories();
+  const accounts = useSelector(state => state.queries.accounts);
+  const payees = useSelector(state => state.queries.payees);
 
-  let { createPayee } = useActions();
+  const { createPayee } = useActions();
 
   function onSelect(value) {
     if (value != null) {
@@ -65,18 +65,18 @@ export default function EditField({ modalProps, name, onSubmit }) {
 
   const { isNarrowWidth } = useResponsive();
   let label, editor, minWidth;
-  let inputStyle = {
+  const inputStyle = {
     ':focus': { boxShadow: 0 },
     ...(isNarrowWidth && itemStyle),
   };
-  let autocompleteProps = {
+  const autocompleteProps = {
     inputProps: { style: inputStyle },
     containerProps: { style: { height: isNarrowWidth ? '90vh' : 275 } },
   };
 
   switch (name) {
     case 'date': {
-      let today = currentDay();
+      const today = currentDay();
       label = 'Date';
       minWidth = 350;
       editor = (
diff --git a/packages/desktop-client/src/components/modals/EditRule.js b/packages/desktop-client/src/components/modals/EditRule.js
index 1af0c6e29c7b093ceecc14fa5911cfe09a78f373..9893fa71f433c9d1c78caae3b850a3d6192ec688 100644
--- a/packages/desktop-client/src/components/modals/EditRule.js
+++ b/packages/desktop-client/src/components/modals/EditRule.js
@@ -54,7 +54,7 @@ function applyErrors(array, errorsArray) {
 }
 
 function getTransactionFields(conditions, actions) {
-  let fields = ['date'];
+  const fields = ['date'];
 
   if (conditions.find(c => c.field === 'imported_payee')) {
     fields.push('imported_payee');
@@ -191,8 +191,9 @@ function ConditionEditor({
   onDelete,
   onAdd,
 }) {
-  let { field, op, value, type, options, error } = condition;
+  const { field: originalField, op, value, type, options, error } = condition;
 
+  let field = originalField;
   if (field === 'amount' && options) {
     if (options.inflow) {
       field = 'amount-inflow';
@@ -251,10 +252,10 @@ function formatAmount(amount) {
 }
 
 function ScheduleDescription({ id }) {
-  let dateFormat = useSelector(state => {
+  const dateFormat = useSelector(state => {
     return state.prefs.local.dateFormat || 'MM/dd/yyyy';
   });
-  let scheduleData = useSchedules({
+  const scheduleData = useSchedules({
     transform: useCallback(q => q.filter({ id }), []),
   });
 
@@ -266,8 +267,8 @@ function ScheduleDescription({ id }) {
     return <View style={{ flex: 1 }}>{id}</View>;
   }
 
-  let [schedule] = scheduleData.schedules;
-  let status = schedule && scheduleData.statuses.get(schedule.id);
+  const [schedule] = scheduleData.schedules;
+  const status = schedule && scheduleData.statuses.get(schedule.id);
 
   return (
     <View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
@@ -300,7 +301,7 @@ function ScheduleDescription({ id }) {
   );
 }
 
-let actionFields = [
+const actionFields = [
   'category',
   'payee',
   'notes',
@@ -310,7 +311,7 @@ let actionFields = [
   'amount',
 ].map(field => [field, mapField(field)]);
 function ActionEditor({ ops, action, editorStyle, onChange, onDelete, onAdd }) {
-  let { field, op, value, type, error, inputKey = 'initial' } = action;
+  const { field, op, value, type, error, inputKey = 'initial' } = action;
 
   return (
     <Editor style={editorStyle} error={error}>
@@ -364,7 +365,7 @@ function ActionEditor({ ops, action, editorStyle, onChange, onDelete, onAdd }) {
 }
 
 function StageInfo() {
-  let [open, setOpen] = useState();
+  const [open, setOpen] = useState();
 
   return (
     <View style={{ position: 'relative', marginLeft: 5 }}>
@@ -439,9 +440,9 @@ function ConditionsList({
         f => !conditions.some(c => c.field.includes(f) || f.includes(c.field)),
       );
     }
-    let field = fields[0] || 'payee';
+    const field = fields[0] || 'payee';
 
-    let copy = [...conditions];
+    const copy = [...conditions];
     copy.splice(index + 1, 0, {
       type: FIELD_TYPES.get(field),
       field,
@@ -463,7 +464,7 @@ function ConditionsList({
     onChangeConditions(
       updateValue(conditions, cond, () => {
         if (field === 'field') {
-          let newCond = { field: value };
+          const newCond = { field: value };
 
           if (value === 'amount-inflow') {
             newCond.field = 'amount';
@@ -475,7 +476,7 @@ function ConditionsList({
 
           newCond.type = FIELD_TYPES.get(newCond.field);
 
-          let prevType = FIELD_TYPES.get(cond.field);
+          const prevType = FIELD_TYPES.get(cond.field);
           if (
             (prevType === 'string' || prevType === 'number') &&
             prevType === newCond.type &&
@@ -490,7 +491,7 @@ function ConditionsList({
             return newInput(makeValue(null, newCond));
           }
         } else if (field === 'op') {
-          let op = value;
+          const op = value;
 
           // Switching between oneOf and other operators is a
           // special-case. It changes the input type, so we need to
@@ -589,7 +590,7 @@ function ConditionsList({
 // TODO:
 // * Dont touch child transactions?
 
-let conditionFields = [
+const conditionFields = [
   'imported_payee',
   'account',
   'category',
@@ -609,15 +610,17 @@ export default function EditRule({
   defaultRule,
   onSave: originalOnSave,
 }) {
-  let [conditions, setConditions] = useState(defaultRule.conditions.map(parse));
-  let [actions, setActions] = useState(defaultRule.actions.map(parse));
-  let [stage, setStage] = useState(defaultRule.stage);
-  let [conditionsOp, setConditionsOp] = useState(defaultRule.conditionsOp);
-  let [transactions, setTransactions] = useState([]);
-  let dispatch = useDispatch();
-  let scrollableEl = useRef();
+  const [conditions, setConditions] = useState(
+    defaultRule.conditions.map(parse),
+  );
+  const [actions, setActions] = useState(defaultRule.actions.map(parse));
+  const [stage, setStage] = useState(defaultRule.stage);
+  const [conditionsOp, setConditionsOp] = useState(defaultRule.conditionsOp);
+  const [transactions, setTransactions] = useState([]);
+  const dispatch = useDispatch();
+  const scrollableEl = useRef();
 
-  let isSchedule = actions.some(action => action.op === 'link-schedule');
+  const isSchedule = actions.some(action => action.op === 'link-schedule');
 
   useEffect(() => {
     dispatch(initiallyLoadPayees());
@@ -630,21 +633,21 @@ export default function EditRule({
   useEffect(() => {
     // Flash the scrollbar
     if (scrollableEl.current) {
-      let el = scrollableEl.current;
-      let top = el.scrollTop;
+      const el = scrollableEl.current;
+      const top = el.scrollTop;
       el.scrollTop = top + 1;
       el.scrollTop = top;
     }
 
     // Run it here
     async function run() {
-      let { filters } = await send('make-filters-from-conditions', {
+      const { filters } = await send('make-filters-from-conditions', {
         conditions: conditions.map(unparse),
       });
 
       if (filters.length > 0) {
         const conditionsOpKey = conditionsOp === 'or' ? '$or' : '$and';
-        let { data: transactions } = await runQuery(
+        const { data: transactions } = await runQuery(
           q('transactions')
             .filter({ [conditionsOpKey]: filters })
             .select('*'),
@@ -657,7 +660,7 @@ export default function EditRule({
     run();
   }, [actions, conditions, conditionsOp]);
 
-  let selectedInst = useSelected('transactions', transactions, []);
+  const selectedInst = useSelected('transactions', transactions, []);
 
   function addInitialAction() {
     addAction(-1);
@@ -665,12 +668,12 @@ export default function EditRule({
 
   function addAction(index) {
     let fields = actionFields.map(f => f[0]);
-    for (let action of actions) {
+    for (const action of actions) {
       fields = fields.filter(f => f !== action.field);
     }
-    let field = fields[0] || 'category';
+    const field = fields[0] || 'category';
 
-    let copy = [...actions];
+    const copy = [...actions];
     copy.splice(index + 1, 0, {
       type: FIELD_TYPES.get(field),
       field,
@@ -683,7 +686,7 @@ export default function EditRule({
   function onChangeAction(action, field, value) {
     setActions(
       updateValue(actions, action, () => {
-        let a = { ...action };
+        const a = { ...action };
         a[field] = value;
 
         if (field === 'field') {
@@ -724,7 +727,7 @@ export default function EditRule({
   }
 
   async function onSave() {
-    let rule = {
+    const rule = {
       ...defaultRule,
       stage,
       conditionsOp,
@@ -732,8 +735,8 @@ export default function EditRule({
       actions: actions.map(unparse),
     };
 
-    let method = rule.id ? 'rule-update' : 'rule-add';
-    let { error, id: newId } = await send(method, rule);
+    const method = rule.id ? 'rule-update' : 'rule-add';
+    const { error, id: newId } = await send(method, rule);
 
     if (error) {
       if (error.conditionErrors) {
@@ -754,7 +757,7 @@ export default function EditRule({
     }
   }
 
-  let editorStyle = {
+  const editorStyle = {
     color: theme.pillText,
     backgroundColor: theme.pillBackground,
     borderRadius: 4,
diff --git a/packages/desktop-client/src/components/modals/FixEncryptionKey.tsx b/packages/desktop-client/src/components/modals/FixEncryptionKey.tsx
index d327898f9281a6ffdd596ff578678d94c454ec5d..c7e0d96365a551b630c78906577a1681adc63f5a 100644
--- a/packages/desktop-client/src/components/modals/FixEncryptionKey.tsx
+++ b/packages/desktop-client/src/components/modals/FixEncryptionKey.tsx
@@ -27,19 +27,19 @@ export default function FixEncryptionKey({
   actions,
   options = {},
 }: FixEncryptionKeyProps) {
-  let { hasExistingKey, cloudFileId, onSuccess } = options;
+  const { hasExistingKey, cloudFileId, onSuccess } = options;
 
-  let [password, setPassword] = useState('');
-  let [error, setError] = useState('');
-  let [loading, setLoading] = useState(false);
-  let [showPassword, setShowPassword] = useState(false);
+  const [password, setPassword] = useState('');
+  const [error, setError] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [showPassword, setShowPassword] = useState(false);
 
   async function onUpdateKey() {
     if (password !== '' && !loading) {
       setLoading(true);
       setError(null);
 
-      let { error } = await send('key-test', {
+      const { error } = await send('key-test', {
         password,
         fileId: cloudFileId,
       });
diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
index 53355f336423ca1b824f289c00aa9ad9b3df1ef9..ccdcad5a0a577946a535324e477dbcd6d135b340 100644
--- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
+++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx
@@ -93,16 +93,16 @@ export default function GoCardlessExternalMsg({
 }: GoCardlessExternalMsgProps) {
   const dispatch = useDispatch();
 
-  let [waiting, setWaiting] = useState<string | null>(null);
-  let [success, setSuccess] = useState<boolean>(false);
-  let [institutionId, setInstitutionId] = useState<string>();
-  let [country, setCountry] = useState<string>();
-  let [error, setError] = useState<'unknown' | 'timeout' | null>(null);
-  let [isGoCardlessSetupComplete, setIsGoCardlessSetupComplete] = useState<
+  const [waiting, setWaiting] = useState<string | null>(null);
+  const [success, setSuccess] = useState<boolean>(false);
+  const [institutionId, setInstitutionId] = useState<string>();
+  const [country, setCountry] = useState<string>();
+  const [error, setError] = useState<'unknown' | 'timeout' | null>(null);
+  const [isGoCardlessSetupComplete, setIsGoCardlessSetupComplete] = useState<
     boolean | null
   >(null);
-  let [menuOpen, setMenuOpen] = useState<boolean>(false);
-  let data = useRef<GoCardlessToken | null>(null);
+  const [menuOpen, setMenuOpen] = useState<boolean>(false);
+  const data = useRef<GoCardlessToken | null>(null);
 
   const {
     data: bankOptions,
@@ -116,7 +116,7 @@ export default function GoCardlessExternalMsg({
     setError(null);
     setWaiting('browser');
 
-    let res = await onMoveExternal({ institutionId });
+    const res = await onMoveExternal({ institutionId });
     if (res.error) {
       setError(res.error);
       setWaiting(null);
diff --git a/packages/desktop-client/src/components/modals/ImportTransactions.js b/packages/desktop-client/src/components/modals/ImportTransactions.js
index 11665ea71e8df96603a1bbf1ca3a4dae919422d1..b66597e11251b8ff564992f12906435f283dac5b 100644
--- a/packages/desktop-client/src/components/modals/ImportTransactions.js
+++ b/packages/desktop-client/src/components/modals/ImportTransactions.js
@@ -23,7 +23,7 @@ import View from '../common/View';
 import { Checkbox, SectionLabel } from '../forms';
 import { TableHeader, TableWithNavigator, Row, Field } from '../table';
 
-let dateFormats = [
+const dateFormats = [
   { format: 'yyyy mm dd', label: 'YYYY MM DD' },
   { format: 'yy mm dd', label: 'YY MM DD' },
   { format: 'mm dd yyyy', label: 'MM DD YYYY' },
@@ -108,7 +108,7 @@ export function parseDate(str, order) {
       day = parts[1];
   }
 
-  let parsed = `${year}-${pad(month)}-${pad(day)}`;
+  const parsed = `${year}-${pad(month)}-${pad(day)}`;
   if (!d.isValid(d.parseISO(parsed))) {
     return null;
   }
@@ -126,15 +126,15 @@ function formatDate(date, format) {
 }
 
 function getFileType(filepath) {
-  let m = filepath.match(/\.([^.]*)$/);
+  const m = filepath.match(/\.([^.]*)$/);
   if (!m) return 'ofx';
-  let rawType = m[1].toLowerCase();
+  const rawType = m[1].toLowerCase();
   if (rawType === 'tsv') return 'csv';
   return rawType;
 }
 
 function ParsedDate({ parseDateFormat, showParsed, dateFormat, date }) {
-  let parsed =
+  const parsed =
     date &&
     formatDate(
       parseDateFormat ? parseDate(date, parseDateFormat) : date,
@@ -162,10 +162,10 @@ function getInitialDateFormat(transactions, mappings) {
     return 'yyyy mm dd';
   }
 
-  let transaction = transactions[0];
-  let date = transaction[mappings.date];
+  const transaction = transactions[0];
+  const date = transaction[mappings.date];
 
-  let found =
+  const found =
     date == null
       ? null
       : dateFormats.find(f => parseDate(date, f.format) != null);
@@ -177,35 +177,35 @@ function getInitialMappings(transactions) {
     return {};
   }
 
-  let transaction = transactions[0];
-  let fields = Object.entries(transaction);
+  const transaction = transactions[0];
+  const fields = Object.entries(transaction);
 
   function key(entry) {
     return entry ? entry[0] : null;
   }
 
-  let dateField = key(
+  const dateField = key(
     fields.find(([name, value]) => name.toLowerCase().includes('date')) ||
       fields.find(([name, value]) => value.match(/^\d+[-/]\d+[-/]\d+$/)),
   );
 
-  let amountField = key(
+  const amountField = key(
     fields.find(([name, value]) => name.toLowerCase().includes('amount')) ||
       fields.find(([name, value]) => value.match(/^-?[.,\d]+$/)),
   );
 
-  let payeeField = key(
+  const payeeField = key(
     fields.find(([name, value]) => name !== dateField && name !== amountField),
   );
 
-  let notesField = key(
+  const notesField = key(
     fields.find(
       ([name, value]) =>
         name !== dateField && name !== amountField && name !== payeeField,
     ),
   );
 
-  let inOutField = key(
+  const inOutField = key(
     fields.find(
       ([name, value]) =>
         name !== dateField &&
@@ -225,8 +225,9 @@ function getInitialMappings(transactions) {
 }
 
 function applyFieldMappings(transaction, mappings) {
-  let result = {};
-  for (let [field, target] of Object.entries(mappings)) {
+  const result = {};
+  for (const [originalField, target] of Object.entries(mappings)) {
+    let field = originalField;
     if (field === 'payee') {
       field = 'payee_name';
     }
@@ -240,8 +241,9 @@ function parseAmount(amount, mapper) {
   if (amount == null) {
     return null;
   }
-  let parsed = typeof amount === 'string' ? looselyParseAmount(amount) : amount;
-  let value = mapper(parsed);
+  const parsed =
+    typeof amount === 'string' ? looselyParseAmount(amount) : amount;
+  const value = mapper(parsed);
   return value;
 }
 
@@ -259,8 +261,8 @@ function parseAmountFields(
     // Split mode is a little weird; first we look for an outflow and
     // if that has a value, we never want to show a number in the
     // inflow. Same for `amount`; we choose outflow first and then inflow
-    let outflow = parseAmount(trans.outflow, n => -Math.abs(n)) * multiplier;
-    let inflow = outflow
+    const outflow = parseAmount(trans.outflow, n => -Math.abs(n)) * multiplier;
+    const inflow = outflow
       ? 0
       : parseAmount(trans.inflow, n => Math.abs(n)) * multiplier;
 
@@ -300,7 +302,7 @@ function Transaction({
   flipAmount,
   multiplierAmount,
 }) {
-  let transaction = useMemo(
+  const transaction = useMemo(
     () =>
       fieldMappings
         ? applyFieldMappings(rawTransaction, fieldMappings)
@@ -434,8 +436,8 @@ function DateFormatSelect({
   // to space if we can't figure it out.
   let delimiter = '-';
   if (transactions.length > 0 && fieldMappings && fieldMappings.date != null) {
-    let date = transactions[0][fieldMappings.date];
-    let m = date && date.match(/[/.,-/\\]/);
+    const date = transactions[0][fieldMappings.date];
+    const m = date && date.match(/[/.,-/\\]/);
     delimiter = m ? m[0] : ' ';
   }
 
@@ -555,7 +557,7 @@ function FieldMappings({
     return null;
   }
 
-  let options = Object.keys(transactions[0]);
+  const options = Object.keys(transactions[0]);
   mappings = mappings || {};
 
   return (
@@ -655,53 +657,53 @@ function FieldMappings({
 }
 
 export default function ImportTransactions({ modalProps, options }) {
-  let dateFormat = useSelector(
+  const dateFormat = useSelector(
     state => state.prefs.local.dateFormat || 'MM/dd/yyyy',
   );
-  let prefs = useSelector(state => state.prefs.local);
-  let { parseTransactions, importTransactions, getPayees, savePrefs } =
+  const prefs = useSelector(state => state.prefs.local);
+  const { parseTransactions, importTransactions, getPayees, savePrefs } =
     useActions();
 
-  let [multiplierAmount, setMultiplierAmount] = useState('');
-  let [loadingState, setLoadingState] = useState('parsing');
-  let [error, setError] = useState(null);
-  let [filename, setFilename] = useState(options.filename);
-  let [transactions, setTransactions] = useState([]);
-  let [filetype, setFileType] = useState(null);
-  let [fieldMappings, setFieldMappings] = useState(null);
-  let [splitMode, setSplitMode] = useState(false);
-  let [inOutMode, setInOutMode] = useState(false);
-  let [outValue, setOutValue] = useState('');
-  let [flipAmount, setFlipAmount] = useState(false);
-  let [multiplierEnabled, setMultiplierEnabled] = useState(false);
-  let { accountId, onImported } = options;
+  const [multiplierAmount, setMultiplierAmount] = useState('');
+  const [loadingState, setLoadingState] = useState('parsing');
+  const [error, setError] = useState(null);
+  const [filename, setFilename] = useState(options.filename);
+  const [transactions, setTransactions] = useState([]);
+  const [filetype, setFileType] = useState(null);
+  const [fieldMappings, setFieldMappings] = useState(null);
+  const [splitMode, setSplitMode] = useState(false);
+  const [inOutMode, setInOutMode] = useState(false);
+  const [outValue, setOutValue] = useState('');
+  const [flipAmount, setFlipAmount] = useState(false);
+  const [multiplierEnabled, setMultiplierEnabled] = useState(false);
+  const { accountId, onImported } = options;
 
   // This cannot be set after parsing the file, because changing it
   // requires re-parsing the file. This is different from the other
   // options which are simple post-processing. That means if you
   // parsed different files without closing the modal, it wouldn't
   // re-read this.
-  let [delimiter, setDelimiter] = useState(
+  const [delimiter, setDelimiter] = useState(
     prefs[`csv-delimiter-${accountId}`] ||
       (filename.endsWith('.tsv') ? '\t' : ','),
   );
-  let [hasHeaderRow, setHasHeaderRow] = useState(
+  const [hasHeaderRow, setHasHeaderRow] = useState(
     prefs[`csv-has-header-${accountId}`] ?? true,
   );
-  let [fallbackMissingPayeeToMemo, setFallbackMissingPayeeToMemo] = useState(
+  const [fallbackMissingPayeeToMemo, setFallbackMissingPayeeToMemo] = useState(
     prefs[`ofx-fallback-missing-payee-${accountId}`] ?? true,
   );
 
-  let [parseDateFormat, setParseDateFormat] = useState(null);
+  const [parseDateFormat, setParseDateFormat] = useState(null);
 
-  let [clearOnImport, setClearOnImport] = useState(true);
+  const [clearOnImport, setClearOnImport] = useState(true);
 
   const enableExperimentalOfxParser = useFeatureFlag('experimentalOfxParser');
 
   async function parse(filename, options) {
     setLoadingState('parsing');
 
-    let filetype = getFileType(filename);
+    const filetype = getFileType(filename);
     setFilename(filename);
     setFileType(filetype);
 
@@ -710,7 +712,7 @@ export default function ImportTransactions({ modalProps, options }) {
       enableExperimentalOfxParser,
     };
 
-    let { errors, transactions } = await parseTransactions(filename, options);
+    const { errors, transactions } = await parseTransactions(filename, options);
     setLoadingState(null);
     setError(null);
 
@@ -734,7 +736,7 @@ export default function ImportTransactions({ modalProps, options }) {
         setFieldMappings(mappings);
 
         // Set initial split mode based on any saved mapping
-        let initialSplitMode = !!(mappings.outflow || mappings.inflow);
+        const initialSplitMode = !!(mappings.outflow || mappings.inflow);
         setSplitMode(initialSplitMode);
 
         setParseDateFormat(
@@ -785,16 +787,16 @@ export default function ImportTransactions({ modalProps, options }) {
       setFlipAmount(!flipAmount);
     }
 
-    let isSplit = !splitMode;
+    const isSplit = !splitMode;
     setSplitMode(isSplit);
     setInOutMode(false);
     setFlipAmount(false);
 
     // Run auto-detection on the fields to try to detect the fields
     // automatically
-    let mappings = getInitialMappings(transactions);
+    const mappings = getInitialMappings(transactions);
 
-    let newFieldMappings = isSplit
+    const newFieldMappings = isSplit
       ? {
           amount: null,
           outflow: mappings.amount,
@@ -835,13 +837,13 @@ export default function ImportTransactions({ modalProps, options }) {
   async function onImport() {
     setLoadingState('importing');
 
-    let finalTransactions = [];
+    const finalTransactions = [];
     let errorMessage;
 
     for (let trans of transactions) {
       trans = fieldMappings ? applyFieldMappings(trans, fieldMappings) : trans;
 
-      let date = isOfxFile(filetype)
+      const date = isOfxFile(filetype)
         ? trans.date
         : parseDate(trans.date, parseDateFormat);
       if (date == null) {
@@ -851,7 +853,7 @@ export default function ImportTransactions({ modalProps, options }) {
         break;
       }
 
-      let { amount } = parseAmountFields(
+      const { amount } = parseAmountFields(
         trans,
         splitMode,
         inOutMode,
@@ -864,7 +866,7 @@ export default function ImportTransactions({ modalProps, options }) {
         break;
       }
 
-      let { inflow, outflow, inOut, ...finalTransaction } = trans;
+      const { inflow, outflow, inOut, ...finalTransaction } = trans;
       finalTransactions.push({
         ...finalTransaction,
         date,
@@ -880,7 +882,7 @@ export default function ImportTransactions({ modalProps, options }) {
     }
 
     if (!isOfxFile(filetype)) {
-      let key = `parse-date-${accountId}-${filetype}`;
+      const key = `parse-date-${accountId}-${filetype}`;
       savePrefs({ [key]: parseDateFormat });
     }
 
@@ -901,7 +903,7 @@ export default function ImportTransactions({ modalProps, options }) {
       savePrefs({ [`flip-amount-${accountId}-${filetype}`]: flipAmount });
     }
 
-    let didChange = await importTransactions(accountId, finalTransactions);
+    const didChange = await importTransactions(accountId, finalTransactions);
     if (didChange) {
       await getPayees();
     }
@@ -913,7 +915,7 @@ export default function ImportTransactions({ modalProps, options }) {
     modalProps.onClose();
   }
 
-  let headers = [
+  const headers = [
     { name: 'Date', width: 200 },
     { name: 'Payee', width: 'flex' },
     { name: 'Notes', width: 'flex' },
diff --git a/packages/desktop-client/src/components/modals/LoadBackup.js b/packages/desktop-client/src/components/modals/LoadBackup.js
index 6e0f3d98e6642334142b32977748c94696ff5c2a..64786e72407bf73b36ac88c31147fc7656056fce 100644
--- a/packages/desktop-client/src/components/modals/LoadBackup.js
+++ b/packages/desktop-client/src/components/modals/LoadBackup.js
@@ -54,7 +54,7 @@ function LoadBackup({
   actions,
   modalProps,
 }) {
-  let [backups, setBackups] = useState([]);
+  const [backups, setBackups] = useState([]);
 
   useEffect(() => {
     send('backups-get', { id: budgetId }).then(setBackups);
diff --git a/packages/desktop-client/src/components/modals/ManageRulesModal.tsx b/packages/desktop-client/src/components/modals/ManageRulesModal.tsx
index 72a7d202ac094f25cb64882e738ea8bc0dcd1b2e..59dccf84a5a0bfdae593c639cffa2cf87219b312 100644
--- a/packages/desktop-client/src/components/modals/ManageRulesModal.tsx
+++ b/packages/desktop-client/src/components/modals/ManageRulesModal.tsx
@@ -16,8 +16,8 @@ export default function ManageRulesModal({
   modalProps,
   payeeId,
 }: ManageRulesModalProps) {
-  let [loading, setLoading] = useState(true);
-  let location = useLocation();
+  const [loading, setLoading] = useState(true);
+  const location = useLocation();
   if (isNonProductionEnvironment()) {
     if (location.pathname !== '/payees') {
       throw new Error(
diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayees.js b/packages/desktop-client/src/components/modals/MergeUnusedPayees.js
index 50d3f36ec9e85beeedbee1a0d11e42f20543db15..d857cdd6a90c78c6684da1b6e849be25c94bcb56 100644
--- a/packages/desktop-client/src/components/modals/MergeUnusedPayees.js
+++ b/packages/desktop-client/src/components/modals/MergeUnusedPayees.js
@@ -12,27 +12,27 @@ import Paragraph from '../common/Paragraph';
 import Text from '../common/Text';
 import View from '../common/View';
 
-let highlightStyle = { color: theme.pageTextPositive };
+const highlightStyle = { color: theme.pageTextPositive };
 
 export default function MergeUnusedPayees({
   modalProps,
   payeeIds,
   targetPayeeId,
 }) {
-  let { payees: allPayees, modalStack } = useSelector(state => ({
+  const { payees: allPayees, modalStack } = useSelector(state => ({
     payees: state.queries.payees,
     modalStack: state.modals.modalStack,
   }));
-  let isEditingRule = !!modalStack.find(m => m.name === 'edit-rule');
-  let dispatch = useDispatch();
-  let [shouldCreateRule, setShouldCreateRule] = useState(true);
-  let flashRef = useRef(null);
+  const isEditingRule = !!modalStack.find(m => m.name === 'edit-rule');
+  const dispatch = useDispatch();
+  const [shouldCreateRule, setShouldCreateRule] = useState(true);
+  const flashRef = useRef(null);
 
   useEffect(() => {
     // Flash the scrollbar
     if (flashRef.current) {
-      let el = flashRef.current;
-      let top = el.scrollTop;
+      const el = flashRef.current;
+      const top = el.scrollTop;
       el.scrollTop = top + 1;
       el.scrollTop = top;
     }
@@ -44,10 +44,10 @@ export default function MergeUnusedPayees({
   //
   // TODO: I think a custom `useSelector` hook that doesn't bind would
   // be nice
-  let [payees] = useState(() =>
+  const [payees] = useState(() =>
     payeeIds.map(id => allPayees.find(p => p.id === id)),
   );
-  let targetPayee = allPayees.find(p => p.id === targetPayeeId);
+  const targetPayee = allPayees.find(p => p.id === targetPayeeId);
 
   if (!targetPayee) {
     return null;
@@ -61,7 +61,7 @@ export default function MergeUnusedPayees({
 
     let ruleId;
     if (shouldCreateRule && !isEditingRule) {
-      let id = await send('rule-add-payee-rename', {
+      const id = await send('rule-add-payee-rename', {
         fromNames: payees.map(p => p.name),
         to: targetPayee.id,
       });
@@ -74,10 +74,10 @@ export default function MergeUnusedPayees({
   }
 
   async function onMergeAndCreateRule() {
-    let ruleId = await onMerge();
+    const ruleId = await onMerge();
 
     if (ruleId) {
-      let rule = await send('rule-get', { id: ruleId });
+      const rule = await send('rule-get', { id: ruleId });
       dispatch(replaceModal('edit-rule', { rule }));
     }
   }
diff --git a/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx
index 1b19f09c3b8915cdb0a5e0de36c08347e9134706..e9146a7e0393ec8d4dde4d1eeba0417b57f20570 100644
--- a/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx
+++ b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx
@@ -33,16 +33,16 @@ export default function PlaidExternalMsg({
   onSuccess,
   onClose: originalOnClose,
 }: PlainExternalMsgProps) {
-  let [waiting, setWaiting] = useState(null);
-  let [success, setSuccess] = useState(false);
-  let [error, setError] = useState(null);
-  let data = useRef(null);
+  const [waiting, setWaiting] = useState(null);
+  const [success, setSuccess] = useState(false);
+  const [error, setError] = useState(null);
+  const data = useRef(null);
 
   async function onJump() {
     setError(null);
     setWaiting('browser');
 
-    let res = await onMoveExternal();
+    const res = await onMoveExternal();
     if (res.error) {
       setError(res.error);
       setWaiting(null);
diff --git a/upcoming-release-notes/2033.md b/upcoming-release-notes/2033.md
new file mode 100644
index 0000000000000000000000000000000000000000..afd0770965a91bdb6f8a9e25b375f1c38d4f2fef
--- /dev/null
+++ b/upcoming-release-notes/2033.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [joel-jeremy]
+---
+
+Apply ESLint prefer-const on components folder part 1