@mx-cartographer/experiences 9.4.37 → 9.4.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,133 +1,136 @@
1
- import { useAccountStore as Te, useAppConfig as Se, useCategoryStore as Ee, useEvent as ye, useGlobalCopyStore as we, useGlobalStore as De, useGlobalUiStore as Le, useTransactionStore as be, useTrendsStore as Ae } from "../common/context/hooks.es.js";
2
- import { useInsightsEnabled as Ie } from "../common/hooks/useInsightsEnabled.es.js";
3
- import { useScreenSize as Re } from "../common/hooks/useScreenSize.es.js";
4
- import { useWidgetLoadTimer as ve } from "../common/hooks/useWidgetLoadTimer.es.js";
5
- import xe from "../common/components/drawer/Drawer.es.js";
6
- import { ANALYTICS_EVENTS as a } from "../common/constants/Analytics.es.js";
7
- import Ne from "../common/components/Loader.es.js";
8
- import { WidgetContainer as Be } from "../common/components/WidgetContainer.es.js";
9
- import We from "../common/components/ConnectDrawer.es.js";
10
- import { EmptyState as ke } from "../common/components/EmptyState.es.js";
11
- import { TRENDS_ANALYTICS_METADATA as d } from "./constants/TrendsWidget.es.js";
12
- import He from "./components/TrendsViewToggle.es.js";
13
- import Ge from "./components/DateRangeText.es.js";
14
- import Fe from "./components/TrendsTableContainer.es.js";
15
- import Me from "./components/CategoriesList.es.js";
16
- import Oe from "./components/TrendsInsights.es.js";
17
- import { CategoryDetails as Ve } from "./components/CategoryDetails.es.js";
18
- import ze from "./components/TrendsChartTotals.es.js";
19
- import { TRENDS_BEAT_TEMPLATES as Ke } from "./constants/TrendsInsights.es.js";
20
- import { buildEmptyStateProps as je } from "./utils/TrendsWidget.es.js";
21
- import i from "react";
22
- import { observer as Pe } from "mobx-react-lite";
1
+ import { useAccountStore as Ee, useAppConfig as ye, useCategoryStore as we, useEvent as De, useGlobalCopyStore as Le, useGlobalStore as be, useGlobalUiStore as Ie, useTransactionStore as Ae, useTrendsStore as Re } from "../common/context/hooks.es.js";
2
+ import { useInsightsEnabled as ve } from "../common/hooks/useInsightsEnabled.es.js";
3
+ import { useScreenSize as xe } from "../common/hooks/useScreenSize.es.js";
4
+ import { useWidgetLoadTimer as Ne } from "../common/hooks/useWidgetLoadTimer.es.js";
5
+ import Be from "../common/components/drawer/Drawer.es.js";
6
+ import { ANALYTICS_EVENTS as c } from "../common/constants/Analytics.es.js";
7
+ import We from "../common/components/Loader.es.js";
8
+ import { WidgetContainer as ke } from "../common/components/WidgetContainer.es.js";
9
+ import He from "../common/components/ConnectDrawer.es.js";
10
+ import { EmptyState as Ge } from "../common/components/EmptyState.es.js";
11
+ import { TRENDS_ANALYTICS_METADATA as m } from "./constants/TrendsWidget.es.js";
12
+ import Fe from "./components/TrendsViewToggle.es.js";
13
+ import Me from "./components/DateRangeText.es.js";
14
+ import Oe from "./components/TrendsTableContainer.es.js";
15
+ import Ve from "./components/CategoriesList.es.js";
16
+ import ze from "./components/TrendsInsights.es.js";
17
+ import { CategoryDetails as Ke } from "./components/CategoryDetails.es.js";
18
+ import je from "./components/TrendsChartTotals.es.js";
19
+ import { TRENDS_BEAT_TEMPLATES as Pe } from "./constants/TrendsInsights.es.js";
20
+ import { buildEmptyStateProps as Ue } from "./utils/TrendsWidget.es.js";
21
+ import o from "react";
22
+ import { observer as Ye } from "mobx-react-lite";
23
23
  import f from "@mui/material/Stack";
24
- import Ue from "@mui/material/Button";
25
- import { ArrowBack as Ye } from "@mxenabled/mx-icons";
26
- import { Fragment as $e, jsx as t, jsxs as c } from "react/jsx-runtime";
24
+ import $e from "@mui/material/Button";
25
+ import { ArrowBack as qe } from "@mxenabled/mx-icons";
26
+ import { Fragment as Je, jsx as t, jsxs as l } from "react/jsx-runtime";
27
27
  import w from "@mui/material/Box";
28
- import { differenceInCalendarMonths as H } from "date-fns/differenceInCalendarMonths";
29
- import { addSeconds as qe } from "date-fns/addSeconds";
30
- var Je = ({ onBackClick: G, onMenuClick: F, onInsightCardClick: M, sx: O }) => {
31
- const { onEvent: s } = ye(), { config: D } = Se(), { isDesktop: V, isLargeDesktop: z, isMobile: C } = Re(), { isAccountDataLoaded: u, loadAccountData: K, visibleAccounts: j } = Te(), { categoriesLoaded: P, loadCategories: U, monthlyCategoryTotals: m, monthlyTotalsLoaded: Y, reloadCategoryTotals: $ } = Ee(), { isTransactionDataLoaded: q, loadTransactionData: J, setFilter: Q } = be(), { selectedCategoryData: _, selectedDateRange: o, setSelectedCategoryData: L, setSelectedDateRange: X } = Ae(), { isInitialized: T, selectedAccounts: Z, selectedAccountGuids: b } = Le(), { trends: l, connect: ee } = we(), { beatStore: A } = De(), I = Ie() && D.show_insights_widget_in_master, g = V || z, [R, te] = i.useState(!1), [S, oe] = i.useState(!1), [h, ie] = i.useState("Chart"), [E, v] = i.useState(""), [x, ne] = i.useState(window.innerHeight), re = g ? 56 : 0, N = x - 208, se = x - (I ? 550 + re : 266), [ae, B] = i.useState(!1), ce = D.show_connections_widget_in_master, y = i.useRef(void 0), le = i.useCallback((e) => {
28
+ import { differenceInCalendarMonths as F } from "date-fns/differenceInCalendarMonths";
29
+ import { addSeconds as Qe } from "date-fns/addSeconds";
30
+ var Xe = ({ onBackClick: M, onMenuClick: O, onInsightCardClick: V, sx: z }) => {
31
+ const { onEvent: s } = De(), { config: D } = ye(), { isDesktop: K, isLargeDesktop: j, isMobile: C } = xe(), { isAccountDataLoaded: u, loadAccountData: P, visibleAccounts: U } = Ee(), { categoriesLoaded: Y, loadCategories: $, monthlyCategoryTotals: a, monthlyTotalsLoaded: q, reloadCategoryTotals: J } = we(), { isTransactionDataLoaded: Q, loadTransactionData: X, setFilter: Z } = Ae(), { isTransactionStoreIdle: L, selectedCategoryData: T, selectedDateRange: n, setSelectedCategoryData: b, setSelectedDateRange: ee } = Re(), { isInitialized: _, selectedAccounts: te, selectedAccountGuids: I } = Ie(), { trends: d, connect: oe } = Le(), { beatStore: A } = be(), R = ve() && D.show_insights_widget_in_master, g = K || j, [v, ne] = o.useState(!1), [S, ie] = o.useState(!1), [h, re] = o.useState("Chart"), [E, x] = o.useState(""), [N, se] = o.useState(window.innerHeight), ae = g ? 56 : 0, B = N - 208, ce = N - (R ? 550 + ae : 266), [le, W] = o.useState(!1), de = D.show_connections_widget_in_master, y = o.useRef(void 0), me = o.useCallback((e) => {
32
32
  if (y.current?.(), y.current = void 0, !e) return;
33
- const n = (r) => {
33
+ const i = (r) => {
34
34
  r.target instanceof HTMLElement && r.target.matches(":focus-visible") && r.target.scrollIntoView({ block: "nearest" });
35
35
  };
36
- e.addEventListener("focusin", n), y.current = () => e.removeEventListener("focusin", n);
36
+ e.addEventListener("focusin", i), y.current = () => e.removeEventListener("focusin", i);
37
37
  }, []);
38
- ve({
38
+ Ne({
39
39
  widgetName: "TrendsWidget",
40
- isLoaded: R
40
+ isLoaded: v
41
41
  });
42
- const W = i.useMemo(() => S ? A.getFilteredBeats({ templates: Ke }) : [], [S]);
43
- i.useEffect(() => {
44
- const e = () => ne(window.innerHeight);
45
- return window.addEventListener("resize", e), u || K().finally(), P || U().finally(), q || J().finally(), () => window.removeEventListener("resize", e);
46
- }, []), i.useEffect(() => {
47
- T && u && (A.loadBeats().finally(() => oe(!0)), $(Z, o.start, o.end).finally(() => {
48
- te(!0), s(a.TRENDS_LOAD_WIDGET, {
49
- ...d,
50
- time_period: `${H(o.end, o.start)}M`
42
+ const k = o.useMemo(() => S ? A.getFilteredBeats({ templates: Pe }) : [], [S]);
43
+ o.useEffect(() => {
44
+ const e = () => se(window.innerHeight);
45
+ return window.addEventListener("resize", e), u || P().finally(), Y || $().finally(), Q || X().finally(), () => window.removeEventListener("resize", e);
46
+ }, []), o.useEffect(() => {
47
+ _ && u && (A.loadBeats().finally(() => ie(!0)), J(te, n.start, n.end).finally(() => {
48
+ ne(!0), s(c.TRENDS_LOAD_WIDGET, {
49
+ ...m,
50
+ time_period: `${F(n.end, n.start)}M`
51
51
  });
52
52
  }));
53
53
  }, [
54
- T,
54
+ _,
55
55
  u,
56
- b.join(","),
57
- o.start.getTime(),
58
- o.end.getTime()
59
- ]), i.useEffect(() => {
60
- if (m.length !== 0) {
56
+ I.join(","),
57
+ n.start.getTime(),
58
+ n.end.getTime()
59
+ ]);
60
+ const H = o.useRef(null);
61
+ o.useEffect(() => {
62
+ if (a.length !== 0 && L && H.current !== a) {
63
+ H.current = a;
61
64
  const e = {
62
- accounts: b,
65
+ accounts: I,
63
66
  dateRange: {
64
- start: o.start,
65
- end: o.end
67
+ start: n.start,
68
+ end: n.end
66
69
  }
67
70
  };
68
- Q({
71
+ Z({
69
72
  ...e,
70
- custom: (n) => !!m.find((r) => r.top_level_category_guid === n.top_level_category_guid || r.category_guid === n.category_guid)
73
+ custom: (i) => !!a.find((r) => r.top_level_category_guid === i.top_level_category_guid || r.category_guid === i.category_guid)
71
74
  });
72
75
  }
73
- }, [m]);
74
- const de = (e) => {
75
- L(e);
76
- }, me = () => {
77
- L(null), s(a.TRENDS_CLICK_BACK, d);
78
- }, ge = () => {
79
- B(!0), s(a.TRENDS_CLICK_CONNECT_ACCOUNTS);
80
- }, fe = (e, n) => {
81
- ie(n ?? h), s(a.TRENDS_CLICK_TOGGLE_VIEW, {
82
- ...d,
83
- toggleView: n
76
+ }, [a, L]);
77
+ const ge = (e) => {
78
+ b(e);
79
+ }, fe = () => {
80
+ b(null), s(c.TRENDS_CLICK_BACK, m);
81
+ }, ue = () => {
82
+ W(!0), s(c.TRENDS_CLICK_CONNECT_ACCOUNTS);
83
+ }, he = (e, i) => {
84
+ re(i ?? h), s(c.TRENDS_CLICK_TOGGLE_VIEW, {
85
+ ...m,
86
+ toggleView: i
84
87
  });
85
- }, ue = (e) => {
86
- const n = qe(e?.[0], 1), r = e?.[1], _e = H(r, n);
87
- X({
88
- start: n,
88
+ }, pe = (e) => {
89
+ const i = Qe(e?.[0], 1), r = e?.[1], Se = F(r, i);
90
+ ee({
91
+ start: i,
89
92
  end: r
90
- }), s(a.TRENDS_CLICK_TIME_WINDOW, {
91
- ...d,
92
- time_period: _e + "M"
93
+ }), s(c.TRENDS_CLICK_TIME_WINDOW, {
94
+ ...m,
95
+ time_period: Se + "M"
93
96
  });
94
- }, he = (e) => {
95
- s(a.TRENDS_CLICK_FILTER, {
96
- ...d,
97
+ }, Ce = (e) => {
98
+ s(c.TRENDS_CLICK_FILTER, {
99
+ ...m,
97
100
  filterValue: e
98
101
  });
99
- }, pe = (e) => {
100
- v(e);
101
- }, Ce = () => {
102
- v(""), s(a.TRENDS_CLICK_ALL_CATEGORIES, d);
102
+ }, Te = (e) => {
103
+ x(e);
104
+ }, _e = () => {
105
+ x(""), s(c.TRENDS_CLICK_ALL_CATEGORIES, m);
103
106
  };
104
- if (!T || !u || !R || !Y) return /* @__PURE__ */ t(Ne, {});
105
- const k = j.length === 0 || m.length === 0, p = je(l, ce, ge);
106
- return /* @__PURE__ */ c(Be, {
107
- calendarActions: { onRangeChanged: ue },
108
- dateRange: o,
107
+ if (!_ || !u || !v || !q) return /* @__PURE__ */ t(We, {});
108
+ const G = U.length === 0 || a.length === 0, p = Ue(d, de, ue);
109
+ return /* @__PURE__ */ l(ke, {
110
+ calendarActions: { onRangeChanged: pe },
111
+ dateRange: n,
109
112
  dateRangeVariant: C ? "timeframetabs" : "timeframebuttons",
110
- onAccountsFilterClick: he,
111
- onBackClick: G,
112
- onMenuClick: F,
113
- sx: O,
114
- title: l.title,
115
- children: [/* @__PURE__ */ c(f, {
116
- ref: le,
113
+ onAccountsFilterClick: Ce,
114
+ onBackClick: M,
115
+ onMenuClick: O,
116
+ sx: z,
117
+ title: d.title,
118
+ children: [/* @__PURE__ */ l(f, {
119
+ ref: me,
117
120
  sx: { px: C ? 0 : 48 },
118
121
  children: [
119
- /* @__PURE__ */ c(f, {
122
+ /* @__PURE__ */ l(f, {
120
123
  flexDirection: "row",
121
124
  justifyContent: "space-between",
122
125
  sx: {
123
126
  px: C ? 16 : 0,
124
127
  py: 16
125
128
  },
126
- children: [/* @__PURE__ */ t(Ge, {
129
+ children: [/* @__PURE__ */ t(Me, {
127
130
  selectedCategoryGuid: E,
128
- selectedDateRange: o
129
- }), /* @__PURE__ */ t(He, {
130
- onTabChange: fe,
131
+ selectedDateRange: n
132
+ }), /* @__PURE__ */ t(Fe, {
133
+ onTabChange: he,
131
134
  selectedTab: h
132
135
  })]
133
136
  }),
@@ -138,76 +141,76 @@ var Je = ({ onBackClick: G, onMenuClick: F, onInsightCardClick: M, sx: O }) => {
138
141
  width: "100%",
139
142
  children: /* @__PURE__ */ t(w, {
140
143
  flexGrow: 1,
141
- children: E && /* @__PURE__ */ c(Ue, {
142
- onClick: Ce,
144
+ children: E && /* @__PURE__ */ l($e, {
145
+ onClick: _e,
143
146
  sx: {
144
147
  p: 0,
145
148
  pr: 5
146
149
  },
147
- children: [/* @__PURE__ */ t(Ye, {}), l.all_categories]
150
+ children: [/* @__PURE__ */ t(qe, {}), d.all_categories]
148
151
  })
149
152
  })
150
153
  }),
151
- k && /* @__PURE__ */ t(ke, {
154
+ G && /* @__PURE__ */ t(Ge, {
152
155
  header: p.header,
153
156
  icon: "multiline_chart",
154
157
  onClick: p.onClickHandler,
155
158
  primaryButton: p.primaryButton,
156
159
  subText: p.description,
157
160
  sx: {
158
- height: N,
161
+ height: B,
159
162
  maxWidth: 432
160
163
  }
161
164
  }),
162
- !k && /* @__PURE__ */ c(f, {
165
+ !G && /* @__PURE__ */ l(f, {
163
166
  flexDirection: g ? "row" : "column",
164
167
  gap: g ? 48 : 16,
165
- children: [h === "Chart" && /* @__PURE__ */ c($e, { children: [/* @__PURE__ */ t(w, {
168
+ children: [h === "Chart" && /* @__PURE__ */ l(Je, { children: [/* @__PURE__ */ t(w, {
166
169
  sx: { width: g ? "68%" : "100%" },
167
- children: /* @__PURE__ */ t(ze, {
168
- availableHeight: N,
170
+ children: /* @__PURE__ */ t(je, {
171
+ availableHeight: B,
169
172
  minHeight: 450,
170
- selectedDateRange: o,
171
- totals: m
173
+ selectedDateRange: n,
174
+ totals: a
172
175
  })
173
- }), /* @__PURE__ */ c(f, {
176
+ }), /* @__PURE__ */ l(f, {
174
177
  gap: 16,
175
178
  sx: { width: g ? "32%" : "100%" },
176
- children: [I && S && W.length > 0 && /* @__PURE__ */ t(Oe, {
177
- beats: W,
178
- onInsightCardClick: M
179
- }), /* @__PURE__ */ t(Me, {
180
- availableHeight: se,
181
- onCategoryClick: de
179
+ children: [R && S && k.length > 0 && /* @__PURE__ */ t(ze, {
180
+ beats: k,
181
+ onInsightCardClick: V
182
+ }), /* @__PURE__ */ t(Ve, {
183
+ availableHeight: ce,
184
+ onCategoryClick: ge
182
185
  })]
183
186
  })] }), h === "Table" && /* @__PURE__ */ t(w, {
184
187
  sx: { width: "100%" },
185
- children: /* @__PURE__ */ t(Fe, {
188
+ children: /* @__PURE__ */ t(Oe, {
186
189
  height: "unset",
187
- onClickRow: pe,
190
+ onClickRow: Te,
188
191
  selectedCategory: E,
189
- selectedDateRange: o
192
+ selectedDateRange: n
190
193
  })
191
194
  })]
192
195
  }),
193
- /* @__PURE__ */ t(xe, {
194
- ariaLabelClose: l.close_category_details,
195
- isOpen: !!_,
196
- onClose: me,
196
+ /* @__PURE__ */ t(Be, {
197
+ ariaLabelClose: d.close_category_details,
198
+ isOpen: !!T,
199
+ onClose: fe,
197
200
  shouldShowHeaderShadow: !0,
198
- title: _?.is_income ? l.category_income : l.category_spending,
199
- children: _ && /* @__PURE__ */ t(Ve, {})
201
+ title: T?.is_income ? d.category_income : d.category_spending,
202
+ children: T && /* @__PURE__ */ t(Ke, {})
200
203
  })
201
204
  ]
202
- }), /* @__PURE__ */ t(We, {
203
- onClose: () => B(!1),
204
- showConnectWidget: ae,
205
- title: ee.mini_title
205
+ }), /* @__PURE__ */ t(He, {
206
+ onClose: () => W(!1),
207
+ showConnectWidget: le,
208
+ title: oe.mini_title
206
209
  })]
207
210
  });
208
- }, bt = Pe(Je);
211
+ }, At = Ye(Xe);
209
212
  export {
210
- bt as default
213
+ At as default
211
214
  };
212
215
 
213
216
  //# sourceMappingURL=TrendsWidget.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TrendsWidget.es.js","names":[],"sources":["../../src/trends/TrendsWidget.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport React from 'react'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\n\nimport { DateRange } from '@mui/x-date-pickers-pro'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\n\nimport { ArrowBack } from '@mxenabled/mx-icons'\n\nimport {\n ANALYTICS_EVENTS,\n ConnectDrawer,\n Drawer,\n EmptyState,\n Loader,\n WidgetContainer,\n useAccountStore,\n useAppConfig,\n useCategoryStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalStore,\n useGlobalUiStore,\n useInsightsEnabled,\n useScreenSize,\n useTransactionStore,\n useTrendsStore,\n useWidgetLoadTimer,\n} from '../common'\nimport { type Beat, type DetailedCategoryWithTransactions, Transaction, WidgetProps } from '../core'\n\nimport DateRangeText from './components/DateRangeText'\nimport TrendsViewToggle, { type TrendsTabValue } from './components/TrendsViewToggle'\nimport TrendsTableContainer from './components/TrendsTableContainer'\nimport CategoriesList from './components/CategoriesList'\nimport InsightsCarousel from './components/TrendsInsights'\nimport { CategoryDetails } from './components/CategoryDetails'\nimport TrendsChartTotals from './components/TrendsChartTotals'\nimport { TRENDS_ANALYTICS_METADATA } from './constants/TrendsWidget'\nimport { TRENDS_BEAT_TEMPLATES } from './constants/TrendsInsights'\nimport { buildEmptyStateProps } from './utils/TrendsWidget'\n\ninterface TrendsWidgetProps extends WidgetProps {\n onInsightCardClick?: (beat?: Beat) => void\n}\n\nconst TrendsWidget: React.FC<TrendsWidgetProps> = ({\n onBackClick,\n onMenuClick,\n onInsightCardClick,\n sx,\n}) => {\n const { onEvent } = useEvent()\n const { config } = useAppConfig()\n const { isDesktop, isLargeDesktop, isMobile } = useScreenSize()\n const { isAccountDataLoaded, loadAccountData, visibleAccounts: accounts } = useAccountStore()\n const {\n categoriesLoaded,\n loadCategories,\n monthlyCategoryTotals,\n monthlyTotalsLoaded,\n reloadCategoryTotals,\n } = useCategoryStore()\n const { isTransactionDataLoaded, loadTransactionData, setFilter } = useTransactionStore()\n const { selectedCategoryData, selectedDateRange, setSelectedCategoryData, setSelectedDateRange } =\n useTrendsStore()\n const { isInitialized, selectedAccounts, selectedAccountGuids } = useGlobalUiStore()\n const { trends: copy, connect: connectCopy } = useGlobalCopyStore()\n const { beatStore } = useGlobalStore()\n const insightsEnabled = useInsightsEnabled()\n\n // allows clients to disable insights in trends while still enabling insights\n const showInsights = insightsEnabled && config.show_insights_widget_in_master\n const isLargeLayout = isDesktop || isLargeDesktop\n\n const [isWidgetInitialized, setIsWidgetInitialized] = React.useState(false)\n const [isBeatsLoaded, setIsBeatsLoaded] = React.useState(false)\n const [selectedTab, setSelectedTab] = React.useState<TrendsTabValue>('Chart')\n const [selectedCategory, setSelectedCategory] = React.useState('')\n\n // Control responsive chart height based on available widget iframe viewport height\n const [viewportHeight, setViewportHeight] = React.useState(window.innerHeight)\n const insightsPadding = isLargeLayout ? 56 : 0\n const availableChartHeight = viewportHeight - 208 // unavailable height on desktop\n const availableListHeight = viewportHeight - (showInsights ? 550 + insightsPadding : 266)\n\n const [showConnectWidget, setShowConnectWidget] = React.useState(false)\n const hasAggregation = config.show_connections_widget_in_master\n\n // iOS Safari doesn't scroll off-screen elements into view on forward Tab\n // inside this non-document scroll container. `:focus-visible` limits the\n // scroll to keyboard focus so pointer clicks on clipped rows don't jump.\n // `block: 'nearest'` is a no-op when already visible. Callback ref (not\n // useEffect) because the content mounts after the loading gate.\n const cleanupFocusScroll = React.useRef<(() => void) | undefined>(undefined)\n const contentRef = React.useCallback((node: HTMLDivElement | null) => {\n cleanupFocusScroll.current?.()\n cleanupFocusScroll.current = undefined\n\n if (!node) return\n\n const handleFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && event.target.matches(':focus-visible')) {\n event.target.scrollIntoView({ block: 'nearest' })\n }\n }\n\n node.addEventListener('focusin', handleFocusIn)\n cleanupFocusScroll.current = () => node.removeEventListener('focusin', handleFocusIn)\n }, [])\n\n useWidgetLoadTimer({\n widgetName: 'TrendsWidget',\n isLoaded: isWidgetInitialized,\n })\n const filteredBeats = React.useMemo(() => {\n if (!isBeatsLoaded) return []\n return beatStore.getFilteredBeats({ templates: TRENDS_BEAT_TEMPLATES })\n }, [isBeatsLoaded])\n\n React.useEffect(() => {\n // Setup resize listener for responsive chart and list heights\n const handleResize = () => setViewportHeight(window.innerHeight)\n window.addEventListener('resize', handleResize)\n\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n if (!categoriesLoaded) {\n loadCategories().finally()\n }\n if (!isTransactionDataLoaded) {\n loadTransactionData().finally()\n }\n\n return () => window.removeEventListener('resize', handleResize)\n }, [])\n\n // Initialize monthlyCategoryTotals, and reload on account or date range change.\n // Depends on primitives rather than `selectedAccounts` / `selectedDateRange`,\n // whose object identities change even when the values do not. (MEW-3910)\n //\n // Both totals are loaded in parallel rather than chaining monthly inside the\n // date-range `.then()`. Chaining defers the monthly request until the first\n // resolves, so a slow superseded range would claim the newest monthly request\n // token and write stale data over the current range. (MEW-3910)\n React.useEffect(() => {\n if (isInitialized && isAccountDataLoaded) {\n beatStore.loadBeats().finally(() => setIsBeatsLoaded(true))\n reloadCategoryTotals(\n selectedAccounts,\n selectedDateRange.start,\n selectedDateRange.end,\n ).finally(() => {\n setIsWidgetInitialized(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_LOAD_WIDGET, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: `${differenceInCalendarMonths(selectedDateRange.end, selectedDateRange.start)}M`,\n })\n })\n }\n }, [\n isInitialized,\n isAccountDataLoaded,\n selectedAccountGuids.join(','),\n selectedDateRange.start.getTime(),\n selectedDateRange.end.getTime(),\n ])\n React.useEffect(() => {\n // if monthlyCategoryTotals has data, filter transactions\n if (monthlyCategoryTotals.length !== 0) {\n const transactionFilter = {\n accounts: selectedAccountGuids,\n dateRange: { start: selectedDateRange.start, end: selectedDateRange.end },\n }\n\n // this filter sets sortedTransactions in the transaction store\n setFilter({\n ...transactionFilter,\n custom: (t: Transaction) =>\n Boolean(\n monthlyCategoryTotals.find(\n (cat) =>\n cat.top_level_category_guid === t.top_level_category_guid ||\n cat.category_guid === t.category_guid,\n ),\n ),\n })\n }\n }, [monthlyCategoryTotals])\n\n const handleDetailOpen = (selected: DetailedCategoryWithTransactions) => {\n setSelectedCategoryData(selected)\n }\n\n const handleDetailClose = () => {\n setSelectedCategoryData(null)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_BACK, TRENDS_ANALYTICS_METADATA)\n }\n\n const handleEmptyStateClick = () => {\n setShowConnectWidget(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_CONNECT_ACCOUNTS)\n }\n\n const onTabChange = (_event: React.SyntheticEvent, newValue: TrendsTabValue) => {\n setSelectedTab(newValue ?? selectedTab)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TOGGLE_VIEW, {\n ...TRENDS_ANALYTICS_METADATA,\n toggleView: newValue,\n })\n }\n\n const onRangeChanged = (dateRange: DateRange<Date>) => {\n const startDate = addSeconds(dateRange?.[0] as Date, 1)\n const endDate = dateRange?.[1] as Date\n const months = differenceInCalendarMonths(endDate, startDate)\n\n setSelectedDateRange({ start: startDate, end: endDate })\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TIME_WINDOW, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: months + 'M',\n })\n }\n\n const onAccountsFilterClick = (selectedAccountGuids?: string[]) => {\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_FILTER, {\n ...TRENDS_ANALYTICS_METADATA,\n filterValue: selectedAccountGuids,\n })\n }\n\n const onClickRow = (guid: string) => {\n setSelectedCategory(guid)\n }\n\n const onViewAllCategories = () => {\n setSelectedCategory('')\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_ALL_CATEGORIES, TRENDS_ANALYTICS_METADATA)\n }\n\n if (!isInitialized || !isAccountDataLoaded || !isWidgetInitialized || !monthlyTotalsLoaded)\n return <Loader />\n\n const isEmptyTrendsState = accounts.length === 0 || monthlyCategoryTotals.length === 0\n\n const emptyStateProps = buildEmptyStateProps(copy, hasAggregation, handleEmptyStateClick)\n\n return (\n <WidgetContainer\n calendarActions={{ onRangeChanged }}\n dateRange={selectedDateRange}\n dateRangeVariant={isMobile ? 'timeframetabs' : 'timeframebuttons'}\n onAccountsFilterClick={onAccountsFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack\n ref={contentRef}\n sx={{\n px: isMobile ? 0 : 48,\n }}\n >\n <Stack\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n sx={{ px: isMobile ? 16 : 0, py: 16 }}\n >\n <DateRangeText\n selectedCategoryGuid={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n <TrendsViewToggle onTabChange={onTabChange} selectedTab={selectedTab} />\n </Stack>\n <Stack alignItems=\"center\" flexDirection=\"row\" sx={{ pb: 8 }} width=\"100%\">\n <Box flexGrow={1}>\n {selectedCategory && (\n <Button onClick={onViewAllCategories} sx={{ p: 0, pr: 5 }}>\n <ArrowBack />\n {copy.all_categories}\n </Button>\n )}\n </Box>\n </Stack>\n\n {isEmptyTrendsState && (\n <EmptyState\n header={emptyStateProps.header}\n icon=\"multiline_chart\"\n onClick={emptyStateProps.onClickHandler}\n primaryButton={emptyStateProps.primaryButton}\n subText={emptyStateProps.description}\n sx={{ height: availableChartHeight, maxWidth: 432 }}\n />\n )}\n {!isEmptyTrendsState && (\n <Stack flexDirection={isLargeLayout ? 'row' : 'column'} gap={isLargeLayout ? 48 : 16}>\n {selectedTab === 'Chart' && (\n <>\n <Box sx={{ width: isLargeLayout ? '68%' : '100%' }}>\n <TrendsChartTotals\n availableHeight={availableChartHeight}\n minHeight={450}\n selectedDateRange={selectedDateRange}\n totals={monthlyCategoryTotals}\n />\n </Box>\n <Stack gap={16} sx={{ width: isLargeLayout ? '32%' : '100%' }}>\n {/* Only show insights enabled and there are beats to show */}\n {showInsights && isBeatsLoaded && filteredBeats.length > 0 && (\n <InsightsCarousel\n beats={filteredBeats}\n onInsightCardClick={onInsightCardClick}\n />\n )}\n <CategoriesList\n availableHeight={availableListHeight}\n onCategoryClick={handleDetailOpen}\n />\n </Stack>\n </>\n )}\n {selectedTab === 'Table' && (\n <Box sx={{ width: '100%' }}>\n <TrendsTableContainer\n height=\"unset\"\n onClickRow={onClickRow}\n selectedCategory={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n </Box>\n )}\n </Stack>\n )}\n <Drawer\n ariaLabelClose={copy.close_category_details}\n isOpen={Boolean(selectedCategoryData)}\n onClose={handleDetailClose}\n shouldShowHeaderShadow={true}\n title={selectedCategoryData?.is_income ? copy.category_income : copy.category_spending}\n >\n {selectedCategoryData && <CategoryDetails />}\n </Drawer>\n </Stack>\n\n <ConnectDrawer\n onClose={() => setShowConnectWidget(false)}\n showConnectWidget={showConnectWidget}\n title={connectCopy.mini_title}\n />\n </WidgetContainer>\n )\n}\n\nexport default observer(TrendsWidget)\n"],"mappings":"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"}
1
+ {"version":3,"file":"TrendsWidget.es.js","names":[],"sources":["../../src/trends/TrendsWidget.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport React from 'react'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\n\nimport { DateRange } from '@mui/x-date-pickers-pro'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\n\nimport { ArrowBack } from '@mxenabled/mx-icons'\n\nimport {\n ANALYTICS_EVENTS,\n ConnectDrawer,\n Drawer,\n EmptyState,\n Loader,\n WidgetContainer,\n useAccountStore,\n useAppConfig,\n useCategoryStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalStore,\n useGlobalUiStore,\n useInsightsEnabled,\n useScreenSize,\n useTransactionStore,\n useTrendsStore,\n useWidgetLoadTimer,\n} from '../common'\nimport { type Beat, type DetailedCategoryWithTransactions, Transaction, WidgetProps } from '../core'\n\nimport DateRangeText from './components/DateRangeText'\nimport TrendsViewToggle, { type TrendsTabValue } from './components/TrendsViewToggle'\nimport TrendsTableContainer from './components/TrendsTableContainer'\nimport CategoriesList from './components/CategoriesList'\nimport InsightsCarousel from './components/TrendsInsights'\nimport { CategoryDetails } from './components/CategoryDetails'\nimport TrendsChartTotals from './components/TrendsChartTotals'\nimport { TRENDS_ANALYTICS_METADATA } from './constants/TrendsWidget'\nimport { TRENDS_BEAT_TEMPLATES } from './constants/TrendsInsights'\nimport { buildEmptyStateProps } from './utils/TrendsWidget'\n\ninterface TrendsWidgetProps extends WidgetProps {\n onInsightCardClick?: (beat?: Beat) => void\n}\n\nconst TrendsWidget: React.FC<TrendsWidgetProps> = ({\n onBackClick,\n onMenuClick,\n onInsightCardClick,\n sx,\n}) => {\n const { onEvent } = useEvent()\n const { config } = useAppConfig()\n const { isDesktop, isLargeDesktop, isMobile } = useScreenSize()\n const { isAccountDataLoaded, loadAccountData, visibleAccounts: accounts } = useAccountStore()\n const {\n categoriesLoaded,\n loadCategories,\n monthlyCategoryTotals,\n monthlyTotalsLoaded,\n reloadCategoryTotals,\n } = useCategoryStore()\n const { isTransactionDataLoaded, loadTransactionData, setFilter } = useTransactionStore()\n const {\n isTransactionStoreIdle,\n selectedCategoryData,\n selectedDateRange,\n setSelectedCategoryData,\n setSelectedDateRange,\n } = useTrendsStore()\n const { isInitialized, selectedAccounts, selectedAccountGuids } = useGlobalUiStore()\n const { trends: copy, connect: connectCopy } = useGlobalCopyStore()\n const { beatStore } = useGlobalStore()\n const insightsEnabled = useInsightsEnabled()\n\n // allows clients to disable insights in trends while still enabling insights\n const showInsights = insightsEnabled && config.show_insights_widget_in_master\n const isLargeLayout = isDesktop || isLargeDesktop\n\n const [isWidgetInitialized, setIsWidgetInitialized] = React.useState(false)\n const [isBeatsLoaded, setIsBeatsLoaded] = React.useState(false)\n const [selectedTab, setSelectedTab] = React.useState<TrendsTabValue>('Chart')\n const [selectedCategory, setSelectedCategory] = React.useState('')\n\n // Control responsive chart height based on available widget iframe viewport height\n const [viewportHeight, setViewportHeight] = React.useState(window.innerHeight)\n const insightsPadding = isLargeLayout ? 56 : 0\n const availableChartHeight = viewportHeight - 208 // unavailable height on desktop\n const availableListHeight = viewportHeight - (showInsights ? 550 + insightsPadding : 266)\n\n const [showConnectWidget, setShowConnectWidget] = React.useState(false)\n const hasAggregation = config.show_connections_widget_in_master\n\n // iOS Safari doesn't scroll off-screen elements into view on forward Tab\n // inside this non-document scroll container. `:focus-visible` limits the\n // scroll to keyboard focus so pointer clicks on clipped rows don't jump.\n // `block: 'nearest'` is a no-op when already visible. Callback ref (not\n // useEffect) because the content mounts after the loading gate.\n const cleanupFocusScroll = React.useRef<(() => void) | undefined>(undefined)\n const contentRef = React.useCallback((node: HTMLDivElement | null) => {\n cleanupFocusScroll.current?.()\n cleanupFocusScroll.current = undefined\n\n if (!node) return\n\n const handleFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && event.target.matches(':focus-visible')) {\n event.target.scrollIntoView({ block: 'nearest' })\n }\n }\n\n node.addEventListener('focusin', handleFocusIn)\n cleanupFocusScroll.current = () => node.removeEventListener('focusin', handleFocusIn)\n }, [])\n\n useWidgetLoadTimer({\n widgetName: 'TrendsWidget',\n isLoaded: isWidgetInitialized,\n })\n const filteredBeats = React.useMemo(() => {\n if (!isBeatsLoaded) return []\n return beatStore.getFilteredBeats({ templates: TRENDS_BEAT_TEMPLATES })\n }, [isBeatsLoaded])\n\n React.useEffect(() => {\n // Setup resize listener for responsive chart and list heights\n const handleResize = () => setViewportHeight(window.innerHeight)\n window.addEventListener('resize', handleResize)\n\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n if (!categoriesLoaded) {\n loadCategories().finally()\n }\n if (!isTransactionDataLoaded) {\n loadTransactionData().finally()\n }\n\n return () => window.removeEventListener('resize', handleResize)\n }, [])\n\n // Initialize monthlyCategoryTotals, and reload on account or date range change.\n // Depends on primitives rather than `selectedAccounts` / `selectedDateRange`,\n // whose object identities change even when the values do not. (MEW-3910)\n //\n // Both totals are loaded in parallel rather than chaining monthly inside the\n // date-range `.then()`. Chaining defers the monthly request until the first\n // resolves, so a slow superseded range would claim the newest monthly request\n // token and write stale data over the current range. (MEW-3910)\n React.useEffect(() => {\n if (isInitialized && isAccountDataLoaded) {\n beatStore.loadBeats().finally(() => setIsBeatsLoaded(true))\n reloadCategoryTotals(\n selectedAccounts,\n selectedDateRange.start,\n selectedDateRange.end,\n ).finally(() => {\n setIsWidgetInitialized(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_LOAD_WIDGET, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: `${differenceInCalendarMonths(selectedDateRange.end, selectedDateRange.start)}M`,\n })\n })\n }\n }, [\n isInitialized,\n isAccountDataLoaded,\n selectedAccountGuids.join(','),\n selectedDateRange.start.getTime(),\n selectedDateRange.end.getTime(),\n ])\n // Totals are refetched on every range/account change, so their identity marks a new filter.\n // Tracking it stops a failed load from re-firing setFilter every time the store goes idle.\n const filteredTotalsRef = React.useRef<typeof monthlyCategoryTotals | null>(null)\n\n React.useEffect(() => {\n // Wait for the transaction store to go idle so the selected range load isn't dropped\n if (\n monthlyCategoryTotals.length !== 0 &&\n isTransactionStoreIdle &&\n filteredTotalsRef.current !== monthlyCategoryTotals\n ) {\n filteredTotalsRef.current = monthlyCategoryTotals\n const transactionFilter = {\n accounts: selectedAccountGuids,\n dateRange: { start: selectedDateRange.start, end: selectedDateRange.end },\n }\n\n // this filter sets sortedTransactions in the transaction store\n setFilter({\n ...transactionFilter,\n custom: (t: Transaction) =>\n Boolean(\n monthlyCategoryTotals.find(\n (cat) =>\n cat.top_level_category_guid === t.top_level_category_guid ||\n cat.category_guid === t.category_guid,\n ),\n ),\n })\n }\n }, [monthlyCategoryTotals, isTransactionStoreIdle])\n\n const handleDetailOpen = (selected: DetailedCategoryWithTransactions) => {\n setSelectedCategoryData(selected)\n }\n\n const handleDetailClose = () => {\n setSelectedCategoryData(null)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_BACK, TRENDS_ANALYTICS_METADATA)\n }\n\n const handleEmptyStateClick = () => {\n setShowConnectWidget(true)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_CONNECT_ACCOUNTS)\n }\n\n const onTabChange = (_event: React.SyntheticEvent, newValue: TrendsTabValue) => {\n setSelectedTab(newValue ?? selectedTab)\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TOGGLE_VIEW, {\n ...TRENDS_ANALYTICS_METADATA,\n toggleView: newValue,\n })\n }\n\n const onRangeChanged = (dateRange: DateRange<Date>) => {\n const startDate = addSeconds(dateRange?.[0] as Date, 1)\n const endDate = dateRange?.[1] as Date\n const months = differenceInCalendarMonths(endDate, startDate)\n\n setSelectedDateRange({ start: startDate, end: endDate })\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_TIME_WINDOW, {\n ...TRENDS_ANALYTICS_METADATA,\n time_period: months + 'M',\n })\n }\n\n const onAccountsFilterClick = (selectedAccountGuids?: string[]) => {\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_FILTER, {\n ...TRENDS_ANALYTICS_METADATA,\n filterValue: selectedAccountGuids,\n })\n }\n\n const onClickRow = (guid: string) => {\n setSelectedCategory(guid)\n }\n\n const onViewAllCategories = () => {\n setSelectedCategory('')\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_ALL_CATEGORIES, TRENDS_ANALYTICS_METADATA)\n }\n\n if (!isInitialized || !isAccountDataLoaded || !isWidgetInitialized || !monthlyTotalsLoaded)\n return <Loader />\n\n const isEmptyTrendsState = accounts.length === 0 || monthlyCategoryTotals.length === 0\n\n const emptyStateProps = buildEmptyStateProps(copy, hasAggregation, handleEmptyStateClick)\n\n return (\n <WidgetContainer\n calendarActions={{ onRangeChanged }}\n dateRange={selectedDateRange}\n dateRangeVariant={isMobile ? 'timeframetabs' : 'timeframebuttons'}\n onAccountsFilterClick={onAccountsFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack\n ref={contentRef}\n sx={{\n px: isMobile ? 0 : 48,\n }}\n >\n <Stack\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n sx={{ px: isMobile ? 16 : 0, py: 16 }}\n >\n <DateRangeText\n selectedCategoryGuid={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n <TrendsViewToggle onTabChange={onTabChange} selectedTab={selectedTab} />\n </Stack>\n <Stack alignItems=\"center\" flexDirection=\"row\" sx={{ pb: 8 }} width=\"100%\">\n <Box flexGrow={1}>\n {selectedCategory && (\n <Button onClick={onViewAllCategories} sx={{ p: 0, pr: 5 }}>\n <ArrowBack />\n {copy.all_categories}\n </Button>\n )}\n </Box>\n </Stack>\n\n {isEmptyTrendsState && (\n <EmptyState\n header={emptyStateProps.header}\n icon=\"multiline_chart\"\n onClick={emptyStateProps.onClickHandler}\n primaryButton={emptyStateProps.primaryButton}\n subText={emptyStateProps.description}\n sx={{ height: availableChartHeight, maxWidth: 432 }}\n />\n )}\n {!isEmptyTrendsState && (\n <Stack flexDirection={isLargeLayout ? 'row' : 'column'} gap={isLargeLayout ? 48 : 16}>\n {selectedTab === 'Chart' && (\n <>\n <Box sx={{ width: isLargeLayout ? '68%' : '100%' }}>\n <TrendsChartTotals\n availableHeight={availableChartHeight}\n minHeight={450}\n selectedDateRange={selectedDateRange}\n totals={monthlyCategoryTotals}\n />\n </Box>\n <Stack gap={16} sx={{ width: isLargeLayout ? '32%' : '100%' }}>\n {/* Only show insights enabled and there are beats to show */}\n {showInsights && isBeatsLoaded && filteredBeats.length > 0 && (\n <InsightsCarousel\n beats={filteredBeats}\n onInsightCardClick={onInsightCardClick}\n />\n )}\n <CategoriesList\n availableHeight={availableListHeight}\n onCategoryClick={handleDetailOpen}\n />\n </Stack>\n </>\n )}\n {selectedTab === 'Table' && (\n <Box sx={{ width: '100%' }}>\n <TrendsTableContainer\n height=\"unset\"\n onClickRow={onClickRow}\n selectedCategory={selectedCategory}\n selectedDateRange={selectedDateRange}\n />\n </Box>\n )}\n </Stack>\n )}\n <Drawer\n ariaLabelClose={copy.close_category_details}\n isOpen={Boolean(selectedCategoryData)}\n onClose={handleDetailClose}\n shouldShowHeaderShadow={true}\n title={selectedCategoryData?.is_income ? copy.category_income : copy.category_spending}\n >\n {selectedCategoryData && <CategoryDetails />}\n </Drawer>\n </Stack>\n\n <ConnectDrawer\n onClose={() => setShowConnectWidget(false)}\n showConnectWidget={showConnectWidget}\n title={connectCopy.mini_title}\n />\n </WidgetContainer>\n )\n}\n\nexport default observer(TrendsWidget)\n"],"mappings":"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"}
@@ -1,44 +1,49 @@
1
- import { useEvent as h, useGlobalCopyStore as I } from "../../common/context/hooks.es.js";
2
- import { ANALYTICS_EVENTS as T } from "../../common/constants/Analytics.es.js";
3
- import { getCategoryColor as s } from "../../core/utils/CategoryUtil.es.js";
4
- import { formatCurrency as g } from "../../core/utils/NumberFormatting.es.js";
5
- import { ListItemRow as v } from "../../common/components/ListItemRow.es.js";
1
+ import { useEvent as C, useGlobalCopyStore as T, useTrendsStore as I } from "../../common/context/hooks.es.js";
2
+ import { ANALYTICS_EVENTS as v } from "../../common/constants/Analytics.es.js";
3
+ import { getCategoryColor as a } from "../../core/utils/CategoryUtil.es.js";
4
+ import { formatCurrency as S } from "../../core/utils/NumberFormatting.es.js";
5
+ import { ListItemRow as g } from "../../common/components/ListItemRow.es.js";
6
6
  import { TRENDS_ANALYTICS_METADATA as x } from "../constants/TrendsWidget.es.js";
7
- import E from "react";
8
- import { observer as y } from "mobx-react-lite";
9
- import { CategoryIcon as A } from "@mxenabled/mxui";
10
- import { ChevronRight as S } from "@mxenabled/mx-icons";
11
- import { jsx as t, jsxs as b } from "react/jsx-runtime";
12
- import { alpha as d, useTheme as u } from "@mui/material/styles";
13
- import L from "@mui/material/Divider";
14
- var V = y(({ totalAmount: a, guid: o, name: r, transactions: e, onClick: m, isLastItem: l = !1, showDivider: p = !0 }) => {
15
- const { trends: i } = I(), { onEvent: c } = h(), n = u(), f = `${e.length} ${e.length === 1 ? i.transaction : i.transactions}`, C = () => {
16
- m?.(), c(T.TRENDS_CLICK_LIST_ITEM, {
7
+ import u from "react";
8
+ import { observer as E } from "mobx-react-lite";
9
+ import { CategoryIcon as y } from "@mxenabled/mxui";
10
+ import { ChevronRight as A } from "@mxenabled/mx-icons";
11
+ import { jsx as o, jsxs as L } from "react/jsx-runtime";
12
+ import { alpha as b, useTheme as R } from "@mui/material/styles";
13
+ import _ from "@mui/material/Divider";
14
+ import N from "@mui/material/Skeleton";
15
+ var H = E(({ totalAmount: c, guid: t, name: m, transactions: i, onClick: r, isLastItem: l = !1, showDivider: p = !0 }) => {
16
+ const { trends: n } = T(), { onEvent: f } = C(), s = R(), { isSelectedRangeLoaded: e } = I(), d = `${i.length} ${i.length === 1 ? n.transaction : n.transactions}`, h = () => {
17
+ r?.(), f(v.TRENDS_CLICK_LIST_ITEM, {
17
18
  ...x,
18
- listItem: r
19
+ listItem: m
19
20
  });
20
21
  };
21
- return /* @__PURE__ */ b(E.Fragment, { children: [/* @__PURE__ */ t(v, {
22
- leftIcon: o ? /* @__PURE__ */ t(A, {
23
- categoryGuid: o,
22
+ return /* @__PURE__ */ L(u.Fragment, { children: [/* @__PURE__ */ o(g, {
23
+ leftIcon: t ? /* @__PURE__ */ o(y, {
24
+ categoryGuid: t,
24
25
  sx: {
25
- bgcolor: d(s(o, n), 0.15),
26
- border: `1px solid ${s(o, n)}`,
26
+ bgcolor: b(a(t, s), 0.15),
27
+ border: `1px solid ${a(t, s)}`,
27
28
  color: "text.primary"
28
29
  }
29
30
  }) : void 0,
30
- onClick: C,
31
- rightContent: g(Math.abs(a), "0,0.00"),
32
- rightIcon: m ? /* @__PURE__ */ t(S, {}) : void 0,
33
- subtitle: f,
34
- title: r
35
- }), p && /* @__PURE__ */ t(L, {
31
+ onClick: e && r ? h : void 0,
32
+ rightContent: S(Math.abs(c), "0,0.00"),
33
+ rightIcon: e && r ? /* @__PURE__ */ o(A, {}) : void 0,
34
+ subtitle: e ? d : /* @__PURE__ */ o(N, {
35
+ "data-testid": "transaction-count-skeleton",
36
+ variant: "text",
37
+ width: 88
38
+ }),
39
+ title: m
40
+ }), p && /* @__PURE__ */ o(_, {
36
41
  component: "li",
37
42
  sx: { ml: l ? 24 : 68 }
38
- })] }, o);
43
+ })] }, t);
39
44
  });
40
45
  export {
41
- V as default
46
+ H as default
42
47
  };
43
48
 
44
49
  //# sourceMappingURL=CategoriesListItem.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CategoriesListItem.es.js","names":[],"sources":["../../../src/trends/components/CategoriesListItem.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Divider from '@mui/material/Divider'\nimport { alpha } from '@mui/material/styles'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\nimport { CategoryIcon } from '@mxenabled/mxui'\n\nimport { ANALYTICS_EVENTS, ListItemRow, useEvent, useGlobalCopyStore } from '../../common'\nimport { type DetailedCategoryWithTransactions } from '../../core'\n\nimport { TRENDS_ANALYTICS_METADATA } from '../constants/TrendsWidget'\nimport { getCategoryColor } from '../../core/utils/CategoryUtil'\nimport { formatCurrency } from '../../core/utils/NumberFormatting'\ninterface CategoriesListItemProps extends DetailedCategoryWithTransactions {\n onClick?: () => void\n isLastItem?: boolean\n showDivider?: boolean\n}\n\nconst CategoriesListItem = observer(\n ({\n totalAmount,\n guid,\n name,\n transactions,\n onClick,\n isLastItem = false,\n showDivider = true,\n }: CategoriesListItemProps) => {\n const { trends: copy } = useGlobalCopyStore()\n const { onEvent } = useEvent()\n const theme = useTheme()\n\n const transactionCountText = `${transactions.length} ${transactions.length === 1 ? copy.transaction : copy.transactions}`\n\n const handleClick = () => {\n onClick?.()\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_LIST_ITEM, {\n ...TRENDS_ANALYTICS_METADATA,\n listItem: name,\n })\n }\n\n return (\n <React.Fragment key={guid}>\n <ListItemRow\n leftIcon={\n guid ? (\n <CategoryIcon\n categoryGuid={guid}\n sx={{\n bgcolor: alpha(getCategoryColor(guid, theme), 0.15),\n border: `1px solid ${getCategoryColor(guid, theme)}`,\n color: 'text.primary',\n }}\n />\n ) : undefined\n }\n onClick={handleClick}\n rightContent={formatCurrency(Math.abs(totalAmount), '0,0.00')}\n rightIcon={onClick ? <ChevronRight /> : undefined}\n subtitle={transactionCountText}\n title={name}\n />\n {showDivider && <Divider component=\"li\" sx={{ ml: isLastItem ? 24 : 68 }} />}\n </React.Fragment>\n )\n },\n)\n\nexport default CategoriesListItem\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAM,IAAqB,EAAA,CACxB,EACC,aAAA,GACA,MAAA,GACA,MAAA,GACA,cAAA,GACA,SAAA,GACA,YAAA,IAAa,IACb,aAAA,IAAc,GAAA,MACe;AAC7B,QAAM,EAAE,QAAQ,EAAA,IAAS,EAAmB,GACtC,EAAE,SAAA,EAAA,IAAY,EAAS,GACvB,IAAQ,EAAS,GAEjB,IAAuB,GAAG,EAAa,MAAA,IAAU,EAAa,WAAW,IAAI,EAAK,cAAc,EAAK,YAAA,IAErG,IAAA,MAAoB;AACxB,IAAA,IAAU,GACV,EAAQ,EAAiB,wBAAwB;AAAA,MAC/C,GAAG;AAAA,MACH,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SACE,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,UACE,IACE,gBAAA,EAAC,GAAD;AAAA,MACE,cAAc;AAAA,MACd,IAAI;AAAA,QACF,SAAS,EAAM,EAAiB,GAAM,CAAK,GAAG,IAAI;AAAA,QAClD,QAAQ,aAAa,EAAiB,GAAM,CAAK,CAAA;AAAA,QACjD,OAAO;AAAA,MACT;AAAA,IACD,CAAA,IACC;AAAA,IAEN,SAAS;AAAA,IACT,cAAc,EAAe,KAAK,IAAI,CAAW,GAAG,QAAQ;AAAA,IAC5D,WAAW,IAAU,gBAAA,EAAC,GAAD,CAAe,CAAA,IAAI;AAAA,IACxC,UAAU;AAAA,IACV,OAAO;AAAA,EACR,CAAA,GACA,KAAe,gBAAA,EAAC,GAAD;AAAA,IAAS,WAAU;AAAA,IAAK,IAAI,EAAE,IAAI,IAAa,KAAK,GAAG;AAAA,EAAI,CAAA,CAC7D,EAAA,GArBK,CAqBL;AAEpB,CACF"}
1
+ {"version":3,"file":"CategoriesListItem.es.js","names":[],"sources":["../../../src/trends/components/CategoriesListItem.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Divider from '@mui/material/Divider'\nimport Skeleton from '@mui/material/Skeleton'\nimport { alpha } from '@mui/material/styles'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\nimport { CategoryIcon } from '@mxenabled/mxui'\n\nimport {\n ANALYTICS_EVENTS,\n ListItemRow,\n useEvent,\n useGlobalCopyStore,\n useTrendsStore,\n} from '../../common'\nimport { type DetailedCategoryWithTransactions } from '../../core'\n\nimport { TRENDS_ANALYTICS_METADATA } from '../constants/TrendsWidget'\nimport { getCategoryColor } from '../../core/utils/CategoryUtil'\nimport { formatCurrency } from '../../core/utils/NumberFormatting'\ninterface CategoriesListItemProps extends DetailedCategoryWithTransactions {\n onClick?: () => void\n isLastItem?: boolean\n showDivider?: boolean\n}\n\nconst CategoriesListItem = observer(\n ({\n totalAmount,\n guid,\n name,\n transactions,\n onClick,\n isLastItem = false,\n showDivider = true,\n }: CategoriesListItemProps) => {\n const { trends: copy } = useGlobalCopyStore()\n const { onEvent } = useEvent()\n const theme = useTheme()\n const { isSelectedRangeLoaded } = useTrendsStore()\n\n const transactionCountText = `${transactions.length} ${transactions.length === 1 ? copy.transaction : copy.transactions}`\n\n const handleClick = () => {\n onClick?.()\n onEvent(ANALYTICS_EVENTS.TRENDS_CLICK_LIST_ITEM, {\n ...TRENDS_ANALYTICS_METADATA,\n listItem: name,\n })\n }\n\n return (\n <React.Fragment key={guid}>\n <ListItemRow\n leftIcon={\n guid ? (\n <CategoryIcon\n categoryGuid={guid}\n sx={{\n bgcolor: alpha(getCategoryColor(guid, theme), 0.15),\n border: `1px solid ${getCategoryColor(guid, theme)}`,\n color: 'text.primary',\n }}\n />\n ) : undefined\n }\n onClick={isSelectedRangeLoaded && onClick ? handleClick : undefined}\n rightContent={formatCurrency(Math.abs(totalAmount), '0,0.00')}\n rightIcon={isSelectedRangeLoaded && onClick ? <ChevronRight /> : undefined}\n subtitle={\n isSelectedRangeLoaded ? (\n transactionCountText\n ) : (\n <Skeleton data-testid=\"transaction-count-skeleton\" variant=\"text\" width={88} />\n )\n }\n title={name}\n />\n {showDivider && <Divider component=\"li\" sx={{ ml: isLastItem ? 24 : 68 }} />}\n </React.Fragment>\n )\n },\n)\n\nexport default CategoriesListItem\n"],"mappings":";;;;;;;;;;;;;;AA6BA,IAAM,IAAqB,EAAA,CACxB,EACC,aAAA,GACA,MAAA,GACA,MAAA,GACA,cAAA,GACA,SAAA,GACA,YAAA,IAAa,IACb,aAAA,IAAc,GAAA,MACe;AAC7B,QAAM,EAAE,QAAQ,EAAA,IAAS,EAAmB,GACtC,EAAE,SAAA,EAAA,IAAY,EAAS,GACvB,IAAQ,EAAS,GACjB,EAAE,uBAAA,EAAA,IAA0B,EAAe,GAE3C,IAAuB,GAAG,EAAa,MAAA,IAAU,EAAa,WAAW,IAAI,EAAK,cAAc,EAAK,YAAA,IAErG,IAAA,MAAoB;AACxB,IAAA,IAAU,GACV,EAAQ,EAAiB,wBAAwB;AAAA,MAC/C,GAAG;AAAA,MACH,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SACE,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,UACE,IACE,gBAAA,EAAC,GAAD;AAAA,MACE,cAAc;AAAA,MACd,IAAI;AAAA,QACF,SAAS,EAAM,EAAiB,GAAM,CAAK,GAAG,IAAI;AAAA,QAClD,QAAQ,aAAa,EAAiB,GAAM,CAAK,CAAA;AAAA,QACjD,OAAO;AAAA,MACT;AAAA,IACD,CAAA,IACC;AAAA,IAEN,SAAS,KAAyB,IAAU,IAAc;AAAA,IAC1D,cAAc,EAAe,KAAK,IAAI,CAAW,GAAG,QAAQ;AAAA,IAC5D,WAAW,KAAyB,IAAU,gBAAA,EAAC,GAAD,CAAe,CAAA,IAAI;AAAA,IACjE,UACE,IACE,IAEA,gBAAA,EAAC,GAAD;AAAA,MAAU,eAAY;AAAA,MAA6B,SAAQ;AAAA,MAAO,OAAO;AAAA,IAAK,CAAA;AAAA,IAGlF,OAAO;AAAA,EACR,CAAA,GACA,KAAe,gBAAA,EAAC,GAAD;AAAA,IAAS,WAAU;AAAA,IAAK,IAAI,EAAE,IAAI,IAAa,KAAK,GAAG;AAAA,EAAI,CAAA,CAC7D,EAAA,GA3BK,CA2BL;AAEpB,CACF"}