@mx-cartographer/experiences 9.4.62 → 9.4.63

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 CHANGED
@@ -1,3 +1,7 @@
1
+ ## [9.4.63] - 10-07-2026
2
+
3
+ - **FIXED** - Trends Tabular View child category rows now open the filtered transaction drawer, matching the chart view MEW-4020
4
+
1
5
  ## [9.4.62] - 10-07-2026
2
6
 
3
7
  - **ADDED** - `withdrawal_block` (Highlight Withdrawal) component block and `WithdrawalCard`: the amount (shown with a leading minus unless it is zero), an `"{amount_label} {withdrawal_date}"` date line and a grey balance footer, read from one `instance_slot.data_series` row (`amount`, `amount_label`, `withdrawal_date`, `balance`, `balance_label`). Text arrives localized from the backend; only `amount` and `balance` are formatted. (WEC-1871)
@@ -7,6 +7,20 @@ export declare class TrendsStore {
7
7
  visibleListLength: number;
8
8
  constructor(globalStore: GlobalStore);
9
9
  setSelectedCategoryData: (data: DetailedCategoryWithTransactions | null) => void;
10
+ /**
11
+ * Resolve a category guid — top level or sub-category — to the data the
12
+ * category details drawer renders.
13
+ *
14
+ * `detailedCategoriesWithTransactions` only holds top-level categories, and a
15
+ * sub-category carries `totalAmount: 0` / `totalMonthlyAmounts: []` so it is
16
+ * not double counted inside its parent. The drawer reads both fields, so a
17
+ * sub-category is rebuilt from its own range total and monthly series.
18
+ *
19
+ * The tabular view only routes sub-category guids here today; the top-level
20
+ * branch keeps this a complete resolver for any guid the drawer is given.
21
+ * @param guid - Guid of the category to resolve
22
+ */
23
+ getCategoryWithTransactions: (guid: string) => DetailedCategoryWithTransactions | undefined;
10
24
  setSelectedDateRange: (dateRange: DateRange) => void;
11
25
  setVisibleListLength: (length: number) => void;
12
26
  get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[];
@@ -1,47 +1,60 @@
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 {
1
+ import { DATE_FORMATS_INTL as o, formatDate as r } from "../constants/DateFormats.es.js";
2
+ import { findDetailedSubCategory as d, getDetailedCategoryTransactions as c } from "../utils/CategoryUtil.es.js";
3
+ import { buildCategoryDetailsChartData as h, filterAndSortCategoriesWithTransactions as D } from "../utils/TrendsUtil.es.js";
4
+ import { endOfMonth as i } from "date-fns/endOfMonth";
5
+ import { isBefore as u } from "date-fns/isBefore";
6
+ import { subMonths as m } from "date-fns/subMonths";
7
+ import { differenceInCalendarMonths as C } from "date-fns/differenceInCalendarMonths";
8
+ import { makeAutoObservable as S } from "mobx";
9
+ import { addSeconds as b } from "date-fns/addSeconds";
10
+ var W = class {
10
11
  globalStore;
11
12
  selectedCategoryData = null;
12
13
  selectedDateRange;
13
14
  visibleListLength = 5;
14
- constructor(e) {
15
- this.globalStore = e, this.selectedDateRange = {
16
- start: c(r(l(/* @__PURE__ */ new Date(), 6)), 1),
17
- end: r(/* @__PURE__ */ new Date())
18
- }, g(this);
19
- }
20
- setSelectedCategoryData = (e) => {
21
- this.selectedCategoryData = e;
15
+ constructor(t) {
16
+ this.globalStore = t, this.selectedDateRange = {
17
+ start: b(i(m(/* @__PURE__ */ new Date(), 6)), 1),
18
+ end: i(/* @__PURE__ */ new Date())
19
+ }, S(this);
20
+ }
21
+ setSelectedCategoryData = (t) => {
22
+ this.selectedCategoryData = t;
23
+ };
24
+ getCategoryWithTransactions = (t) => {
25
+ const { detailedCategories: e, detailedCategoriesWithTransactions: n } = this.globalStore.categoryStore, s = n.find((g) => g.guid === t);
26
+ if (s) return s;
27
+ const a = d(e, t);
28
+ if (!a) return;
29
+ const [l] = c([{
30
+ ...a,
31
+ totalAmount: a.currentAmount,
32
+ totalMonthlyAmounts: a.monthlyAmounts
33
+ }], this.globalStore.transactionStore.sortedTransactions);
34
+ return l;
22
35
  };
23
- setSelectedDateRange = (e) => {
24
- this.selectedDateRange = e;
36
+ setSelectedDateRange = (t) => {
37
+ this.selectedDateRange = t;
25
38
  };
26
- setVisibleListLength = (e) => {
27
- this.visibleListLength = e;
39
+ setVisibleListLength = (t) => {
40
+ this.visibleListLength = t;
28
41
  };
29
42
  get sortedDetailedCategoriesWithTransactions() {
30
- return o(this.globalStore.categoryStore.detailedCategoriesWithTransactions);
43
+ return D(this.globalStore.categoryStore.detailedCategoriesWithTransactions);
31
44
  }
32
45
  get isTransactionStoreIdle() {
33
- const { isTransactionDataLoaded: e, transactionsLoading: t } = this.globalStore.transactionStore;
34
- return e && !t;
46
+ const { isTransactionDataLoaded: t, transactionsLoading: e } = this.globalStore.transactionStore;
47
+ return t && !e;
35
48
  }
36
49
  get isSelectedRangeLoaded() {
37
- const { isTransactionDataLoaded: e, cachedStartDate: t } = this.globalStore.transactionStore;
38
- return e && !n(this.selectedDateRange.start, t);
50
+ const { isTransactionDataLoaded: t, cachedStartDate: e } = this.globalStore.transactionStore;
51
+ return t && !u(this.selectedDateRange.start, e);
39
52
  }
40
53
  get selectedDateRangeMonthCount() {
41
- return d(this.selectedDateRange.end, this.selectedDateRange.start) + 1;
54
+ return C(this.selectedDateRange.end, this.selectedDateRange.start) + 1;
42
55
  }
43
56
  get selectedDateRangeMonthRange() {
44
- return `${s(this.selectedDateRange.start, a.MONTH_LONG)} - ${s(this.selectedDateRange.end, a.MONTH_LONG)}`;
57
+ return `${r(this.selectedDateRange.start, o.MONTH_LONG)} - ${r(this.selectedDateRange.end, o.MONTH_LONG)}`;
45
58
  }
46
59
  get visibleCategories() {
47
60
  return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength);
@@ -50,11 +63,11 @@ var R = class {
50
63
  return this.sortedDetailedCategoriesWithTransactions.slice(this.visibleListLength);
51
64
  }
52
65
  get categoryDetailsChartData() {
53
- return i(this.selectedCategoryData, this.selectedDateRangeMonthCount);
66
+ return h(this.selectedCategoryData, this.selectedDateRangeMonthCount);
54
67
  }
55
68
  };
56
69
  export {
57
- R as TrendsStore
70
+ W as TrendsStore
58
71
  };
59
72
 
60
73
  //# 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 { 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
+ {"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'\nimport { findDetailedSubCategory, getDetailedCategoryTransactions } from '../utils/CategoryUtil'\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 /**\n * Resolve a category guid — top level or sub-category — to the data the\n * category details drawer renders.\n *\n * `detailedCategoriesWithTransactions` only holds top-level categories, and a\n * sub-category carries `totalAmount: 0` / `totalMonthlyAmounts: []` so it is\n * not double counted inside its parent. The drawer reads both fields, so a\n * sub-category is rebuilt from its own range total and monthly series.\n *\n * The tabular view only routes sub-category guids here today; the top-level\n * branch keeps this a complete resolver for any guid the drawer is given.\n * @param guid - Guid of the category to resolve\n */\n getCategoryWithTransactions = (guid: string): DetailedCategoryWithTransactions | undefined => {\n const { detailedCategories, detailedCategoriesWithTransactions } =\n this.globalStore.categoryStore\n\n const topLevelCategory = detailedCategoriesWithTransactions.find(\n (category) => category.guid === guid,\n )\n if (topLevelCategory) return topLevelCategory\n\n const subCategory = findDetailedSubCategory(detailedCategories, guid)\n if (!subCategory) return undefined\n\n const [subCategoryWithTransactions] = getDetailedCategoryTransactions(\n [\n {\n ...subCategory,\n totalAmount: subCategory.currentAmount,\n totalMonthlyAmounts: subCategory.monthlyAmounts,\n },\n ],\n this.globalStore.transactionStore.sortedTransactions,\n )\n\n return subCategoryWithTransactions\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":";;;;;;;;;AAiBA,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,8BAAA,CAA+B,MAA+D;AAC5F,UAAM,EAAE,oBAAA,GAAoB,oCAAA,EAAA,IAC1B,KAAK,YAAY,eAEb,IAAmB,EAAmC,KAAA,CACzD,MAAa,EAAS,SAAS,CAClC;AACA,QAAI,EAAkB,QAAO;AAE7B,UAAM,IAAc,EAAwB,GAAoB,CAAI;AACpE,QAAI,CAAC,EAAa;AAElB,UAAM,CAAC,CAAA,IAA+B,EACpC,CACE;AAAA,MACE,GAAG;AAAA,MACH,aAAa,EAAY;AAAA,MACzB,qBAAqB,EAAY;AAAA,IACnC,CACF,GACA,KAAK,YAAY,iBAAiB,kBACpC;AAEA,WAAO;AAAA,EACT;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,137 +1,142 @@
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";
1
+ import { useAccountStore as we, useAppConfig as De, useCategoryStore as Le, useEvent as be, useGlobalCopyStore as Ie, useGlobalStore as Ae, useGlobalUiStore as Re, useTransactionStore as xe, useTrendsStore as ve } from "../common/context/hooks.es.js";
2
+ import { useInsightsEnabled as Ne } from "../common/hooks/useInsightsEnabled.es.js";
3
+ import { useScreenSize as We } from "../common/hooks/useScreenSize.es.js";
4
+ import { useWidgetLoadTimer as Be } from "../common/hooks/useWidgetLoadTimer.es.js";
5
+ import ke from "../common/components/drawer/Drawer.es.js";
6
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";
7
+ import He from "../common/components/Loader.es.js";
8
+ import { WidgetContainer as Ge } from "../common/components/WidgetContainer.es.js";
9
+ import Fe from "../common/components/ConnectDrawer.es.js";
10
+ import { EmptyState as Me } from "../common/components/EmptyState.es.js";
11
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";
12
+ import Oe from "./components/TrendsViewToggle.es.js";
13
+ import Ve from "./components/DateRangeText.es.js";
14
+ import ze from "./components/TrendsTableContainer.es.js";
15
+ import Ke from "./components/CategoriesList.es.js";
16
+ import je from "./components/TrendsInsights.es.js";
17
+ import { CategoryDetails as Pe } from "./components/CategoryDetails.es.js";
18
+ import $e from "./components/TrendsChartTotals.es.js";
19
+ import { TRENDS_BEAT_TEMPLATES as Ue } from "./constants/TrendsInsights.es.js";
20
+ import { buildEmptyStateProps as Ye } from "./utils/TrendsWidget.es.js";
21
+ import n from "react";
22
+ import { observer as qe } from "mobx-react-lite";
23
23
  import f from "@mui/material/Stack";
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";
24
+ import Je from "@mui/material/Button";
25
+ import { ArrowBack as Qe } from "@mxenabled/mx-icons";
26
+ import { Fragment as Xe, jsx as t, jsxs as l } from "react/jsx-runtime";
27
27
  import w from "@mui/material/Box";
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
- if (y.current?.(), y.current = void 0, !e) return;
33
- const i = (r) => {
34
- r.target instanceof HTMLElement && r.target.matches(":focus-visible") && r.target.scrollIntoView({ block: "nearest" });
28
+ import { differenceInCalendarMonths as M } from "date-fns/differenceInCalendarMonths";
29
+ import { addSeconds as Ze } from "date-fns/addSeconds";
30
+ var et = ({ onBackClick: O, onMenuClick: V, onInsightCardClick: z, sx: K }) => {
31
+ const { onEvent: s } = be(), { config: D } = De(), { isDesktop: j, isLargeDesktop: P, isMobile: T } = We(), { isAccountDataLoaded: u, loadAccountData: $, visibleAccounts: U } = we(), { categoriesLoaded: Y, loadCategories: q, monthlyCategoryTotals: a, monthlyTotalsLoaded: J, reloadCategoryTotals: Q } = Le(), { isTransactionDataLoaded: X, loadTransactionData: Z, setFilter: ee } = xe(), { getCategoryWithTransactions: te, isTransactionStoreIdle: L, selectedCategoryData: _, selectedDateRange: r, setSelectedCategoryData: b, setSelectedDateRange: oe } = ve(), { isInitialized: S, selectedAccounts: ne, selectedAccountGuids: I } = Re(), { trends: d, connect: re } = Ie(), { beatStore: A, captureException: ie } = Ae(), R = Ne() && D.show_insights_widget_in_master, g = j || P, [x, se] = n.useState(!1), [y, ae] = n.useState(!1), [p, ce] = n.useState("Chart"), [h, v] = n.useState(""), [N, le] = n.useState(window.innerHeight), de = g ? 56 : 0, W = N - 208, me = N - (R ? 550 + de : 266), [ge, B] = n.useState(!1), fe = D.show_connections_widget_in_master, E = n.useRef(void 0), ue = n.useCallback((e) => {
32
+ if (E.current?.(), E.current = void 0, !e) return;
33
+ const o = (i) => {
34
+ i.target instanceof HTMLElement && i.target.matches(":focus-visible") && i.target.scrollIntoView({ block: "nearest" });
35
35
  };
36
- e.addEventListener("focusin", i), y.current = () => e.removeEventListener("focusin", i);
36
+ e.addEventListener("focusin", o), E.current = () => e.removeEventListener("focusin", o);
37
37
  }, []);
38
- Ne({
38
+ Be({
39
39
  widgetName: "TrendsWidget",
40
- isLoaded: v
40
+ isLoaded: x
41
41
  });
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, {
42
+ const k = n.useMemo(() => y ? A.getFilteredBeats({ templates: Ue }) : [], [y]);
43
+ n.useEffect(() => {
44
+ const e = () => le(window.innerHeight);
45
+ return window.addEventListener("resize", e), u || $().finally(), Y || q().finally(), X || Z().finally(), () => window.removeEventListener("resize", e);
46
+ }, []), n.useEffect(() => {
47
+ S && u && (A.loadBeats().finally(() => ae(!0)), Q(ne, r.start, r.end).finally(() => {
48
+ se(!0), s(c.TRENDS_LOAD_WIDGET, {
49
49
  ...m,
50
- time_period: `${F(n.end, n.start)}M`
50
+ time_period: `${M(r.end, r.start)}M`
51
51
  });
52
52
  }));
53
53
  }, [
54
- _,
54
+ S,
55
55
  u,
56
56
  I.join(","),
57
- n.start.getTime(),
58
- n.end.getTime()
57
+ r.start.getTime(),
58
+ r.end.getTime()
59
59
  ]);
60
- const H = o.useRef(null);
61
- o.useEffect(() => {
60
+ const H = n.useRef(null);
61
+ n.useEffect(() => {
62
62
  if (a.length !== 0 && L && H.current !== a) {
63
63
  H.current = a;
64
64
  const e = {
65
65
  accounts: I,
66
66
  dateRange: {
67
- start: n.start,
68
- end: n.end
67
+ start: r.start,
68
+ end: r.end
69
69
  }
70
70
  };
71
- Z({
71
+ ee({
72
72
  ...e,
73
- custom: (i) => !!a.find((r) => r.top_level_category_guid === i.top_level_category_guid || r.category_guid === i.category_guid)
73
+ custom: (o) => !!a.find((i) => i.top_level_category_guid === o.top_level_category_guid || i.category_guid === o.category_guid)
74
74
  });
75
75
  }
76
76
  }, [a, L]);
77
- const ge = (e) => {
77
+ const G = (e) => {
78
78
  b(e);
79
- }, fe = () => {
79
+ }, pe = () => {
80
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, {
81
+ }, he = () => {
82
+ B(!0), s(c.TRENDS_CLICK_CONNECT_ACCOUNTS);
83
+ }, Ce = (e, o) => {
84
+ ce(o ?? p), s(c.TRENDS_CLICK_TOGGLE_VIEW, {
85
85
  ...m,
86
- toggleView: i
86
+ toggleView: o
87
87
  });
88
- }, pe = (e) => {
89
- const i = Qe(e?.[0], 1), r = e?.[1], Se = F(r, i);
90
- ee({
91
- start: i,
92
- end: r
88
+ }, Te = (e) => {
89
+ const o = Ze(e?.[0], 1), i = e?.[1], Ee = M(i, o);
90
+ oe({
91
+ start: o,
92
+ end: i
93
93
  }), s(c.TRENDS_CLICK_TIME_WINDOW, {
94
94
  ...m,
95
- time_period: Se + "M"
95
+ time_period: Ee + "M"
96
96
  });
97
- }, Ce = (e) => {
97
+ }, _e = (e) => {
98
98
  s(c.TRENDS_CLICK_FILTER, {
99
99
  ...m,
100
100
  filterValue: e
101
101
  });
102
- }, Te = (e) => {
103
- x(e);
104
- }, _e = () => {
105
- x(""), s(c.TRENDS_CLICK_ALL_CATEGORIES, m);
102
+ }, Se = (e) => {
103
+ if (!h) {
104
+ v(e);
105
+ return;
106
+ }
107
+ const o = te(e);
108
+ o ? G(o) : ie(/* @__PURE__ */ new Error(`TrendsWidget: no category found for guid ${e}`));
109
+ }, ye = () => {
110
+ v(""), s(c.TRENDS_CLICK_ALL_CATEGORIES, m);
106
111
  };
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,
112
- dateRangeVariant: C ? "timeframetabs" : "timeframebuttons",
113
- onAccountsFilterClick: Ce,
114
- onBackClick: M,
115
- onMenuClick: O,
116
- sx: z,
112
+ if (!S || !u || !x || !J) return /* @__PURE__ */ t(He, {});
113
+ const F = U.length === 0 || a.length === 0, C = Ye(d, fe, he);
114
+ return /* @__PURE__ */ l(Ge, {
115
+ calendarActions: { onRangeChanged: Te },
116
+ dateRange: r,
117
+ dateRangeVariant: T ? "timeframetabs" : "timeframebuttons",
118
+ onAccountsFilterClick: _e,
119
+ onBackClick: O,
120
+ onMenuClick: V,
121
+ sx: K,
117
122
  title: d.title,
118
123
  children: [/* @__PURE__ */ l(f, {
119
- ref: me,
120
- sx: { px: C ? 0 : 48 },
124
+ ref: ue,
125
+ sx: { px: T ? 0 : 48 },
121
126
  children: [
122
127
  /* @__PURE__ */ l(f, {
123
128
  flexDirection: "row",
124
129
  justifyContent: "space-between",
125
130
  sx: {
126
- px: C ? 16 : 0,
131
+ px: T ? 16 : 0,
127
132
  py: 16
128
133
  },
129
- children: [/* @__PURE__ */ t(Me, {
130
- selectedCategoryGuid: E,
131
- selectedDateRange: n
132
- }), /* @__PURE__ */ t(Fe, {
133
- onTabChange: he,
134
- selectedTab: h
134
+ children: [/* @__PURE__ */ t(Ve, {
135
+ selectedCategoryGuid: h,
136
+ selectedDateRange: r
137
+ }), /* @__PURE__ */ t(Oe, {
138
+ onTabChange: Ce,
139
+ selectedTab: p
135
140
  })]
136
141
  }),
137
142
  /* @__PURE__ */ t(f, {
@@ -141,76 +146,76 @@ var Xe = ({ onBackClick: M, onMenuClick: O, onInsightCardClick: V, sx: z }) => {
141
146
  width: "100%",
142
147
  children: /* @__PURE__ */ t(w, {
143
148
  flexGrow: 1,
144
- children: E && /* @__PURE__ */ l($e, {
145
- onClick: _e,
149
+ children: h && /* @__PURE__ */ l(Je, {
150
+ onClick: ye,
146
151
  sx: {
147
152
  p: 0,
148
153
  pr: 5
149
154
  },
150
- children: [/* @__PURE__ */ t(qe, {}), d.all_categories]
155
+ children: [/* @__PURE__ */ t(Qe, {}), d.all_categories]
151
156
  })
152
157
  })
153
158
  }),
154
- G && /* @__PURE__ */ t(Ge, {
155
- header: p.header,
159
+ F && /* @__PURE__ */ t(Me, {
160
+ header: C.header,
156
161
  icon: "multiline_chart",
157
- onClick: p.onClickHandler,
158
- primaryButton: p.primaryButton,
159
- subText: p.description,
162
+ onClick: C.onClickHandler,
163
+ primaryButton: C.primaryButton,
164
+ subText: C.description,
160
165
  sx: {
161
- height: B,
166
+ height: W,
162
167
  maxWidth: 432
163
168
  }
164
169
  }),
165
- !G && /* @__PURE__ */ l(f, {
170
+ !F && /* @__PURE__ */ l(f, {
166
171
  flexDirection: g ? "row" : "column",
167
172
  gap: g ? 48 : 16,
168
- children: [h === "Chart" && /* @__PURE__ */ l(Je, { children: [/* @__PURE__ */ t(w, {
173
+ children: [p === "Chart" && /* @__PURE__ */ l(Xe, { children: [/* @__PURE__ */ t(w, {
169
174
  sx: { width: g ? "68%" : "100%" },
170
- children: /* @__PURE__ */ t(je, {
171
- availableHeight: B,
175
+ children: /* @__PURE__ */ t($e, {
176
+ availableHeight: W,
172
177
  minHeight: 450,
173
- selectedDateRange: n,
178
+ selectedDateRange: r,
174
179
  totals: a
175
180
  })
176
181
  }), /* @__PURE__ */ l(f, {
177
182
  gap: 16,
178
183
  sx: { width: g ? "32%" : "100%" },
179
- children: [R && S && k.length > 0 && /* @__PURE__ */ t(ze, {
184
+ children: [R && y && k.length > 0 && /* @__PURE__ */ t(je, {
180
185
  beats: k,
181
- onInsightCardClick: V
182
- }), /* @__PURE__ */ t(Ve, {
183
- availableHeight: ce,
184
- onCategoryClick: ge
186
+ onInsightCardClick: z
187
+ }), /* @__PURE__ */ t(Ke, {
188
+ availableHeight: me,
189
+ onCategoryClick: G
185
190
  })]
186
- })] }), h === "Table" && /* @__PURE__ */ t(w, {
191
+ })] }), p === "Table" && /* @__PURE__ */ t(w, {
187
192
  sx: { width: "100%" },
188
- children: /* @__PURE__ */ t(Oe, {
193
+ children: /* @__PURE__ */ t(ze, {
189
194
  height: "unset",
190
- onClickRow: Te,
191
- selectedCategory: E,
192
- selectedDateRange: n
195
+ onClickRow: Se,
196
+ selectedCategory: h,
197
+ selectedDateRange: r
193
198
  })
194
199
  })]
195
200
  }),
196
- /* @__PURE__ */ t(Be, {
201
+ /* @__PURE__ */ t(ke, {
197
202
  ariaLabelClose: d.close_category_details,
198
- isOpen: !!T,
199
- onClose: fe,
203
+ isOpen: !!_,
204
+ onClose: pe,
200
205
  shouldShowHeaderShadow: !0,
201
- title: T?.is_income ? d.category_income : d.category_spending,
202
- children: T && /* @__PURE__ */ t(Ke, {})
206
+ title: _?.is_income ? d.category_income : d.category_spending,
207
+ children: _ && /* @__PURE__ */ t(Pe, {})
203
208
  })
204
209
  ]
205
- }), /* @__PURE__ */ t(He, {
206
- onClose: () => W(!1),
207
- showConnectWidget: le,
208
- title: oe.mini_title
210
+ }), /* @__PURE__ */ t(Fe, {
211
+ onClose: () => B(!1),
212
+ showConnectWidget: ge,
213
+ title: re.mini_title
209
214
  })]
210
215
  });
211
- }, At = Ye(Xe);
216
+ }, xt = qe(et);
212
217
  export {
213
- At as default
218
+ xt as default
214
219
  };
215
220
 
216
221
  //# 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 {\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
+ {"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 getCategoryWithTransactions,\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, captureException } = 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 // Top-level table rows drill into their sub-categories; once drilled in, a\n // sub-category row opens the same category details drawer the chart view's\n // category list reaches (table view parity). The non-navigable total and\n // \"General [Parent]\" rows are filtered out in TrendsTable.\n const onClickRow = (guid: string) => {\n if (!selectedCategory) {\n setSelectedCategory(guid)\n return\n }\n const category = getCategoryWithTransactions(guid)\n if (category) handleDetailOpen(category)\n // Every navigable sub-category row resolves today; log a miss so a future\n // regression on a cursor:pointer row isn't a silent dead click.\n else captureException(new Error(`TrendsWidget: no category found for guid ${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,GAAA,IAAc,GAAoB,GAClF,EACJ,6BAAA,IACA,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,GAAW,kBAAA,GAAA,IAAqB,GAAe,GAIjD,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,GAAU;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,IAAA,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,GAMM,KAAA,CAAc,MAAiB;AACnC,QAAI,CAAC,GAAkB;AACrB,MAAA,EAAoB,CAAI;AACxB;AAAA,IACF;AACA,UAAM,IAAW,GAA4B,CAAI;AACjD,IAAI,IAAU,EAAiB,CAAQ,IAGlC,GAAiB,oBAAI,MAAM,4CAA4C,CAAA,EAAM,CAAC;AAAA,EACrF,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"}
@@ -38,12 +38,10 @@ var G = ({ selectedDateRange: m, selectedCategory: l, onClickRow: c, height: w =
38
38
  children: [(!o || o && o.is_income) && /* @__PURE__ */ g(p, {
39
39
  columns: d,
40
40
  onRowClick: c,
41
- parentCategory: o,
42
41
  rows: h
43
42
  }), (!o || o && !o.is_income) && /* @__PURE__ */ g(p, {
44
43
  columns: d,
45
44
  onRowClick: c,
46
- parentCategory: o,
47
45
  rows: u,
48
46
  totalRow: y
49
47
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"TrendsTableContainer.es.js","names":[],"sources":["../../../src/trends/components/TrendsTableContainer.tsx"],"sourcesContent":["import React from 'react'\n\nimport Stack from '@mui/material/Stack'\n\nimport { useCategoryStore, useGlobalCopyStore } from '../../common'\n\nimport {\n generateMonthHeaders,\n getTrendsTableColumns,\n getTrendsTableRows,\n} from '../utils/TrendsTable'\n\nimport { TrendsTable } from './trendstable/TrendsTable'\n\ninterface TrendsTableProps {\n sx?: any\n height?: number | string\n selectedDateRange: { start: Date; end: Date }\n selectedCategory?: string\n onClickRow?: (category: string) => void\n}\n\nconst TrendsTableContainer: React.FC<TrendsTableProps> = ({\n selectedDateRange,\n selectedCategory,\n onClickRow,\n height = '100%',\n sx = {},\n}) => {\n const { trends: copy } = useGlobalCopyStore()\n const { trendsCategories } = useCategoryStore()\n\n // Generate all headers for the selected date range\n const monthHeaders = React.useMemo(() => {\n return generateMonthHeaders(selectedDateRange.start, selectedDateRange.end)\n }, [selectedDateRange])\n\n const columns = React.useMemo(() => {\n return getTrendsTableColumns(monthHeaders, copy)\n }, [monthHeaders, copy])\n\n const parentCategory = React.useMemo(() => {\n if (selectedCategory) {\n return trendsCategories.find((category) => category.guid === selectedCategory)\n }\n return undefined\n }, [selectedCategory, trendsCategories])\n\n const [incomeRows, spendingRows] = React.useMemo(() => {\n let categories = trendsCategories\n if (parentCategory) {\n categories = parentCategory.subCategories.filter((c) =>\n c.monthlyAmounts.some((ma) => ma.amount !== 0),\n )\n }\n\n return [\n getTrendsTableRows(categories, copy, true, monthHeaders, parentCategory),\n getTrendsTableRows(categories, copy, false, monthHeaders, parentCategory),\n ]\n }, [trendsCategories, monthHeaders, parentCategory, copy])\n\n const totalSpendingRow = {\n id: 'total',\n category: copy.table_column_total,\n category_guid: 'total',\n isParent: false,\n top_level_category_guid: 'total',\n total: spendingRows.reduce((sum, row) => sum + row.total, 0),\n monthlyAmounts: spendingRows.reduce(\n (amounts, row) => {\n Object.entries(row.monthlyAmounts).forEach(([month, amount]) => {\n amounts[month] = (amounts[month] || 0) + amount\n })\n return amounts\n },\n {} as Record<string, number>,\n ),\n }\n\n return (\n <Stack\n gap={24}\n sx={{ height: height, width: '100%', overflowX: 'auto', boxShadow: 'none', ...sx }}\n >\n {(!parentCategory || (parentCategory && parentCategory.is_income)) && (\n <TrendsTable\n columns={columns}\n onRowClick={onClickRow}\n parentCategory={parentCategory}\n rows={incomeRows}\n />\n )}\n {(!parentCategory || (parentCategory && !parentCategory.is_income)) && (\n <TrendsTable\n columns={columns}\n onRowClick={onClickRow}\n parentCategory={parentCategory}\n rows={spendingRows}\n totalRow={totalSpendingRow}\n />\n )}\n </Stack>\n )\n}\n\nexport default TrendsTableContainer\n"],"mappings":";;;;;;AAsBA,IAAM,IAAA,CAAoD,EACxD,mBAAA,GACA,kBAAA,GACA,YAAA,GACA,QAAA,IAAS,QACT,IAAA,IAAK,CAAC,EAAA,MACF;AACJ,QAAM,EAAE,QAAQ,EAAA,IAAS,EAAmB,GACtC,EAAE,kBAAA,EAAA,IAAqB,EAAiB,GAGxC,IAAe,EAAM,QAAA,MAClB,EAAqB,EAAkB,OAAO,EAAkB,GAAG,GACzE,CAAC,CAAiB,CAAC,GAEhB,IAAU,EAAM,QAAA,MACb,EAAsB,GAAc,CAAI,GAC9C,CAAC,GAAc,CAAI,CAAC,GAEjB,IAAiB,EAAM,QAAA,MAAc;AACzC,QAAI,EACF,QAAO,EAAiB,KAAA,CAAM,MAAa,EAAS,SAAS,CAAgB;AAAA,EAGjF,GAAG,CAAC,GAAkB,CAAgB,CAAC,GAEjC,CAAC,GAAY,CAAA,IAAgB,EAAM,QAAA,MAAc;AACrD,QAAI,IAAa;AACjB,WAAI,MACF,IAAa,EAAe,cAAc,OAAA,CAAQ,MAChD,EAAE,eAAe,KAAA,CAAM,MAAO,EAAG,WAAW,CAAC,CAC/C,IAGK,CACL,EAAmB,GAAY,GAAM,IAAM,GAAc,CAAc,GACvE,EAAmB,GAAY,GAAM,IAAO,GAAc,CAAc,CAC1E;AAAA,EACF,GAAG;AAAA,IAAC;AAAA,IAAkB;AAAA,IAAc;AAAA,IAAgB;AAAA,EAAI,CAAC,GAEnD,IAAmB;AAAA,IACvB,IAAI;AAAA,IACJ,UAAU,EAAK;AAAA,IACf,eAAe;AAAA,IACf,UAAU;AAAA,IACV,yBAAyB;AAAA,IACzB,OAAO,EAAa,OAAA,CAAQ,GAAK,MAAQ,IAAM,EAAI,OAAO,CAAC;AAAA,IAC3D,gBAAgB,EAAa,OAAA,CAC1B,GAAS,OACR,OAAO,QAAQ,EAAI,cAAc,EAAE,QAAA,CAAS,CAAC,GAAO,CAAA,MAAY;AAC9D,MAAA,EAAQ,CAAA,KAAU,EAAQ,CAAA,KAAU,KAAK;AAAA,IAC3C,CAAC,GACM,IAET,CAAC,CACH;AAAA,EACF;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK;AAAA,IACL,IAAI;AAAA,MAAU,QAAA;AAAA,MAAQ,OAAO;AAAA,MAAQ,WAAW;AAAA,MAAQ,WAAW;AAAA,MAAQ,GAAG;AAAA,IAAG;AAAA,IAFnF,UAAA,EAII,CAAC,KAAmB,KAAkB,EAAe,cACrD,gBAAA,EAAC,GAAD;AAAA,MACW,SAAA;AAAA,MACT,YAAY;AAAA,MACI,gBAAA;AAAA,MAChB,MAAM;AAAA,IACP,CAAA,IAED,CAAC,KAAmB,KAAkB,CAAC,EAAe,cACtD,gBAAA,EAAC,GAAD;AAAA,MACW,SAAA;AAAA,MACT,YAAY;AAAA,MACI,gBAAA;AAAA,MAChB,MAAM;AAAA,MACN,UAAU;AAAA,IACX,CAAA,CAEE;AAAA;AAEX"}
1
+ {"version":3,"file":"TrendsTableContainer.es.js","names":[],"sources":["../../../src/trends/components/TrendsTableContainer.tsx"],"sourcesContent":["import React from 'react'\n\nimport Stack from '@mui/material/Stack'\n\nimport { useCategoryStore, useGlobalCopyStore } from '../../common'\n\nimport {\n generateMonthHeaders,\n getTrendsTableColumns,\n getTrendsTableRows,\n} from '../utils/TrendsTable'\n\nimport { TrendsTable } from './trendstable/TrendsTable'\n\ninterface TrendsTableProps {\n sx?: any\n height?: number | string\n selectedDateRange: { start: Date; end: Date }\n selectedCategory?: string\n onClickRow?: (category: string) => void\n}\n\nconst TrendsTableContainer: React.FC<TrendsTableProps> = ({\n selectedDateRange,\n selectedCategory,\n onClickRow,\n height = '100%',\n sx = {},\n}) => {\n const { trends: copy } = useGlobalCopyStore()\n const { trendsCategories } = useCategoryStore()\n\n // Generate all headers for the selected date range\n const monthHeaders = React.useMemo(() => {\n return generateMonthHeaders(selectedDateRange.start, selectedDateRange.end)\n }, [selectedDateRange])\n\n const columns = React.useMemo(() => {\n return getTrendsTableColumns(monthHeaders, copy)\n }, [monthHeaders, copy])\n\n const parentCategory = React.useMemo(() => {\n if (selectedCategory) {\n return trendsCategories.find((category) => category.guid === selectedCategory)\n }\n return undefined\n }, [selectedCategory, trendsCategories])\n\n const [incomeRows, spendingRows] = React.useMemo(() => {\n let categories = trendsCategories\n if (parentCategory) {\n categories = parentCategory.subCategories.filter((c) =>\n c.monthlyAmounts.some((ma) => ma.amount !== 0),\n )\n }\n\n return [\n getTrendsTableRows(categories, copy, true, monthHeaders, parentCategory),\n getTrendsTableRows(categories, copy, false, monthHeaders, parentCategory),\n ]\n }, [trendsCategories, monthHeaders, parentCategory, copy])\n\n const totalSpendingRow = {\n id: 'total',\n category: copy.table_column_total,\n category_guid: 'total',\n isParent: false,\n top_level_category_guid: 'total',\n total: spendingRows.reduce((sum, row) => sum + row.total, 0),\n monthlyAmounts: spendingRows.reduce(\n (amounts, row) => {\n Object.entries(row.monthlyAmounts).forEach(([month, amount]) => {\n amounts[month] = (amounts[month] || 0) + amount\n })\n return amounts\n },\n {} as Record<string, number>,\n ),\n }\n\n return (\n <Stack\n gap={24}\n sx={{ height: height, width: '100%', overflowX: 'auto', boxShadow: 'none', ...sx }}\n >\n {(!parentCategory || (parentCategory && parentCategory.is_income)) && (\n <TrendsTable columns={columns} onRowClick={onClickRow} rows={incomeRows} />\n )}\n {(!parentCategory || (parentCategory && !parentCategory.is_income)) && (\n <TrendsTable\n columns={columns}\n onRowClick={onClickRow}\n rows={spendingRows}\n totalRow={totalSpendingRow}\n />\n )}\n </Stack>\n )\n}\n\nexport default TrendsTableContainer\n"],"mappings":";;;;;;AAsBA,IAAM,IAAA,CAAoD,EACxD,mBAAA,GACA,kBAAA,GACA,YAAA,GACA,QAAA,IAAS,QACT,IAAA,IAAK,CAAC,EAAA,MACF;AACJ,QAAM,EAAE,QAAQ,EAAA,IAAS,EAAmB,GACtC,EAAE,kBAAA,EAAA,IAAqB,EAAiB,GAGxC,IAAe,EAAM,QAAA,MAClB,EAAqB,EAAkB,OAAO,EAAkB,GAAG,GACzE,CAAC,CAAiB,CAAC,GAEhB,IAAU,EAAM,QAAA,MACb,EAAsB,GAAc,CAAI,GAC9C,CAAC,GAAc,CAAI,CAAC,GAEjB,IAAiB,EAAM,QAAA,MAAc;AACzC,QAAI,EACF,QAAO,EAAiB,KAAA,CAAM,MAAa,EAAS,SAAS,CAAgB;AAAA,EAGjF,GAAG,CAAC,GAAkB,CAAgB,CAAC,GAEjC,CAAC,GAAY,CAAA,IAAgB,EAAM,QAAA,MAAc;AACrD,QAAI,IAAa;AACjB,WAAI,MACF,IAAa,EAAe,cAAc,OAAA,CAAQ,MAChD,EAAE,eAAe,KAAA,CAAM,MAAO,EAAG,WAAW,CAAC,CAC/C,IAGK,CACL,EAAmB,GAAY,GAAM,IAAM,GAAc,CAAc,GACvE,EAAmB,GAAY,GAAM,IAAO,GAAc,CAAc,CAC1E;AAAA,EACF,GAAG;AAAA,IAAC;AAAA,IAAkB;AAAA,IAAc;AAAA,IAAgB;AAAA,EAAI,CAAC,GAEnD,IAAmB;AAAA,IACvB,IAAI;AAAA,IACJ,UAAU,EAAK;AAAA,IACf,eAAe;AAAA,IACf,UAAU;AAAA,IACV,yBAAyB;AAAA,IACzB,OAAO,EAAa,OAAA,CAAQ,GAAK,MAAQ,IAAM,EAAI,OAAO,CAAC;AAAA,IAC3D,gBAAgB,EAAa,OAAA,CAC1B,GAAS,OACR,OAAO,QAAQ,EAAI,cAAc,EAAE,QAAA,CAAS,CAAC,GAAO,CAAA,MAAY;AAC9D,MAAA,EAAQ,CAAA,KAAU,EAAQ,CAAA,KAAU,KAAK;AAAA,IAC3C,CAAC,GACM,IAET,CAAC,CACH;AAAA,EACF;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK;AAAA,IACL,IAAI;AAAA,MAAU,QAAA;AAAA,MAAQ,OAAO;AAAA,MAAQ,WAAW;AAAA,MAAQ,WAAW;AAAA,MAAQ,GAAG;AAAA,IAAG;AAAA,IAFnF,UAAA,EAII,CAAC,KAAmB,KAAkB,EAAe,cACrD,gBAAA,EAAC,GAAD;AAAA,MAAsB,SAAA;AAAA,MAAS,YAAY;AAAA,MAAY,MAAM;AAAA,IAAa,CAAA,IAE1E,CAAC,KAAmB,KAAkB,CAAC,EAAe,cACtD,gBAAA,EAAC,GAAD;AAAA,MACW,SAAA;AAAA,MACT,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,UAAU;AAAA,IACX,CAAA,CAEE;AAAA;AAEX"}
@@ -1,12 +1,10 @@
1
- import { DetailedCategory } from '../../../core';
2
1
  import { GridColDef } from '@mui/x-data-grid-pro';
3
2
  import { TrendsTableRow } from '../../utils/TrendsTable';
4
3
  interface TrendsTableProps {
5
4
  columns: GridColDef[];
6
5
  onRowClick?: (category: string) => void;
7
- parentCategory?: DetailedCategory;
8
6
  rows: TrendsTableRow[];
9
7
  totalRow?: TrendsTableRow;
10
8
  }
11
- export declare const TrendsTable: ({ columns, onRowClick, parentCategory, rows, totalRow, }: TrendsTableProps) => import("react/jsx-runtime").JSX.Element;
9
+ export declare const TrendsTable: ({ columns, onRowClick, rows, totalRow }: TrendsTableProps) => import("react/jsx-runtime").JSX.Element;
12
10
  export {};
@@ -1,37 +1,42 @@
1
- import { CategoryGuidToName as l } from "../../../core/constants/Category.es.js";
2
- import { useEvent as m } from "../../../common/context/hooks.es.js";
3
- import { ANALYTICS_EVENTS as u } from "../../../common/constants/Analytics.es.js";
4
- import { TRENDS_ANALYTICS_METADATA as c } from "../../constants/TrendsWidget.es.js";
5
- import { AccessibleSortIcon as b } from "./AccessibleSortIcon.es.js";
6
- import { jsx as g } from "react/jsx-runtime";
7
- import { useTheme as T } from "@mui/material/styles";
8
- import { DataGridPro as p } from "@mui/x-data-grid-pro";
9
- var y = ({ columns: t, onRowClick: i, parentCategory: s, rows: d, totalRow: o }) => {
10
- const n = T(), { onEvent: a } = m(), r = n.palette.mode === "light";
11
- return /* @__PURE__ */ g(p, {
1
+ import { CategoryGuidToName as m } from "../../../core/constants/Category.es.js";
2
+ import { useEvent as g } from "../../../common/context/hooks.es.js";
3
+ import { ANALYTICS_EVENTS as b } from "../../../common/constants/Analytics.es.js";
4
+ import { TRENDS_ANALYTICS_METADATA as f } from "../../constants/TrendsWidget.es.js";
5
+ import { AccessibleSortIcon as p } from "./AccessibleSortIcon.es.js";
6
+ import { jsx as T } from "react/jsx-runtime";
7
+ import { useTheme as _ } from "@mui/material/styles";
8
+ import { DataGridPro as y } from "@mui/x-data-grid-pro";
9
+ var t = (e) => e.id !== "total" && !e.isParent, D = ({ columns: e, onRowClick: i, rows: d, totalRow: a }) => {
10
+ const l = _(), { onEvent: u } = g(), n = l.palette.mode === "light", c = !!i, s = (r) => {
11
+ t(r) && (i?.(r.category_guid), u(b.TRENDS_CLICK_LIST_ITEM, {
12
+ ...f,
13
+ listItem: m[r.category_guid] ?? r.category,
14
+ destination: r.top_level_category_guid === r.category_guid ? "drill_down" : "drawer"
15
+ }));
16
+ };
17
+ return /* @__PURE__ */ T(y, {
12
18
  autoHeight: !0,
13
- columns: t,
19
+ columns: e,
14
20
  disableColumnFilter: !0,
15
21
  disableColumnMenu: !0,
22
+ getRowClassName: (r) => t(r.row) ? "" : "trends-row-static",
16
23
  hideFooter: !0,
17
24
  initialState: { sorting: { sortModel: [{
18
25
  field: "category",
19
26
  sort: "asc"
20
27
  }] } },
21
- onRowClick: (e) => {
22
- s || i?.(e.row.category_guid), a(u.TRENDS_CLICK_LIST_ITEM, {
23
- ...c,
24
- listItem: l[e.row.category_guid]
25
- });
28
+ onCellKeyDown: (r, o) => {
29
+ o.key !== "Enter" && o.key !== " " || t(r.row) && (o.preventDefault(), s(r.row));
26
30
  },
27
- pinnedRows: { bottom: o ? [o] : [] },
31
+ onRowClick: (r) => s(r.row),
32
+ pinnedRows: { bottom: a ? [a] : [] },
28
33
  rowHeight: 64,
29
34
  rows: d,
30
35
  slotProps: { baseIconButton: {
31
36
  color: "secondary",
32
37
  sx: { ml: 8 }
33
38
  } },
34
- slots: { columnHeaderSortIcon: b },
39
+ slots: { columnHeaderSortIcon: p },
35
40
  sortingOrder: ["asc", "desc"],
36
41
  sx: {
37
42
  borderColor: "divider",
@@ -39,15 +44,17 @@ var y = ({ columns: t, onRowClick: i, parentCategory: s, rows: d, totalRow: o })
39
44
  borderStyle: "solid",
40
45
  borderRadius: 2,
41
46
  "& .MuiDataGrid-columnHeaders": {
42
- bgcolor: r ? "neutral.50" : "neutral.800",
47
+ bgcolor: n ? "neutral.50" : "neutral.800",
43
48
  borderBottom: "none"
44
49
  },
45
- "& .trends-table-header": { bgcolor: r ? "neutral.50" : "neutral.800" }
50
+ "& .trends-table-header": { bgcolor: n ? "neutral.50" : "neutral.800" },
51
+ "& .MuiDataGrid-row": { cursor: c ? "pointer" : "default" },
52
+ "& .trends-row-static": { cursor: "default" }
46
53
  }
47
54
  });
48
55
  };
49
56
  export {
50
- y as TrendsTable
57
+ D as TrendsTable
51
58
  };
52
59
 
53
60
  //# sourceMappingURL=TrendsTable.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TrendsTable.es.js","names":[],"sources":["../../../../src/trends/components/trendstable/TrendsTable.tsx"],"sourcesContent":["import { ANALYTICS_EVENTS, useEvent } from '../../../common'\nimport { CategoryGuidToName } from '../../../core/constants'\nimport { DetailedCategory } from '../../../core'\nimport { TRENDS_ANALYTICS_METADATA } from '../../constants/TrendsWidget'\nimport { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'\nimport { useTheme } from '@mui/material/styles'\nimport { TrendsTableRow } from '../../utils/TrendsTable'\nimport { AccessibleSortIcon } from './AccessibleSortIcon'\n\ninterface TrendsTableProps {\n columns: GridColDef[]\n onRowClick?: (category: string) => void\n parentCategory?: DetailedCategory\n rows: TrendsTableRow[]\n totalRow?: TrendsTableRow\n}\n\nexport const TrendsTable = ({\n columns,\n onRowClick,\n parentCategory,\n rows,\n totalRow,\n}: TrendsTableProps) => {\n const theme = useTheme()\n const { onEvent } = useEvent()\n const isLightMode = theme.palette.mode === 'light'\n\n return (\n <DataGridPro\n // autoHeight sizes the grid to its content instead of measuring a flex\n // parent. The parent is an overflow:auto Stack with no fixed height, so the\n // default virtualized layout makes x-data-grid's useGridDimensions loop on\n // its own ResizeObserver measurement (a feedback loop that spikes to React's\n // \"Maximum update depth exceeded\" under a starved CI worker in jsdom). Content\n // sizing removes the measurement feedback and is correct for this unbounded,\n // page-scrolling table.\n autoHeight={true}\n columns={columns}\n disableColumnFilter={true}\n disableColumnMenu={true}\n hideFooter={true}\n initialState={{ sorting: { sortModel: [{ field: 'category', sort: 'asc' }] } }}\n onRowClick={(r) => {\n if (!parentCategory) {\n onRowClick?.(r.row.category_guid)\n }\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_LIST_ITEM, {\n ...TRENDS_ANALYTICS_METADATA,\n listItem: CategoryGuidToName[r.row.category_guid],\n })\n }}\n pinnedRows={{\n bottom: totalRow ? [totalRow] : [],\n }}\n rowHeight={64}\n rows={rows}\n slotProps={{ baseIconButton: { color: 'secondary', sx: { ml: 8 } } }}\n slots={{ columnHeaderSortIcon: AccessibleSortIcon }}\n sortingOrder={['asc', 'desc']}\n sx={{\n borderColor: 'divider',\n borderWidth: 1,\n borderStyle: 'solid',\n borderRadius: 2,\n '& .MuiDataGrid-columnHeaders': {\n bgcolor: isLightMode ? 'neutral.50' : 'neutral.800',\n borderBottom: 'none',\n },\n '& .trends-table-header': {\n bgcolor: isLightMode ? 'neutral.50' : 'neutral.800',\n },\n }}\n />\n )\n}\n"],"mappings":";;;;;;;;AAiBA,IAAa,IAAA,CAAe,EAC1B,SAAA,GACA,YAAA,GACA,gBAAA,GACA,MAAA,GACA,UAAA,EAAA,MACsB;AACtB,QAAM,IAAQ,EAAS,GACjB,EAAE,SAAA,EAAA,IAAY,EAAS,GACvB,IAAc,EAAM,QAAQ,SAAS;AAE3C,SACE,gBAAA,EAAC,GAAD;AAAA,IAQE,YAAY;AAAA,IACH,SAAA;AAAA,IACT,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,cAAc,EAAE,SAAS,EAAE,WAAW,CAAC;AAAA,MAAE,OAAO;AAAA,MAAY,MAAM;AAAA,IAAM,CAAC,EAAE,EAAE;AAAA,IAC7E,YAAA,CAAa,MAAM;AACjB,MAAK,KACH,IAAa,EAAE,IAAI,aAAa,GAElC,EAAQ,EAAiB,wBAAwB;AAAA,QAC/C,GAAG;AAAA,QACH,UAAU,EAAmB,EAAE,IAAI,aAAA;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IACA,YAAY,EACV,QAAQ,IAAW,CAAC,CAAQ,IAAI,CAAC,EACnC;AAAA,IACA,WAAW;AAAA,IACL,MAAA;AAAA,IACN,WAAW,EAAE,gBAAgB;AAAA,MAAE,OAAO;AAAA,MAAa,IAAI,EAAE,IAAI,EAAE;AAAA,IAAE,EAAE;AAAA,IACnE,OAAO,EAAE,sBAAsB,EAAmB;AAAA,IAClD,cAAc,CAAC,OAAO,MAAM;AAAA,IAC5B,IAAI;AAAA,MACF,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,gCAAgC;AAAA,QAC9B,SAAS,IAAc,eAAe;AAAA,QACtC,cAAc;AAAA,MAChB;AAAA,MACA,0BAA0B,EACxB,SAAS,IAAc,eAAe,cACxC;AAAA,IACF;AAAA,EACD,CAAA;AAEL"}
1
+ {"version":3,"file":"TrendsTable.es.js","names":[],"sources":["../../../../src/trends/components/trendstable/TrendsTable.tsx"],"sourcesContent":["import { ANALYTICS_EVENTS, useEvent } from '../../../common'\nimport { CategoryGuidToName } from '../../../core/constants'\nimport { TRENDS_ANALYTICS_METADATA } from '../../constants/TrendsWidget'\nimport { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'\nimport { useTheme } from '@mui/material/styles'\nimport { TrendsTableRow } from '../../utils/TrendsTable'\nimport { AccessibleSortIcon } from './AccessibleSortIcon'\n\ninterface TrendsTableProps {\n columns: GridColDef[]\n onRowClick?: (category: string) => void\n rows: TrendsTableRow[]\n totalRow?: TrendsTableRow\n}\n\n// The pinned total row and the synthetic \"General [Parent]\" row (isParent: true,\n// only present in a drilled-in table) are summaries, not navigation destinations.\nconst isRowNavigable = (row: TrendsTableRow) => row.id !== 'total' && !row.isParent\n\nexport const TrendsTable = ({ columns, onRowClick, rows, totalRow }: TrendsTableProps) => {\n const theme = useTheme()\n const { onEvent } = useEvent()\n const isLightMode = theme.palette.mode === 'light'\n const isRowInteractive = Boolean(onRowClick)\n\n // Shared by pointer and keyboard activation; non-navigable rows are dropped so\n // neither path acts on them.\n const activateRow = (row: TrendsTableRow) => {\n if (!isRowNavigable(row)) return\n onRowClick?.(row.category_guid)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_LIST_ITEM, {\n ...TRENDS_ANALYTICS_METADATA,\n // Fall back to the row's display name for user-created categories, which\n // are absent from the static default-category map.\n listItem: CategoryGuidToName[row.category_guid] ?? row.category,\n // A top-level row (guid is its own top level) drills down; a sub-category\n // row opens the drawer.\n destination: row.top_level_category_guid === row.category_guid ? 'drill_down' : 'drawer',\n })\n }\n\n return (\n <DataGridPro\n // autoHeight sizes the grid to its content instead of measuring a flex\n // parent. The parent is an overflow:auto Stack with no fixed height, so the\n // default virtualized layout makes x-data-grid's useGridDimensions loop on\n // its own ResizeObserver measurement (a feedback loop that spikes to React's\n // \"Maximum update depth exceeded\" under a starved CI worker in jsdom). Content\n // sizing removes the measurement feedback and is correct for this unbounded,\n // page-scrolling table.\n autoHeight={true}\n columns={columns}\n disableColumnFilter={true}\n disableColumnMenu={true}\n getRowClassName={(params) => (isRowNavigable(params.row) ? '' : 'trends-row-static')}\n hideFooter={true}\n initialState={{ sorting: { sortModel: [{ field: 'category', sort: 'asc' }] } }}\n onCellKeyDown={(params, event) => {\n // Rows are reachable only by grid cell navigation, so Enter/Space on a\n // cell is the keyboard equivalent of clicking the row. Guard before\n // preventDefault so a non-navigable row keeps the grid's native key\n // handling instead of being swallowed with no action. Space would\n // otherwise scroll the grid.\n if (event.key !== 'Enter' && event.key !== ' ') return\n if (!isRowNavigable(params.row)) return\n event.preventDefault()\n activateRow(params.row)\n }}\n onRowClick={(r) => activateRow(r.row)}\n pinnedRows={{\n bottom: totalRow ? [totalRow] : [],\n }}\n rowHeight={64}\n rows={rows}\n slotProps={{ baseIconButton: { color: 'secondary', sx: { ml: 8 } } }}\n slots={{ columnHeaderSortIcon: AccessibleSortIcon }}\n sortingOrder={['asc', 'desc']}\n sx={{\n borderColor: 'divider',\n borderWidth: 1,\n borderStyle: 'solid',\n borderRadius: 2,\n '& .MuiDataGrid-columnHeaders': {\n bgcolor: isLightMode ? 'neutral.50' : 'neutral.800',\n borderBottom: 'none',\n },\n '& .trends-table-header': {\n bgcolor: isLightMode ? 'neutral.50' : 'neutral.800',\n },\n '& .MuiDataGrid-row': { cursor: isRowInteractive ? 'pointer' : 'default' },\n // getRowClassName stamps trends-row-static on every non-navigable row,\n // including the pinned total row.\n '& .trends-row-static': { cursor: 'default' },\n }}\n />\n )\n}\n"],"mappings":";;;;;;;;AAiBA,IAAM,IAAA,CAAkB,MAAwB,EAAI,OAAO,WAAW,CAAC,EAAI,UAE9D,IAAA,CAAe,EAAE,SAAA,GAAS,YAAA,GAAY,MAAA,GAAM,UAAA,EAAA,MAAiC;AACxF,QAAM,IAAQ,EAAS,GACjB,EAAE,SAAA,EAAA,IAAY,EAAS,GACvB,IAAc,EAAM,QAAQ,SAAS,SACrC,IAAmB,EAAQ,GAI3B,IAAA,CAAe,MAAwB;AAC3C,IAAK,EAAe,CAAG,MACvB,IAAa,EAAI,aAAa,GAC9B,EAAQ,EAAiB,wBAAwB;AAAA,MAC/C,GAAG;AAAA,MAGH,UAAU,EAAmB,EAAI,aAAA,KAAkB,EAAI;AAAA,MAGvD,aAAa,EAAI,4BAA4B,EAAI,gBAAgB,eAAe;AAAA,IAClF,CAAC;AAAA,EACH;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IAQE,YAAY;AAAA,IACH,SAAA;AAAA,IACT,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAA,CAAkB,MAAY,EAAe,EAAO,GAAG,IAAI,KAAK;AAAA,IAChE,YAAY;AAAA,IACZ,cAAc,EAAE,SAAS,EAAE,WAAW,CAAC;AAAA,MAAE,OAAO;AAAA,MAAY,MAAM;AAAA,IAAM,CAAC,EAAE,EAAE;AAAA,IAC7E,eAAA,CAAgB,GAAQ,MAAU;AAMhC,MAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,OACtC,EAAe,EAAO,GAAG,MAC9B,EAAM,eAAe,GACrB,EAAY,EAAO,GAAG;AAAA,IACxB;AAAA,IACA,YAAA,CAAa,MAAM,EAAY,EAAE,GAAG;AAAA,IACpC,YAAY,EACV,QAAQ,IAAW,CAAC,CAAQ,IAAI,CAAC,EACnC;AAAA,IACA,WAAW;AAAA,IACL,MAAA;AAAA,IACN,WAAW,EAAE,gBAAgB;AAAA,MAAE,OAAO;AAAA,MAAa,IAAI,EAAE,IAAI,EAAE;AAAA,IAAE,EAAE;AAAA,IACnE,OAAO,EAAE,sBAAsB,EAAmB;AAAA,IAClD,cAAc,CAAC,OAAO,MAAM;AAAA,IAC5B,IAAI;AAAA,MACF,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,gCAAgC;AAAA,QAC9B,SAAS,IAAc,eAAe;AAAA,QACtC,cAAc;AAAA,MAChB;AAAA,MACA,0BAA0B,EACxB,SAAS,IAAc,eAAe,cACxC;AAAA,MACA,sBAAsB,EAAE,QAAQ,IAAmB,YAAY,UAAU;AAAA,MAGzE,wBAAwB,EAAE,QAAQ,UAAU;AAAA,IAC9C;AAAA,EACD,CAAA;AAEL"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.4.62",
3
+ "version": "9.4.63",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",