Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename redux hooks #4101

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
import type { InitConfig } from 'loot-core/server/main';

// @ts-ignore: bundle not available until we build it
// eslint-disable-next-line import/extensions
// eslint-disable-next-line import/extensions, import/no-unresolved
import * as bundle from './app/bundle.api.js';
import * as injected from './injected';
import { validateNodeVersion } from './validateNodeVersion';
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/auth/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { createContext, useContext, type ReactNode } from 'react';

import { useServerURL } from '../components/ServerContext';
import { useSelector } from '../redux';
import { useAppSelector } from '../redux';

import { type Permissions } from './types';

Expand All @@ -16,7 +16,7 @@ type AuthProviderProps = {
};

export const AuthProvider = ({ children }: AuthProviderProps) => {
const userData = useSelector(state => state.user.data);
const userData = useAppSelector(state => state.user.data);
const serverUrl = useServerURL();

const hasPermission = (permission?: Permissions) => {
Expand Down
6 changes: 3 additions & 3 deletions packages/desktop-client/src/auth/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type RemoteFile, type SyncedLocalFile } from 'loot-core/types/file';

import { View } from '../components/common/View';
import { useMetadataPref } from '../hooks/useMetadataPref';
import { useSelector } from '../redux';
import { useAppSelector } from '../redux';

import { useAuth } from './AuthProvider';
import { type Permissions } from './types';
Expand All @@ -23,13 +23,13 @@ export const ProtectedRoute = ({
const { hasPermission } = useAuth();
const [permissionGranted, setPermissionGranted] = useState(false);
const [cloudFileId] = useMetadataPref('cloudFileId');
const allFiles = useSelector(state => state.budgets.allFiles || []);
const allFiles = useAppSelector(state => state.budgets.allFiles || []);
const remoteFiles = allFiles.filter(
(f): f is SyncedLocalFile | RemoteFile =>
f.state === 'remote' || f.state === 'synced' || f.state === 'detached',
);
const currentFile = remoteFiles.find(f => f.cloudFileId === cloudFileId);
const userData = useSelector(state => state.user.data);
const userData = useAppSelector(state => state.user.data);

useEffect(() => {
const hasRequiredPermission = hasPermission(permission);
Expand Down
8 changes: 4 additions & 4 deletions packages/desktop-client/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {

import { useMetadataPref } from '../hooks/useMetadataPref';
import { installPolyfills } from '../polyfills';
import { useDispatch, useSelector } from '../redux';
import { useAppDispatch, useAppSelector } from '../redux';
import { styles, hasHiddenScrollbars, ThemeStyle, useTheme } from '../style';
import { ExposeNavigate } from '../util/router-tools';

Expand All @@ -49,8 +49,8 @@ function AppInner() {
const [cloudFileId] = useMetadataPref('cloudFileId');
const { t } = useTranslation();
const { showBoundary: showErrorBoundary } = useErrorBoundary();
const dispatch = useDispatch();
const userData = useSelector(state => state.user.data);
const dispatch = useAppDispatch();
const userData = useAppSelector(state => state.user.data);

useEffect(() => {
const maybeUpdate = async <T,>(cb?: () => T): Promise<T> => {
Expand Down Expand Up @@ -163,7 +163,7 @@ export function App() {
const [hiddenScrollbars, setHiddenScrollbars] = useState(
hasHiddenScrollbars(),
);
const dispatch = useDispatch();
const dispatch = useAppDispatch();

useEffect(() => {
function checkScrollbars() {
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/AppBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTransition, animated } from 'react-spring';
import { css } from '@emotion/css';

import { AnimatedLoading } from '../icons/AnimatedLoading';
import { useSelector } from '../redux';
import { useAppSelector } from '../redux';
import { theme } from '../style';

import { Background } from './Background';
Expand All @@ -16,7 +16,7 @@ type AppBackgroundProps = {
};

export function AppBackground({ isLoading }: AppBackgroundProps) {
const loadingText = useSelector(state => state.app.loadingText);
const loadingText = useAppSelector(state => state.app.loadingText);
const showLoading = isLoading || loadingText !== null;
const transitions = useTransition(loadingText, {
from: { opacity: 0, transform: 'translateY(-100px)' },
Expand Down
6 changes: 4 additions & 2 deletions packages/desktop-client/src/components/BankSyncStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ import React from 'react';
import { Trans } from 'react-i18next';
import { useTransition, animated } from 'react-spring';

import { useSelector } from '../redux';
import { useAppSelector } from '../redux';
import { theme, styles } from '../style';

import { AnimatedRefresh } from './AnimatedRefresh';
import { Text } from './common/Text';
import { View } from './common/View';

export function BankSyncStatus() {
const accountsSyncing = useSelector(state => state.account.accountsSyncing);
const accountsSyncing = useAppSelector(
state => state.account.accountsSyncing,
);
const accountsSyncingCount = accountsSyncing.length;
const count = accountsSyncingCount;

Expand Down
6 changes: 3 additions & 3 deletions packages/desktop-client/src/components/FinancesApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useAccounts } from '../hooks/useAccounts';
import { useLocalPref } from '../hooks/useLocalPref';
import { useMetaThemeColor } from '../hooks/useMetaThemeColor';
import { useNavigate } from '../hooks/useNavigate';
import { useSelector, useDispatch } from '../redux';
import { useAppSelector, useAppDispatch } from '../redux';
import { theme } from '../style';
import { getIsOutdated, getLatestVersion } from '../util/versions';

Expand Down Expand Up @@ -86,11 +86,11 @@ export function FinancesApp() {
const { isNarrowWidth } = useResponsive();
useMetaThemeColor(isNarrowWidth ? theme.mobileViewTheme : null);

const dispatch = useDispatch();
const dispatch = useAppDispatch();
const { t } = useTranslation();

const accounts = useAccounts();
const accountsLoaded = useSelector(state => state.queries.accountsLoaded);
const accountsLoaded = useAppSelector(state => state.queries.accountsLoaded);

const [lastUsedVersion, setLastUsedVersion] = useLocalPref(
'flags.updateNotificationShownForVersion',
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/HelpMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { pushModal } from 'loot-core/client/actions/modals';

import { useFeatureFlag } from '../hooks/useFeatureFlag';
import { SvgHelp } from '../icons/v2/Help';
import { useDispatch } from '../redux';
import { useAppDispatch } from '../redux';

import { Button } from './common/Button2';
import { Menu } from './common/Menu';
Expand Down Expand Up @@ -75,7 +75,7 @@ export const HelpMenu = () => {
const [isMenuOpen, toggleMenuOpen, setMenuOpen] = useToggle();
const menuButtonRef = useRef(null);

const dispatch = useDispatch();
const dispatch = useAppDispatch();
const page = useLocation().pathname;

const handleItemSelect = (item: HelpMenuItem) => {
Expand Down
10 changes: 5 additions & 5 deletions packages/desktop-client/src/components/LoggedInUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useAuth } from '../auth/AuthProvider';
import { Permissions } from '../auth/types';
import { useMetadataPref } from '../hooks/useMetadataPref';
import { useNavigate } from '../hooks/useNavigate';
import { useSelector, useDispatch } from '../redux';
import { useAppSelector, useAppDispatch } from '../redux';
import { theme, styles } from '../style';

import { Button } from './common/Button2';
Expand All @@ -33,9 +33,9 @@ export function LoggedInUser({
color,
}: LoggedInUserProps) {
const { t } = useTranslation();
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const userData = useSelector(state => state.user.data);
const userData = useAppSelector(state => state.user.data);
const [loading, setLoading] = useState(true);
const [menuOpen, setMenuOpen] = useState(false);
const serverUrl = useServerURL();
Expand All @@ -45,12 +45,12 @@ export function LoggedInUser({
const location = useLocation();
const { hasPermission } = useAuth();
const multiuserEnabled = useMultiuserEnabled();
const allFiles = useSelector(state => state.budgets.allFiles || []);
const allFiles = useAppSelector(state => state.budgets.allFiles || []);
const remoteFiles = allFiles.filter(
f => f.state === 'remote' || f.state === 'synced' || f.state === 'detached',
) as (SyncedLocalFile | RemoteFile)[];
const currentFile = remoteFiles.find(f => f.cloudFileId === cloudFileId);
const hasSyncedPrefs = useSelector(state => state.prefs.synced);
const hasSyncedPrefs = useAppSelector(state => state.prefs.synced);

useEffect(() => {
async function init() {
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/ManageRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { useAccounts } from '../hooks/useAccounts';
import { useCategories } from '../hooks/useCategories';
import { usePayees } from '../hooks/usePayees';
import { useSelected, SelectedProvider } from '../hooks/useSelected';
import { useDispatch } from '../redux';
import { useAppDispatch } from '../redux';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Migration to typed Redux hooks is incomplete

  • UserAccess.tsx and UserDirectory.tsx in the admin components still use untyped useDispatch
  • The ESLint rule to prevent untyped Redux hooks is not implemented yet
🔗 Analysis chain

LGTM! Changes align with Redux Toolkit's TypeScript recommendations.

The migration from useDispatch to useAppDispatch is implemented correctly and consistently.

Let's verify the ESLint rule mentioned in the PR objectives:

Also applies to: 116-116

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify ESLint rule preventing untyped Redux hooks
# Expected: Find ESLint configuration that bans untyped hooks

# Look for ESLint config files
fd -e js -e json -e yaml -e yml '\.eslint' -x cat {} \; | grep -A 5 -B 5 'react-redux'

# Check if there are any remaining untyped hooks
rg "import.*\{.*useDispatch.*\}.*from\s+['\"]react-redux['\"]"

Length of output: 491


Script:

#!/bin/bash
# Check redux/index.ts implementation
cat packages/desktop-client/src/redux/index.ts

# Look for ESLint config in package.json
cat packages/desktop-client/package.json | jq '.eslintConfig'

Length of output: 382

import { theme } from '../style';

import { Button } from './common/Button2';
Expand Down Expand Up @@ -113,7 +113,7 @@ export function ManageRules({
const [allRules, setAllRules] = useState([]);
const [page, setPage] = useState(0);
const [filter, setFilter] = useState('');
const dispatch = useDispatch();
const dispatch = useAppDispatch();

const { schedules = [] } = useSchedules({
query: useMemo(() => q('schedules').select('*'), []),
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as monthUtils from 'loot-core/src/shared/months';

import { useMetadataPref } from '../hooks/useMetadataPref';
import { useModalState } from '../hooks/useModalState';
import { useDispatch } from '../redux';
import { useAppDispatch } from '../redux';

import { ModalTitle, ModalHeader } from './common/Modal';
import { AccountAutocompleteModal } from './modals/AccountAutocompleteModal';
Expand Down Expand Up @@ -79,7 +79,7 @@ import { NamespaceContext } from './spreadsheet/NamespaceContext';

export function Modals() {
const location = useLocation();
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const { modalStack } = useModalState();
const [budgetId] = useMetadataPref('id');

Expand Down
10 changes: 6 additions & 4 deletions packages/desktop-client/src/components/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type { NotificationWithId } from 'loot-core/src/client/state-types/notifi

import { AnimatedLoading } from '../icons/AnimatedLoading';
import { SvgDelete } from '../icons/v0';
import { useSelector, useDispatch } from '../redux';
import { useAppSelector, useAppDispatch } from '../redux';
import { styles, theme } from '../style';

import { Button, ButtonWithLoading } from './common/Button2';
Expand Down Expand Up @@ -262,10 +262,12 @@ function Notification({
}

export function Notifications({ style }: { style?: CSSProperties }) {
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const { isNarrowWidth } = useResponsive();
const notifications = useSelector(state => state.notifications.notifications);
const notificationInset = useSelector(state => state.notifications.inset);
const notifications = useAppSelector(
state => state.notifications.notifications,
);
const notificationInset = useAppSelector(state => state.notifications.inset);
return (
<View
style={{
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/Titlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
SvgViewHide,
SvgViewShow,
} from '../icons/v2';
import { useDispatch } from '../redux';
import { useAppDispatch } from '../redux';
import { theme, styles, type CSSProperties } from '../style';

import { AccountSyncCheck } from './accounts/AccountSyncCheck';
Expand Down Expand Up @@ -110,7 +110,7 @@ type SyncButtonProps = {
function SyncButton({ style, isMobile = false }: SyncButtonProps) {
const { t } = useTranslation();
const [cloudFileId] = useMetadataPref('cloudFileId');
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const [syncing, setSyncing] = useState(false);
const [syncState, setSyncState] = useState<
null | 'offline' | 'local' | 'disabled' | 'error'
Expand Down
8 changes: 4 additions & 4 deletions packages/desktop-client/src/components/UpdateNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import { setAppState, updateApp } from 'loot-core/client/app/appSlice';

import { SvgClose } from '../icons/v1';
import { useSelector, useDispatch } from '../redux';
import { useAppSelector, useAppDispatch } from '../redux';
import { theme } from '../style';

import { Button } from './common/Button2';
Expand All @@ -14,12 +14,12 @@ import { View } from './common/View';

export function UpdateNotification() {
const { t } = useTranslation();
const updateInfo = useSelector(state => state.app.updateInfo);
const showUpdateNotification = useSelector(
const updateInfo = useAppSelector(state => state.app.updateInfo);
const showUpdateNotification = useAppSelector(
state => state.app.showUpdateNotification,
);

const dispatch = useDispatch();
const dispatch = useAppDispatch();
const onRestart = () => {
dispatch(updateApp());
};
Expand Down
18 changes: 12 additions & 6 deletions packages/desktop-client/src/components/accounts/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ import {
} from '../../hooks/useSplitsExpanded';
import { useSyncedPref } from '../../hooks/useSyncedPref';
import { useTransactionBatchActions } from '../../hooks/useTransactionBatchActions';
import { useSelector, useDispatch } from '../../redux';
import { useAppSelector, useAppDispatch } from '../../redux';
import { styles, theme } from '../../style';
import { Button } from '../common/Button2';
import { Text } from '../common/Text';
Expand Down Expand Up @@ -1908,7 +1908,7 @@ type AccountHackProps = Omit<

function AccountHack(props: AccountHackProps) {
const { dispatch: splitsExpandedDispatch } = useSplitsExpanded();
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const {
onBatchEdit,
onBatchDuplicate,
Expand Down Expand Up @@ -1936,8 +1936,10 @@ export function Account() {
const location = useLocation();

const { grouped: categoryGroups } = useCategories();
const newTransactions = useSelector(state => state.queries.newTransactions);
const matchedTransactions = useSelector(
const newTransactions = useAppSelector(
state => state.queries.newTransactions,
);
const matchedTransactions = useAppSelector(
state => state.queries.matchedTransactions,
);
const accounts = useAccounts();
Expand All @@ -1958,8 +1960,12 @@ export function Account() {
const [showExtraBalances, setShowExtraBalances] = useSyncedPref(
`show-extra-balances-${params.id || 'all-accounts'}`,
);
const modalShowing = useSelector(state => state.modals.modalStack.length > 0);
const accountsSyncing = useSelector(state => state.account.accountsSyncing);
const modalShowing = useAppSelector(
state => state.modals.modalStack.length > 0,
);
const accountsSyncing = useAppSelector(
state => state.account.accountsSyncing,
);
const filterConditions = location?.state?.filterConditions || [];

const savedFiters = useFilters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { authorizeBank } from '../../gocardless';
import { useAccounts } from '../../hooks/useAccounts';
import { useFailedAccounts } from '../../hooks/useFailedAccounts';
import { SvgExclamationOutline } from '../../icons/v1';
import { useDispatch } from '../../redux';
import { useAppDispatch } from '../../redux';
import { theme } from '../../style';
import { Button } from '../common/Button2';
import { Link } from '../common/Link';
Expand Down Expand Up @@ -84,7 +84,7 @@ function useErrorMessage() {
export function AccountSyncCheck() {
const accounts = useAccounts();
const failedAccounts = useFailedAccounts();
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const { id } = useParams();
const [open, setOpen] = useState(false);
const triggerRef = useRef(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { type UserAccessEntity } from 'loot-core/types/models/userAccess';
import { useMetadataPref } from '../../../hooks/useMetadataPref';
import { SvgLockOpen } from '../../../icons/v1';
import { SvgLockClosed } from '../../../icons/v2';
import { useDispatch } from '../../../redux';
import { useAppDispatch } from '../../../redux';
import { theme } from '../../../style';
import { Button } from '../../common/Button2';
import { Link } from '../../common/Link';
Expand Down Expand Up @@ -269,7 +269,7 @@ type LockToggleProps = {

function LockToggle({ style, onToggleSave }: LockToggleProps) {
const [hover, setHover] = useState(false);
const dispatch = useDispatch();
const dispatch = useAppDispatch();

return (
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getUserAccessErrors } from 'loot-core/shared/errors';
import { type UserAvailable } from 'loot-core/types/models';

import { useMetadataPref } from '../../../hooks/useMetadataPref';
import { useDispatch } from '../../../redux';
import { useAppDispatch } from '../../../redux';
import { theme } from '../../../style';
import { View } from '../../common/View';
import { Checkbox } from '../../forms';
Expand All @@ -23,7 +23,7 @@ type UserAccessProps = {
export const UserAccessRow = memo(
({ access, hovered, onHover }: UserAccessProps) => {
const { t } = useTranslation();
const dispatch = useDispatch();
const dispatch = useAppDispatch();

const backgroundFocus = hovered;
const [marked, setMarked] = useState(
Expand Down
Loading
Loading