diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx index d794cd93451..655e853ccf4 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx @@ -2094,9 +2094,9 @@ export const TransactionTable = forwardRef((props, ref) => { result = props.transactions.filter((t, idx) => { if (t.parent_id) { if (idx >= index) { - return splitsExpanded.expanded(t.parent_id); + return splitsExpanded.isExpanded(t.parent_id); } else if (prevSplitsExpanded.current) { - return prevSplitsExpanded.current.expanded(t.parent_id); + return prevSplitsExpanded.current.isExpanded(t.parent_id); } } return true; @@ -2113,7 +2113,7 @@ export const TransactionTable = forwardRef((props, ref) => { result = props.transactions.filter(t => { if (t.parent_id) { - return splitsExpanded.expanded(t.parent_id); + return splitsExpanded.isExpanded(t.parent_id); } return true; }); @@ -2584,7 +2584,7 @@ export const TransactionTable = forwardRef((props, ref) => { transactionsByParent={transactionsByParent} transferAccountsByTransaction={transferAccountsByTransaction} selectedItems={selectedItems} - isExpanded={splitsExpanded.expanded} + isExpanded={splitsExpanded.isExpanded} onSave={onSave} onDelete={onDelete} onDuplicate={onDuplicate} diff --git a/packages/desktop-client/src/hooks/useSplitsExpanded.jsx b/packages/desktop-client/src/hooks/useSplitsExpanded.tsx similarity index 64% rename from packages/desktop-client/src/hooks/useSplitsExpanded.jsx rename to packages/desktop-client/src/hooks/useSplitsExpanded.tsx index 8b8bb4ed249..25386d2dcec 100644 --- a/packages/desktop-client/src/hooks/useSplitsExpanded.jsx +++ b/packages/desktop-client/src/hooks/useSplitsExpanded.tsx @@ -4,10 +4,68 @@ import React, { useEffect, useContext, useReducer, + type Dispatch, + type ReactNode, } from 'react'; import { useSelector, useDispatch } from 'react-redux'; -const SplitsExpandedContext = createContext(null); +import { + type SplitMode, + type SplitState, +} from 'loot-core/client/state-types/app'; + +type ToggleSplitAction = { + type: 'toggle-split'; + id: string; +}; + +type OpenSplitAction = { + type: 'open-split'; + id: string; +}; + +type CloseSplitsAction = { + type: 'close-splits'; + ids: string[]; +}; + +type SetModeAction = { + type: 'set-mode'; + mode: SplitMode; +}; + +type SwitchModeAction = { + type: 'switch-mode'; + id: string; +}; + +type FinishSwitchModeAction = { + type: 'finish-switch-mode'; +}; + +type Actions = + | ToggleSplitAction + | OpenSplitAction + | CloseSplitsAction + | SetModeAction + | SwitchModeAction + | FinishSwitchModeAction; + +type SplitsStateContext = { + state: SplitState; + dispatch: Dispatch; +}; + +const SplitsExpandedContext = createContext({ + state: { + mode: 'collapse', + ids: new Set(), + transitionId: null, + }, + dispatch: () => { + throw new Error('Unitialised context method called: dispatch'); + }, +}); export function useSplitsExpanded() { const data = useContext(SplitsExpandedContext); @@ -15,7 +73,7 @@ export function useSplitsExpanded() { return useMemo( () => ({ ...data, - expanded: id => + isExpanded: (id: string) => data.state.mode === 'collapse' ? !data.state.ids.has(id) : data.state.ids.has(id), @@ -24,12 +82,20 @@ export function useSplitsExpanded() { ); } -export function SplitsExpandedProvider({ children, initialMode = 'expand' }) { +type SplitsExpandedProviderProps = { + children?: ReactNode; + initialMode: SplitMode; +}; + +export function SplitsExpandedProvider({ + children, + initialMode = 'expand', +}: SplitsExpandedProviderProps) { const cachedState = useSelector(state => state.app.lastSplitState); const reduxDispatch = useDispatch(); const [state, dispatch] = useReducer( - (state, action) => { + (state: SplitState, action: Actions): SplitState => { switch (action.type) { case 'toggle-split': { const ids = new Set([...state.ids]); @@ -66,7 +132,7 @@ export function SplitsExpandedProvider({ children, initialMode = 'expand' }) { return { ...state, mode: action.mode, - ids: new Set(), + ids: new Set(), transitionId: null, }; } @@ -80,15 +146,17 @@ export function SplitsExpandedProvider({ children, initialMode = 'expand' }) { ...state, mode: state.mode === 'expand' ? 'collapse' : 'expand', transitionId: action.id, - ids: new Set(), + ids: new Set(), }; case 'finish-switch-mode': return { ...state, transitionId: null }; - default: - throw new Error('Unknown action type: ' + action.type); } }, - cachedState.current || { ids: new Set(), mode: initialMode }, + cachedState.current || { + ids: new Set(), + mode: initialMode, + transitionId: null, + }, ); useEffect(() => { diff --git a/packages/loot-core/src/client/state-types/app.d.ts b/packages/loot-core/src/client/state-types/app.d.ts index 7420aa7251b..fd4e4f34414 100644 --- a/packages/loot-core/src/client/state-types/app.d.ts +++ b/packages/loot-core/src/client/state-types/app.d.ts @@ -1,7 +1,12 @@ import type { UndoState } from '../../server/undo'; import type * as constants from '../constants'; -export type SplitState = { ids: Set; mode: 'collapse' | 'expand' }; +export type SplitMode = 'collapse' | 'expand'; +export type SplitState = { + ids: Set; + mode: SplitMode; + transitionId: string | null; +}; export type AppState = { loadingText: string | null; diff --git a/upcoming-release-notes/3945.md b/upcoming-release-notes/3945.md new file mode 100644 index 00000000000..219e2d8618a --- /dev/null +++ b/upcoming-release-notes/3945.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [dkhalife] +--- + +Migrate useSplitsExpanded to TypeScript \ No newline at end of file