From 97ec8f8d3a63717e10f18e00a86ee54f9b1a2498 Mon Sep 17 00:00:00 2001
From: Neil <55785687+carkom@users.noreply.github.com>
Date: Thu, 18 Apr 2024 20:38:25 +0100
Subject: [PATCH] Custom Reports: Add filters to sessionStorage (#2612)

* Add filters to sessionStorage

* notes

* setSessionReports util
---
 .../src/components/reports/ChooseGraph.tsx    |  5 ++
 .../src/components/reports/ReportSidebar.jsx  | 89 +++++--------------
 .../src/components/reports/ReportTopbar.jsx   |  8 +-
 .../components/reports/graphs/BarGraph.tsx    |  4 +
 .../components/reports/graphs/DonutGraph.tsx  |  4 +
 .../reports/reports/CustomReport.jsx          | 44 +++++----
 .../components/reports/setSessionReport.ts    | 18 ++++
 upcoming-release-notes/2612.md                |  6 ++
 8 files changed, 90 insertions(+), 88 deletions(-)
 create mode 100644 packages/desktop-client/src/components/reports/setSessionReport.ts
 create mode 100644 upcoming-release-notes/2612.md

diff --git a/packages/desktop-client/src/components/reports/ChooseGraph.tsx b/packages/desktop-client/src/components/reports/ChooseGraph.tsx
index 2a671ffc4..3e294fbff 100644
--- a/packages/desktop-client/src/components/reports/ChooseGraph.tsx
+++ b/packages/desktop-client/src/components/reports/ChooseGraph.tsx
@@ -2,6 +2,7 @@
 import React, { useRef } from 'react';
 
 import { type GroupedEntity } from 'loot-core/src/types/models/reports';
+import { type RuleConditionEntity } from 'loot-core/types/models/rule';
 
 import { type CSSProperties } from '../../style';
 import { styles } from '../../style/styles';
@@ -20,6 +21,7 @@ import { ReportOptions } from './ReportOptions';
 
 type ChooseGraphProps = {
   data: GroupedEntity;
+  filters?: RuleConditionEntity[];
   mode: string;
   graphType: string;
   balanceType: string;
@@ -36,6 +38,7 @@ type ChooseGraphProps = {
 
 export function ChooseGraph({
   data,
+  filters,
   mode,
   graphType,
   balanceType,
@@ -101,6 +104,7 @@ export function ChooseGraph({
         style={graphStyle}
         compact={compact}
         data={data}
+        filters={filters}
         groupBy={groupBy}
         balanceTypeOp={balanceTypeOp}
         viewLabels={viewLabels}
@@ -118,6 +122,7 @@ export function ChooseGraph({
         style={graphStyle}
         compact={compact}
         data={data}
+        filters={filters}
         groupBy={groupBy}
         balanceTypeOp={balanceTypeOp}
         viewLabels={viewLabels}
diff --git a/packages/desktop-client/src/components/reports/ReportSidebar.jsx b/packages/desktop-client/src/components/reports/ReportSidebar.jsx
index af3339562..e48fb0be5 100644
--- a/packages/desktop-client/src/components/reports/ReportSidebar.jsx
+++ b/packages/desktop-client/src/components/reports/ReportSidebar.jsx
@@ -16,6 +16,7 @@ import { getLiveRange } from './getLiveRange';
 import { ModeButton } from './ModeButton';
 import { ReportOptions } from './ReportOptions';
 import { validateEnd, validateStart } from './reportRanges';
+import { setSessionReport } from './setSessionReport';
 
 export function ReportSidebar({
   customReportItems,
@@ -44,11 +45,7 @@ export function ReportSidebar({
 }) {
   const [menuOpen, setMenuOpen] = useState(false);
   const onSelectRange = cond => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({ ...storedReport, dateRange: cond }),
-    );
+    setSessionReport('dateRange', cond);
     onReportChange({ type: 'modify' });
     setDateRange(cond);
     onChangeDates(
@@ -57,29 +54,19 @@ export function ReportSidebar({
   };
 
   const onChangeMode = cond => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({ ...storedReport, mode: cond }),
-    );
+    setSessionReport('mode', cond);
     onReportChange({ type: 'modify' });
     setMode(cond);
     let graph;
     if (cond === 'time') {
       if (customReportItems.graphType === 'BarGraph') {
-        sessionStorage.setItem(
-          'report',
-          JSON.stringify({ ...storedReport, graphType: 'StackedBarGraph' }),
-        );
+        setSessionReport('graphType', 'StackedBarGraph');
         setGraphType('StackedBarGraph');
         graph = 'StackedBarGraph';
       }
     } else {
       if (customReportItems.graphType === 'StackedBarGraph') {
-        sessionStorage.setItem(
-          'report',
-          JSON.stringify({ ...storedReport, graphType: 'BarGraph' }),
-        );
+        setSessionReport('graphType', 'BarGraph');
         setGraphType('BarGraph');
         graph = 'BarGraph';
       }
@@ -88,22 +75,14 @@ export function ReportSidebar({
   };
 
   const onChangeSplit = cond => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({ ...storedReport, groupBy: cond }),
-    );
+    setSessionReport('groupBy', cond);
     onReportChange({ type: 'modify' });
     setGroupBy(cond);
     defaultItems(cond);
   };
 
   const onChangeBalanceType = cond => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({ ...storedReport, balanceType: cond }),
-    );
+    setSessionReport('balanceType', cond);
     onReportChange({ type: 'modify' });
     setBalanceType(cond);
   };
@@ -203,6 +182,7 @@ export function ReportSidebar({
           <Select
             value={customReportItems.interval}
             onChange={e => {
+              setSessionReport('interval', e);
               setInterval(e);
               onReportChange({ type: 'modify' });
               if (
@@ -249,49 +229,32 @@ export function ReportSidebar({
               >
                 <Menu
                   onMenuSelect={type => {
-                    const storedReport = JSON.parse(
-                      sessionStorage.getItem('report'),
-                    );
                     onReportChange({ type: 'modify' });
 
                     if (type === 'show-hidden-categories') {
-                      sessionStorage.setItem(
-                        'report',
-                        JSON.stringify({
-                          ...storedReport,
-                          showHiddenCategories:
-                            !customReportItems.showHiddenCategories,
-                        }),
+                      setSessionReport(
+                        'showHiddenCategories',
+                        !customReportItems.showHiddenCategories,
                       );
                       setShowHiddenCategories(
                         !customReportItems.showHiddenCategories,
                       );
                     } else if (type === 'show-off-budget') {
-                      sessionStorage.setItem(
-                        'report',
-                        JSON.stringify({
-                          ...storedReport,
-                          showOffBudget: !customReportItems.showOffBudget,
-                        }),
+                      setSessionReport(
+                        'showOffBudget',
+                        !customReportItems.showOffBudget,
                       );
                       setShowOffBudget(!customReportItems.showOffBudget);
                     } else if (type === 'show-empty-items') {
-                      sessionStorage.setItem(
-                        'report',
-                        JSON.stringify({
-                          ...storedReport,
-                          showEmpty: !customReportItems.showEmpty,
-                        }),
+                      setSessionReport(
+                        'showEmpty',
+                        !customReportItems.showEmpty,
                       );
                       setShowEmpty(!customReportItems.showEmpty);
                     } else if (type === 'show-uncategorized') {
-                      sessionStorage.setItem(
-                        'report',
-                        JSON.stringify({
-                          ...storedReport,
-                          showUncategorized:
-                            !customReportItems.showUncategorized,
-                        }),
+                      setSessionReport(
+                        'showUncategorized',
+                        !customReportItems.showUncategorized,
                       );
                       setShowUncategorized(
                         !customReportItems.showUncategorized,
@@ -352,11 +315,7 @@ export function ReportSidebar({
           <ModeButton
             selected={!customReportItems.isDateStatic}
             onSelect={() => {
-              const storedReport = JSON.parse(sessionStorage.getItem('report'));
-              sessionStorage.setItem(
-                'report',
-                JSON.stringify({ ...storedReport, isDateStatic: false }),
-              );
+              setSessionReport('isDateStatic', false);
               setIsDateStatic(false);
               onSelectRange(customReportItems.dateRange);
             }}
@@ -366,11 +325,7 @@ export function ReportSidebar({
           <ModeButton
             selected={customReportItems.isDateStatic}
             onSelect={() => {
-              const storedReport = JSON.parse(sessionStorage.getItem('report'));
-              sessionStorage.setItem(
-                'report',
-                JSON.stringify({ ...storedReport, isDateStatic: true }),
-              );
+              setSessionReport('isDateStatic', true);
               setIsDateStatic(true);
               onChangeDates(
                 customReportItems.startDate,
diff --git a/packages/desktop-client/src/components/reports/ReportTopbar.jsx b/packages/desktop-client/src/components/reports/ReportTopbar.jsx
index 3a98f00ee..6a78e7d8d 100644
--- a/packages/desktop-client/src/components/reports/ReportTopbar.jsx
+++ b/packages/desktop-client/src/components/reports/ReportTopbar.jsx
@@ -16,6 +16,7 @@ import { FilterButton } from '../filters/FiltersMenu';
 
 import { GraphButton } from './GraphButton';
 import { SaveReport } from './SaveReport';
+import { setSessionReport } from './setSessionReport';
 
 export function ReportTopbar({
   customReportItems,
@@ -32,11 +33,7 @@ export function ReportTopbar({
   defaultItems,
 }) {
   const onChangeGraph = cond => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({ ...storedReport, graphType: cond }),
-    );
+    setSessionReport('graphType', cond);
     onReportChange({ type: 'modify' });
     setGraphType(cond);
     defaultItems(cond);
@@ -171,6 +168,7 @@ export function ReportTopbar({
         compact
         hover
         onApply={e => {
+          setSessionReport('conditions', [...customReportItems.conditions, e]);
           onApplyFilter(e);
           onReportChange({ type: 'modify' });
         }}
diff --git a/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx b/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx
index e9d5252b4..e420579bd 100644
--- a/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx
+++ b/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx
@@ -20,6 +20,7 @@ import {
   amountToCurrencyNoDecimal,
 } from 'loot-core/src/shared/util';
 import { type GroupedEntity } from 'loot-core/src/types/models/reports';
+import { type RuleConditionEntity } from 'loot-core/types/models/rule';
 
 import { useAccounts } from '../../../hooks/useAccounts';
 import { useCategories } from '../../../hooks/useCategories';
@@ -132,6 +133,7 @@ const customLabel = (props, typeOp) => {
 type BarGraphProps = {
   style?: CSSProperties;
   data: GroupedEntity;
+  filters: RuleConditionEntity[];
   groupBy: string;
   balanceTypeOp: string;
   compact?: boolean;
@@ -143,6 +145,7 @@ type BarGraphProps = {
 export function BarGraph({
   style,
   data,
+  filters,
   groupBy,
   balanceTypeOp,
   compact,
@@ -187,6 +190,7 @@ export function BarGraph({
     const offBudgetAccounts = accounts.filter(f => f.offbudget).map(e => e.id);
 
     const conditions = [
+      ...filters,
       { field, op: 'is', value: item.id, type: 'id' },
       {
         field: 'date',
diff --git a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx
index f30d2560d..e7fe93c5c 100644
--- a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx
+++ b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx
@@ -5,6 +5,7 @@ import { PieChart, Pie, Cell, Sector, ResponsiveContainer } from 'recharts';
 
 import { amountToCurrency } from 'loot-core/src/shared/util';
 import { type GroupedEntity } from 'loot-core/src/types/models/reports';
+import { type RuleConditionEntity } from 'loot-core/types/models/rule';
 
 import { useAccounts } from '../../../hooks/useAccounts';
 import { useCategories } from '../../../hooks/useCategories';
@@ -176,6 +177,7 @@ const customLabel = props => {
 type DonutGraphProps = {
   style?: CSSProperties;
   data: GroupedEntity;
+  filters: RuleConditionEntity[];
   groupBy: string;
   balanceTypeOp: string;
   compact?: boolean;
@@ -187,6 +189,7 @@ type DonutGraphProps = {
 export function DonutGraph({
   style,
   data,
+  filters,
   groupBy,
   balanceTypeOp,
   compact,
@@ -211,6 +214,7 @@ export function DonutGraph({
     const offBudgetAccounts = accounts.filter(f => f.offbudget).map(e => e.id);
 
     const conditions = [
+      ...filters,
       { field, op: 'is', value: item.id, type: 'id' },
       {
         field: 'date',
diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
index 527ebf375..81292f60e 100644
--- a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
+++ b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
@@ -29,6 +29,7 @@ import { ReportOptions, defaultReport } from '../ReportOptions';
 import { ReportSidebar } from '../ReportSidebar';
 import { ReportSummary } from '../ReportSummary';
 import { ReportTopbar } from '../ReportTopbar';
+import { setSessionReport } from '../setSessionReport';
 import { createCustomSpreadsheet } from '../spreadsheets/custom-spreadsheet';
 import { createGroupedSpreadsheet } from '../spreadsheets/grouped-spreadsheet';
 import { useReport } from '../useReport';
@@ -103,7 +104,11 @@ export function CustomReport() {
   const [earliestTransaction, setEarliestTransaction] = useState('');
   const [report, setReport] = useState(loadReport);
   const [savedStatus, setSavedStatus] = useState(
-    location.state ? (location.state.report ? 'saved' : 'new') : 'new',
+    location.state
+      ? location.state.report
+        ? 'saved'
+        : loadReport.savedStatus ?? 'new'
+      : loadReport.savedStatus ?? 'new',
   );
 
   useEffect(() => {
@@ -342,15 +347,8 @@ export function CustomReport() {
   };
 
   const onChangeDates = (dateStart, dateEnd) => {
-    const storedReport = JSON.parse(sessionStorage.getItem('report'));
-    sessionStorage.setItem(
-      'report',
-      JSON.stringify({
-        ...storedReport,
-        startDate: dateStart,
-        endDate: dateEnd,
-      }),
-    );
+    setSessionReport('startDate', dateStart);
+    setSessionReport('endDate', dateEnd);
     setStartDate(dateStart);
     setEndDate(dateEnd);
     onReportChange({ type: 'modify' });
@@ -401,6 +399,7 @@ export function CustomReport() {
   const onReportChange = ({ savedReport, type }) => {
     switch (type) {
       case 'add-update':
+        setSessionReport('savedStatus', 'saved');
         setSavedStatus('saved');
         setReport(savedReport);
         break;
@@ -409,11 +408,12 @@ export function CustomReport() {
         break;
       case 'modify':
         if (report.name) {
+          setSessionReport('savedStatus', 'modified');
           setSavedStatus('modified');
         }
         break;
       case 'reload':
-        sessionStorage.clear();
+        setSessionReport('savedStatus', 'saved');
         setSavedStatus('saved');
         setReportData(report);
         break;
@@ -424,7 +424,7 @@ export function CustomReport() {
         setReportData(defaultReport);
         break;
       case 'choose':
-        sessionStorage.clear();
+        setSessionReport('savedStatus', 'saved');
         setSavedStatus('saved');
         setReport(savedReport);
         setReportData(savedReport);
@@ -515,10 +515,21 @@ export function CustomReport() {
             >
               <AppliedFilters
                 filters={filters}
-                onUpdate={onUpdateFilter}
-                onDelete={filter =>
-                  onChangeAppliedFilter(filter, onDeleteFilter)
-                }
+                onUpdate={(oldFilter, newFilter) => {
+                  setSessionReport(
+                    'conditions',
+                    filters.map(f => (f === oldFilter ? newFilter : f)),
+                  );
+                  onReportChange({ type: 'modify' });
+                  onUpdateFilter(oldFilter, newFilter);
+                }}
+                onDelete={deletedFilter => {
+                  setSessionReport(
+                    'conditions',
+                    filters.filter(f => f !== deletedFilter),
+                  );
+                  onChangeAppliedFilter(deletedFilter, onDeleteFilter);
+                }}
                 conditionsOp={conditionsOp}
                 onCondOpChange={filter =>
                   onChangeAppliedFilter(filter, onCondOpChange)
@@ -578,6 +589,7 @@ export function CustomReport() {
                 {dataCheck ? (
                   <ChooseGraph
                     data={data}
+                    filters={filters}
                     mode={mode}
                     graphType={graphType}
                     balanceType={balanceType}
diff --git a/packages/desktop-client/src/components/reports/setSessionReport.ts b/packages/desktop-client/src/components/reports/setSessionReport.ts
new file mode 100644
index 000000000..f1ab555be
--- /dev/null
+++ b/packages/desktop-client/src/components/reports/setSessionReport.ts
@@ -0,0 +1,18 @@
+import { type RuleConditionEntity } from 'loot-core/types/models/rule';
+
+export const setSessionReport = (
+  propName: string,
+  propValue: string | boolean | RuleConditionEntity[],
+) => {
+  const storedReport =
+    sessionStorage.report && JSON.parse(sessionStorage.getItem('report') || '');
+  const result: Record<string, string | boolean | RuleConditionEntity[]> = {};
+  result[propName] = propValue;
+  sessionStorage.setItem(
+    'report',
+    JSON.stringify({
+      ...storedReport,
+      ...result,
+    }),
+  );
+};
diff --git a/upcoming-release-notes/2612.md b/upcoming-release-notes/2612.md
new file mode 100644
index 000000000..6bfd1d29d
--- /dev/null
+++ b/upcoming-release-notes/2612.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [carkom]
+---
+
+Fixing some of the sessionStorage issues plus adding filters to sessionStorage.
-- 
GitLab