From 2a1c452aacb848d1d66d93859e3453de2987f7bd Mon Sep 17 00:00:00 2001
From: shall0pass <20625555+shall0pass@users.noreply.github.com>
Date: Tue, 2 Apr 2024 10:37:49 -0500
Subject: [PATCH] Append, Prepend, or Replace notes in bulk actions (#2468)

* sort of working

* fix null condition, move buttons up

* visual and workflow updates

* update colors on hover

* release note

* fix another condition that inserted null
---
 .../src/components/accounts/Account.jsx       |  14 +-
 .../src/components/modals/EditField.jsx       | 135 +++++++++++++++++-
 upcoming-release-notes/2468.md                |   6 +
 3 files changed, 147 insertions(+), 8 deletions(-)
 create mode 100644 upcoming-release-notes/2468.md

diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx
index 3efff4ec9..5b51fe436 100644
--- a/packages/desktop-client/src/components/accounts/Account.jsx
+++ b/packages/desktop-client/src/components/accounts/Account.jsx
@@ -800,7 +800,8 @@ class AccountInternal extends PureComponent {
   };
 
   onBatchEdit = async (name, ids) => {
-    const onChange = async (name, value) => {
+    const onChange = async (name, value, mode) => {
+      const newValue = value === null ? '' : value;
       this.setState({ workingHard: true });
 
       const { data } = await runQuery(
@@ -834,6 +835,17 @@ class AccountInternal extends PureComponent {
           return;
         }
 
+        if (name === 'notes') {
+          if (mode === 'prepend') {
+            value =
+              trans.notes === null ? newValue : newValue + ' ' + trans.notes;
+          } else if (mode === 'append') {
+            value =
+              trans.notes === null ? newValue : trans.notes + ' ' + newValue;
+          } else if (mode === 'replace') {
+            value = newValue;
+          }
+        }
         const transaction = {
           ...trans,
           [name]: value,
diff --git a/packages/desktop-client/src/components/modals/EditField.jsx b/packages/desktop-client/src/components/modals/EditField.jsx
index 03d68eae6..52f1bb791 100644
--- a/packages/desktop-client/src/components/modals/EditField.jsx
+++ b/packages/desktop-client/src/components/modals/EditField.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
 
 import { parseISO, format as formatDate, parse as parseDate } from 'date-fns';
 
@@ -27,6 +27,7 @@ import {
   CreatePayeeButton,
   PayeeItem,
 } from '../autocomplete/PayeeAutocomplete';
+import { Button } from '../common/Button';
 import { Input } from '../common/Input';
 import { Modal } from '../common/Modal';
 import { View } from '../common/View';
@@ -44,12 +45,18 @@ export function EditField({ modalProps, name, onSubmit, onClose }) {
   const payees = usePayees();
 
   const { createPayee } = useActions();
-
   const onCloseInner = () => {
     modalProps.onClose();
     onClose?.();
   };
 
+  function onSelectNote(value, mode) {
+    if (value != null) {
+      onSubmit(name, value, mode);
+    }
+    onCloseInner();
+  }
+
   function onSelect(value) {
     if (value != null) {
       // Process the value if needed
@@ -80,6 +87,8 @@ export function EditField({ modalProps, name, onSubmit, onClose }) {
     containerProps: { style: { height: isNarrowWidth ? '90vh' : 275 } },
   };
 
+  const [noteAmend, onChangeMode] = useState('replace');
+
   switch (name) {
     case 'date': {
       const today = currentDay();
@@ -201,11 +210,123 @@ export function EditField({ modalProps, name, onSubmit, onClose }) {
     case 'notes':
       label = 'Notes';
       editor = (
-        <Input
-          focused={true}
-          onEnter={e => onSelect(e.target.value)}
-          style={inputStyle}
-        />
+        <>
+          <View
+            style={{
+              flexDirection: 'row',
+              marginTop: 5,
+              marginBottom: 5,
+              marginLeft: 8,
+              marginRight: 4,
+              alignItems: 'center',
+              justifyContent: 'center',
+            }}
+          >
+            <Button
+              selected={noteAmend === 'prepend'}
+              style={{
+                padding: '5px 10px',
+                width: '33.33%',
+                backgroundColor: theme.menuBackground,
+                marginRight: 5,
+                fontSize: 'inherit',
+                ...(noteAmend === 'prepend' && {
+                  backgroundColor: theme.buttonPrimaryBackground,
+                  color: theme.buttonPrimaryText,
+                  ':hover': {
+                    backgroundColor: theme.buttonPrimaryBackgroundHover,
+                    color: theme.buttonPrimaryTextHover,
+                  },
+                }),
+                ...(noteAmend !== 'prepend' && {
+                  backgroundColor: theme.buttonNormalBackground,
+                  color: theme.buttonNormalText,
+                  ':hover': {
+                    backgroundColor: theme.buttonNormalBackgroundHover,
+                    color: theme.buttonNormalTextHover,
+                  },
+                }),
+              }}
+              onClick={() => {
+                onChangeMode('prepend');
+                document.getElementById('noteInput').focus();
+              }}
+            >
+              Prepend
+            </Button>
+            <Button
+              selected={noteAmend === 'replace'}
+              style={{
+                padding: '5px 10px',
+                width: '33.34%',
+                backgroundColor: theme.menuBackground,
+                marginRight: 5,
+                fontSize: 'inherit',
+                ...(noteAmend === 'replace' && {
+                  backgroundColor: theme.buttonPrimaryBackground,
+                  color: theme.buttonPrimaryText,
+                  ':hover': {
+                    backgroundColor: theme.buttonPrimaryBackgroundHover,
+                    color: theme.buttonPrimaryTextHover,
+                  },
+                }),
+                ...(noteAmend !== 'replace' && {
+                  backgroundColor: theme.buttonNormalBackground,
+                  color: theme.buttonNormalText,
+                  ':hover': {
+                    backgroundColor: theme.buttonNormalBackgroundHover,
+                    color: theme.buttonNormalTextHover,
+                  },
+                }),
+              }}
+              onClick={() => {
+                onChangeMode('replace');
+                document.getElementById('noteInput').focus();
+              }}
+            >
+              Replace
+            </Button>
+            <Button
+              selected={noteAmend === 'append'}
+              style={{
+                padding: '5px 10px',
+                width: '33.33%',
+                backgroundColor: theme.menuBackground,
+                marginRight: 5,
+                fontSize: 'inherit',
+                ...(noteAmend === 'append' && {
+                  backgroundColor: theme.buttonPrimaryBackground,
+                  color: theme.buttonPrimaryText,
+                  ':hover': {
+                    backgroundColor: theme.buttonPrimaryBackgroundHover,
+                    color: theme.buttonPrimaryTextHover,
+                  },
+                }),
+                ...(noteAmend !== 'append' && {
+                  backgroundColor: theme.buttonNormalBackground,
+                  color: theme.buttonNormalText,
+                  ':hover': {
+                    backgroundColor: theme.buttonNormalBackgroundHover,
+                    color: theme.buttonNormalTextHover,
+                  },
+                }),
+              }}
+              onClick={() => {
+                onChangeMode('append');
+                document.getElementById('noteInput').focus();
+              }}
+            >
+              Append
+            </Button>
+          </View>
+          <Input
+            id="noteInput"
+            autoFocus
+            focused={true}
+            onEnter={e => onSelectNote(e.target.value, noteAmend)}
+            style={inputStyle}
+          />
+        </>
       );
       break;
 
diff --git a/upcoming-release-notes/2468.md b/upcoming-release-notes/2468.md
new file mode 100644
index 000000000..10af8057a
--- /dev/null
+++ b/upcoming-release-notes/2468.md
@@ -0,0 +1,6 @@
+---
+category: Features
+authors: [shall0pass]
+---
+
+Add options to prepend or append text to a transaction note using the bulk edit dialog.
-- 
GitLab