Fix automations not saving on modal close (#5811)

* Fix automations not saving on modal close

* Add release notes

* CodeRabbit feedback

* Fix

* PR feedback

* Revert unnecessary change
This commit is contained in:
Julian Dominguez-Schatz
2025-11-08 15:49:20 -05:00
committed by GitHub
parent 47c09ffcfa
commit 31455d475c
5 changed files with 55 additions and 13 deletions

View File

@@ -451,7 +451,7 @@ export default defineConfig(
'react-hooks/exhaustive-deps': [
'warn',
{
additionalHooks: '(useQuery)',
additionalHooks: '(useQuery|useEffectAfterMount)',
},
],

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo, useReducer, useState } from 'react';
import { useMemo, useReducer, useRef, useState } from 'react';
import { SpaceBetween } from '@actual-app/components/space-between';
import { type CSSProperties } from '@actual-app/components/styles';
@@ -9,16 +9,17 @@ import {
} from 'loot-core/types/models';
import { type Template } from 'loot-core/types/models/templates';
import { type Action } from './actions';
import { BudgetAutomationEditor } from './BudgetAutomationEditor';
import { BudgetAutomationReadOnly } from './BudgetAutomationReadOnly';
import { DEFAULT_PRIORITY, getInitialState, templateReducer } from './reducer';
import { useEffectAfterMount } from '@desktop-client/hooks/useEffectAfterMount';
type BudgetAutomationProps = {
categories: CategoryGroupEntity[];
schedules: readonly ScheduleEntity[];
template?: Template;
onSave?: () => void;
onSave?: (template: Template) => void;
onDelete?: () => void;
style?: CSSProperties;
readOnlyStyle?: CSSProperties;
@@ -44,17 +45,16 @@ export const BudgetAutomation = ({
}: BudgetAutomationProps) => {
const [isEditing, setIsEditing] = useState(false);
const [state, originalDispatch] = useReducer(
const [state, dispatch] = useReducer(
templateReducer,
getInitialState(template ?? DEFAULT_TEMPLATE),
);
const dispatch = useCallback(
(action: Action) => {
originalDispatch(action);
onSave?.();
},
[originalDispatch, onSave],
);
const onSaveRef = useRef(onSave);
onSaveRef.current = onSave;
useEffectAfterMount(() => {
onSaveRef.current?.(state.template);
}, [state]);
const categoryNameMap = useMemo(() => {
return categories.reduce(

View File

@@ -1,4 +1,4 @@
import { type CSSProperties, useMemo, useState } from 'react';
import { type CSSProperties, useCallback, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Button } from '@actual-app/components/button';
@@ -72,6 +72,17 @@ function BudgetAutomationList({
]);
};
const onSave = useCallback(
(index: number) => (template: Template) => {
setAutomations(prev =>
prev.map((oldAutomation, mapIndex) =>
mapIndex === index ? template : oldAutomation,
),
);
},
[setAutomations],
);
return (
<SpaceBetween
direction="vertical"
@@ -84,6 +95,7 @@ function BudgetAutomationList({
{automations.map((automation, index) => (
<BudgetAutomation
key={automationIds[index]}
onSave={onSave(index)}
onDelete={onDelete(index)}
template={automation}
categories={categories}

View File

@@ -0,0 +1,24 @@
import {
type DependencyList,
type EffectCallback,
useEffect,
useRef,
} from 'react';
/**
* A version of useEffect that doesn't run on the initial mount.
*/
export function useEffectAfterMount(
effect: EffectCallback,
deps?: DependencyList | undefined,
) {
const isFirstRender = useRef(true);
useEffect(() => {
if (!isFirstRender.current) {
return effect();
}
isFirstRender.current = false;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
}

View File

@@ -0,0 +1,6 @@
---
category: Bugfix
authors: [jfdoming]
---
Fix automations not saving on modal close