diff --git a/packages/desktop-client/src/components/reports/getLiveRange.ts b/packages/desktop-client/src/components/reports/getLiveRange.ts index 37aff3458f7edbc0b4810706ee9ddc4b34aa1863..a7030ebe680edbc7ca32708e6e02b0d71ec28143 100644 --- a/packages/desktop-client/src/components/reports/getLiveRange.ts +++ b/packages/desktop-client/src/components/reports/getLiveRange.ts @@ -1,4 +1,5 @@ import * as monthUtils from 'loot-core/src/shared/months'; +import { type LocalPrefs } from 'loot-core/types/prefs'; import { ReportOptions } from './ReportOptions'; import { getSpecificRange, validateRange } from './reportRanges'; @@ -6,7 +7,7 @@ import { getSpecificRange, validateRange } from './reportRanges'; export function getLiveRange( cond: string, earliestTransaction: string, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ) { let dateStart; let dateEnd; diff --git a/packages/desktop-client/src/components/reports/reportRanges.ts b/packages/desktop-client/src/components/reports/reportRanges.ts index 12a80d9d27655fc058c9ed327b1b820328d846b3..8c6326cabbec37a49ca990c690560b23c0091e96 100644 --- a/packages/desktop-client/src/components/reports/reportRanges.ts +++ b/packages/desktop-client/src/components/reports/reportRanges.ts @@ -1,11 +1,12 @@ import * as monthUtils from 'loot-core/src/shared/months'; +import { type LocalPrefs } from 'loot-core/types/prefs'; export function validateStart( earliest: string, start: string, end: string, interval?: string, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ) { let addDays; let dateStart; @@ -45,7 +46,7 @@ export function validateEnd( start: string, end: string, interval?: string, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ) { let subDays; let dateEnd; @@ -96,7 +97,7 @@ function boundedRange( start: string, end: string, interval?: string, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ) { let latest; switch (interval) { @@ -130,7 +131,7 @@ export function getSpecificRange( offset: number, addNumber: number | null, type?: string, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ) { const currentDay = monthUtils.currentDay(); diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx index d69f94675176a4713d1146015035e41001cecd1b..bdb9c74970ad855ce163ba3a97c8f88be5cc6741 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx @@ -38,7 +38,7 @@ import { fromDateRepr } from '../util'; export function CustomReport() { const categories = useCategories(); const [_firstDayOfWeekIdx] = useLocalPref('firstDayOfWeekIdx'); - const firstDayOfWeekIdx = _firstDayOfWeekIdx || 0; + const firstDayOfWeekIdx = _firstDayOfWeekIdx || '0'; const [viewLegend = false, setViewLegendPref] = useLocalPref('reportsViewLegend'); @@ -152,6 +152,7 @@ export function CustomReport() { const [dateStart, dateEnd] = getLiveRange( dateRange, trans ? trans.date : monthUtils.currentDay(), + firstDayOfWeekIdx, ); setStartDate(dateStart); setEndDate(dateEnd); diff --git a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx index 4ef5c08932bb0ea6d1b1f6ea796831e8f79e8c5d..e66632295785d3e727e54bd8d718ab593c388758 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx @@ -6,6 +6,7 @@ import { type CustomReportEntity } from 'loot-core/types/models/reports'; import { useAccounts } from '../../../hooks/useAccounts'; import { useCategories } from '../../../hooks/useCategories'; +import { useLocalPref } from '../../../hooks/useLocalPref'; import { usePayees } from '../../../hooks/usePayees'; import { styles } from '../../../style/index'; import { theme } from '../../../style/theme'; @@ -78,6 +79,8 @@ export function CustomReportListCards({ const payees = usePayees(); const accounts = useAccounts(); const categories = useCategories(); + const [_firstDayOfWeekIdx] = useLocalPref('firstDayOfWeekIdx'); + const firstDayOfWeekIdx = _firstDayOfWeekIdx || '0'; const [isCardHovered, setIsCardHovered] = useState(''); @@ -227,6 +230,7 @@ export function CustomReportListCards({ accounts={accounts} categories={categories} earliestTransaction={earliestTransaction} + firstDayOfWeekIdx={firstDayOfWeekIdx} /> </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 fe5f0c1b5f1720c65fe94c82e606414f988d843c..ad9e9e732fea161ff47560d7a0145e49a5c10c72 100644 --- a/packages/desktop-client/src/components/reports/reports/GetCardData.tsx +++ b/packages/desktop-client/src/components/reports/reports/GetCardData.tsx @@ -1,11 +1,13 @@ import React, { useMemo } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; +import * as monthUtils from 'loot-core/src/shared/months'; import { type AccountEntity } from 'loot-core/types/models/account'; import { type CategoryEntity } from 'loot-core/types/models/category'; import { type CategoryGroupEntity } from 'loot-core/types/models/category-group'; import { type PayeeEntity } from 'loot-core/types/models/payee'; import { type CustomReportEntity } from 'loot-core/types/models/reports'; +import { type LocalPrefs } from 'loot-core/types/prefs'; import { styles } from '../../../style/styles'; import { theme } from '../../../style/theme'; @@ -31,18 +33,46 @@ function ErrorFallback() { ); } +function convertFromDate( + interval: string | undefined, +): 'dayFromDate' | 'monthFromDate' | 'yearFromDate' { + switch (interval) { + case 'Monthly': + return 'monthFromDate'; + case 'Yearly': + return 'yearFromDate'; + default: + return 'dayFromDate'; + } +} + +function convertRangeInclusive( + interval: string | undefined, +): 'dayRangeInclusive' | 'rangeInclusive' | 'yearRangeInclusive' { + switch (interval) { + case 'Monthly': + return 'rangeInclusive'; + case 'Yearly': + return 'yearRangeInclusive'; + default: + return 'dayRangeInclusive'; + } +} + export function GetCardData({ report, payees, accounts, categories, earliestTransaction, + firstDayOfWeekIdx, }: { report: CustomReportEntity; payees: PayeeEntity[]; accounts: AccountEntity[]; categories: { list: CategoryEntity[]; grouped: CategoryGroupEntity[] }; earliestTransaction: string; + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx']; }) { let startDate = report.startDate; let endDate = report.endDate; @@ -51,11 +81,32 @@ export function GetCardData({ const [dateStart, dateEnd] = getLiveRange( report.dateRange, earliestTransaction, + firstDayOfWeekIdx, ); startDate = dateStart || report.startDate; endDate = dateEnd || report.startDate; } + const fromDate = convertFromDate(report.interval); + const rangeInclusive = convertRangeInclusive(report.interval); + + let intervalDateStart; + let intervalDateEnd; + let intervals; + if (report.interval === 'Weekly') { + intervalDateStart = monthUtils.weekFromDate(startDate, firstDayOfWeekIdx); + intervalDateEnd = monthUtils.weekFromDate(endDate, firstDayOfWeekIdx); + intervals = monthUtils.weekRangeInclusive( + intervalDateStart, + intervalDateEnd, + firstDayOfWeekIdx, + ); + } else { + intervalDateStart = monthUtils[fromDate](startDate); + intervalDateEnd = monthUtils[fromDate](endDate); + intervals = monthUtils[rangeInclusive](intervalDateStart, intervalDateEnd); + } + const getGroupData = useMemo(() => { return createGroupedSpreadsheet({ startDate, @@ -70,8 +121,9 @@ export function GetCardData({ showHiddenCategories: report.showHiddenCategories, showUncategorized: report.showUncategorized, balanceTypeOp: ReportOptions.balanceTypeMap.get(report.balanceType), + firstDayOfWeekIdx, }); - }, [report, categories, startDate, endDate]); + }, [report, categories, startDate, endDate, firstDayOfWeekIdx]); const getGraphData = useMemo(() => { return createCustomSpreadsheet({ startDate, @@ -90,8 +142,17 @@ export function GetCardData({ payees, accounts, graphType: report.graphType, + firstDayOfWeekIdx, }); - }, [report, categories, payees, accounts, startDate, endDate]); + }, [ + report, + categories, + payees, + accounts, + startDate, + endDate, + firstDayOfWeekIdx, + ]); const graphData = useReport('default' + report.name, getGraphData); const groupedData = useReport('grouped' + report.name, getGroupData); @@ -109,6 +170,7 @@ export function GetCardData({ interval={report.interval} compact={true} style={{ height: 'auto', flex: 1 }} + intervalsCount={intervals.length} /> </ErrorBoundary> ) : ( diff --git a/packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts b/packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts index d79175b2effb8dfd24839558335dfe9de8c7f311..1f4569ccca36189f4d02924a24c1a8f1d7580e36 100644 --- a/packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts +++ b/packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts @@ -17,6 +17,7 @@ import { type DataEntity, type GroupedEntity, } from 'loot-core/src/types/models/reports'; +import { type LocalPrefs } from 'loot-core/types/prefs'; import { categoryLists, @@ -47,7 +48,7 @@ export type createCustomSpreadsheetProps = { payees?: PayeeEntity[]; accounts?: AccountEntity[]; graphType?: string; - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6; + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx']; setDataCheck?: (value: boolean) => void; }; diff --git a/packages/loot-core/src/shared/months.ts b/packages/loot-core/src/shared/months.ts index f059bbf36cf4f24b596a36dcc3ff4bb2c016bd48..634324780a269bf3a7810f1f4296389a8599c72b 100644 --- a/packages/loot-core/src/shared/months.ts +++ b/packages/loot-core/src/shared/months.ts @@ -3,8 +3,10 @@ import * as d from 'date-fns'; import memoizeOne from 'memoize-one'; import * as Platform from '../client/platform'; +import { type LocalPrefs } from '../types/prefs'; type DateLike = string | Date; +type Day = 0 | 1 | 2 | 3 | 4 | 5 | 6; export function _parse(value: DateLike): Date { if (typeof value === 'string') { @@ -89,10 +91,11 @@ export function monthFromDate(date: DateLike): string { export function weekFromDate( date: DateLike, - firstDayOfWeekIdx: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx: LocalPrefs['firstDayOfWeekIdx'], ): string { + const converted = parseInt(firstDayOfWeekIdx || '0') as Day; return d.format( - _parse(d.startOfWeek(_parse(date), { weekStartsOn: firstDayOfWeekIdx })), + _parse(d.startOfWeek(_parse(date), { weekStartsOn: converted })), 'yyyy-MM-dd', ); } @@ -110,13 +113,14 @@ export function currentMonth(): string { } export function currentWeek( - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ): string { if (global.IS_TESTING || Platform.isPlaywright) { return global.currentWeek || '2017-01-01'; } else { + const converted = parseInt(firstDayOfWeekIdx || '0') as Day; return d.format( - _parse(d.startOfWeek(new Date(), { weekStartsOn: firstDayOfWeekIdx })), + _parse(d.startOfWeek(new Date(), { weekStartsOn: converted })), 'yyyy-MM-dd', ); } @@ -248,7 +252,7 @@ export function _weekRange( start: DateLike, end: DateLike, inclusive = false, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ): string[] { const weeks: string[] = []; let week = weekFromDate(start, firstDayOfWeekIdx); @@ -267,7 +271,7 @@ export function _weekRange( export function weekRangeInclusive( start: DateLike, end: DateLike, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ): string[] { return _weekRange(start, end, true, firstDayOfWeekIdx); } @@ -349,10 +353,11 @@ export function getMonthEnd(day: string): string { export function getWeekEnd( date: DateLike, - firstDayOfWeekIdx?: 0 | 1 | 2 | 3 | 4 | 5 | 6, + firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ): string { + const converted = parseInt(firstDayOfWeekIdx || '0') as Day; return d.format( - _parse(d.endOfWeek(_parse(date), { weekStartsOn: firstDayOfWeekIdx })), + _parse(d.endOfWeek(_parse(date), { weekStartsOn: converted })), 'yyyy-MM-dd', ); } diff --git a/upcoming-release-notes/2637.md b/upcoming-release-notes/2637.md new file mode 100644 index 0000000000000000000000000000000000000000..f8543fb8297db532e522b373b5f659d63a870677 --- /dev/null +++ b/upcoming-release-notes/2637.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [carkom] +--- + +Fixing typescript issues with firstDayOfWeek. Also fixes bug with TableGraph report card.