From edd34b790368e1dc09f19694597aceabeae2cd7b Mon Sep 17 00:00:00 2001
From: Robert Dyer <rdyer@unl.edu>
Date: Fri, 12 Apr 2024 12:56:46 -0500
Subject: [PATCH] Dim categories hidden by their groups (#2582)

* Dim categories hidden by their groups

* Dim hidden cats on mobile view

* Do not show hide/show menu on mobile for categories in hidden groups

* Rename catGroup to categoryGroup

* Fix lint issue

* Hide menu line

* Pass in categoryGroup instead of isHidden

* avoid need for extra local

* fix lint issues
---
 packages/desktop-client/src/components/Modals.tsx |  1 +
 .../src/components/budget/BudgetCategories.jsx    |  2 ++
 .../src/components/budget/ExpenseCategory.tsx     | 10 ++++++++--
 .../src/components/budget/SidebarCategory.tsx     | 11 ++++++++---
 .../src/components/mobile/budget/BudgetTable.jsx  |  4 +++-
 .../src/components/mobile/budget/index.tsx        |  2 ++
 .../src/components/modals/CategoryMenuModal.tsx   | 15 ++++++++++++---
 .../loot-core/src/client/state-types/modals.d.ts  |  1 +
 upcoming-release-notes/2582.md                    |  6 ++++++
 9 files changed, 43 insertions(+), 9 deletions(-)
 create mode 100644 upcoming-release-notes/2582.md

diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx
index 2953f58e4..95e071360 100644
--- a/packages/desktop-client/src/components/Modals.tsx
+++ b/packages/desktop-client/src/components/Modals.tsx
@@ -429,6 +429,7 @@ export function Modals() {
               key={name}
               modalProps={modalProps}
               categoryId={options.categoryId}
+              categoryGroup={options.categoryGroup}
               onSave={options.onSave}
               onEditNotes={options.onEditNotes}
               onDelete={options.onDelete}
diff --git a/packages/desktop-client/src/components/budget/BudgetCategories.jsx b/packages/desktop-client/src/components/budget/BudgetCategories.jsx
index fd708f382..962697d9a 100644
--- a/packages/desktop-client/src/components/budget/BudgetCategories.jsx
+++ b/packages/desktop-client/src/components/budget/BudgetCategories.jsx
@@ -66,6 +66,7 @@ export const BudgetCategories = memo(
               cat => ({
                 type: 'expense-category',
                 value: cat,
+                group,
               }),
             ),
           ];
@@ -250,6 +251,7 @@ export const BudgetCategories = memo(
               content = (
                 <ExpenseCategory
                   cat={item.value}
+                  categoryGroup={item.group}
                   editingCell={editingCell}
                   MonthComponent={dataComponents.ExpenseCategoryComponent}
                   dragState={dragState}
diff --git a/packages/desktop-client/src/components/budget/ExpenseCategory.tsx b/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
index 16a5fa61d..5007b81c8 100644
--- a/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
+++ b/packages/desktop-client/src/components/budget/ExpenseCategory.tsx
@@ -1,7 +1,10 @@
 // @ts-strict-ignore
 import React, { type ComponentProps } from 'react';
 
-import { type CategoryEntity } from 'loot-core/src/types/models';
+import {
+  type CategoryGroupEntity,
+  type CategoryEntity,
+} from 'loot-core/src/types/models';
 
 import { theme } from '../../style';
 import { View } from '../common/View';
@@ -20,6 +23,7 @@ import { SidebarCategory } from './SidebarCategory';
 
 type ExpenseCategoryProps = {
   cat: CategoryEntity;
+  categoryGroup?: CategoryGroupEntity;
   editingCell: { id: string; cell: string } | null;
   dragState: DragState<CategoryEntity>;
   MonthComponent: ComponentProps<typeof RenderMonths>['component'];
@@ -35,6 +39,7 @@ type ExpenseCategoryProps = {
 
 export function ExpenseCategory({
   cat,
+  categoryGroup,
   editingCell,
   dragState,
   MonthComponent,
@@ -72,7 +77,7 @@ export function ExpenseCategory({
       collapsed={true}
       style={{
         backgroundColor: theme.tableBackground,
-        opacity: cat.hidden ? 0.5 : undefined,
+        opacity: cat.hidden || categoryGroup?.hidden ? 0.5 : undefined,
       }}
     >
       <DropHighlight pos={dropPos} offset={{ top: 1 }} />
@@ -81,6 +86,7 @@ export function ExpenseCategory({
         <SidebarCategory
           innerRef={dragRef}
           category={cat}
+          categoryGroup={categoryGroup}
           dragPreview={dragging && dragState.preview}
           dragging={dragging && !dragState.preview}
           editing={
diff --git a/packages/desktop-client/src/components/budget/SidebarCategory.tsx b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
index 8ca35fde6..f62255cf9 100644
--- a/packages/desktop-client/src/components/budget/SidebarCategory.tsx
+++ b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
@@ -1,7 +1,10 @@
 // @ts-strict-ignore
 import React, { type CSSProperties, type Ref, useState } from 'react';
 
-import { type CategoryEntity } from 'loot-core/src/types/models';
+import {
+  type CategoryGroupEntity,
+  type CategoryEntity,
+} from 'loot-core/src/types/models';
 
 import { SvgCheveronDown } from '../../icons/v1';
 import { theme } from '../../style';
@@ -15,6 +18,7 @@ import { Tooltip } from '../tooltips';
 type SidebarCategoryProps = {
   innerRef: Ref<HTMLDivElement>;
   category: CategoryEntity;
+  categoryGroup?: CategoryGroupEntity;
   dragPreview?: boolean;
   dragging?: boolean;
   editing: boolean;
@@ -30,6 +34,7 @@ type SidebarCategoryProps = {
 export function SidebarCategory({
   innerRef,
   category,
+  categoryGroup,
   dragPreview,
   dragging,
   editing,
@@ -50,7 +55,7 @@ export function SidebarCategory({
         alignItems: 'center',
         userSelect: 'none',
         WebkitUserSelect: 'none',
-        opacity: category.hidden ? 0.33 : undefined,
+        opacity: category.hidden || categoryGroup?.hidden ? 0.33 : undefined,
       }}
     >
       <div
@@ -99,7 +104,7 @@ export function SidebarCategory({
                 setMenuOpen(false);
               }}
               items={[
-                {
+                !categoryGroup?.hidden && {
                   name: 'toggle-visibility',
                   text: category.hidden ? 'Show' : 'Hide',
                 },
diff --git a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx
index 9e1f43d21..5b8798d43 100644
--- a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx
+++ b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx
@@ -227,6 +227,7 @@ function ExpenseCategoryPreview({ name, pending, style }) {
 const ExpenseCategory = memo(function ExpenseCategory({
   type,
   category,
+  isHidden,
   goal,
   budgeted,
   spent,
@@ -322,7 +323,7 @@ const ExpenseCategory = memo(function ExpenseCategory({
         backgroundColor: 'transparent',
         borderBottomWidth: 0,
         borderTopWidth: index > 0 ? 1 : 0,
-        opacity: !!category.hidden ? 0.5 : undefined,
+        opacity: isHidden ? 0.5 : undefined,
         ...style,
       }}
       data-testid="row"
@@ -894,6 +895,7 @@ const ExpenseGroup = memo(function ExpenseGroup({
               show3Cols={show3Cols}
               type={type}
               category={category}
+              isHidden={!!category.hidden || group.hidden}
               goal={
                 type === 'report'
                   ? reportBudget.catGoal(category.id)
diff --git a/packages/desktop-client/src/components/mobile/budget/index.tsx b/packages/desktop-client/src/components/mobile/budget/index.tsx
index 4374b7246..d3c2bd2a7 100644
--- a/packages/desktop-client/src/components/mobile/budget/index.tsx
+++ b/packages/desktop-client/src/components/mobile/budget/index.tsx
@@ -343,9 +343,11 @@ function BudgetInner(props: BudgetInnerProps) {
 
   const onEditCategory = id => {
     const category = categories.find(c => c.id === id);
+    const categoryGroup = categoryGroups.find(g => g.id === category.cat_group);
     dispatch(
       pushModal('category-menu', {
         categoryId: category.id,
+        categoryGroup,
         onSave: onSaveCategory,
         onEditNotes: onEditCategoryNotes,
         onDelete: onDeleteCategory,
diff --git a/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx b/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx
index b88d52a0a..75ffcaa1e 100644
--- a/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx
+++ b/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx
@@ -4,6 +4,7 @@ import React, { useState } from 'react';
 import { useLiveQuery } from 'loot-core/src/client/query-hooks';
 import { q } from 'loot-core/src/shared/query';
 import {
+  type CategoryGroupEntity,
   type CategoryEntity,
   type NoteEntity,
 } from 'loot-core/src/types/models';
@@ -23,6 +24,7 @@ import { Tooltip } from '../tooltips';
 type CategoryMenuModalProps = {
   modalProps: CommonModalProps;
   categoryId: string;
+  categoryGroup?: CategoryGroupEntity;
   onSave: (category: CategoryEntity) => void;
   onEditNotes: (id: string) => void;
   onDelete: (categoryId: string) => void;
@@ -32,6 +34,7 @@ type CategoryMenuModalProps = {
 export function CategoryMenuModal({
   modalProps,
   categoryId,
+  categoryGroup,
   onSave,
   onEditNotes,
   onDelete,
@@ -102,6 +105,7 @@ export function CategoryMenuModal({
       leftHeaderContent={
         <AdditionalCategoryMenu
           category={category}
+          categoryGroup={categoryGroup}
           onDelete={_onDelete}
           onToggleVisibility={_onToggleVisibility}
         />
@@ -152,7 +156,12 @@ export function CategoryMenuModal({
   );
 }
 
-function AdditionalCategoryMenu({ category, onDelete, onToggleVisibility }) {
+function AdditionalCategoryMenu({
+  category,
+  categoryGroup,
+  onDelete,
+  onToggleVisibility,
+}) {
   const [menuOpen, setMenuOpen] = useState(false);
   const itemStyle: CSSProperties = {
     ...styles.mediumText,
@@ -184,13 +193,13 @@ function AdditionalCategoryMenu({ category, onDelete, onToggleVisibility }) {
             <Menu
               getItemStyle={() => itemStyle}
               items={[
-                {
+                !categoryGroup?.hidden && {
                   name: 'toggleVisibility',
                   text: category.hidden ? 'Show' : 'Hide',
                   icon: category.hidden ? SvgViewShow : SvgViewHide,
                   iconSize: 16,
                 },
-                Menu.line,
+                !categoryGroup?.hidden && Menu.line,
                 {
                   name: 'delete',
                   text: 'Delete',
diff --git a/packages/loot-core/src/client/state-types/modals.d.ts b/packages/loot-core/src/client/state-types/modals.d.ts
index 4d4f45f8d..eef5b20f8 100644
--- a/packages/loot-core/src/client/state-types/modals.d.ts
+++ b/packages/loot-core/src/client/state-types/modals.d.ts
@@ -143,6 +143,7 @@ type FinanceModals = {
   };
   'category-menu': {
     categoryId: string;
+    categoryGroup?: CategoryGroupEntity;
     onSave: (category: CategoryEntity) => void;
     onEditNotes: (id: string) => void;
     onDelete: (categoryId: string) => void;
diff --git a/upcoming-release-notes/2582.md b/upcoming-release-notes/2582.md
new file mode 100644
index 000000000..f532a2565
--- /dev/null
+++ b/upcoming-release-notes/2582.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [psybers]
+---
+
+Dim categories in the budget view if hidden by their category group.
-- 
GitLab