From b6550094771d1b35e9c88a3d544a311109d51416 Mon Sep 17 00:00:00 2001
From: Neil <55785687+carkom@users.noreply.github.com>
Date: Sat, 6 Apr 2024 22:46:58 +0100
Subject: [PATCH] Custom Reports: Fix live range (#2557)

* fix live range

* card updates

* type fix

* notes
---
 .../src/components/reports/ReportSidebar.jsx  | 41 ++---------------
 .../src/components/reports/getLiveRange.ts    | 44 +++++++++++++++++++
 .../src/components/reports/reportRanges.ts    |  2 +-
 .../reports/reports/CustomReport.jsx          | 34 +++++++++-----
 .../reports/reports/CustomReportListCards.tsx | 13 +++++-
 .../reports/reports/GetCardData.tsx           | 31 +++++++++----
 upcoming-release-notes/2557.md                |  6 +++
 7 files changed, 111 insertions(+), 60 deletions(-)
 create mode 100644 packages/desktop-client/src/components/reports/getLiveRange.ts
 create mode 100644 upcoming-release-notes/2557.md

diff --git a/packages/desktop-client/src/components/reports/ReportSidebar.jsx b/packages/desktop-client/src/components/reports/ReportSidebar.jsx
index e916183c7..3b2585eba 100644
--- a/packages/desktop-client/src/components/reports/ReportSidebar.jsx
+++ b/packages/desktop-client/src/components/reports/ReportSidebar.jsx
@@ -11,14 +11,10 @@ import { View } from '../common/View';
 import { Tooltip } from '../tooltips';
 
 import { CategorySelector } from './CategorySelector';
+import { getLiveRange } from './getLiveRange';
 import { ModeButton } from './ModeButton';
 import { ReportOptions } from './ReportOptions';
-import {
-  getSpecificRange,
-  validateEnd,
-  validateRange,
-  validateStart,
-} from './reportRanges';
+import { validateEnd, validateStart } from './reportRanges';
 
 export function ReportSidebar({
   customReportItems,
@@ -48,38 +44,7 @@ export function ReportSidebar({
   const onSelectRange = cond => {
     onReportChange({ type: 'modify' });
     setDateRange(cond);
-    let dateStart;
-    let dateEnd;
-    switch (cond) {
-      case 'All time':
-        onChangeDates(earliestTransaction, monthUtils.currentDay());
-        break;
-      case 'Year to date':
-        [dateStart, dateEnd] = validateRange(
-          earliestTransaction,
-          monthUtils.getYearStart(monthUtils.currentMonth()) + '-01',
-          monthUtils.currentDay(),
-        );
-        onChangeDates(dateStart, dateEnd);
-        break;
-      case 'Last year':
-        [dateStart, dateEnd] = validateRange(
-          earliestTransaction,
-          monthUtils.getYearStart(
-            monthUtils.prevYear(monthUtils.currentMonth()),
-          ) + '-01',
-          monthUtils.getYearEnd(monthUtils.prevYear(monthUtils.currentDate())) +
-            '-31',
-        );
-        onChangeDates(dateStart, dateEnd);
-        break;
-      default:
-        [dateStart, dateEnd] = getSpecificRange(
-          ReportOptions.dateRangeMap.get(cond),
-          cond === 'Last month' ? 0 : null,
-        );
-        onChangeDates(dateStart, dateEnd);
-    }
+    onChangeDates(...getLiveRange(cond, earliestTransaction));
   };
 
   const onChangeMode = cond => {
diff --git a/packages/desktop-client/src/components/reports/getLiveRange.ts b/packages/desktop-client/src/components/reports/getLiveRange.ts
new file mode 100644
index 000000000..a1a44274b
--- /dev/null
+++ b/packages/desktop-client/src/components/reports/getLiveRange.ts
@@ -0,0 +1,44 @@
+import * as monthUtils from 'loot-core/src/shared/months';
+
+import { ReportOptions } from './ReportOptions';
+import { getSpecificRange, validateRange } from './reportRanges';
+
+export function getLiveRange(cond: string, earliestTransaction: string) {
+  let dateStart;
+  let dateEnd;
+  const rangeName = ReportOptions.dateRangeMap.get(cond);
+  switch (rangeName) {
+    case 'yearToDate':
+      [dateStart, dateEnd] = validateRange(
+        earliestTransaction,
+        monthUtils.getYearStart(monthUtils.currentMonth()) + '-01',
+        monthUtils.currentDay(),
+      );
+      break;
+    case 'lastYear':
+      [dateStart, dateEnd] = validateRange(
+        earliestTransaction,
+        monthUtils.getYearStart(
+          monthUtils.prevYear(monthUtils.currentMonth()),
+        ) + '-01',
+        monthUtils.getYearEnd(monthUtils.prevYear(monthUtils.currentDate())) +
+          '-31',
+      );
+      break;
+    case 'allMonths':
+      dateStart = earliestTransaction;
+      dateEnd = monthUtils.currentDay();
+      break;
+    default:
+      if (typeof rangeName === 'number') {
+        [dateStart, dateEnd] = getSpecificRange(
+          rangeName,
+          cond === 'Last month' ? 0 : null,
+        );
+      } else {
+        break;
+      }
+  }
+
+  return [dateStart, dateEnd];
+}
diff --git a/packages/desktop-client/src/components/reports/reportRanges.ts b/packages/desktop-client/src/components/reports/reportRanges.ts
index 588c56291..48892d63f 100644
--- a/packages/desktop-client/src/components/reports/reportRanges.ts
+++ b/packages/desktop-client/src/components/reports/reportRanges.ts
@@ -115,7 +115,7 @@ function boundedRange(
   return [start, end];
 }
 
-export function getSpecificRange(offset: number, addNumber: number) {
+export function getSpecificRange(offset: number, addNumber: number | null) {
   const currentDay = monthUtils.currentDay();
   const dateStart = monthUtils.subMonths(currentDay, offset) + '-01';
   const dateEnd = monthUtils.getMonthEnd(
diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
index c7e89460b..c6da3eb0a 100644
--- a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
+++ b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx
@@ -21,6 +21,7 @@ import { AppliedFilters } from '../../filters/AppliedFilters';
 import { PrivacyFilter } from '../../PrivacyFilter';
 import { ChooseGraph } from '../ChooseGraph';
 import { defaultsList, disabledList } from '../disabledList';
+import { getLiveRange } from '../getLiveRange';
 import { Header } from '../Header';
 import { LoadingIndicator } from '../LoadingIndicator';
 import { ReportLegend } from '../ReportLegend';
@@ -93,18 +94,6 @@ export function CustomReport() {
     location.state ? (location.state.report ? 'saved' : 'new') : 'new',
   );
 
-  useEffect(() => {
-    const format =
-      ReportOptions.intervalMap.get(interval).toLowerCase() + 'FromDate';
-
-    const dateStart = monthUtils[format](startDate);
-    const dateEnd = monthUtils[format](endDate);
-
-    setIntervals(
-      monthUtils[ReportOptions.intervalRange.get(interval)](dateStart, dateEnd),
-    );
-  }, [interval, startDate, endDate]);
-
   useEffect(() => {
     if (selectedCategories === undefined && categories.list.length !== 0) {
       setSelectedCategories(categories.list);
@@ -138,10 +127,31 @@ export function CustomReport() {
         .reverse();
 
       setAllIntervals(allInter);
+
+      if (!isDateStatic) {
+        const [dateStart, dateEnd] = getLiveRange(
+          dateRange,
+          trans ? trans.date : monthUtils.currentDay(),
+        );
+        setStartDate(dateStart);
+        setEndDate(dateEnd);
+      }
     }
     run();
   }, [interval]);
 
+  useEffect(() => {
+    const format =
+      ReportOptions.intervalMap.get(interval).toLowerCase() + 'FromDate';
+
+    const dateStart = monthUtils[format](startDate);
+    const dateEnd = monthUtils[format](endDate);
+
+    setIntervals(
+      monthUtils[ReportOptions.intervalRange.get(interval)](dateStart, dateEnd),
+    );
+  }, [interval, startDate, endDate]);
+
   const balanceTypeOp = ReportOptions.balanceTypeMap.get(balanceType);
   const payees = usePayees();
   const accounts = useAccounts();
diff --git a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx
index 292352d18..4ef5c0893 100644
--- a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx
+++ b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx
@@ -1,6 +1,7 @@
-import React, { createRef, useMemo, useState } from 'react';
+import React, { createRef, useEffect, useMemo, useState } from 'react';
 
 import { send, sendCatch } from 'loot-core/platform/client/fetch/index';
+import * as monthUtils from 'loot-core/src/shared/months';
 import { type CustomReportEntity } from 'loot-core/types/models/reports';
 
 import { useAccounts } from '../../../hooks/useAccounts';
@@ -72,6 +73,7 @@ export function CustomReportListCards({
   const [err, setErr] = useState('');
   const [name, setName] = useState('');
   const inputRef = createRef<HTMLInputElement>();
+  const [earliestTransaction, setEarliestTransaction] = useState('');
 
   const payees = usePayees();
   const accounts = useAccounts();
@@ -85,6 +87,14 @@ export function CustomReportListCards({
     onDeleteMenuOpen(reportData === undefined ? '' : reportData, false);
   };
 
+  useEffect(() => {
+    async function run() {
+      const trans = await send('get-earliest-transaction');
+      setEarliestTransaction(trans ? trans.date : monthUtils.currentDay());
+    }
+    run();
+  }, []);
+
   const onAddUpdate = async ({
     reportData,
   }: {
@@ -216,6 +226,7 @@ export function CustomReportListCards({
                         payees={payees}
                         accounts={accounts}
                         categories={categories}
+                        earliestTransaction={earliestTransaction}
                       />
                     </View>
                   </ReportCard>
diff --git a/packages/desktop-client/src/components/reports/reports/GetCardData.tsx b/packages/desktop-client/src/components/reports/reports/GetCardData.tsx
index ade04b9cc..44f58d368 100644
--- a/packages/desktop-client/src/components/reports/reports/GetCardData.tsx
+++ b/packages/desktop-client/src/components/reports/reports/GetCardData.tsx
@@ -11,6 +11,7 @@ import { styles } from '../../../style/styles';
 import { theme } from '../../../style/theme';
 import { Text } from '../../common/Text';
 import { ChooseGraph } from '../ChooseGraph';
+import { getLiveRange } from '../getLiveRange';
 import { LoadingIndicator } from '../LoadingIndicator';
 import { ReportOptions } from '../ReportOptions';
 import { createCustomSpreadsheet } from '../spreadsheets/custom-spreadsheet';
@@ -35,16 +36,30 @@ export function GetCardData({
   payees,
   accounts,
   categories,
+  earliestTransaction,
 }: {
   report: CustomReportEntity;
   payees: PayeeEntity[];
   accounts: AccountEntity[];
   categories: { list: CategoryEntity[]; grouped: CategoryGroupEntity[] };
+  earliestTransaction: string;
 }) {
+  let startDate = report.startDate;
+  let endDate = report.endDate;
+
+  if (!report.isDateStatic) {
+    const [dateStart, dateEnd] = getLiveRange(
+      report.dateRange,
+      earliestTransaction,
+    );
+    startDate = dateStart || report.startDate;
+    endDate = dateEnd || report.startDate;
+  }
+
   const getGroupData = useMemo(() => {
     return createGroupedSpreadsheet({
-      startDate: report.startDate,
-      endDate: report.endDate,
+      startDate,
+      endDate,
       interval: report.interval,
       categories,
       selectedCategories: report.selectedCategories ?? categories.list,
@@ -56,11 +71,11 @@ export function GetCardData({
       showUncategorized: report.showUncategorized,
       balanceTypeOp: ReportOptions.balanceTypeMap.get(report.balanceType),
     });
-  }, [report, categories]);
+  }, [report, categories, startDate, endDate]);
   const getGraphData = useMemo(() => {
     return createCustomSpreadsheet({
-      startDate: report.startDate,
-      endDate: report.endDate,
+      startDate,
+      endDate,
       interval: report.interval,
       categories,
       selectedCategories: report.selectedCategories ?? categories.list,
@@ -76,7 +91,7 @@ export function GetCardData({
       accounts,
       graphType: report.graphType,
     });
-  }, [report, categories, payees, accounts]);
+  }, [report, categories, payees, accounts, startDate, endDate]);
   const graphData = useReport('default' + report.name, getGraphData);
   const groupedData = useReport('grouped' + report.name, getGroupData);
 
@@ -86,8 +101,8 @@ export function GetCardData({
   return data?.data ? (
     <ErrorBoundary FallbackComponent={ErrorFallback}>
       <ChooseGraph
-        startDate={report.startDate}
-        endDate={report.endDate}
+        startDate={startDate}
+        endDate={endDate}
         data={data}
         mode={report.mode}
         graphType={report.graphType}
diff --git a/upcoming-release-notes/2557.md b/upcoming-release-notes/2557.md
new file mode 100644
index 000000000..5faddb6b1
--- /dev/null
+++ b/upcoming-release-notes/2557.md
@@ -0,0 +1,6 @@
+---
+category: Bugfix
+authors: [carkom]
+---
+
+Fixes live dateRange not updating with new month (interval).
-- 
GitLab