From b08756cc39f87d217ab48f6340f9d60a5a8cb36c Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Mon, 4 Nov 2024 17:56:14 +0000 Subject: [PATCH] :recycle: custom reports - moving to url identifiers (#3744) --- .../src/components/reports/ReportCard.tsx | 8 +- .../src/components/reports/ReportRouter.tsx | 1 + .../src/components/reports/ReportSidebar.tsx | 8 +- .../src/components/reports/ReportTopbar.tsx | 10 +- .../src/components/reports/SaveReport.tsx | 31 +++++-- .../reports/reports/CustomReport.tsx | 91 +++++++++++++------ .../reports/reports/CustomReportListCards.tsx | 3 +- .../src/client/data-hooks/reports.ts | 9 ++ upcoming-release-notes/3744.md | 6 ++ 9 files changed, 108 insertions(+), 59 deletions(-) create mode 100644 upcoming-release-notes/3744.md diff --git a/packages/desktop-client/src/components/reports/ReportCard.tsx b/packages/desktop-client/src/components/reports/ReportCard.tsx index 9954c11832..25be83ee0d 100644 --- a/packages/desktop-client/src/components/reports/ReportCard.tsx +++ b/packages/desktop-client/src/components/reports/ReportCard.tsx @@ -6,8 +6,6 @@ import React, { type CSSProperties, } from 'react'; -import { type CustomReportEntity } from 'loot-core/src/types/models'; - import { useIsInViewport } from '../../hooks/useIsInViewport'; import { useNavigate } from '../../hooks/useNavigate'; import { useResponsive } from '../../ResponsiveProvider'; @@ -23,7 +21,6 @@ type ReportCardProps = { isEditing?: boolean; to?: string; children: ReactNode; - report?: CustomReportEntity; menuItems?: ComponentProps['items']; onMenuSelect?: ComponentProps['onMenuSelect']; size?: number; @@ -33,7 +30,6 @@ type ReportCardProps = { export function ReportCard({ isEditing, to, - report, menuItems, onMenuSelect, children, @@ -99,9 +95,7 @@ export function ReportCard({ navigate(to, { state: { report } }) - } + onClick={isEditing ? undefined : () => navigate(to)} style={{ height: '100%', width: '100%', diff --git a/packages/desktop-client/src/components/reports/ReportRouter.tsx b/packages/desktop-client/src/components/reports/ReportRouter.tsx index 71719624fa..28a3f45e21 100644 --- a/packages/desktop-client/src/components/reports/ReportRouter.tsx +++ b/packages/desktop-client/src/components/reports/ReportRouter.tsx @@ -16,6 +16,7 @@ export function ReportRouter() { } /> } /> } /> + } /> } /> } /> diff --git a/packages/desktop-client/src/components/reports/ReportSidebar.tsx b/packages/desktop-client/src/components/reports/ReportSidebar.tsx index 011739c5a3..1d3706ac60 100644 --- a/packages/desktop-client/src/components/reports/ReportSidebar.tsx +++ b/packages/desktop-client/src/components/reports/ReportSidebar.tsx @@ -51,13 +51,7 @@ type ReportSidebarProps = { dateEnd: string, mode: TimeFrame['mode'], ) => void; - onReportChange: ({ - savedReport, - type, - }: { - savedReport?: CustomReportEntity; - type: string; - }) => void; + onReportChange: ({ type }: { type: 'modify' }) => void; disabledItems: (type: string) => string[]; defaultItems: (item: string) => void; defaultModeItems: (graph: string, item: string) => void; diff --git a/packages/desktop-client/src/components/reports/ReportTopbar.tsx b/packages/desktop-client/src/components/reports/ReportTopbar.tsx index b218f2b370..74e1847951 100644 --- a/packages/desktop-client/src/components/reports/ReportTopbar.tsx +++ b/packages/desktop-client/src/components/reports/ReportTopbar.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { type ComponentProps } from 'react'; import { type CustomReportEntity } from 'loot-core/types/models/reports'; import { type RuleConditionEntity } from 'loot-core/types/models/rule'; @@ -32,13 +32,7 @@ type ReportTopbarProps = { viewLabels: boolean; onApplyFilter: (newFilter: RuleConditionEntity) => void; onChangeViews: (viewType: string) => void; - onReportChange: ({ - savedReport, - type, - }: { - savedReport?: CustomReportEntity; - type: string; - }) => void; + onReportChange: ComponentProps['onReportChange']; isItemDisabled: (type: string) => boolean; defaultItems: (item: string) => void; }; diff --git a/packages/desktop-client/src/components/reports/SaveReport.tsx b/packages/desktop-client/src/components/reports/SaveReport.tsx index 5c0a454dd1..a486dd273a 100644 --- a/packages/desktop-client/src/components/reports/SaveReport.tsx +++ b/packages/desktop-client/src/components/reports/SaveReport.tsx @@ -19,13 +19,30 @@ type SaveReportProps = { customReportItems: T; report: CustomReportEntity; savedStatus: string; - onReportChange: ({ - savedReport, - type, - }: { - savedReport?: T; - type: string; - }) => void; + onReportChange: ( + params: + | { + type: 'add-update'; + savedReport: CustomReportEntity; + } + | { + type: 'rename'; + savedReport?: CustomReportEntity; + } + | { + type: 'modify'; + } + | { + type: 'reload'; + } + | { + type: 'reset'; + } + | { + type: 'choose'; + savedReport?: CustomReportEntity; + }, + ) => void; }; export function SaveReport({ diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx index 8a31f03806..76d49d7fee 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx @@ -1,9 +1,10 @@ import React, { useState, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation } from 'react-router-dom'; +import { useLocation, useParams } from 'react-router-dom'; import * as d from 'date-fns'; +import { useReport as useCustomReport } from 'loot-core/src/client/data-hooks/reports'; import { calculateHasWarning } from 'loot-core/src/client/reports'; import { send } from 'loot-core/src/platform/client/fetch'; import * as monthUtils from 'loot-core/src/shared/months'; @@ -103,6 +104,21 @@ function useSelectedCategories( } export function CustomReport() { + const params = useParams(); + const { data: report, isLoading } = useCustomReport(params.id ?? ''); + + if (isLoading) { + return ; + } + + return ; +} + +type CustomReportInnerProps = { + report?: CustomReportEntity; +}; + +function CustomReportInner({ report: initialReport }: CustomReportInnerProps) { const { t } = useTranslation(); const categories = useCategories(); const { isNarrowWidth } = useResponsive(); @@ -138,9 +154,7 @@ export function CustomReport() { const session = reportFromSessionStorage ? JSON.parse(reportFromSessionStorage) : {}; - const combine = location.state - ? (location.state.report ?? defaultReport) - : defaultReport; + const combine = initialReport ?? defaultReport; const loadReport = { ...combine, ...session }; const [allIntervals, setAllIntervals] = useState< @@ -243,17 +257,13 @@ export function CustomReport() { const [earliestTransaction, setEarliestTransaction] = useState(''); const [report, setReport] = useState(loadReport); const [savedStatus, setSavedStatus] = useState( - location.state - ? location.state.report - ? 'saved' - : (loadReport.savedStatus ?? 'new') - : (loadReport.savedStatus ?? 'new'), + session.savedStatus ?? (initialReport ? 'saved' : 'new'), ); useEffect(() => { async function run() { onApplyFilter(null); - report.conditions.forEach((condition: RuleConditionEntity) => + report.conditions?.forEach((condition: RuleConditionEntity) => onApplyFilter(condition), ); const trans = await send('get-earliest-transaction'); @@ -473,11 +483,10 @@ export function CustomReport() { const defaultModeItems = (graph: string, item: string) => { const chooseGraph = graph || graphType; - const newGraph = (disabledList.modeGraphsMap.get(item) || []).includes( - chooseGraph, - ) - ? defaultsList.modeGraphsMap.get(item) - : chooseGraph; + const newGraph = + ((disabledList.modeGraphsMap.get(item) || []).includes(chooseGraph) + ? defaultsList.modeGraphsMap.get(item) + : chooseGraph) ?? chooseGraph; if ((disabledList.modeGraphsMap.get(item) || []).includes(graphType)) { setSessionReport('graphType', newGraph); setGraphType(newGraph); @@ -594,21 +603,43 @@ export function CustomReport() { onConditionsOpChange(input.conditionsOp); }; - const onReportChange = ({ - savedReport, - type, - }: { - savedReport?: CustomReportEntity; - type: string; - }) => { - switch (type) { + const onReportChange = ( + params: + | { + type: 'add-update'; + savedReport: CustomReportEntity; + } + | { + type: 'rename'; + savedReport?: CustomReportEntity; + } + | { + type: 'modify'; + } + | { + type: 'reload'; + } + | { + type: 'reset'; + } + | { + type: 'choose'; + savedReport?: CustomReportEntity; + }, + ) => { + switch (params.type) { case 'add-update': + sessionStorage.clear(); setSessionReport('savedStatus', 'saved'); setSavedStatus('saved'); - setReport(savedReport); + setReport(params.savedReport); + + if (params.savedReport.id !== initialReport?.id) { + navigate(`/reports/custom/${params.savedReport.id}`); + } break; case 'rename': - setReport({ ...report, name: savedReport?.name || '' }); + setReport({ ...report, name: params.savedReport?.name || '' }); break; case 'modify': if (report.name) { @@ -617,9 +648,10 @@ export function CustomReport() { } break; case 'reload': + sessionStorage.clear(); setSessionReport('savedStatus', 'saved'); setSavedStatus('saved'); - setReportData(report); + setReportData(initialReport ?? defaultReport); break; case 'reset': sessionStorage.clear(); @@ -628,10 +660,13 @@ export function CustomReport() { setReportData(defaultReport); break; case 'choose': + sessionStorage.clear(); + const newReport = params.savedReport || report; setSessionReport('savedStatus', 'saved'); setSavedStatus('saved'); - setReport(savedReport); - setReportData(savedReport || report); + setReport(newReport); + setReportData(newReport); + navigate(`/reports/custom/${newReport.id}`); break; default: } diff --git a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx index a96c99415e..ee6c3b7240 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx @@ -119,8 +119,7 @@ function CustomReportListCardsInner({ return ( report.id === id), + isLoading, + }; +} diff --git a/upcoming-release-notes/3744.md b/upcoming-release-notes/3744.md new file mode 100644 index 0000000000..d1a4081d4c --- /dev/null +++ b/upcoming-release-notes/3744.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Custom reports: moving from session storage and local state for inner report pages to using unique URL identifiers for each custom report page.