@mx-cartographer/experiences 9.4.38 → 9.4.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/common/components/ListItemRow.d.ts +1 -1
- package/dist/common/components/ListItemRow.es.js.map +1 -1
- package/dist/core/stores/TrendsStore.d.ts +2 -0
- package/dist/core/stores/TrendsStore.es.js +24 -15
- package/dist/core/stores/TrendsStore.es.js.map +1 -1
- package/dist/trends/TrendsWidget.es.js +131 -128
- package/dist/trends/TrendsWidget.es.js.map +1 -1
- package/dist/trends/components/CategoriesListItem.es.js +34 -29
- package/dist/trends/components/CategoriesListItem.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## [9.4.39] - 09-23-2026
|
|
2
|
+
|
|
3
|
+
- **FIXED** - Trends category rows no longer show a nonzero total with "0 transactions" and no chevron. (MEW-4021)
|
|
4
|
+
|
|
1
5
|
## [9.4.38] - 09-22-2026
|
|
2
6
|
|
|
3
7
|
- **FIXED** - `LineChart` x-axis now shows every tick label instead of dropping overlapping ones, so month labels no longer disappear on small views. On the Trends 1 Year (12-month) view on small screens, labels render as single letters so all twelve fit; the full month is preserved as the accessible name so screen readers and tooltips are unchanged (MEW-4096)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListItemRow.es.js","names":[],"sources":["../../../src/common/components/ListItemRow.tsx"],"sourcesContent":["import React from 'react'\n\nimport ListItem from '@mui/material/ListItem'\nimport ListItemButton from '@mui/material/ListItemButton'\nimport ListItemIcon from '@mui/material/ListItemIcon'\nimport ListItemText from '@mui/material/ListItemText'\nimport Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\n\ninterface ListItemRowProps {\n onClick?: () => void\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n title?: string\n subtitle?:
|
|
1
|
+
{"version":3,"file":"ListItemRow.es.js","names":[],"sources":["../../../src/common/components/ListItemRow.tsx"],"sourcesContent":["import React from 'react'\n\nimport ListItem from '@mui/material/ListItem'\nimport ListItemButton from '@mui/material/ListItemButton'\nimport ListItemIcon from '@mui/material/ListItemIcon'\nimport ListItemText from '@mui/material/ListItemText'\nimport Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\n\ninterface ListItemRowProps {\n onClick?: () => void\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n title?: string\n subtitle?: React.ReactNode\n rightContent?: React.ReactNode\n titleBold?: boolean\n rightContentBold?: boolean\n}\n\nexport const ListItemRow: React.FC<ListItemRowProps> = ({\n onClick,\n leftIcon,\n rightIcon,\n title,\n subtitle,\n rightContent,\n titleBold = true,\n rightContentBold = true,\n}) => {\n const content = (\n <React.Fragment>\n {leftIcon && <ListItemIcon sx={{ ml: 0 }}>{leftIcon}</ListItemIcon>}\n <ListItemText>\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n marginLeft: 12,\n }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Text bold={titleBold} variant=\"body1\">\n {title}\n </Text>\n {subtitle && <Text variant=\"caption\">{subtitle}</Text>}\n </Stack>\n <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}>\n {rightContent && (\n <Text bold={rightContentBold} display=\"flex\" variant=\"body1\">\n {rightContent}\n </Text>\n )}\n {rightIcon && <ListItemIcon>{rightIcon}</ListItemIcon>}\n </Stack>\n </Stack>\n </ListItemText>\n </React.Fragment>\n )\n\n return (\n <ListItem>\n {onClick ? (\n <ListItemButton\n onClick={onClick}\n sx={{\n py: 14,\n }}\n >\n {content}\n </ListItemButton>\n ) : (\n <Stack\n sx={{\n py: 14,\n px: 24,\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n }}\n >\n {content}\n </Stack>\n )}\n </ListItem>\n )\n}\n"],"mappings":";;;;;;;;AAqBA,IAAa,IAAA,CAA2C,EACtD,SAAA,GACA,UAAA,GACA,WAAA,GACA,OAAA,GACA,UAAA,GACA,cAAA,GACA,WAAA,IAAY,IACZ,kBAAA,IAAmB,GAAA,MACf;AACJ,QAAM,IACJ,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACG,KAAY,gBAAA,EAAC,GAAD;AAAA,IAAc,IAAI,EAAE,IAAI,EAAE;AAAA,IAAI,UAAA;AAAA,EAAuB,CAAA,GAClE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IALF,UAAA,CAOE,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,MAAM;AAAA,QAAG,UAAU;AAAA,MAAE;AAAA,MAAlC,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAW,SAAQ;AAAA,QAC5B,UAAA;AAAA,MACG,CAAA,GACL,KAAY,gBAAA,EAAC,GAAD;AAAA,QAAM,SAAQ;AAAA,QAAW,UAAA;AAAA,MAAe,CAAA,CAChD;AAAA,IACP,CAAA,GAAA,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,eAAe;AAAA,QAAO,YAAY;AAAA,QAAU,KAAK;AAAA,MAAE;AAAA,MAAhE,UAAA,CACG,KACC,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAkB,SAAQ;AAAA,QAAO,SAAQ;AAAA,QAClD,UAAA;AAAA,MACG,CAAA,GAEP,KAAa,gBAAA,EAAC,GAAD,EAAA,UAAe,EAAwB,CAAA,CAChD;AAAA,IACF,CAAA,CAAA;AAAA,EACK,CAAA,EAAA,CAAA,CACA,EAAA,CAAA;AAGlB,SACE,gBAAA,EAAC,GAAD,EAAA,UACG,IACC,gBAAA,EAAC,GAAD;AAAA,IACW,SAAA;AAAA,IACT,IAAI,EACF,IAAI,GACN;AAAA,IAEC,UAAA;AAAA,EACa,CAAA,IAEhB,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IAEC,UAAA;AAAA,EACI,CAAA,EAED,CAAA;AAEd"}
|
|
@@ -10,6 +10,8 @@ export declare class TrendsStore {
|
|
|
10
10
|
setSelectedDateRange: (dateRange: DateRange) => void;
|
|
11
11
|
setVisibleListLength: (length: number) => void;
|
|
12
12
|
get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[];
|
|
13
|
+
get isTransactionStoreIdle(): boolean;
|
|
14
|
+
get isSelectedRangeLoaded(): boolean;
|
|
13
15
|
get selectedDateRangeMonthCount(): number;
|
|
14
16
|
get selectedDateRangeMonthRange(): string;
|
|
15
17
|
get visibleCategories(): DetailedCategoryWithTransactions[];
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { DATE_FORMATS_INTL as
|
|
2
|
-
import { buildCategoryDetailsChartData as i, filterAndSortCategoriesWithTransactions as
|
|
3
|
-
import { endOfMonth as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
1
|
+
import { DATE_FORMATS_INTL as a, formatDate as s } from "../constants/DateFormats.es.js";
|
|
2
|
+
import { buildCategoryDetailsChartData as i, filterAndSortCategoriesWithTransactions as o } from "../utils/TrendsUtil.es.js";
|
|
3
|
+
import { endOfMonth as r } from "date-fns/endOfMonth";
|
|
4
|
+
import { isBefore as n } from "date-fns/isBefore";
|
|
5
|
+
import { subMonths as l } from "date-fns/subMonths";
|
|
6
|
+
import { differenceInCalendarMonths as d } from "date-fns/differenceInCalendarMonths";
|
|
7
|
+
import { makeAutoObservable as g } from "mobx";
|
|
8
|
+
import { addSeconds as c } from "date-fns/addSeconds";
|
|
9
|
+
var R = class {
|
|
9
10
|
globalStore;
|
|
10
11
|
selectedCategoryData = null;
|
|
11
12
|
selectedDateRange;
|
|
12
13
|
visibleListLength = 5;
|
|
13
14
|
constructor(e) {
|
|
14
15
|
this.globalStore = e, this.selectedDateRange = {
|
|
15
|
-
start:
|
|
16
|
-
end:
|
|
17
|
-
},
|
|
16
|
+
start: c(r(l(/* @__PURE__ */ new Date(), 6)), 1),
|
|
17
|
+
end: r(/* @__PURE__ */ new Date())
|
|
18
|
+
}, g(this);
|
|
18
19
|
}
|
|
19
20
|
setSelectedCategoryData = (e) => {
|
|
20
21
|
this.selectedCategoryData = e;
|
|
@@ -26,13 +27,21 @@ var u = class {
|
|
|
26
27
|
this.visibleListLength = e;
|
|
27
28
|
};
|
|
28
29
|
get sortedDetailedCategoriesWithTransactions() {
|
|
29
|
-
return
|
|
30
|
+
return o(this.globalStore.categoryStore.detailedCategoriesWithTransactions);
|
|
31
|
+
}
|
|
32
|
+
get isTransactionStoreIdle() {
|
|
33
|
+
const { isTransactionDataLoaded: e, transactionsLoading: t } = this.globalStore.transactionStore;
|
|
34
|
+
return e && !t;
|
|
35
|
+
}
|
|
36
|
+
get isSelectedRangeLoaded() {
|
|
37
|
+
const { isTransactionDataLoaded: e, cachedStartDate: t } = this.globalStore.transactionStore;
|
|
38
|
+
return e && !n(this.selectedDateRange.start, t);
|
|
30
39
|
}
|
|
31
40
|
get selectedDateRangeMonthCount() {
|
|
32
|
-
return
|
|
41
|
+
return d(this.selectedDateRange.end, this.selectedDateRange.start) + 1;
|
|
33
42
|
}
|
|
34
43
|
get selectedDateRangeMonthRange() {
|
|
35
|
-
return `${
|
|
44
|
+
return `${s(this.selectedDateRange.start, a.MONTH_LONG)} - ${s(this.selectedDateRange.end, a.MONTH_LONG)}`;
|
|
36
45
|
}
|
|
37
46
|
get visibleCategories() {
|
|
38
47
|
return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength);
|
|
@@ -45,7 +54,7 @@ var u = class {
|
|
|
45
54
|
}
|
|
46
55
|
};
|
|
47
56
|
export {
|
|
48
|
-
|
|
57
|
+
R as TrendsStore
|
|
49
58
|
};
|
|
50
59
|
|
|
51
60
|
//# sourceMappingURL=TrendsStore.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrendsStore.es.js","names":[],"sources":["../../../src/core/stores/TrendsStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { subMonths } from 'date-fns/subMonths'\n\nimport type { DateRange, DetailedCategoryWithTransactions } from '../types'\nimport { DATE_FORMATS_INTL, formatDate } from '../constants'\nimport {\n buildCategoryDetailsChartData,\n filterAndSortCategoriesWithTransactions,\n} from '../utils/TrendsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class TrendsStore {\n globalStore: GlobalStore\n selectedCategoryData: DetailedCategoryWithTransactions | null = null\n selectedDateRange: DateRange\n visibleListLength: number = 5\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.selectedDateRange = {\n start: addSeconds(endOfMonth(subMonths(new Date(), 6)), 1),\n end: endOfMonth(new Date()),\n }\n makeAutoObservable(this)\n }\n\n setSelectedCategoryData = (data: DetailedCategoryWithTransactions | null) => {\n this.selectedCategoryData = data\n }\n\n setSelectedDateRange = (dateRange: DateRange) => {\n this.selectedDateRange = dateRange\n }\n\n setVisibleListLength = (length: number) => {\n this.visibleListLength = length\n }\n\n get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return filterAndSortCategoriesWithTransactions(\n this.globalStore.categoryStore.detailedCategoriesWithTransactions,\n )\n }\n\n get selectedDateRangeMonthCount(): number {\n return differenceInCalendarMonths(this.selectedDateRange.end, this.selectedDateRange.start) + 1\n }\n\n get selectedDateRangeMonthRange(): string {\n const startMonth = formatDate(this.selectedDateRange.start, DATE_FORMATS_INTL.MONTH_LONG)\n const endMonth = formatDate(this.selectedDateRange.end, DATE_FORMATS_INTL.MONTH_LONG)\n return `${startMonth} - ${endMonth}`\n }\n\n get visibleCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength)\n }\n\n get collapsedCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(this.visibleListLength)\n }\n\n get categoryDetailsChartData() {\n return buildCategoryDetailsChartData(\n this.selectedCategoryData,\n this.selectedDateRangeMonthCount,\n )\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"TrendsStore.es.js","names":[],"sources":["../../../src/core/stores/TrendsStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { isBefore } from 'date-fns/isBefore'\nimport { subMonths } from 'date-fns/subMonths'\n\nimport type { DateRange, DetailedCategoryWithTransactions } from '../types'\nimport { DATE_FORMATS_INTL, formatDate } from '../constants'\nimport {\n buildCategoryDetailsChartData,\n filterAndSortCategoriesWithTransactions,\n} from '../utils/TrendsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class TrendsStore {\n globalStore: GlobalStore\n selectedCategoryData: DetailedCategoryWithTransactions | null = null\n selectedDateRange: DateRange\n visibleListLength: number = 5\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.selectedDateRange = {\n start: addSeconds(endOfMonth(subMonths(new Date(), 6)), 1),\n end: endOfMonth(new Date()),\n }\n makeAutoObservable(this)\n }\n\n setSelectedCategoryData = (data: DetailedCategoryWithTransactions | null) => {\n this.selectedCategoryData = data\n }\n\n setSelectedDateRange = (dateRange: DateRange) => {\n this.selectedDateRange = dateRange\n }\n\n setVisibleListLength = (length: number) => {\n this.visibleListLength = length\n }\n\n get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return filterAndSortCategoriesWithTransactions(\n this.globalStore.categoryStore.detailedCategoriesWithTransactions,\n )\n }\n\n get isTransactionStoreIdle(): boolean {\n const { isTransactionDataLoaded, transactionsLoading } = this.globalStore.transactionStore\n return isTransactionDataLoaded && !transactionsLoading\n }\n\n get isSelectedRangeLoaded(): boolean {\n const { isTransactionDataLoaded, cachedStartDate } = this.globalStore.transactionStore\n return isTransactionDataLoaded && !isBefore(this.selectedDateRange.start, cachedStartDate)\n }\n\n get selectedDateRangeMonthCount(): number {\n return differenceInCalendarMonths(this.selectedDateRange.end, this.selectedDateRange.start) + 1\n }\n\n get selectedDateRangeMonthRange(): string {\n const startMonth = formatDate(this.selectedDateRange.start, DATE_FORMATS_INTL.MONTH_LONG)\n const endMonth = formatDate(this.selectedDateRange.end, DATE_FORMATS_INTL.MONTH_LONG)\n return `${startMonth} - ${endMonth}`\n }\n\n get visibleCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength)\n }\n\n get collapsedCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(this.visibleListLength)\n }\n\n get categoryDetailsChartData() {\n return buildCategoryDetailsChartData(\n this.selectedCategoryData,\n this.selectedDateRangeMonthCount,\n )\n }\n}\n"],"mappings":";;;;;;;;AAgBA,IAAa,IAAb,MAAyB;AAAA,EACvB;AAAA,EACA,uBAAgE;AAAA,EAChE;AAAA,EACA,oBAA4B;AAAA,EAE5B,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,oBAAoB;AAAA,MACvB,OAAO,EAAW,EAAW,EAAU,oBAAI,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;AAAA,MACzD,KAAK,EAAW,oBAAI,KAAK,CAAC;AAAA,IAC5B,GACA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,0BAAA,CAA2B,MAAkD;AAC3E,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEA,uBAAA,CAAwB,MAAyB;AAC/C,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,uBAAA,CAAwB,MAAmB;AACzC,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,IAAI,2CAA+E;AACjF,WAAO,EACL,KAAK,YAAY,cAAc,kCACjC;AAAA,EACF;AAAA,EAEA,IAAI,yBAAkC;AACpC,UAAM,EAAE,yBAAA,GAAyB,qBAAA,EAAA,IAAwB,KAAK,YAAY;AAC1E,WAAO,KAA2B,CAAC;AAAA,EACrC;AAAA,EAEA,IAAI,wBAAiC;AACnC,UAAM,EAAE,yBAAA,GAAyB,iBAAA,EAAA,IAAoB,KAAK,YAAY;AACtE,WAAO,KAA2B,CAAC,EAAS,KAAK,kBAAkB,OAAO,CAAe;AAAA,EAC3F;AAAA,EAEA,IAAI,8BAAsC;AACxC,WAAO,EAA2B,KAAK,kBAAkB,KAAK,KAAK,kBAAkB,KAAK,IAAI;AAAA,EAChG;AAAA,EAEA,IAAI,8BAAsC;AAGxC,WAAO,GAFY,EAAW,KAAK,kBAAkB,OAAO,EAAkB,UAEpE,CAAA,MADO,EAAW,KAAK,kBAAkB,KAAK,EAAkB,UAChD,CAAA;AAAA,EAC5B;AAAA,EAEA,IAAI,oBAAwD;AAC1D,WAAO,KAAK,yCAAyC,MAAM,GAAG,KAAK,iBAAiB;AAAA,EACtF;AAAA,EAEA,IAAI,sBAA0D;AAC5D,WAAO,KAAK,yCAAyC,MAAM,KAAK,iBAAiB;AAAA,EACnF;AAAA,EAEA,IAAI,2BAA2B;AAC7B,WAAO,EACL,KAAK,sBACL,KAAK,2BACP;AAAA,EACF;AACF"}
|
|
@@ -1,133 +1,136 @@
|
|
|
1
|
-
import { useAccountStore as
|
|
2
|
-
import { useInsightsEnabled as
|
|
3
|
-
import { useScreenSize as
|
|
4
|
-
import { useWidgetLoadTimer as
|
|
5
|
-
import
|
|
6
|
-
import { ANALYTICS_EVENTS as
|
|
7
|
-
import
|
|
8
|
-
import { WidgetContainer as
|
|
9
|
-
import
|
|
10
|
-
import { EmptyState as
|
|
11
|
-
import { TRENDS_ANALYTICS_METADATA as
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import { CategoryDetails as
|
|
18
|
-
import
|
|
19
|
-
import { TRENDS_BEAT_TEMPLATES as
|
|
20
|
-
import { buildEmptyStateProps as
|
|
21
|
-
import
|
|
22
|
-
import { observer as
|
|
1
|
+
import { useAccountStore as Ee, useAppConfig as ye, useCategoryStore as we, useEvent as De, useGlobalCopyStore as Le, useGlobalStore as be, useGlobalUiStore as Ie, useTransactionStore as Ae, useTrendsStore as Re } from "../common/context/hooks.es.js";
|
|
2
|
+
import { useInsightsEnabled as ve } from "../common/hooks/useInsightsEnabled.es.js";
|
|
3
|
+
import { useScreenSize as xe } from "../common/hooks/useScreenSize.es.js";
|
|
4
|
+
import { useWidgetLoadTimer as Ne } from "../common/hooks/useWidgetLoadTimer.es.js";
|
|
5
|
+
import Be from "../common/components/drawer/Drawer.es.js";
|
|
6
|
+
import { ANALYTICS_EVENTS as c } from "../common/constants/Analytics.es.js";
|
|
7
|
+
import We from "../common/components/Loader.es.js";
|
|
8
|
+
import { WidgetContainer as ke } from "../common/components/WidgetContainer.es.js";
|
|
9
|
+
import He from "../common/components/ConnectDrawer.es.js";
|
|
10
|
+
import { EmptyState as Ge } from "../common/components/EmptyState.es.js";
|
|
11
|
+
import { TRENDS_ANALYTICS_METADATA as m } from "./constants/TrendsWidget.es.js";
|
|
12
|
+
import Fe from "./components/TrendsViewToggle.es.js";
|
|
13
|
+
import Me from "./components/DateRangeText.es.js";
|
|
14
|
+
import Oe from "./components/TrendsTableContainer.es.js";
|
|
15
|
+
import Ve from "./components/CategoriesList.es.js";
|
|
16
|
+
import ze from "./components/TrendsInsights.es.js";
|
|
17
|
+
import { CategoryDetails as Ke } from "./components/CategoryDetails.es.js";
|
|
18
|
+
import je from "./components/TrendsChartTotals.es.js";
|
|
19
|
+
import { TRENDS_BEAT_TEMPLATES as Pe } from "./constants/TrendsInsights.es.js";
|
|
20
|
+
import { buildEmptyStateProps as Ue } from "./utils/TrendsWidget.es.js";
|
|
21
|
+
import o from "react";
|
|
22
|
+
import { observer as Ye } from "mobx-react-lite";
|
|
23
23
|
import f from "@mui/material/Stack";
|
|
24
|
-
import
|
|
25
|
-
import { ArrowBack as
|
|
26
|
-
import { Fragment as
|
|
24
|
+
import $e from "@mui/material/Button";
|
|
25
|
+
import { ArrowBack as qe } from "@mxenabled/mx-icons";
|
|
26
|
+
import { Fragment as Je, jsx as t, jsxs as l } from "react/jsx-runtime";
|
|
27
27
|
import w from "@mui/material/Box";
|
|
28
|
-
import { differenceInCalendarMonths as
|
|
29
|
-
import { addSeconds as
|
|
30
|
-
var
|
|
31
|
-
const { onEvent: s } =
|
|
28
|
+
import { differenceInCalendarMonths as F } from "date-fns/differenceInCalendarMonths";
|
|
29
|
+
import { addSeconds as Qe } from "date-fns/addSeconds";
|
|
30
|
+
var Xe = ({ onBackClick: M, onMenuClick: O, onInsightCardClick: V, sx: z }) => {
|
|
31
|
+
const { onEvent: s } = De(), { config: D } = ye(), { isDesktop: K, isLargeDesktop: j, isMobile: C } = xe(), { isAccountDataLoaded: u, loadAccountData: P, visibleAccounts: U } = Ee(), { categoriesLoaded: Y, loadCategories: $, monthlyCategoryTotals: a, monthlyTotalsLoaded: q, reloadCategoryTotals: J } = we(), { isTransactionDataLoaded: Q, loadTransactionData: X, setFilter: Z } = Ae(), { isTransactionStoreIdle: L, selectedCategoryData: T, selectedDateRange: n, setSelectedCategoryData: b, setSelectedDateRange: ee } = Re(), { isInitialized: _, selectedAccounts: te, selectedAccountGuids: I } = Ie(), { trends: d, connect: oe } = Le(), { beatStore: A } = be(), R = ve() && D.show_insights_widget_in_master, g = K || j, [v, ne] = o.useState(!1), [S, ie] = o.useState(!1), [h, re] = o.useState("Chart"), [E, x] = o.useState(""), [N, se] = o.useState(window.innerHeight), ae = g ? 56 : 0, B = N - 208, ce = N - (R ? 550 + ae : 266), [le, W] = o.useState(!1), de = D.show_connections_widget_in_master, y = o.useRef(void 0), me = o.useCallback((e) => {
|
|
32
32
|
if (y.current?.(), y.current = void 0, !e) return;
|
|
33
|
-
const
|
|
33
|
+
const i = (r) => {
|
|
34
34
|
r.target instanceof HTMLElement && r.target.matches(":focus-visible") && r.target.scrollIntoView({ block: "nearest" });
|
|
35
35
|
};
|
|
36
|
-
e.addEventListener("focusin",
|
|
36
|
+
e.addEventListener("focusin", i), y.current = () => e.removeEventListener("focusin", i);
|
|
37
37
|
}, []);
|
|
38
|
-
|
|
38
|
+
Ne({
|
|
39
39
|
widgetName: "TrendsWidget",
|
|
40
|
-
isLoaded:
|
|
40
|
+
isLoaded: v
|
|
41
41
|
});
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const e = () =>
|
|
45
|
-
return window.addEventListener("resize", e), u ||
|
|
46
|
-
}, []),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
...
|
|
50
|
-
time_period: `${
|
|
42
|
+
const k = o.useMemo(() => S ? A.getFilteredBeats({ templates: Pe }) : [], [S]);
|
|
43
|
+
o.useEffect(() => {
|
|
44
|
+
const e = () => se(window.innerHeight);
|
|
45
|
+
return window.addEventListener("resize", e), u || P().finally(), Y || $().finally(), Q || X().finally(), () => window.removeEventListener("resize", e);
|
|
46
|
+
}, []), o.useEffect(() => {
|
|
47
|
+
_ && u && (A.loadBeats().finally(() => ie(!0)), J(te, n.start, n.end).finally(() => {
|
|
48
|
+
ne(!0), s(c.TRENDS_LOAD_WIDGET, {
|
|
49
|
+
...m,
|
|
50
|
+
time_period: `${F(n.end, n.start)}M`
|
|
51
51
|
});
|
|
52
52
|
}));
|
|
53
53
|
}, [
|
|
54
|
-
|
|
54
|
+
_,
|
|
55
55
|
u,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
])
|
|
60
|
-
|
|
56
|
+
I.join(","),
|
|
57
|
+
n.start.getTime(),
|
|
58
|
+
n.end.getTime()
|
|
59
|
+
]);
|
|
60
|
+
const H = o.useRef(null);
|
|
61
|
+
o.useEffect(() => {
|
|
62
|
+
if (a.length !== 0 && L && H.current !== a) {
|
|
63
|
+
H.current = a;
|
|
61
64
|
const e = {
|
|
62
|
-
accounts:
|
|
65
|
+
accounts: I,
|
|
63
66
|
dateRange: {
|
|
64
|
-
start:
|
|
65
|
-
end:
|
|
67
|
+
start: n.start,
|
|
68
|
+
end: n.end
|
|
66
69
|
}
|
|
67
70
|
};
|
|
68
|
-
|
|
71
|
+
Z({
|
|
69
72
|
...e,
|
|
70
|
-
custom: (
|
|
73
|
+
custom: (i) => !!a.find((r) => r.top_level_category_guid === i.top_level_category_guid || r.category_guid === i.category_guid)
|
|
71
74
|
});
|
|
72
75
|
}
|
|
73
|
-
}, [
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
...
|
|
83
|
-
toggleView:
|
|
76
|
+
}, [a, L]);
|
|
77
|
+
const ge = (e) => {
|
|
78
|
+
b(e);
|
|
79
|
+
}, fe = () => {
|
|
80
|
+
b(null), s(c.TRENDS_CLICK_BACK, m);
|
|
81
|
+
}, ue = () => {
|
|
82
|
+
W(!0), s(c.TRENDS_CLICK_CONNECT_ACCOUNTS);
|
|
83
|
+
}, he = (e, i) => {
|
|
84
|
+
re(i ?? h), s(c.TRENDS_CLICK_TOGGLE_VIEW, {
|
|
85
|
+
...m,
|
|
86
|
+
toggleView: i
|
|
84
87
|
});
|
|
85
|
-
},
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
start:
|
|
88
|
+
}, pe = (e) => {
|
|
89
|
+
const i = Qe(e?.[0], 1), r = e?.[1], Se = F(r, i);
|
|
90
|
+
ee({
|
|
91
|
+
start: i,
|
|
89
92
|
end: r
|
|
90
|
-
}), s(
|
|
91
|
-
...
|
|
92
|
-
time_period:
|
|
93
|
+
}), s(c.TRENDS_CLICK_TIME_WINDOW, {
|
|
94
|
+
...m,
|
|
95
|
+
time_period: Se + "M"
|
|
93
96
|
});
|
|
94
|
-
},
|
|
95
|
-
s(
|
|
96
|
-
...
|
|
97
|
+
}, Ce = (e) => {
|
|
98
|
+
s(c.TRENDS_CLICK_FILTER, {
|
|
99
|
+
...m,
|
|
97
100
|
filterValue: e
|
|
98
101
|
});
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
|
|
102
|
+
}, Te = (e) => {
|
|
103
|
+
x(e);
|
|
104
|
+
}, _e = () => {
|
|
105
|
+
x(""), s(c.TRENDS_CLICK_ALL_CATEGORIES, m);
|
|
103
106
|
};
|
|
104
|
-
if (!
|
|
105
|
-
const
|
|
106
|
-
return /* @__PURE__ */
|
|
107
|
-
calendarActions: { onRangeChanged:
|
|
108
|
-
dateRange:
|
|
107
|
+
if (!_ || !u || !v || !q) return /* @__PURE__ */ t(We, {});
|
|
108
|
+
const G = U.length === 0 || a.length === 0, p = Ue(d, de, ue);
|
|
109
|
+
return /* @__PURE__ */ l(ke, {
|
|
110
|
+
calendarActions: { onRangeChanged: pe },
|
|
111
|
+
dateRange: n,
|
|
109
112
|
dateRangeVariant: C ? "timeframetabs" : "timeframebuttons",
|
|
110
|
-
onAccountsFilterClick:
|
|
111
|
-
onBackClick:
|
|
112
|
-
onMenuClick:
|
|
113
|
-
sx:
|
|
114
|
-
title:
|
|
115
|
-
children: [/* @__PURE__ */
|
|
116
|
-
ref:
|
|
113
|
+
onAccountsFilterClick: Ce,
|
|
114
|
+
onBackClick: M,
|
|
115
|
+
onMenuClick: O,
|
|
116
|
+
sx: z,
|
|
117
|
+
title: d.title,
|
|
118
|
+
children: [/* @__PURE__ */ l(f, {
|
|
119
|
+
ref: me,
|
|
117
120
|
sx: { px: C ? 0 : 48 },
|
|
118
121
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ l(f, {
|
|
120
123
|
flexDirection: "row",
|
|
121
124
|
justifyContent: "space-between",
|
|
122
125
|
sx: {
|
|
123
126
|
px: C ? 16 : 0,
|
|
124
127
|
py: 16
|
|
125
128
|
},
|
|
126
|
-
children: [/* @__PURE__ */ t(
|
|
129
|
+
children: [/* @__PURE__ */ t(Me, {
|
|
127
130
|
selectedCategoryGuid: E,
|
|
128
|
-
selectedDateRange:
|
|
129
|
-
}), /* @__PURE__ */ t(
|
|
130
|
-
onTabChange:
|
|
131
|
+
selectedDateRange: n
|
|
132
|
+
}), /* @__PURE__ */ t(Fe, {
|
|
133
|
+
onTabChange: he,
|
|
131
134
|
selectedTab: h
|
|
132
135
|
})]
|
|
133
136
|
}),
|
|
@@ -138,76 +141,76 @@ var Je = ({ onBackClick: G, onMenuClick: F, onInsightCardClick: M, sx: O }) => {
|
|
|
138
141
|
width: "100%",
|
|
139
142
|
children: /* @__PURE__ */ t(w, {
|
|
140
143
|
flexGrow: 1,
|
|
141
|
-
children: E && /* @__PURE__ */
|
|
142
|
-
onClick:
|
|
144
|
+
children: E && /* @__PURE__ */ l($e, {
|
|
145
|
+
onClick: _e,
|
|
143
146
|
sx: {
|
|
144
147
|
p: 0,
|
|
145
148
|
pr: 5
|
|
146
149
|
},
|
|
147
|
-
children: [/* @__PURE__ */ t(
|
|
150
|
+
children: [/* @__PURE__ */ t(qe, {}), d.all_categories]
|
|
148
151
|
})
|
|
149
152
|
})
|
|
150
153
|
}),
|
|
151
|
-
|
|
154
|
+
G && /* @__PURE__ */ t(Ge, {
|
|
152
155
|
header: p.header,
|
|
153
156
|
icon: "multiline_chart",
|
|
154
157
|
onClick: p.onClickHandler,
|
|
155
158
|
primaryButton: p.primaryButton,
|
|
156
159
|
subText: p.description,
|
|
157
160
|
sx: {
|
|
158
|
-
height:
|
|
161
|
+
height: B,
|
|
159
162
|
maxWidth: 432
|
|
160
163
|
}
|
|
161
164
|
}),
|
|
162
|
-
!
|
|
165
|
+
!G && /* @__PURE__ */ l(f, {
|
|
163
166
|
flexDirection: g ? "row" : "column",
|
|
164
167
|
gap: g ? 48 : 16,
|
|
165
|
-
children: [h === "Chart" && /* @__PURE__ */
|
|
168
|
+
children: [h === "Chart" && /* @__PURE__ */ l(Je, { children: [/* @__PURE__ */ t(w, {
|
|
166
169
|
sx: { width: g ? "68%" : "100%" },
|
|
167
|
-
children: /* @__PURE__ */ t(
|
|
168
|
-
availableHeight:
|
|
170
|
+
children: /* @__PURE__ */ t(je, {
|
|
171
|
+
availableHeight: B,
|
|
169
172
|
minHeight: 450,
|
|
170
|
-
selectedDateRange:
|
|
171
|
-
totals:
|
|
173
|
+
selectedDateRange: n,
|
|
174
|
+
totals: a
|
|
172
175
|
})
|
|
173
|
-
}), /* @__PURE__ */
|
|
176
|
+
}), /* @__PURE__ */ l(f, {
|
|
174
177
|
gap: 16,
|
|
175
178
|
sx: { width: g ? "32%" : "100%" },
|
|
176
|
-
children: [
|
|
177
|
-
beats:
|
|
178
|
-
onInsightCardClick:
|
|
179
|
-
}), /* @__PURE__ */ t(
|
|
180
|
-
availableHeight:
|
|
181
|
-
onCategoryClick:
|
|
179
|
+
children: [R && S && k.length > 0 && /* @__PURE__ */ t(ze, {
|
|
180
|
+
beats: k,
|
|
181
|
+
onInsightCardClick: V
|
|
182
|
+
}), /* @__PURE__ */ t(Ve, {
|
|
183
|
+
availableHeight: ce,
|
|
184
|
+
onCategoryClick: ge
|
|
182
185
|
})]
|
|
183
186
|
})] }), h === "Table" && /* @__PURE__ */ t(w, {
|
|
184
187
|
sx: { width: "100%" },
|
|
185
|
-
children: /* @__PURE__ */ t(
|
|
188
|
+
children: /* @__PURE__ */ t(Oe, {
|
|
186
189
|
height: "unset",
|
|
187
|
-
onClickRow:
|
|
190
|
+
onClickRow: Te,
|
|
188
191
|
selectedCategory: E,
|
|
189
|
-
selectedDateRange:
|
|
192
|
+
selectedDateRange: n
|
|
190
193
|
})
|
|
191
194
|
})]
|
|
192
195
|
}),
|
|
193
|
-
/* @__PURE__ */ t(
|
|
194
|
-
ariaLabelClose:
|
|
195
|
-
isOpen: !!
|
|
196
|
-
onClose:
|
|
196
|
+
/* @__PURE__ */ t(Be, {
|
|
197
|
+
ariaLabelClose: d.close_category_details,
|
|
198
|
+
isOpen: !!T,
|
|
199
|
+
onClose: fe,
|
|
197
200
|
shouldShowHeaderShadow: !0,
|
|
198
|
-
title:
|
|
199
|
-
children:
|
|
201
|
+
title: T?.is_income ? d.category_income : d.category_spending,
|
|
202
|
+
children: T && /* @__PURE__ */ t(Ke, {})
|
|
200
203
|
})
|
|
201
204
|
]
|
|
202
|
-
}), /* @__PURE__ */ t(
|
|
203
|
-
onClose: () =>
|
|
204
|
-
showConnectWidget:
|
|
205
|
-
title:
|
|
205
|
+
}), /* @__PURE__ */ t(He, {
|
|
206
|
+
onClose: () => W(!1),
|
|
207
|
+
showConnectWidget: le,
|
|
208
|
+
title: oe.mini_title
|
|
206
209
|
})]
|
|
207
210
|
});
|
|
208
|
-
},
|
|
211
|
+
}, At = Ye(Xe);
|
|
209
212
|
export {
|
|
210
|
-
|
|
213
|
+
At as default
|
|
211
214
|
};
|
|
212
215
|
|
|
213
216
|
//# sourceMappingURL=TrendsWidget.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrendsWidget.es.js","names":[],"sources":["../../src/trends/TrendsWidget.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport React from 'react'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\n\nimport { DateRange } from '@mui/x-date-pickers-pro'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\n\nimport { ArrowBack } from '@mxenabled/mx-icons'\n\nimport {\n ANALYTICS_EVENTS,\n ConnectDrawer,\n Drawer,\n EmptyState,\n Loader,\n WidgetContainer,\n useAccountStore,\n useAppConfig,\n useCategoryStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalStore,\n useGlobalUiStore,\n useInsightsEnabled,\n useScreenSize,\n useTransactionStore,\n useTrendsStore,\n useWidgetLoadTimer,\n} from '../common'\nimport { type Beat, type DetailedCategoryWithTransactions, Transaction, WidgetProps } from '../core'\n\nimport DateRangeText from './components/DateRangeText'\nimport TrendsViewToggle, { type TrendsTabValue } from './components/TrendsViewToggle'\nimport TrendsTableContainer from './components/TrendsTableContainer'\nimport CategoriesList from './components/CategoriesList'\nimport InsightsCarousel from './components/TrendsInsights'\nimport { CategoryDetails } from './components/CategoryDetails'\nimport TrendsChartTotals from './components/TrendsChartTotals'\nimport { TRENDS_ANALYTICS_METADATA } from './constants/TrendsWidget'\nimport { TRENDS_BEAT_TEMPLATES } from './constants/TrendsInsights'\nimport { buildEmptyStateProps } from './utils/TrendsWidget'\n\ninterface TrendsWidgetProps extends WidgetProps {\n onInsightCardClick?: (beat?: Beat) => void\n}\n\nconst TrendsWidget: React.FC<TrendsWidgetProps> = ({\n onBackClick,\n onMenuClick,\n onInsightCardClick,\n sx,\n}) => {\n const { onEvent } = useEvent()\n const { config } = useAppConfig()\n const { isDesktop, isLargeDesktop, isMobile } = useScreenSize()\n const { isAccountDataLoaded, loadAccountData, visibleAccounts: accounts } = useAccountStore()\n const {\n categoriesLoaded,\n loadCategories,\n monthlyCategoryTotals,\n monthlyTotalsLoaded,\n reloadCategoryTotals,\n } = useCategoryStore()\n const { isTransactionDataLoaded, loadTransactionData, setFilter } = useTransactionStore()\n const { selectedCategoryData, selectedDateRange, setSelectedCategoryData, setSelectedDateRange } =\n useTrendsStore()\n const { isInitialized, selectedAccounts, selectedAccountGuids } = useGlobalUiStore()\n const { trends: copy, connect: connectCopy } = useGlobalCopyStore()\n const { beatStore } = useGlobalStore()\n const insightsEnabled = useInsightsEnabled()\n\n // allows clients to disable insights in trends while still enabling insights\n const showInsights = insightsEnabled && config.show_insights_widget_in_master\n const isLargeLayout = isDesktop || isLargeDesktop\n\n const [isWidgetInitialized, setIsWidgetInitialized] = React.useState(false)\n const [isBeatsLoaded, setIsBeatsLoaded] = React.useState(false)\n const [selectedTab, setSelectedTab] = React.useState<TrendsTabValue>('Chart')\n const [selectedCategory, setSelectedCategory] = React.useState('')\n\n // Control responsive chart height based on available widget iframe viewport height\n const [viewportHeight, setViewportHeight] = React.useState(window.innerHeight)\n const insightsPadding = isLargeLayout ? 56 : 0\n const availableChartHeight = viewportHeight - 208 // unavailable height on desktop\n const availableListHeight = viewportHeight - (showInsights ? 550 + insightsPadding : 266)\n\n const [showConnectWidget, setShowConnectWidget] = React.useState(false)\n const hasAggregation = config.show_connections_widget_in_master\n\n // iOS Safari doesn't scroll off-screen elements into view on forward Tab\n // inside this non-document scroll container. `:focus-visible` limits the\n // scroll to keyboard focus so pointer clicks on clipped rows don't jump.\n // `block: 'nearest'` is a no-op when already visible. Callback ref (not\n // useEffect) because the content mounts after the loading gate.\n const cleanupFocusScroll = React.useRef<(() => void) | undefined>(undefined)\n const contentRef = React.useCallback((node: HTMLDivElement | null) => {\n cleanupFocusScroll.current?.()\n cleanupFocusScroll.current = undefined\n\n if (!node) return\n\n const handleFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && event.target.matches(':focus-visible')) {\n event.target.scrollIntoView({ block: 'nearest' })\n }\n }\n\n node.addEventListener('focusin', handleFocusIn)\n cleanupFocusScroll.current = () => node.removeEventListener('focusin', handleFocusIn)\n }, [])\n\n useWidgetLoadTimer({\n widgetName: 'TrendsWidget',\n isLoaded: isWidgetInitialized,\n })\n const filteredBeats = React.useMemo(() => {\n if (!isBeatsLoaded) return []\n return beatStore.getFilteredBeats({ templates: TRENDS_BEAT_TEMPLATES })\n }, [isBeatsLoaded])\n\n React.useEffect(() => {\n // Setup resize listener for responsive chart and list heights\n const handleResize = () => setViewportHeight(window.innerHeight)\n window.addEventListener('resize', handleResize)\n\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n if (!categoriesLoaded) {\n loadCategories().finally()\n }\n if (!isTransactionDataLoaded) {\n loadTransactionData().finally()\n }\n\n return () => window.removeEventListener('resize', handleResize)\n }, [])\n\n // Initialize monthlyCategoryTotals, and reload on account or date range change.\n // Depends on primitives rather than `selectedAccounts` / `selectedDateRange`,\n // whose object identities change even when the values do not. (MEW-3910)\n //\n // Both totals are loaded in parallel rather than chaining monthly inside the\n // date-range `.then()`. Chaining defers the monthly request until the first\n // resolves, so a slow superseded range would claim the newest monthly request\n // token and write stale data over the current range. (MEW-3910)\n React.useEffect(() => {\n if (isInitialized && isAccountDataLoaded) {\n beatStore.loadBeats().finally(() => setIsBeatsLoaded(true))\n reloadCategoryTotals(\n selectedAccounts,\n selectedDateRange.start,\n selectedDateRange.end,\n ).finally(() => {\n setIsWidgetInitialized(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_LOAD_WIDGET, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: `${differenceInCalendarMonths(selectedDateRange.end, selectedDateRange.start)}M`,\n })\n })\n }\n }, [\n isInitialized,\n isAccountDataLoaded,\n selectedAccountGuids.join(','),\n selectedDateRange.start.getTime(),\n selectedDateRange.end.getTime(),\n ])\n React.useEffect(() => {\n // if monthlyCategoryTotals has data, filter transactions\n if (monthlyCategoryTotals.length !== 0) {\n const transactionFilter = {\n accounts: selectedAccountGuids,\n dateRange: { start: selectedDateRange.start, end: selectedDateRange.end },\n }\n\n // this filter sets sortedTransactions in the transaction store\n setFilter({\n ...transactionFilter,\n custom: (t: Transaction) =>\n Boolean(\n monthlyCategoryTotals.find(\n (cat) =>\n cat.top_level_category_guid === t.top_level_category_guid ||\n cat.category_guid === t.category_guid,\n ),\n ),\n })\n }\n }, [monthlyCategoryTotals])\n\n const handleDetailOpen = (selected: DetailedCategoryWithTransactions) => {\n setSelectedCategoryData(selected)\n }\n\n const handleDetailClose = () => {\n setSelectedCategoryData(null)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_BACK, TRENDS_ANALYTICS_METADATA)\n }\n\n const handleEmptyStateClick = () => {\n setShowConnectWidget(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_CONNECT_ACCOUNTS)\n }\n\n const onTabChange = (_event: React.SyntheticEvent, newValue: TrendsTabValue) => {\n setSelectedTab(newValue ?? selectedTab)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TOGGLE_VIEW, {\n ...TRENDS_ANALYTICS_METADATA,\n toggleView: newValue,\n })\n }\n\n const onRangeChanged = (dateRange: DateRange<Date>) => {\n const startDate = addSeconds(dateRange?.[0] as Date, 1)\n const endDate = dateRange?.[1] as Date\n const months = differenceInCalendarMonths(endDate, startDate)\n\n setSelectedDateRange({ start: startDate, end: endDate })\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TIME_WINDOW, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: months + 'M',\n })\n }\n\n const onAccountsFilterClick = (selectedAccountGuids?: string[]) => {\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_FILTER, {\n ...TRENDS_ANALYTICS_METADATA,\n filterValue: selectedAccountGuids,\n })\n }\n\n const onClickRow = (guid: string) => {\n setSelectedCategory(guid)\n }\n\n const onViewAllCategories = () => {\n setSelectedCategory('')\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_ALL_CATEGORIES, TRENDS_ANALYTICS_METADATA)\n }\n\n if (!isInitialized || !isAccountDataLoaded || !isWidgetInitialized || !monthlyTotalsLoaded)\n return <Loader />\n\n const isEmptyTrendsState = accounts.length === 0 || monthlyCategoryTotals.length === 0\n\n const emptyStateProps = buildEmptyStateProps(copy, hasAggregation, handleEmptyStateClick)\n\n return (\n <WidgetContainer\n calendarActions={{ onRangeChanged }}\n dateRange={selectedDateRange}\n dateRangeVariant={isMobile ? 'timeframetabs' : 'timeframebuttons'}\n onAccountsFilterClick={onAccountsFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack\n ref={contentRef}\n sx={{\n px: isMobile ? 0 : 48,\n }}\n >\n <Stack\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n sx={{ px: isMobile ? 16 : 0, py: 16 }}\n >\n <DateRangeText\n selectedCategoryGuid={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n <TrendsViewToggle onTabChange={onTabChange} selectedTab={selectedTab} />\n </Stack>\n <Stack alignItems=\"center\" flexDirection=\"row\" sx={{ pb: 8 }} width=\"100%\">\n <Box flexGrow={1}>\n {selectedCategory && (\n <Button onClick={onViewAllCategories} sx={{ p: 0, pr: 5 }}>\n <ArrowBack />\n {copy.all_categories}\n </Button>\n )}\n </Box>\n </Stack>\n\n {isEmptyTrendsState && (\n <EmptyState\n header={emptyStateProps.header}\n icon=\"multiline_chart\"\n onClick={emptyStateProps.onClickHandler}\n primaryButton={emptyStateProps.primaryButton}\n subText={emptyStateProps.description}\n sx={{ height: availableChartHeight, maxWidth: 432 }}\n />\n )}\n {!isEmptyTrendsState && (\n <Stack flexDirection={isLargeLayout ? 'row' : 'column'} gap={isLargeLayout ? 48 : 16}>\n {selectedTab === 'Chart' && (\n <>\n <Box sx={{ width: isLargeLayout ? '68%' : '100%' }}>\n <TrendsChartTotals\n availableHeight={availableChartHeight}\n minHeight={450}\n selectedDateRange={selectedDateRange}\n totals={monthlyCategoryTotals}\n />\n </Box>\n <Stack gap={16} sx={{ width: isLargeLayout ? '32%' : '100%' }}>\n {/* Only show insights enabled and there are beats to show */}\n {showInsights && isBeatsLoaded && filteredBeats.length > 0 && (\n <InsightsCarousel\n beats={filteredBeats}\n onInsightCardClick={onInsightCardClick}\n />\n )}\n <CategoriesList\n availableHeight={availableListHeight}\n onCategoryClick={handleDetailOpen}\n />\n </Stack>\n </>\n )}\n {selectedTab === 'Table' && (\n <Box sx={{ width: '100%' }}>\n <TrendsTableContainer\n height=\"unset\"\n onClickRow={onClickRow}\n selectedCategory={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n </Box>\n )}\n </Stack>\n )}\n <Drawer\n ariaLabelClose={copy.close_category_details}\n isOpen={Boolean(selectedCategoryData)}\n onClose={handleDetailClose}\n shouldShowHeaderShadow={true}\n title={selectedCategoryData?.is_income ? copy.category_income : copy.category_spending}\n >\n {selectedCategoryData && <CategoryDetails />}\n </Drawer>\n </Stack>\n\n <ConnectDrawer\n onClose={() => setShowConnectWidget(false)}\n showConnectWidget={showConnectWidget}\n title={connectCopy.mini_title}\n />\n </WidgetContainer>\n )\n}\n\nexport default observer(TrendsWidget)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TrendsWidget.es.js","names":[],"sources":["../../src/trends/TrendsWidget.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport React from 'react'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\n\nimport { DateRange } from '@mui/x-date-pickers-pro'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\n\nimport { ArrowBack } from '@mxenabled/mx-icons'\n\nimport {\n ANALYTICS_EVENTS,\n ConnectDrawer,\n Drawer,\n EmptyState,\n Loader,\n WidgetContainer,\n useAccountStore,\n useAppConfig,\n useCategoryStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalStore,\n useGlobalUiStore,\n useInsightsEnabled,\n useScreenSize,\n useTransactionStore,\n useTrendsStore,\n useWidgetLoadTimer,\n} from '../common'\nimport { type Beat, type DetailedCategoryWithTransactions, Transaction, WidgetProps } from '../core'\n\nimport DateRangeText from './components/DateRangeText'\nimport TrendsViewToggle, { type TrendsTabValue } from './components/TrendsViewToggle'\nimport TrendsTableContainer from './components/TrendsTableContainer'\nimport CategoriesList from './components/CategoriesList'\nimport InsightsCarousel from './components/TrendsInsights'\nimport { CategoryDetails } from './components/CategoryDetails'\nimport TrendsChartTotals from './components/TrendsChartTotals'\nimport { TRENDS_ANALYTICS_METADATA } from './constants/TrendsWidget'\nimport { TRENDS_BEAT_TEMPLATES } from './constants/TrendsInsights'\nimport { buildEmptyStateProps } from './utils/TrendsWidget'\n\ninterface TrendsWidgetProps extends WidgetProps {\n onInsightCardClick?: (beat?: Beat) => void\n}\n\nconst TrendsWidget: React.FC<TrendsWidgetProps> = ({\n onBackClick,\n onMenuClick,\n onInsightCardClick,\n sx,\n}) => {\n const { onEvent } = useEvent()\n const { config } = useAppConfig()\n const { isDesktop, isLargeDesktop, isMobile } = useScreenSize()\n const { isAccountDataLoaded, loadAccountData, visibleAccounts: accounts } = useAccountStore()\n const {\n categoriesLoaded,\n loadCategories,\n monthlyCategoryTotals,\n monthlyTotalsLoaded,\n reloadCategoryTotals,\n } = useCategoryStore()\n const { isTransactionDataLoaded, loadTransactionData, setFilter } = useTransactionStore()\n const {\n isTransactionStoreIdle,\n selectedCategoryData,\n selectedDateRange,\n setSelectedCategoryData,\n setSelectedDateRange,\n } = useTrendsStore()\n const { isInitialized, selectedAccounts, selectedAccountGuids } = useGlobalUiStore()\n const { trends: copy, connect: connectCopy } = useGlobalCopyStore()\n const { beatStore } = useGlobalStore()\n const insightsEnabled = useInsightsEnabled()\n\n // allows clients to disable insights in trends while still enabling insights\n const showInsights = insightsEnabled && config.show_insights_widget_in_master\n const isLargeLayout = isDesktop || isLargeDesktop\n\n const [isWidgetInitialized, setIsWidgetInitialized] = React.useState(false)\n const [isBeatsLoaded, setIsBeatsLoaded] = React.useState(false)\n const [selectedTab, setSelectedTab] = React.useState<TrendsTabValue>('Chart')\n const [selectedCategory, setSelectedCategory] = React.useState('')\n\n // Control responsive chart height based on available widget iframe viewport height\n const [viewportHeight, setViewportHeight] = React.useState(window.innerHeight)\n const insightsPadding = isLargeLayout ? 56 : 0\n const availableChartHeight = viewportHeight - 208 // unavailable height on desktop\n const availableListHeight = viewportHeight - (showInsights ? 550 + insightsPadding : 266)\n\n const [showConnectWidget, setShowConnectWidget] = React.useState(false)\n const hasAggregation = config.show_connections_widget_in_master\n\n // iOS Safari doesn't scroll off-screen elements into view on forward Tab\n // inside this non-document scroll container. `:focus-visible` limits the\n // scroll to keyboard focus so pointer clicks on clipped rows don't jump.\n // `block: 'nearest'` is a no-op when already visible. Callback ref (not\n // useEffect) because the content mounts after the loading gate.\n const cleanupFocusScroll = React.useRef<(() => void) | undefined>(undefined)\n const contentRef = React.useCallback((node: HTMLDivElement | null) => {\n cleanupFocusScroll.current?.()\n cleanupFocusScroll.current = undefined\n\n if (!node) return\n\n const handleFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && event.target.matches(':focus-visible')) {\n event.target.scrollIntoView({ block: 'nearest' })\n }\n }\n\n node.addEventListener('focusin', handleFocusIn)\n cleanupFocusScroll.current = () => node.removeEventListener('focusin', handleFocusIn)\n }, [])\n\n useWidgetLoadTimer({\n widgetName: 'TrendsWidget',\n isLoaded: isWidgetInitialized,\n })\n const filteredBeats = React.useMemo(() => {\n if (!isBeatsLoaded) return []\n return beatStore.getFilteredBeats({ templates: TRENDS_BEAT_TEMPLATES })\n }, [isBeatsLoaded])\n\n React.useEffect(() => {\n // Setup resize listener for responsive chart and list heights\n const handleResize = () => setViewportHeight(window.innerHeight)\n window.addEventListener('resize', handleResize)\n\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n if (!categoriesLoaded) {\n loadCategories().finally()\n }\n if (!isTransactionDataLoaded) {\n loadTransactionData().finally()\n }\n\n return () => window.removeEventListener('resize', handleResize)\n }, [])\n\n // Initialize monthlyCategoryTotals, and reload on account or date range change.\n // Depends on primitives rather than `selectedAccounts` / `selectedDateRange`,\n // whose object identities change even when the values do not. (MEW-3910)\n //\n // Both totals are loaded in parallel rather than chaining monthly inside the\n // date-range `.then()`. Chaining defers the monthly request until the first\n // resolves, so a slow superseded range would claim the newest monthly request\n // token and write stale data over the current range. (MEW-3910)\n React.useEffect(() => {\n if (isInitialized && isAccountDataLoaded) {\n beatStore.loadBeats().finally(() => setIsBeatsLoaded(true))\n reloadCategoryTotals(\n selectedAccounts,\n selectedDateRange.start,\n selectedDateRange.end,\n ).finally(() => {\n setIsWidgetInitialized(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_LOAD_WIDGET, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: `${differenceInCalendarMonths(selectedDateRange.end, selectedDateRange.start)}M`,\n })\n })\n }\n }, [\n isInitialized,\n isAccountDataLoaded,\n selectedAccountGuids.join(','),\n selectedDateRange.start.getTime(),\n selectedDateRange.end.getTime(),\n ])\n // Totals are refetched on every range/account change, so their identity marks a new filter.\n // Tracking it stops a failed load from re-firing setFilter every time the store goes idle.\n const filteredTotalsRef = React.useRef<typeof monthlyCategoryTotals | null>(null)\n\n React.useEffect(() => {\n // Wait for the transaction store to go idle so the selected range load isn't dropped\n if (\n monthlyCategoryTotals.length !== 0 &&\n isTransactionStoreIdle &&\n filteredTotalsRef.current !== monthlyCategoryTotals\n ) {\n filteredTotalsRef.current = monthlyCategoryTotals\n const transactionFilter = {\n accounts: selectedAccountGuids,\n dateRange: { start: selectedDateRange.start, end: selectedDateRange.end },\n }\n\n // this filter sets sortedTransactions in the transaction store\n setFilter({\n ...transactionFilter,\n custom: (t: Transaction) =>\n Boolean(\n monthlyCategoryTotals.find(\n (cat) =>\n cat.top_level_category_guid === t.top_level_category_guid ||\n cat.category_guid === t.category_guid,\n ),\n ),\n })\n }\n }, [monthlyCategoryTotals, isTransactionStoreIdle])\n\n const handleDetailOpen = (selected: DetailedCategoryWithTransactions) => {\n setSelectedCategoryData(selected)\n }\n\n const handleDetailClose = () => {\n setSelectedCategoryData(null)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_BACK, TRENDS_ANALYTICS_METADATA)\n }\n\n const handleEmptyStateClick = () => {\n setShowConnectWidget(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_CONNECT_ACCOUNTS)\n }\n\n const onTabChange = (_event: React.SyntheticEvent, newValue: TrendsTabValue) => {\n setSelectedTab(newValue ?? selectedTab)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TOGGLE_VIEW, {\n ...TRENDS_ANALYTICS_METADATA,\n toggleView: newValue,\n })\n }\n\n const onRangeChanged = (dateRange: DateRange<Date>) => {\n const startDate = addSeconds(dateRange?.[0] as Date, 1)\n const endDate = dateRange?.[1] as Date\n const months = differenceInCalendarMonths(endDate, startDate)\n\n setSelectedDateRange({ start: startDate, end: endDate })\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TIME_WINDOW, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: months + 'M',\n })\n }\n\n const onAccountsFilterClick = (selectedAccountGuids?: string[]) => {\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_FILTER, {\n ...TRENDS_ANALYTICS_METADATA,\n filterValue: selectedAccountGuids,\n })\n }\n\n const onClickRow = (guid: string) => {\n setSelectedCategory(guid)\n }\n\n const onViewAllCategories = () => {\n setSelectedCategory('')\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_ALL_CATEGORIES, TRENDS_ANALYTICS_METADATA)\n }\n\n if (!isInitialized || !isAccountDataLoaded || !isWidgetInitialized || !monthlyTotalsLoaded)\n return <Loader />\n\n const isEmptyTrendsState = accounts.length === 0 || monthlyCategoryTotals.length === 0\n\n const emptyStateProps = buildEmptyStateProps(copy, hasAggregation, handleEmptyStateClick)\n\n return (\n <WidgetContainer\n calendarActions={{ onRangeChanged }}\n dateRange={selectedDateRange}\n dateRangeVariant={isMobile ? 'timeframetabs' : 'timeframebuttons'}\n onAccountsFilterClick={onAccountsFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack\n ref={contentRef}\n sx={{\n px: isMobile ? 0 : 48,\n }}\n >\n <Stack\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n sx={{ px: isMobile ? 16 : 0, py: 16 }}\n >\n <DateRangeText\n selectedCategoryGuid={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n <TrendsViewToggle onTabChange={onTabChange} selectedTab={selectedTab} />\n </Stack>\n <Stack alignItems=\"center\" flexDirection=\"row\" sx={{ pb: 8 }} width=\"100%\">\n <Box flexGrow={1}>\n {selectedCategory && (\n <Button onClick={onViewAllCategories} sx={{ p: 0, pr: 5 }}>\n <ArrowBack />\n {copy.all_categories}\n </Button>\n )}\n </Box>\n </Stack>\n\n {isEmptyTrendsState && (\n <EmptyState\n header={emptyStateProps.header}\n icon=\"multiline_chart\"\n onClick={emptyStateProps.onClickHandler}\n primaryButton={emptyStateProps.primaryButton}\n subText={emptyStateProps.description}\n sx={{ height: availableChartHeight, maxWidth: 432 }}\n />\n )}\n {!isEmptyTrendsState && (\n <Stack flexDirection={isLargeLayout ? 'row' : 'column'} gap={isLargeLayout ? 48 : 16}>\n {selectedTab === 'Chart' && (\n <>\n <Box sx={{ width: isLargeLayout ? '68%' : '100%' }}>\n <TrendsChartTotals\n availableHeight={availableChartHeight}\n minHeight={450}\n selectedDateRange={selectedDateRange}\n totals={monthlyCategoryTotals}\n />\n </Box>\n <Stack gap={16} sx={{ width: isLargeLayout ? '32%' : '100%' }}>\n {/* Only show insights enabled and there are beats to show */}\n {showInsights && isBeatsLoaded && filteredBeats.length > 0 && (\n <InsightsCarousel\n beats={filteredBeats}\n onInsightCardClick={onInsightCardClick}\n />\n )}\n <CategoriesList\n availableHeight={availableListHeight}\n onCategoryClick={handleDetailOpen}\n />\n </Stack>\n </>\n )}\n {selectedTab === 'Table' && (\n <Box sx={{ width: '100%' }}>\n <TrendsTableContainer\n height=\"unset\"\n onClickRow={onClickRow}\n selectedCategory={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n </Box>\n )}\n </Stack>\n )}\n <Drawer\n ariaLabelClose={copy.close_category_details}\n isOpen={Boolean(selectedCategoryData)}\n onClose={handleDetailClose}\n shouldShowHeaderShadow={true}\n title={selectedCategoryData?.is_income ? copy.category_income : copy.category_spending}\n >\n {selectedCategoryData && <CategoryDetails />}\n </Drawer>\n </Stack>\n\n <ConnectDrawer\n onClose={() => setShowConnectWidget(false)}\n showConnectWidget={showConnectWidget}\n title={connectCopy.mini_title}\n />\n </WidgetContainer>\n )\n}\n\nexport default observer(TrendsWidget)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,IAAM,KAAA,CAA6C,EACjD,aAAA,GACA,aAAA,GACA,oBAAA,GACA,IAAA,EAAA,MACI;AACJ,QAAM,EAAE,SAAA,EAAA,IAAY,GAAS,GACvB,EAAE,QAAA,EAAA,IAAW,GAAa,GAC1B,EAAE,WAAA,GAAW,gBAAA,GAAgB,UAAA,EAAA,IAAa,GAAc,GACxD,EAAE,qBAAA,GAAqB,iBAAA,GAAiB,iBAAiB,EAAA,IAAa,GAAgB,GACtF,EACJ,kBAAA,GACA,gBAAA,GACA,uBAAA,GACA,qBAAA,GACA,sBAAA,EAAA,IACE,GAAiB,GACf,EAAE,yBAAA,GAAyB,qBAAA,GAAqB,WAAA,EAAA,IAAc,GAAoB,GAClF,EACJ,wBAAA,GACA,sBAAA,GACA,mBAAA,GACA,yBAAA,GACA,sBAAA,GAAA,IACE,GAAe,GACb,EAAE,eAAA,GAAe,kBAAA,IAAkB,sBAAA,EAAA,IAAyB,GAAiB,GAC7E,EAAE,QAAQ,GAAM,SAAS,GAAA,IAAgB,GAAmB,GAC5D,EAAE,WAAA,EAAA,IAAc,GAAe,GAI/B,IAHkB,GAGH,KAAmB,EAAO,gCACzC,IAAgB,KAAa,GAE7B,CAAC,GAAqB,EAAA,IAA0B,EAAM,SAAS,EAAK,GACpE,CAAC,GAAe,EAAA,IAAoB,EAAM,SAAS,EAAK,GACxD,CAAC,GAAa,EAAA,IAAkB,EAAM,SAAyB,OAAO,GACtE,CAAC,GAAkB,CAAA,IAAuB,EAAM,SAAS,EAAE,GAG3D,CAAC,GAAgB,EAAA,IAAqB,EAAM,SAAS,OAAO,WAAW,GACvE,KAAkB,IAAgB,KAAK,GACvC,IAAuB,IAAiB,KACxC,KAAsB,KAAkB,IAAe,MAAM,KAAkB,MAE/E,CAAC,IAAmB,CAAA,IAAwB,EAAM,SAAS,EAAK,GAChE,KAAiB,EAAO,mCAOxB,IAAqB,EAAM,OAAiC,MAAS,GACrE,KAAa,EAAM,YAAA,CAAa,MAAgC;AAIpE,QAHA,EAAmB,UAAU,GAC7B,EAAmB,UAAU,QAEzB,CAAC,EAAM;AAEX,UAAM,IAAA,CAAiB,MAAsB;AAC3C,MAAI,EAAM,kBAAkB,eAAe,EAAM,OAAO,QAAQ,gBAAgB,KAC9E,EAAM,OAAO,eAAe,EAAE,OAAO,UAAU,CAAC;AAAA,IAEpD;AAEA,IAAA,EAAK,iBAAiB,WAAW,CAAa,GAC9C,EAAmB,UAAA,MAAgB,EAAK,oBAAoB,WAAW,CAAa;AAAA,EACtF,GAAG,CAAC,CAAC;AAEL,EAAA,GAAmB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ,CAAC;AACD,QAAM,IAAgB,EAAM,QAAA,MACrB,IACE,EAAU,iBAAiB,EAAE,WAAW,GAAsB,CAAC,IAD3C,CAAC,GAE3B,CAAC,CAAa,CAAC;AAElB,EAAA,EAAM,UAAA,MAAgB;AAEpB,UAAM,IAAA,MAAqB,GAAkB,OAAO,WAAW;AAC/D,kBAAO,iBAAiB,UAAU,CAAY,GAEzC,KACH,EAAgB,EAAE,QAAQ,GAEvB,KACH,EAAe,EAAE,QAAQ,GAEtB,KACH,EAAoB,EAAE,QAAQ,GAGhC,MAAa,OAAO,oBAAoB,UAAU,CAAY;AAAA,EAChE,GAAG,CAAC,CAAC,GAUL,EAAM,UAAA,MAAgB;AACpB,IAAI,KAAiB,MACnB,EAAU,UAAU,EAAE,QAAA,MAAc,GAAiB,EAAI,CAAC,GAC1D,EACE,IACA,EAAkB,OAClB,EAAkB,GACpB,EAAE,QAAA,MAAc;AACd,MAAA,GAAuB,EAAI,GAC3B,EAAQ,EAAiB,oBAAoB;AAAA,QAC3C,GAAG;AAAA,QACH,aAAa,GAAG,EAA2B,EAAkB,KAAK,EAAkB,KAAK,CAAA;AAAA,MAC3F,CAAC;AAAA,IACH,CAAC;AAAA,EAEL,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA,EAAqB,KAAK,GAAG;AAAA,IAC7B,EAAkB,MAAM,QAAQ;AAAA,IAChC,EAAkB,IAAI,QAAQ;AAAA,EAChC,CAAC;AAGD,QAAM,IAAoB,EAAM,OAA4C,IAAI;AAEhF,EAAA,EAAM,UAAA,MAAgB;AAEpB,QACE,EAAsB,WAAW,KACjC,KACA,EAAkB,YAAY,GAC9B;AACA,MAAA,EAAkB,UAAU;AAC5B,YAAM,IAAoB;AAAA,QACxB,UAAU;AAAA,QACV,WAAW;AAAA,UAAE,OAAO,EAAkB;AAAA,UAAO,KAAK,EAAkB;AAAA,QAAI;AAAA,MAC1E;AAGA,MAAA,EAAU;AAAA,QACR,GAAG;AAAA,QACH,QAAA,CAAS,MACP,EACE,EAAsB,KAAA,CACnB,MACC,EAAI,4BAA4B,EAAE,2BAClC,EAAI,kBAAkB,EAAE,aAC5B;AAAA,MAEN,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,GAAuB,CAAsB,CAAC;AAElD,QAAM,KAAA,CAAoB,MAA+C;AACvE,IAAA,EAAwB,CAAQ;AAAA,EAClC,GAEM,KAAA,MAA0B;AAC9B,IAAA,EAAwB,IAAI,GAC5B,EAAQ,EAAiB,mBAAmB,CAAyB;AAAA,EACvE,GAEM,KAAA,MAA8B;AAClC,IAAA,EAAqB,EAAI,GACzB,EAAQ,EAAiB,6BAA6B;AAAA,EACxD,GAEM,KAAA,CAAe,GAA8B,MAA6B;AAC9E,IAAA,GAAe,KAAY,CAAW,GACtC,EAAQ,EAAiB,0BAA0B;AAAA,MACjD,GAAG;AAAA,MACH,YAAY;AAAA,IACd,CAAC;AAAA,EACH,GAEM,KAAA,CAAkB,MAA+B;AACrD,UAAM,IAAY,GAAW,IAAY,CAAA,GAAY,CAAC,GAChD,IAAU,IAAY,CAAA,GACtB,KAAS,EAA2B,GAAS,CAAS;AAE5D,IAAA,GAAqB;AAAA,MAAE,OAAO;AAAA,MAAW,KAAK;AAAA,IAAQ,CAAC,GACvD,EAAQ,EAAiB,0BAA0B;AAAA,MACjD,GAAG;AAAA,MACH,aAAa,KAAS;AAAA,IACxB,CAAC;AAAA,EACH,GAEM,KAAA,CAAyB,MAAoC;AACjE,IAAA,EAAQ,EAAiB,qBAAqB;AAAA,MAC5C,GAAG;AAAA,MACH,aAAa;AAAA,IACf,CAAC;AAAA,EACH,GAEM,KAAA,CAAc,MAAiB;AACnC,IAAA,EAAoB,CAAI;AAAA,EAC1B,GAEM,KAAA,MAA4B;AAChC,IAAA,EAAoB,EAAE,GACtB,EAAQ,EAAiB,6BAA6B,CAAyB;AAAA,EACjF;AAEA,MAAI,CAAC,KAAiB,CAAC,KAAuB,CAAC,KAAuB,CAAC,EACrE,QAAO,gBAAA,EAAC,IAAD,CAAS,CAAA;AAElB,QAAM,IAAqB,EAAS,WAAW,KAAK,EAAsB,WAAW,GAE/E,IAAkB,GAAqB,GAAM,IAAgB,EAAqB;AAExF,SACE,gBAAA,EAAC,IAAD;AAAA,IACE,iBAAiB,EAAE,gBAAA,GAAe;AAAA,IAClC,WAAW;AAAA,IACX,kBAAkB,IAAW,kBAAkB;AAAA,IACxB,uBAAA;AAAA,IACV,aAAA;AAAA,IACA,aAAA;AAAA,IACT,IAAA;AAAA,IACJ,OAAO,EAAK;AAAA,IARd,UAAA,CAUE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,IAAI,EACF,IAAI,IAAW,IAAI,GACrB;AAAA,MAJF,UAAA;AAAA,QAME,gBAAA,EAAC,GAAD;AAAA,UACE,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,IAAI;AAAA,YAAE,IAAI,IAAW,KAAK;AAAA,YAAG,IAAI;AAAA,UAAG;AAAA,UAHtC,UAAA,CAKE,gBAAA,EAAC,IAAD;AAAA,YACE,sBAAsB;AAAA,YACH,mBAAA;AAAA,UACpB,CAAA,GACD,gBAAA,EAAC,IAAD;AAAA,YAA+B,aAAA;AAAA,YAA0B,aAAA;AAAA,UAAc,CAAA,CAClE;AAAA;QACP,gBAAA,EAAC,GAAD;AAAA,UAAO,YAAW;AAAA,UAAS,eAAc;AAAA,UAAM,IAAI,EAAE,IAAI,EAAE;AAAA,UAAG,OAAM;AAAA,UAClE,UAAA,gBAAA,EAAC,GAAD;AAAA,YAAK,UAAU;AAAA,YACZ,UAAA,KACC,gBAAA,EAAC,IAAD;AAAA,cAAQ,SAAS;AAAA,cAAqB,IAAI;AAAA,gBAAE,GAAG;AAAA,gBAAG,IAAI;AAAA,cAAE;AAAA,cAAxD,UAAA,CACE,gBAAA,EAAC,IAAD,CAAY,CAAA,GACX,EAAK,cACA;AAAA;UAEP,CAAA;AAAA,QACA,CAAA;AAAA,QAEN,KACC,gBAAA,EAAC,IAAD;AAAA,UACE,QAAQ,EAAgB;AAAA,UACxB,MAAK;AAAA,UACL,SAAS,EAAgB;AAAA,UACzB,eAAe,EAAgB;AAAA,UAC/B,SAAS,EAAgB;AAAA,UACzB,IAAI;AAAA,YAAE,QAAQ;AAAA,YAAsB,UAAU;AAAA,UAAI;AAAA,QACnD,CAAA;AAAA,QAEF,CAAC,KACA,gBAAA,EAAC,GAAD;AAAA,UAAO,eAAe,IAAgB,QAAQ;AAAA,UAAU,KAAK,IAAgB,KAAK;AAAA,UAAlF,UAAA,CACG,MAAgB,WACf,gBAAA,EAAA,IAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,YAAK,IAAI,EAAE,OAAO,IAAgB,QAAQ,OAAO;AAAA,YAC/C,UAAA,gBAAA,EAAC,IAAD;AAAA,cACE,iBAAiB;AAAA,cACjB,WAAW;AAAA,cACQ,mBAAA;AAAA,cACnB,QAAQ;AAAA,YACT,CAAA;AAAA,UACE,CAAA,GACL,gBAAA,EAAC,GAAD;AAAA,YAAO,KAAK;AAAA,YAAI,IAAI,EAAE,OAAO,IAAgB,QAAQ,OAAO;AAAA,YAA5D,UAAA,CAEG,KAAgB,KAAiB,EAAc,SAAS,KACvD,gBAAA,EAAC,IAAD;AAAA,cACE,OAAO;AAAA,cACa,oBAAA;AAAA,YACrB,CAAA,GAEH,gBAAA,EAAC,IAAD;AAAA,cACE,iBAAiB;AAAA,cACjB,iBAAiB;AAAA,YAClB,CAAA,CACI;AAAA,UACP,CAAA,CAAA,EAAA,CAAA,GAEH,MAAgB,WACf,gBAAA,EAAC,GAAD;AAAA,YAAK,IAAI,EAAE,OAAO,OAAO;AAAA,YACvB,UAAA,gBAAA,EAAC,IAAD;AAAA,cACE,QAAO;AAAA,cACK,YAAA;AAAA,cACM,kBAAA;AAAA,cACC,mBAAA;AAAA,YACpB,CAAA;AAAA,UACE,CAAA,CAEF;AAAA;QAET,gBAAA,EAAC,IAAD;AAAA,UACE,gBAAgB,EAAK;AAAA,UACrB,QAAQ,EAAQ;AAAA,UAChB,SAAS;AAAA,UACT,wBAAwB;AAAA,UACxB,OAAO,GAAsB,YAAY,EAAK,kBAAkB,EAAK;AAAA,UAEpE,UAAA,KAAwB,gBAAA,EAAC,IAAD,CAAkB,CAAA;AAAA,QACrC,CAAA;AAAA,MACH;AAAA,IAEP,CAAA,GAAA,gBAAA,EAAC,IAAD;AAAA,MACE,SAAA,MAAe,EAAqB,EAAK;AAAA,MACtB,mBAAA;AAAA,MACnB,OAAO,GAAY;AAAA,IACpB,CAAA,CACc;AAAA;AAErB,GAEA,KAAe,GAAS,EAAY"}
|
|
@@ -1,44 +1,49 @@
|
|
|
1
|
-
import { useEvent as
|
|
2
|
-
import { ANALYTICS_EVENTS as
|
|
3
|
-
import { getCategoryColor as
|
|
4
|
-
import { formatCurrency as
|
|
5
|
-
import { ListItemRow as
|
|
1
|
+
import { useEvent as C, useGlobalCopyStore as T, useTrendsStore as I } from "../../common/context/hooks.es.js";
|
|
2
|
+
import { ANALYTICS_EVENTS as v } from "../../common/constants/Analytics.es.js";
|
|
3
|
+
import { getCategoryColor as a } from "../../core/utils/CategoryUtil.es.js";
|
|
4
|
+
import { formatCurrency as S } from "../../core/utils/NumberFormatting.es.js";
|
|
5
|
+
import { ListItemRow as g } from "../../common/components/ListItemRow.es.js";
|
|
6
6
|
import { TRENDS_ANALYTICS_METADATA as x } from "../constants/TrendsWidget.es.js";
|
|
7
|
-
import
|
|
8
|
-
import { observer as
|
|
9
|
-
import { CategoryIcon as
|
|
10
|
-
import { ChevronRight as
|
|
11
|
-
import { jsx as
|
|
12
|
-
import { alpha as
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
import u from "react";
|
|
8
|
+
import { observer as E } from "mobx-react-lite";
|
|
9
|
+
import { CategoryIcon as y } from "@mxenabled/mxui";
|
|
10
|
+
import { ChevronRight as A } from "@mxenabled/mx-icons";
|
|
11
|
+
import { jsx as o, jsxs as L } from "react/jsx-runtime";
|
|
12
|
+
import { alpha as b, useTheme as R } from "@mui/material/styles";
|
|
13
|
+
import _ from "@mui/material/Divider";
|
|
14
|
+
import N from "@mui/material/Skeleton";
|
|
15
|
+
var H = E(({ totalAmount: c, guid: t, name: m, transactions: i, onClick: r, isLastItem: l = !1, showDivider: p = !0 }) => {
|
|
16
|
+
const { trends: n } = T(), { onEvent: f } = C(), s = R(), { isSelectedRangeLoaded: e } = I(), d = `${i.length} ${i.length === 1 ? n.transaction : n.transactions}`, h = () => {
|
|
17
|
+
r?.(), f(v.TRENDS_CLICK_LIST_ITEM, {
|
|
17
18
|
...x,
|
|
18
|
-
listItem:
|
|
19
|
+
listItem: m
|
|
19
20
|
});
|
|
20
21
|
};
|
|
21
|
-
return /* @__PURE__ */
|
|
22
|
-
leftIcon:
|
|
23
|
-
categoryGuid:
|
|
22
|
+
return /* @__PURE__ */ L(u.Fragment, { children: [/* @__PURE__ */ o(g, {
|
|
23
|
+
leftIcon: t ? /* @__PURE__ */ o(y, {
|
|
24
|
+
categoryGuid: t,
|
|
24
25
|
sx: {
|
|
25
|
-
bgcolor:
|
|
26
|
-
border: `1px solid ${
|
|
26
|
+
bgcolor: b(a(t, s), 0.15),
|
|
27
|
+
border: `1px solid ${a(t, s)}`,
|
|
27
28
|
color: "text.primary"
|
|
28
29
|
}
|
|
29
30
|
}) : void 0,
|
|
30
|
-
onClick:
|
|
31
|
-
rightContent:
|
|
32
|
-
rightIcon:
|
|
33
|
-
subtitle:
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
onClick: e && r ? h : void 0,
|
|
32
|
+
rightContent: S(Math.abs(c), "0,0.00"),
|
|
33
|
+
rightIcon: e && r ? /* @__PURE__ */ o(A, {}) : void 0,
|
|
34
|
+
subtitle: e ? d : /* @__PURE__ */ o(N, {
|
|
35
|
+
"data-testid": "transaction-count-skeleton",
|
|
36
|
+
variant: "text",
|
|
37
|
+
width: 88
|
|
38
|
+
}),
|
|
39
|
+
title: m
|
|
40
|
+
}), p && /* @__PURE__ */ o(_, {
|
|
36
41
|
component: "li",
|
|
37
42
|
sx: { ml: l ? 24 : 68 }
|
|
38
|
-
})] },
|
|
43
|
+
})] }, t);
|
|
39
44
|
});
|
|
40
45
|
export {
|
|
41
|
-
|
|
46
|
+
H as default
|
|
42
47
|
};
|
|
43
48
|
|
|
44
49
|
//# sourceMappingURL=CategoriesListItem.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoriesListItem.es.js","names":[],"sources":["../../../src/trends/components/CategoriesListItem.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Divider from '@mui/material/Divider'\nimport { alpha } from '@mui/material/styles'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\nimport { CategoryIcon } from '@mxenabled/mxui'\n\nimport {
|
|
1
|
+
{"version":3,"file":"CategoriesListItem.es.js","names":[],"sources":["../../../src/trends/components/CategoriesListItem.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Divider from '@mui/material/Divider'\nimport Skeleton from '@mui/material/Skeleton'\nimport { alpha } from '@mui/material/styles'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\nimport { CategoryIcon } from '@mxenabled/mxui'\n\nimport {\n ANALYTICS_EVENTS,\n ListItemRow,\n useEvent,\n useGlobalCopyStore,\n useTrendsStore,\n} from '../../common'\nimport { type DetailedCategoryWithTransactions } from '../../core'\n\nimport { TRENDS_ANALYTICS_METADATA } from '../constants/TrendsWidget'\nimport { getCategoryColor } from '../../core/utils/CategoryUtil'\nimport { formatCurrency } from '../../core/utils/NumberFormatting'\ninterface CategoriesListItemProps extends DetailedCategoryWithTransactions {\n onClick?: () => void\n isLastItem?: boolean\n showDivider?: boolean\n}\n\nconst CategoriesListItem = observer(\n ({\n totalAmount,\n guid,\n name,\n transactions,\n onClick,\n isLastItem = false,\n showDivider = true,\n }: CategoriesListItemProps) => {\n const { trends: copy } = useGlobalCopyStore()\n const { onEvent } = useEvent()\n const theme = useTheme()\n const { isSelectedRangeLoaded } = useTrendsStore()\n\n const transactionCountText = `${transactions.length} ${transactions.length === 1 ? copy.transaction : copy.transactions}`\n\n const handleClick = () => {\n onClick?.()\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_LIST_ITEM, {\n ...TRENDS_ANALYTICS_METADATA,\n listItem: name,\n })\n }\n\n return (\n <React.Fragment key={guid}>\n <ListItemRow\n leftIcon={\n guid ? (\n <CategoryIcon\n categoryGuid={guid}\n sx={{\n bgcolor: alpha(getCategoryColor(guid, theme), 0.15),\n border: `1px solid ${getCategoryColor(guid, theme)}`,\n color: 'text.primary',\n }}\n />\n ) : undefined\n }\n onClick={isSelectedRangeLoaded && onClick ? handleClick : undefined}\n rightContent={formatCurrency(Math.abs(totalAmount), '0,0.00')}\n rightIcon={isSelectedRangeLoaded && onClick ? <ChevronRight /> : undefined}\n subtitle={\n isSelectedRangeLoaded ? (\n transactionCountText\n ) : (\n <Skeleton data-testid=\"transaction-count-skeleton\" variant=\"text\" width={88} />\n )\n }\n title={name}\n />\n {showDivider && <Divider component=\"li\" sx={{ ml: isLastItem ? 24 : 68 }} />}\n </React.Fragment>\n )\n },\n)\n\nexport default CategoriesListItem\n"],"mappings":";;;;;;;;;;;;;;AA6BA,IAAM,IAAqB,EAAA,CACxB,EACC,aAAA,GACA,MAAA,GACA,MAAA,GACA,cAAA,GACA,SAAA,GACA,YAAA,IAAa,IACb,aAAA,IAAc,GAAA,MACe;AAC7B,QAAM,EAAE,QAAQ,EAAA,IAAS,EAAmB,GACtC,EAAE,SAAA,EAAA,IAAY,EAAS,GACvB,IAAQ,EAAS,GACjB,EAAE,uBAAA,EAAA,IAA0B,EAAe,GAE3C,IAAuB,GAAG,EAAa,MAAA,IAAU,EAAa,WAAW,IAAI,EAAK,cAAc,EAAK,YAAA,IAErG,IAAA,MAAoB;AACxB,IAAA,IAAU,GACV,EAAQ,EAAiB,wBAAwB;AAAA,MAC/C,GAAG;AAAA,MACH,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SACE,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,UACE,IACE,gBAAA,EAAC,GAAD;AAAA,MACE,cAAc;AAAA,MACd,IAAI;AAAA,QACF,SAAS,EAAM,EAAiB,GAAM,CAAK,GAAG,IAAI;AAAA,QAClD,QAAQ,aAAa,EAAiB,GAAM,CAAK,CAAA;AAAA,QACjD,OAAO;AAAA,MACT;AAAA,IACD,CAAA,IACC;AAAA,IAEN,SAAS,KAAyB,IAAU,IAAc;AAAA,IAC1D,cAAc,EAAe,KAAK,IAAI,CAAW,GAAG,QAAQ;AAAA,IAC5D,WAAW,KAAyB,IAAU,gBAAA,EAAC,GAAD,CAAe,CAAA,IAAI;AAAA,IACjE,UACE,IACE,IAEA,gBAAA,EAAC,GAAD;AAAA,MAAU,eAAY;AAAA,MAA6B,SAAQ;AAAA,MAAO,OAAO;AAAA,IAAK,CAAA;AAAA,IAGlF,OAAO;AAAA,EACR,CAAA,GACA,KAAe,gBAAA,EAAC,GAAD;AAAA,IAAS,WAAU;AAAA,IAAK,IAAI,EAAE,IAAI,IAAa,KAAK,GAAG;AAAA,EAAI,CAAA,CAC7D,EAAA,GA3BK,CA2BL;AAEpB,CACF"}
|