From 839da0b25a2fbedbbb329357f9119329c744cbeb Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez Date: Sat, 28 Oct 2023 09:42:47 -0700 Subject: [PATCH] Inline mobile category and group edit (#1781) * Inline mobile category and group edit * Release notes * Allow one edit at any time * Mobile: long press to edit category/group * Mobile: set userSelect: 'none' * Move getLongPressEvents * Add role to prevent tap-to-search * Add role to text * Prevent default on longpress * Add tabIndex to disable tap-to-search * Add back userSelect * Role updates * Remove userSelect * Revert long press category name * Remove unused import * Fix lint error * Edit mode * Do not allow to start an edit when another field is currenty being edited * Fix blur event not firing * Grey out zero spent or balance values * VRT update * Fix budget cell being zero on click * Delete useLongPress --- ...with-budgeted-amounts-1-chromium-linux.png | Bin 25957 -> 26722 bytes .../src/components/budget/MobileBudget.js | 2 +- .../components/budget/MobileBudgetTable.js | 905 +++++++++++------- .../src/components/budget/util.ts | 2 +- .../src/components/util/AmountInput.js | 14 +- upcoming-release-notes/1781.md | 6 + 6 files changed, 570 insertions(+), 359 deletions(-) create mode 100644 upcoming-release-notes/1781.md diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png index a29cc002d921b1bd979392fe7e65ed6cde7fb97d..fcc9a4669d82c893648a2d68c4cb536ae271f234 100644 GIT binary patch literal 26722 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

W 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 O0;wu$Dpbi^g#QnMAfki- literal 25957 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 Dl+b69 diff --git a/packages/desktop-client/src/components/budget/MobileBudget.js b/packages/desktop-client/src/components/budget/MobileBudget.js index 1499783b722..d945c45cf38 100644 --- a/packages/desktop-client/src/components/budget/MobileBudget.js +++ b/packages/desktop-client/src/components/budget/MobileBudget.js @@ -363,11 +363,11 @@ class Budget extends Component { type={budgetType} month={currentMonth} monthBounds={bounds} - editMode={editMode} navigation={navigation} // refreshControl={ // // } + editMode={editMode} onEditMode={flag => this.setState({ editMode: flag })} onShowBudgetDetails={this.onShowBudgetDetails} onPrevMonth={this.onPrevMonth} diff --git a/packages/desktop-client/src/components/budget/MobileBudgetTable.js b/packages/desktop-client/src/components/budget/MobileBudgetTable.js index 0deb57870a6..e02095ab704 100644 --- a/packages/desktop-client/src/components/budget/MobileBudgetTable.js +++ b/packages/desktop-client/src/components/budget/MobileBudgetTable.js @@ -1,4 +1,4 @@ -import React, { memo, useState } from 'react'; +import React, { memo, useEffect, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import memoizeOne from 'memoize-one'; @@ -8,9 +8,7 @@ import * as monthUtils from 'loot-core/src/shared/months'; import ArrowThinLeft from '../../icons/v1/ArrowThinLeft'; import ArrowThinRight from '../../icons/v1/ArrowThinRight'; -import Close from '../../icons/v1/Close'; import DotsHorizontalTriple from '../../icons/v1/DotsHorizontalTriple'; -import EditPencil from '../../icons/v1/EditPencil'; import { useResponsive } from '../../ResponsiveProvider'; import { theme, styles } from '../../style'; import Button from '../common/Button'; @@ -35,6 +33,7 @@ import { AmountInput } from '../util/AmountInput'; // import { DragDrop, Draggable, Droppable, DragDropHighlight } from './dragdrop'; import { ListItem, ROW_HEIGHT } from './MobileTable'; +import { makeAmountGrey } from './util'; function ToBudget({ toBudget, onClick }) { let amount = useSheetValue(toBudget); @@ -113,13 +112,13 @@ function Saved({ projected }) { function BudgetCell({ name, binding, - editing, style, textStyle, categoryId, month, onBudgetAction, - onEditing, + onEdit, + isEditing, }) { let sheetValue = useSheetValue(binding); @@ -131,16 +130,12 @@ function BudgetCell({ } function onAmountClick(e) { - onEditing?.(categoryId); + onEdit?.(categoryId); } return ( - e.preventDefault()} - > - {editing ? ( + + {isEditing ? ( onEditing?.(null)} + onBlur={() => onEdit?.(null)} /> ) : ( @@ -218,21 +215,24 @@ function ExpenseCategoryPreview({ name, pending, style }) { const ExpenseCategory = memo(function ExpenseCategory({ category, - editing, index, // gestures, - editMode, blank, style, month, - onEditingBudget, + editMode, + isEditing, + onEdit, + isEditingBudget, + onEditBudget, onSave, onDelete, onBudgetAction, show3Cols, showBudgetedCol, }) { - let opacity = editMode || blank ? 0 : 1; + let opacity = blank ? 0 : 1; + let showEditables = editMode || isEditing; let [categoryName, setCategoryName] = useState(category.name); let [isHidden, setIsHidden] = useState(category.hidden); @@ -243,7 +243,13 @@ const ExpenseCategory = memo(function ExpenseCategory({ let tooltip = useTooltip(); - let onTooltipClose = () => { + useEffect(() => { + if (!isEditing && tooltip.isOpen) { + tooltip.close(); + } + }, [isEditing]); + + let onSubmit = () => { if (categoryName) { onSave?.({ ...category, @@ -252,11 +258,11 @@ const ExpenseCategory = memo(function ExpenseCategory({ } else { setCategoryName(category.name); } - tooltip.close(); + onEdit?.(null); }; let onMenuSelect = type => { - tooltip.close(); + onEdit?.(null); switch (type) { case 'toggle-visibility': setIsHidden(!isHidden); @@ -273,18 +279,84 @@ const ExpenseCategory = memo(function ExpenseCategory({ } }; + let listItemRef = useRef(); + let inputRef = useRef(); + let content = ( 0 ? 1 : 0, opacity: isHidden ? 0.5 : undefined, ...style, }} data-testid="row" + innerRef={listItemRef} > - + + + + + } + style={{ width: '100%' }} + placeholder="Category Name" + value={categoryName} + onUpdate={setCategoryName} + onEnter={onSubmit} + onBlur={e => { + if (!listItemRef.current?.contains(e.relatedTarget)) { + onSubmit(); + } + }} + /> + {tooltip.isOpen && ( + { + tooltip.close(); + inputRef.current?.focus(); + }} + > +

+ + )} + + onEdit?.(category.id)} + style={{ ...(showEditables && { display: 'none' }), flex: 1 }} + > {category.name} - {tooltip.isOpen && ( - - - - - - } - placeholder="Category Name" - value={categoryName} - onUpdate={setCategoryName} - onEnter={onTooltipClose} - /> - - - - - )} - {show3Cols || showBudgetedCol ? ( - - ) : null} - {show3Cols || !showBudgetedCol ? ( - - ) : null} + + value < 0 && { color: theme.errorText }} + getStyle={value => + value < 0 ? { color: theme.errorText } : makeAmountGrey(value) + } type="financial" /> @@ -431,6 +458,8 @@ const ExpenseCategory = memo(function ExpenseCategory({ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({ group, editMode, + isEditing, + onEdit, blank, onAddCategory, onSave, @@ -438,14 +467,21 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({ show3Cols, showBudgetedCol, }) { - let opacity = editMode || blank ? 0 : 1; + let opacity = blank ? 0 : 1; + let showEditables = editMode || isEditing; let [groupName, setGroupName] = useState(group.name); let [isHidden, setIsHidden] = useState(group.hidden); let tooltip = useTooltip(); - let onTooltipClose = () => { + useEffect(() => { + if (!isEditing && tooltip.isOpen) { + tooltip.close(); + } + }, [isEditing]); + + let onSubmit = () => { if (groupName) { onSave?.({ ...group, @@ -454,11 +490,11 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({ } else { setGroupName(group.name); } - tooltip.close(); + onEdit?.(null); }; let onMenuSelect = type => { - tooltip.close(); + onEdit?.(null); switch (type) { case 'add-category': onAddCategory?.(group.id, group.is_income); @@ -478,6 +514,9 @@ const ExpenseGroupTotals = memo(function ExpenseGroupTotals({ } }; + let listItemRef = useRef(); + let inputRef = useRef(); + let content = ( - + + + + + } + style={{ width: '100%' }} + placeholder="Category Group Name" + value={groupName} + onUpdate={setGroupName} + onEnter={onSubmit} + onBlur={e => { + if (!listItemRef.current?.contains(e.relatedTarget)) { + onSubmit(); + } + }} + /> + {tooltip.isOpen && ( + { + tooltip.close(); + inputRef.current?.focus(); + }} + > + + + )} + + onEdit?.(group.id)} + style={{ ...(showEditables && { display: 'none' }), flex: 1 }} + > {group.name} - {tooltip.isOpen && ( - - - - - - } - placeholder="Category Group Name" - value={groupName} - onUpdate={setGroupName} - onEnter={onTooltipClose} - /> - - - - - )} - {show3Cols || showBudgetedCol ? ( - - ) : null} - {show3Cols || !showBudgetedCol ? ( - - ) : null} + + { + useEffect(() => { + if (!isEditing && tooltip.isOpen) { + tooltip.close(); + } + }, [isEditing]); + + let onSubmit = () => { if (groupName) { onSave?.({ ...group, @@ -655,11 +716,11 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({ } else { setGroupName(group.name); } - tooltip.close(); + onEdit?.(null); }; let onMenuSelect = type => { - tooltip.close(); + onEdit?.(null); switch (type) { case 'add-category': onAddCategory?.(group.id, group.is_income); @@ -679,6 +740,9 @@ const IncomeGroupTotals = memo(function IncomeGroupTotals({ } }; + let listItemRef = useRef(); + let inputRef = useRef(); + return ( - + + + + + } + style={{ width: '100%' }} + placeholder="Category Group Name" + value={groupName} + onUpdate={setGroupName} + onEnter={onSubmit} + onBlur={e => { + if (!listItemRef.current?.contains(e.relatedTarget)) { + onSubmit(); + } + }} + /> + {tooltip.isOpen && ( + { + tooltip.close(); + inputRef.current?.focus(); + }} + > + + + )} + + onEdit?.(group.id)} + > {group.name} - {tooltip.isOpen && ( - - - - - - } - placeholder="Category Group Name" - value={groupName} - onUpdate={setGroupName} - onEnter={onTooltipClose} - /> - - - - - )} {budget && ( { + useEffect(() => { + if (!isEditing && tooltip.isOpen) { + tooltip.close(); + } + }, [isEditing]); + + let onSubmit = () => { if (categoryName) { onSave?.({ ...category, @@ -801,11 +893,11 @@ const IncomeCategory = memo(function IncomeCategory({ } else { setCategoryName(category.name); } - tooltip.close(); + onEdit?.(null); }; let onMenuSelect = type => { - tooltip.close(); + onEdit?.(null); switch (type) { case 'toggle-visibility': setIsHidden(!isHidden); @@ -822,6 +914,9 @@ const IncomeCategory = memo(function IncomeCategory({ } }; + let listItemRef = useRef(); + let inputRef = useRef(); + return ( - + + + + + } + style={{ width: '100%' }} + placeholder="Category Name" + value={categoryName} + onUpdate={setCategoryName} + onEnter={onSubmit} + onBlur={e => { + if (!listItemRef.current?.contains(e.relatedTarget)) { + onSubmit(); + } + }} + /> + {tooltip.isOpen && ( + { + tooltip.close(); + inputRef.current?.focus(); + }} + > + + + )} + + onEdit?.(category.id)} + > {category.name} - {tooltip.isOpen && ( - - - - - - } - placeholder="Category Name" - value={categoryName} - onUpdate={setCategoryName} - onEnter={onTooltipClose} - /> - - - - - )} {budget && ( {group.categories .filter(category => !category.hidden || showHiddenCategories) .map((category, index) => { - const editing = editingId === category.id; + const isEditingCategory = editingCategoryId === category.id; + const isEditingCategoryBudget = + editingBudgetCategoryId === category.id; return ( @@ -1099,6 +1224,9 @@ function IncomeGroup({ onAddCategory={onAddCategory} onSave={onSave} onDelete={onDelete} + editMode={editMode} + isEditing={editingGroupId === group.id} + onEdit={onEditGroup} /> {group.categories @@ -1122,6 +1250,9 @@ function IncomeGroup({ index={index} onSave={onSaveCategory} onDelete={onDeleteCategory} + editMode={editMode} + isEditing={editingCategoryId === category.id} + onEdit={onEditCategory} /> ); })} @@ -1133,8 +1264,12 @@ function IncomeGroup({ function BudgetGroups({ type, categoryGroups, - editingId, - onEditingCategoryBudget, + editingGroupId, + onEditGroup, + editingCategoryId, + onEditCategory, + editingBudgetCategoryId, + onEditCategoryBudget, editMode, gestures, month, @@ -1172,12 +1307,16 @@ function BudgetGroups({ )} @@ -1220,12 +1364,6 @@ function BudgetGroups({ } export function BudgetTable(props) { - const [editingCategoryBudgetId, setEditingCategoryBudget] = useState(null); - function onEditingCategoryBudget(id) { - setEditingCategoryBudget(id); - } - const { width } = useResponsive(); - const show3Cols = width >= 360; const { type, categoryGroups, @@ -1245,11 +1383,47 @@ export function BudgetTable(props) { onReorderCategory, onReorderGroup, onShowBudgetDetails, - onOpenActionSheet, + // onOpenActionSheet, onBudgetAction, savePrefs, } = props; + const GROUP_TYPE = 'group'; + const [editingGroupId, setEditingGroupId] = useState(null); + function onEditGroup(id) { + onEdit(GROUP_TYPE, id); + } + + const CATEGORY_TYPE = 'category'; + const [editingCategoryId, setEditingCategoryId] = useState(null); + function onEditCategory(id) { + onEdit(CATEGORY_TYPE, id); + } + + const CATEGORY_BUDGET_TYPE = 'category-budget'; + const [editingBudgetCategoryId, setEditingBudgetCategoryId] = useState(null); + function onEditCategoryBudget(id) { + onEdit(CATEGORY_BUDGET_TYPE, id); + } + + function onEdit(type, id) { + // Do not allow editing if another field is currently being edited. + // Cancel the currently editing field in that case. + const currentlyEditing = + editingGroupId || editingCategoryId || editingBudgetCategoryId; + + setEditingGroupId(type === GROUP_TYPE && !currentlyEditing ? id : null); + setEditingCategoryId( + type === CATEGORY_TYPE && !currentlyEditing ? id : null, + ); + setEditingBudgetCategoryId( + type === CATEGORY_BUDGET_TYPE && !currentlyEditing ? id : null, + ); + } + + const { width } = useResponsive(); + const show3Cols = width >= 360; + // let editMode = false; // neuter editMode -- sorry, not rewriting drag-n-drop right now let currentMonth = monthUtils.currentMonth(); let format = useFormat(); @@ -1284,14 +1458,12 @@ export function BudgetTable(props) { onEditMode(false)} - onOpenActionSheet={onOpenActionSheet} + onEditMode={onEditMode} + // onOpenActionSheet={onOpenActionSheet} onPrevMonth={onPrevMonth} onNextMonth={onNextMonth} showHiddenCategories={showHiddenCategories} @@ -1408,14 +1580,18 @@ export function BudgetTable(props) { { tooltip.close(); switch (name) { - case 'toggle-hidden': + case 'edit-mode': + onEditMode?.(true); + break; + case 'toggle-hidden-categories': toggleHiddenCategories(); break; default: @@ -1591,36 +1776,56 @@ function BudgetHeader({ flexDirection: 'row', }} > - + {!editMode ? ( + + ) : ( + + )} ); diff --git a/packages/desktop-client/src/components/budget/util.ts b/packages/desktop-client/src/components/budget/util.ts index f8c4af733a1..82f97f4d257 100644 --- a/packages/desktop-client/src/components/budget/util.ts +++ b/packages/desktop-client/src/components/budget/util.ts @@ -22,7 +22,7 @@ export function separateGroups(categoryGroups: CategoryGroupEntity[]) { } export function makeAmountGrey(value: number | string) { - return value === 0 || value === '0' || value === '' + return value === 0 || value === '0' || value === '' || value == null ? { color: theme.altMenuItemText } : null; } diff --git a/packages/desktop-client/src/components/util/AmountInput.js b/packages/desktop-client/src/components/util/AmountInput.js index 2aeb94ab9b4..bc59bf268e4 100644 --- a/packages/desktop-client/src/components/util/AmountInput.js +++ b/packages/desktop-client/src/components/util/AmountInput.js @@ -1,9 +1,7 @@ import React, { useRef, useState } from 'react'; -import { - currencyToInteger, - integerToCurrency, -} from 'loot-core/src/shared/util'; +import evalArithmetic from 'loot-core/src/shared/arithmetic'; +import { amountToInteger } from 'loot-core/src/shared/util'; import { useMergedRefs } from '../../hooks/useMergedRefs'; import Add from '../../icons/v1/Add'; @@ -12,11 +10,12 @@ import { theme } from '../../style'; import Button from '../common/Button'; import InputWithContent from '../common/InputWithContent'; import View from '../common/View'; +import useFormat from '../spreadsheet/useFormat'; export function AmountInput({ id, inputRef, - initialValue = 0, + initialValue, zeroSign = '-', // + or - onChange, onBlur, @@ -24,10 +23,11 @@ export function AmountInput({ textStyle, focused, }) { + let format = useFormat(); let [negative, setNegative] = useState( (initialValue === 0 && zeroSign === '-') || initialValue < 0, ); - let initialValueAbsolute = integerToCurrency(Math.abs(initialValue || 0)); + let initialValueAbsolute = format(Math.abs(initialValue), 'financial'); let [value, setValue] = useState(initialValueAbsolute); let buttonRef = useRef(); @@ -38,7 +38,7 @@ export function AmountInput({ function fireChange(val, neg) { let valueOrInitial = Math.abs( - currencyToInteger(val ? val : initialValueAbsolute), + amountToInteger(evalArithmetic(val, initialValueAbsolute)), ); let amount = neg ? valueOrInitial * -1 : valueOrInitial; diff --git a/upcoming-release-notes/1781.md b/upcoming-release-notes/1781.md new file mode 100644 index 00000000000..536b390a50d --- /dev/null +++ b/upcoming-release-notes/1781.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [joel-jeremy] +--- + +Inline mobile edits.