@mx-cartographer/experiences 9.4.38 → 9.4.40

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,11 @@
1
+ ## [9.4.40] - 09-24-2026
2
+
3
+ - **FIXED** - double error reporting from Recurring Transactions. Its errors now surface only through `onCaptureException`, and `GlobalStore.captureException` falls back to `console.error` when the host provides no handler (MEW-4169)
4
+
5
+ ## [9.4.39] - 09-23-2026
6
+
7
+ - **FIXED** - Trends category rows no longer show a nonzero total with "0 transactions" and no chevron. (MEW-4021)
8
+
1
9
  ## [9.4.38] - 09-22-2026
2
10
 
3
11
  - **FIXED** - `LineChart` x-axis now shows every tick label instead of dropping overlapping ones, so month labels no longer disappear on small views. On the Trends 1 Year (12-month) view on small screens, labels render as single letters so all twelve fit; the full month is preserved as the accessible name so screen readers and tooltips are unchanged (MEW-4096)
@@ -4,7 +4,7 @@ interface ListItemRowProps {
4
4
  leftIcon?: React.ReactNode;
5
5
  rightIcon?: React.ReactNode;
6
6
  title?: string;
7
- subtitle?: string;
7
+ subtitle?: React.ReactNode;
8
8
  rightContent?: React.ReactNode;
9
9
  titleBold?: boolean;
10
10
  rightContentBold?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"ListItemRow.es.js","names":[],"sources":["../../../src/common/components/ListItemRow.tsx"],"sourcesContent":["import React from 'react'\n\nimport ListItem from '@mui/material/ListItem'\nimport ListItemButton from '@mui/material/ListItemButton'\nimport ListItemIcon from '@mui/material/ListItemIcon'\nimport ListItemText from '@mui/material/ListItemText'\nimport Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\n\ninterface ListItemRowProps {\n onClick?: () => void\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n title?: string\n subtitle?: string\n rightContent?: React.ReactNode\n titleBold?: boolean\n rightContentBold?: boolean\n}\n\nexport const ListItemRow: React.FC<ListItemRowProps> = ({\n onClick,\n leftIcon,\n rightIcon,\n title,\n subtitle,\n rightContent,\n titleBold = true,\n rightContentBold = true,\n}) => {\n const content = (\n <React.Fragment>\n {leftIcon && <ListItemIcon sx={{ ml: 0 }}>{leftIcon}</ListItemIcon>}\n <ListItemText>\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n marginLeft: 12,\n }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Text bold={titleBold} variant=\"body1\">\n {title}\n </Text>\n {subtitle && <Text variant=\"caption\">{subtitle}</Text>}\n </Stack>\n <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}>\n {rightContent && (\n <Text bold={rightContentBold} display=\"flex\" variant=\"body1\">\n {rightContent}\n </Text>\n )}\n {rightIcon && <ListItemIcon>{rightIcon}</ListItemIcon>}\n </Stack>\n </Stack>\n </ListItemText>\n </React.Fragment>\n )\n\n return (\n <ListItem>\n {onClick ? (\n <ListItemButton\n onClick={onClick}\n sx={{\n py: 14,\n }}\n >\n {content}\n </ListItemButton>\n ) : (\n <Stack\n sx={{\n py: 14,\n px: 24,\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n }}\n >\n {content}\n </Stack>\n )}\n </ListItem>\n )\n}\n"],"mappings":";;;;;;;;AAqBA,IAAa,IAAA,CAA2C,EACtD,SAAA,GACA,UAAA,GACA,WAAA,GACA,OAAA,GACA,UAAA,GACA,cAAA,GACA,WAAA,IAAY,IACZ,kBAAA,IAAmB,GAAA,MACf;AACJ,QAAM,IACJ,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACG,KAAY,gBAAA,EAAC,GAAD;AAAA,IAAc,IAAI,EAAE,IAAI,EAAE;AAAA,IAAI,UAAA;AAAA,EAAuB,CAAA,GAClE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IALF,UAAA,CAOE,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,MAAM;AAAA,QAAG,UAAU;AAAA,MAAE;AAAA,MAAlC,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAW,SAAQ;AAAA,QAC5B,UAAA;AAAA,MACG,CAAA,GACL,KAAY,gBAAA,EAAC,GAAD;AAAA,QAAM,SAAQ;AAAA,QAAW,UAAA;AAAA,MAAe,CAAA,CAChD;AAAA,IACP,CAAA,GAAA,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,eAAe;AAAA,QAAO,YAAY;AAAA,QAAU,KAAK;AAAA,MAAE;AAAA,MAAhE,UAAA,CACG,KACC,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAkB,SAAQ;AAAA,QAAO,SAAQ;AAAA,QAClD,UAAA;AAAA,MACG,CAAA,GAEP,KAAa,gBAAA,EAAC,GAAD,EAAA,UAAe,EAAwB,CAAA,CAChD;AAAA,IACF,CAAA,CAAA;AAAA,EACK,CAAA,EAAA,CAAA,CACA,EAAA,CAAA;AAGlB,SACE,gBAAA,EAAC,GAAD,EAAA,UACG,IACC,gBAAA,EAAC,GAAD;AAAA,IACW,SAAA;AAAA,IACT,IAAI,EACF,IAAI,GACN;AAAA,IAEC,UAAA;AAAA,EACa,CAAA,IAEhB,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IAEC,UAAA;AAAA,EACI,CAAA,EAED,CAAA;AAEd"}
1
+ {"version":3,"file":"ListItemRow.es.js","names":[],"sources":["../../../src/common/components/ListItemRow.tsx"],"sourcesContent":["import React from 'react'\n\nimport ListItem from '@mui/material/ListItem'\nimport ListItemButton from '@mui/material/ListItemButton'\nimport ListItemIcon from '@mui/material/ListItemIcon'\nimport ListItemText from '@mui/material/ListItemText'\nimport Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\n\ninterface ListItemRowProps {\n onClick?: () => void\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n title?: string\n subtitle?: React.ReactNode\n rightContent?: React.ReactNode\n titleBold?: boolean\n rightContentBold?: boolean\n}\n\nexport const ListItemRow: React.FC<ListItemRowProps> = ({\n onClick,\n leftIcon,\n rightIcon,\n title,\n subtitle,\n rightContent,\n titleBold = true,\n rightContentBold = true,\n}) => {\n const content = (\n <React.Fragment>\n {leftIcon && <ListItemIcon sx={{ ml: 0 }}>{leftIcon}</ListItemIcon>}\n <ListItemText>\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n marginLeft: 12,\n }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Text bold={titleBold} variant=\"body1\">\n {title}\n </Text>\n {subtitle && <Text variant=\"caption\">{subtitle}</Text>}\n </Stack>\n <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}>\n {rightContent && (\n <Text bold={rightContentBold} display=\"flex\" variant=\"body1\">\n {rightContent}\n </Text>\n )}\n {rightIcon && <ListItemIcon>{rightIcon}</ListItemIcon>}\n </Stack>\n </Stack>\n </ListItemText>\n </React.Fragment>\n )\n\n return (\n <ListItem>\n {onClick ? (\n <ListItemButton\n onClick={onClick}\n sx={{\n py: 14,\n }}\n >\n {content}\n </ListItemButton>\n ) : (\n <Stack\n sx={{\n py: 14,\n px: 24,\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n }}\n >\n {content}\n </Stack>\n )}\n </ListItem>\n )\n}\n"],"mappings":";;;;;;;;AAqBA,IAAa,IAAA,CAA2C,EACtD,SAAA,GACA,UAAA,GACA,WAAA,GACA,OAAA,GACA,UAAA,GACA,cAAA,GACA,WAAA,IAAY,IACZ,kBAAA,IAAmB,GAAA,MACf;AACJ,QAAM,IACJ,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACG,KAAY,gBAAA,EAAC,GAAD;AAAA,IAAc,IAAI,EAAE,IAAI,EAAE;AAAA,IAAI,UAAA;AAAA,EAAuB,CAAA,GAClE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IALF,UAAA,CAOE,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,MAAM;AAAA,QAAG,UAAU;AAAA,MAAE;AAAA,MAAlC,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAW,SAAQ;AAAA,QAC5B,UAAA;AAAA,MACG,CAAA,GACL,KAAY,gBAAA,EAAC,GAAD;AAAA,QAAM,SAAQ;AAAA,QAAW,UAAA;AAAA,MAAe,CAAA,CAChD;AAAA,IACP,CAAA,GAAA,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,eAAe;AAAA,QAAO,YAAY;AAAA,QAAU,KAAK;AAAA,MAAE;AAAA,MAAhE,UAAA,CACG,KACC,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAkB,SAAQ;AAAA,QAAO,SAAQ;AAAA,QAClD,UAAA;AAAA,MACG,CAAA,GAEP,KAAa,gBAAA,EAAC,GAAD,EAAA,UAAe,EAAwB,CAAA,CAChD;AAAA,IACF,CAAA,CAAA;AAAA,EACK,CAAA,EAAA,CAAA,CACA,EAAA,CAAA;AAGlB,SACE,gBAAA,EAAC,GAAD,EAAA,UACG,IACC,gBAAA,EAAC,GAAD;AAAA,IACW,SAAA;AAAA,IACT,IAAI,EACF,IAAI,GACN;AAAA,IAEC,UAAA;AAAA,EACa,CAAA,IAEhB,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IAEC,UAAA;AAAA,EACI,CAAA,EAED,CAAA;AAEd"}
@@ -8,7 +8,7 @@ import { CategoryStore as w } from "./CategoryStore.es.js";
8
8
  import { ConnectStore as d } from "./ConnectStore.es.js";
9
9
  import { DebtsStore as u } from "./DebtsStore.es.js";
10
10
  import { FinstrongStore as b } from "./FinstrongStore.es.js";
11
- import { DefaultAppConfig as h } from "../constants/DefaultConfig.es.js";
11
+ import { DefaultAppConfig as S } from "../constants/DefaultConfig.es.js";
12
12
  import { GlobalUiStore as y } from "./GlobalUiStore.es.js";
13
13
  import { GlobalCopyStore as C } from "./GlobalCopyStore.es.js";
14
14
  import { GoalStore as U } from "./GoalStore.es.js";
@@ -24,8 +24,8 @@ import { TransactionStore as M } from "./TransactionStore.es.js";
24
24
  import { TrendsStore as V } from "./TrendsStore.es.js";
25
25
  import { UserStore as W } from "./UserStore.es.js";
26
26
  import { autorun as v, makeAutoObservable as z } from "mobx";
27
- var St = class {
28
- appConfig = h;
27
+ var ht = class {
28
+ appConfig = S;
29
29
  endpoint = "/";
30
30
  sessionToken = "";
31
31
  onCaptureException;
@@ -55,7 +55,7 @@ var St = class {
55
55
  userStore;
56
56
  globalUiStore;
57
57
  insightsV2Store;
58
- constructor(t = h, o = "/", r, e, i) {
58
+ constructor(t = S, o = "/", r, e, i) {
59
59
  this.appConfig = t, this.endpoint = o, this.sessionToken = t.options.session_token ?? "", this.onCaptureException = i, this.onError = r, this.onStoreUpdate = e, this.accountStore = new p(this), this.appDataStore = new c(this), this.analyticsStore = new m(this), this.beatStore = new f(this), this.budgetsStore = new l(this), this.cashflowStore = new g(this), this.categoryStore = new w(this), this.connectStore = new d(this), this.copyStore = new C(this), this.debtsStore = new u(this), this.finstrongStore = new b(this), this.goalStore = new U(this), this.helpStore = new D(this), this.holdingStore = new A(this), this.merchantStore = new E(this), this.netWorthStore = new x(this), this.notificationStore = new k(this), this.recurringTransactionsStore = new G(this), this.settingsStore = new I(this), this.transactionStore = new M(this), this.trendsStore = new V(this), this.userStore = new W(this), this.globalUiStore = new y(this), this.insightsV2Store = new T(this), z(this), v(() => {
60
60
  const { transactions: s } = this.transactionStore;
61
61
  this.emitUpdate({ transactions: s });
@@ -65,7 +65,11 @@ var St = class {
65
65
  return this.globalUiStore.isInitialized;
66
66
  }
67
67
  captureException = (t, o) => {
68
- this.onCaptureException?.(t, o);
68
+ if (this.onCaptureException) {
69
+ this.onCaptureException(t, o);
70
+ return;
71
+ }
72
+ console.error("Unreported error:", t, o);
69
73
  };
70
74
  emitUpdate = (t) => {
71
75
  this.onStoreUpdate?.(t);
@@ -78,12 +82,12 @@ var St = class {
78
82
  this.userStore.loadUserFeatures()
79
83
  ]);
80
84
  };
81
- loadData = async ({ accounts: t, appData: o, associatedBeats: r, categories: e, institutions: i, transactionRules: s, transactions: a, userFeatures: n, merchantBudgets: S } = {}) => {
82
- (!o || !n) && await this.loadConfigData(), o && this.appDataStore.setAppData(o), n && this.userStore.setUserFeatures(n), t && (await this.accountStore.loadMembers(), i && this.accountStore.setInstitutions(i), this.accountStore.setAccounts(t)), r && this.transactionStore.setAssociatedBeats(r), e && this.categoryStore.setCategories(e), a && this.transactionStore.setTransactions(a), s && this.transactionStore.setTransactionRules(s), S && this.budgetsStore.setMerchantBudgets(S);
85
+ loadData = async ({ accounts: t, appData: o, associatedBeats: r, categories: e, institutions: i, transactionRules: s, transactions: a, userFeatures: n, merchantBudgets: h } = {}) => {
86
+ (!o || !n) && await this.loadConfigData(), o && this.appDataStore.setAppData(o), n && this.userStore.setUserFeatures(n), t && (await this.accountStore.loadMembers(), i && this.accountStore.setInstitutions(i), this.accountStore.setAccounts(t)), r && this.transactionStore.setAssociatedBeats(r), e && this.categoryStore.setCategories(e), a && this.transactionStore.setTransactions(a), s && this.transactionStore.setTransactionRules(s), h && this.budgetsStore.setMerchantBudgets(h);
83
87
  };
84
88
  };
85
89
  export {
86
- St as GlobalStore
90
+ ht as GlobalStore
87
91
  };
88
92
 
89
93
  //# sourceMappingURL=GlobalStore.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalStore.es.js","names":[],"sources":["../../../src/core/stores/GlobalStore.ts"],"sourcesContent":["import { autorun, makeAutoObservable } from 'mobx'\n\nimport { DefaultAppConfig } from '../constants/DefaultConfig'\n\nimport {\n AccountStore,\n AnalyticsStore,\n AppDataStore,\n BeatStore,\n BudgetsStore,\n CashflowStore,\n CategoryStore,\n ConnectStore,\n DebtsStore,\n FinstrongStore,\n GlobalCopyStore,\n GlobalUiStore,\n GoalStore,\n HelpStore,\n HoldingStore,\n InsightsV2Store,\n MerchantStore,\n NetWorthStore,\n NotificationStore,\n RecurringTransactionsStore,\n SettingsStore,\n TransactionStore,\n TrendsStore,\n UserStore,\n} from '../stores'\n\nimport type {\n Account,\n Category,\n Institution,\n Member,\n AppConfig,\n AppData,\n Beat,\n GlobalCaptureException,\n GlobalErrorHandler,\n MerchantBudget,\n Tag,\n Tagging,\n Transaction,\n TransactionRule,\n UserFeature,\n} from '../types'\n\ninterface LoadDataProps {\n accounts?: Account[]\n appData?: AppData\n associatedBeats?: Beat[]\n categories?: Category[]\n institutions?: Institution[]\n members?: Member[]\n merchantBudgets?: MerchantBudget[]\n taggings?: Tagging[]\n tags?: Tag[]\n transactionRules?: TransactionRule[]\n transactions?: Transaction[]\n userFeatures?: UserFeature[]\n}\n\ntype OnStoreUpdate = (update: ObservedUpdate) => void\ntype ObservedUpdate = {\n transactions: Transaction[]\n}\nexport class GlobalStore {\n // Global properties\n appConfig: AppConfig = DefaultAppConfig\n endpoint: string = '/'\n sessionToken: string = ''\n onCaptureException?: GlobalCaptureException\n onError?: GlobalErrorHandler\n onStoreUpdate?: OnStoreUpdate\n\n // Data Stores\n accountStore: AccountStore\n appDataStore: AppDataStore\n analyticsStore: AnalyticsStore\n beatStore: BeatStore\n budgetsStore: BudgetsStore\n cashflowStore: CashflowStore\n categoryStore: CategoryStore\n connectStore: ConnectStore\n copyStore: GlobalCopyStore\n debtsStore: DebtsStore\n finstrongStore: FinstrongStore\n goalStore: GoalStore\n helpStore: HelpStore\n holdingStore: HoldingStore\n merchantStore: MerchantStore\n netWorthStore: NetWorthStore\n notificationStore: NotificationStore\n recurringTransactionsStore: RecurringTransactionsStore\n settingsStore: SettingsStore\n transactionStore: TransactionStore\n trendsStore: TrendsStore\n userStore: UserStore\n\n // UI Stores\n globalUiStore: GlobalUiStore\n insightsV2Store: InsightsV2Store\n\n constructor(\n appConfig: AppConfig = DefaultAppConfig,\n endpoint: string = '/',\n onError?: GlobalErrorHandler,\n onStoreUpdate?: OnStoreUpdate,\n onCaptureException?: GlobalCaptureException,\n ) {\n this.appConfig = appConfig\n this.endpoint = endpoint\n this.sessionToken = appConfig.options.session_token ?? ''\n this.onCaptureException = onCaptureException\n this.onError = onError\n this.onStoreUpdate = onStoreUpdate\n\n this.accountStore = new AccountStore(this)\n this.appDataStore = new AppDataStore(this)\n this.analyticsStore = new AnalyticsStore(this)\n this.beatStore = new BeatStore(this)\n this.budgetsStore = new BudgetsStore(this)\n this.cashflowStore = new CashflowStore(this)\n this.categoryStore = new CategoryStore(this)\n this.connectStore = new ConnectStore(this)\n this.copyStore = new GlobalCopyStore(this)\n this.debtsStore = new DebtsStore(this)\n this.finstrongStore = new FinstrongStore(this)\n this.goalStore = new GoalStore(this)\n this.helpStore = new HelpStore(this)\n this.holdingStore = new HoldingStore(this)\n this.merchantStore = new MerchantStore(this)\n this.netWorthStore = new NetWorthStore(this)\n this.notificationStore = new NotificationStore(this)\n this.recurringTransactionsStore = new RecurringTransactionsStore(this)\n this.settingsStore = new SettingsStore(this)\n this.transactionStore = new TransactionStore(this)\n this.trendsStore = new TrendsStore(this)\n this.userStore = new UserStore(this)\n\n this.globalUiStore = new GlobalUiStore(this)\n this.insightsV2Store = new InsightsV2Store(this)\n\n makeAutoObservable(this)\n\n // detects a change based on an observed value\n autorun(() => {\n // destructure or assign new variables to observe changes to them\n // in this case we are observing changes to `transactions`\n const { transactions } = this.transactionStore\n this.emitUpdate({\n transactions,\n })\n })\n }\n\n get isInitialized() {\n return this.globalUiStore.isInitialized\n }\n\n captureException = (error: unknown, context?: Record<string, string>) => {\n this.onCaptureException?.(error, context)\n }\n\n // emits change triggered in the autorun\n emitUpdate = (change: ObservedUpdate) => {\n this.onStoreUpdate?.(change)\n }\n\n loadConfigData = async () => {\n await Promise.all([\n // Load copy, config and user data\n this.copyStore.loadCopy(),\n this.appDataStore.loadAppData(),\n this.accountStore.refreshMembers(),\n this.userStore.loadUserFeatures(),\n ])\n }\n\n loadData = async ({\n accounts,\n appData,\n associatedBeats,\n categories,\n institutions,\n transactionRules,\n transactions,\n userFeatures,\n merchantBudgets,\n }: LoadDataProps = {}) => {\n if (!appData || !userFeatures) {\n await this.loadConfigData()\n }\n\n // Keep for backwards compatibility for Insights\n if (appData) {\n this.appDataStore.setAppData(appData)\n }\n\n if (userFeatures) {\n this.userStore.setUserFeatures(userFeatures)\n }\n\n if (accounts) {\n await this.accountStore.loadMembers()\n if (institutions) {\n this.accountStore.setInstitutions(institutions)\n }\n this.accountStore.setAccounts(accounts)\n }\n\n if (associatedBeats) {\n this.transactionStore.setAssociatedBeats(associatedBeats)\n }\n\n if (categories) {\n this.categoryStore.setCategories(categories)\n }\n\n if (transactions) {\n this.transactionStore.setTransactions(transactions)\n }\n\n if (transactionRules) {\n this.transactionStore.setTransactionRules(transactionRules)\n }\n\n if (merchantBudgets) {\n this.budgetsStore.setMerchantBudgets(merchantBudgets)\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"GlobalStore.es.js","names":[],"sources":["../../../src/core/stores/GlobalStore.ts"],"sourcesContent":["import { autorun, makeAutoObservable } from 'mobx'\n\nimport { DefaultAppConfig } from '../constants/DefaultConfig'\n\nimport {\n AccountStore,\n AnalyticsStore,\n AppDataStore,\n BeatStore,\n BudgetsStore,\n CashflowStore,\n CategoryStore,\n ConnectStore,\n DebtsStore,\n FinstrongStore,\n GlobalCopyStore,\n GlobalUiStore,\n GoalStore,\n HelpStore,\n HoldingStore,\n InsightsV2Store,\n MerchantStore,\n NetWorthStore,\n NotificationStore,\n RecurringTransactionsStore,\n SettingsStore,\n TransactionStore,\n TrendsStore,\n UserStore,\n} from '../stores'\n\nimport type {\n Account,\n Category,\n Institution,\n Member,\n AppConfig,\n AppData,\n Beat,\n GlobalCaptureException,\n GlobalErrorHandler,\n MerchantBudget,\n Tag,\n Tagging,\n Transaction,\n TransactionRule,\n UserFeature,\n} from '../types'\n\ninterface LoadDataProps {\n accounts?: Account[]\n appData?: AppData\n associatedBeats?: Beat[]\n categories?: Category[]\n institutions?: Institution[]\n members?: Member[]\n merchantBudgets?: MerchantBudget[]\n taggings?: Tagging[]\n tags?: Tag[]\n transactionRules?: TransactionRule[]\n transactions?: Transaction[]\n userFeatures?: UserFeature[]\n}\n\ntype OnStoreUpdate = (update: ObservedUpdate) => void\ntype ObservedUpdate = {\n transactions: Transaction[]\n}\nexport class GlobalStore {\n // Global properties\n appConfig: AppConfig = DefaultAppConfig\n endpoint: string = '/'\n sessionToken: string = ''\n onCaptureException?: GlobalCaptureException\n onError?: GlobalErrorHandler\n onStoreUpdate?: OnStoreUpdate\n\n // Data Stores\n accountStore: AccountStore\n appDataStore: AppDataStore\n analyticsStore: AnalyticsStore\n beatStore: BeatStore\n budgetsStore: BudgetsStore\n cashflowStore: CashflowStore\n categoryStore: CategoryStore\n connectStore: ConnectStore\n copyStore: GlobalCopyStore\n debtsStore: DebtsStore\n finstrongStore: FinstrongStore\n goalStore: GoalStore\n helpStore: HelpStore\n holdingStore: HoldingStore\n merchantStore: MerchantStore\n netWorthStore: NetWorthStore\n notificationStore: NotificationStore\n recurringTransactionsStore: RecurringTransactionsStore\n settingsStore: SettingsStore\n transactionStore: TransactionStore\n trendsStore: TrendsStore\n userStore: UserStore\n\n // UI Stores\n globalUiStore: GlobalUiStore\n insightsV2Store: InsightsV2Store\n\n constructor(\n appConfig: AppConfig = DefaultAppConfig,\n endpoint: string = '/',\n onError?: GlobalErrorHandler,\n onStoreUpdate?: OnStoreUpdate,\n onCaptureException?: GlobalCaptureException,\n ) {\n this.appConfig = appConfig\n this.endpoint = endpoint\n this.sessionToken = appConfig.options.session_token ?? ''\n this.onCaptureException = onCaptureException\n this.onError = onError\n this.onStoreUpdate = onStoreUpdate\n\n this.accountStore = new AccountStore(this)\n this.appDataStore = new AppDataStore(this)\n this.analyticsStore = new AnalyticsStore(this)\n this.beatStore = new BeatStore(this)\n this.budgetsStore = new BudgetsStore(this)\n this.cashflowStore = new CashflowStore(this)\n this.categoryStore = new CategoryStore(this)\n this.connectStore = new ConnectStore(this)\n this.copyStore = new GlobalCopyStore(this)\n this.debtsStore = new DebtsStore(this)\n this.finstrongStore = new FinstrongStore(this)\n this.goalStore = new GoalStore(this)\n this.helpStore = new HelpStore(this)\n this.holdingStore = new HoldingStore(this)\n this.merchantStore = new MerchantStore(this)\n this.netWorthStore = new NetWorthStore(this)\n this.notificationStore = new NotificationStore(this)\n this.recurringTransactionsStore = new RecurringTransactionsStore(this)\n this.settingsStore = new SettingsStore(this)\n this.transactionStore = new TransactionStore(this)\n this.trendsStore = new TrendsStore(this)\n this.userStore = new UserStore(this)\n\n this.globalUiStore = new GlobalUiStore(this)\n this.insightsV2Store = new InsightsV2Store(this)\n\n makeAutoObservable(this)\n\n // detects a change based on an observed value\n autorun(() => {\n // destructure or assign new variables to observe changes to them\n // in this case we are observing changes to `transactions`\n const { transactions } = this.transactionStore\n this.emitUpdate({\n transactions,\n })\n })\n }\n\n get isInitialized() {\n return this.globalUiStore.isInitialized\n }\n\n captureException = (error: unknown, context?: Record<string, string>) => {\n if (this.onCaptureException) {\n this.onCaptureException(error, context)\n return\n }\n console.error('Unreported error:', error, context)\n }\n\n // emits change triggered in the autorun\n emitUpdate = (change: ObservedUpdate) => {\n this.onStoreUpdate?.(change)\n }\n\n loadConfigData = async () => {\n await Promise.all([\n // Load copy, config and user data\n this.copyStore.loadCopy(),\n this.appDataStore.loadAppData(),\n this.accountStore.refreshMembers(),\n this.userStore.loadUserFeatures(),\n ])\n }\n\n loadData = async ({\n accounts,\n appData,\n associatedBeats,\n categories,\n institutions,\n transactionRules,\n transactions,\n userFeatures,\n merchantBudgets,\n }: LoadDataProps = {}) => {\n if (!appData || !userFeatures) {\n await this.loadConfigData()\n }\n\n // Keep for backwards compatibility for Insights\n if (appData) {\n this.appDataStore.setAppData(appData)\n }\n\n if (userFeatures) {\n this.userStore.setUserFeatures(userFeatures)\n }\n\n if (accounts) {\n await this.accountStore.loadMembers()\n if (institutions) {\n this.accountStore.setInstitutions(institutions)\n }\n this.accountStore.setAccounts(accounts)\n }\n\n if (associatedBeats) {\n this.transactionStore.setAssociatedBeats(associatedBeats)\n }\n\n if (categories) {\n this.categoryStore.setCategories(categories)\n }\n\n if (transactions) {\n this.transactionStore.setTransactions(transactions)\n }\n\n if (transactionRules) {\n this.transactionStore.setTransactionRules(transactionRules)\n }\n\n if (merchantBudgets) {\n this.budgetsStore.setMerchantBudgets(merchantBudgets)\n }\n }\n}\n"],"mappings":"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"}
@@ -159,6 +159,7 @@ export declare class RecurringTransactionsStore {
159
159
  * @param transaction - The transaction to unlink.
160
160
  */
161
161
  markRecurrenceAsUnpaid: (transaction: Transaction) => Promise<void>;
162
+ private captureError;
162
163
  setAlert: (message: string, severity?: RecurringAlertProps["severity"]) => {
163
164
  message: string;
164
165
  severity: import('@mui/types').OverridableStringUnion<import('@mui/material').AlertColor, import('@mui/material').AlertPropsColorOverrides> | undefined;
@@ -1,24 +1,24 @@
1
- import { RepeatingTransactionsApi as p } from "../api/RepeatingTransactionsApi.es.js";
2
- import { RecurrenceStatus as n, RecurrenceType as o } from "../types/RepeatingTransaction.es.js";
3
- import { augmentRepeatingTransactions as c, buildAllRecurrences as m } from "../utils/RecurringTransactionsUtil.es.js";
1
+ import { RepeatingTransactionsApi as l } from "../api/RepeatingTransactionsApi.es.js";
2
+ import { RecurrenceStatus as n, RecurrenceType as c } from "../types/RepeatingTransaction.es.js";
3
+ import { augmentRepeatingTransactions as o, buildAllRecurrences as m } from "../utils/RecurringTransactionsUtil.es.js";
4
4
  import { endOfMonth as R } from "date-fns/endOfMonth";
5
5
  import { isBefore as T } from "date-fns/isBefore";
6
6
  import { startOfMonth as f } from "date-fns/startOfMonth";
7
- import { startOfToday as a } from "date-fns/startOfToday";
7
+ import { startOfToday as s } from "date-fns/startOfToday";
8
8
  import { isSameDay as g } from "date-fns/isSameDay";
9
9
  import { isWithinInterval as h } from "date-fns/isWithinInterval";
10
- import { subDays as S } from "date-fns/subDays";
11
- import { makeAutoObservable as y, runInAction as u } from "mobx";
12
- import { isAfter as l } from "date-fns/isAfter";
13
- var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
10
+ import { subDays as y } from "date-fns/subDays";
11
+ import { makeAutoObservable as S, runInAction as u } from "mobx";
12
+ import { isAfter as p } from "date-fns/isAfter";
13
+ var d = (e, t) => h(t.expectedDate, e), a = (e, t) => e + t.amount, U = class {
14
14
  globalStore;
15
- api = new p("/", "");
15
+ api = new l("/", "");
16
16
  repeatingTransactions = [];
17
17
  isDataLoaded = !1;
18
18
  selectedDay;
19
19
  dateRange = {
20
- start: f(a()),
21
- end: R(a())
20
+ start: f(s()),
21
+ end: R(s())
22
22
  };
23
23
  selectedRepeatingTransactionGuid = null;
24
24
  selectedRecurrence = null;
@@ -27,7 +27,7 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
27
27
  severity: void 0
28
28
  };
29
29
  constructor(e) {
30
- this.globalStore = e, this.api = new p(e.endpoint, e.sessionToken, e.onError), y(this, {
30
+ this.globalStore = e, this.api = new l(e.endpoint, e.sessionToken, e.onError), S(this, {
31
31
  recurrencesForRange: !1,
32
32
  upcomingExpensesForRange: !1,
33
33
  upcomingIncomeForRange: !1,
@@ -39,16 +39,16 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
39
39
  return this.globalStore.copyStore.copy.recurring;
40
40
  }
41
41
  get detailedRepeatingTransactions() {
42
- return c(this.globalStore.accountStore.visibleAccounts, this.repeatingTransactions, this.globalStore.transactionStore.transactions);
42
+ return o(this.globalStore.accountStore.visibleAccounts, this.repeatingTransactions, this.globalStore.transactionStore.transactions);
43
43
  }
44
44
  recurrencesForRange = (e) => {
45
45
  const t = this.globalStore.accountStore.visibleAccounts;
46
46
  return m(this.detailedRepeatingTransactions, e).filter((r) => t.some((i) => i.guid === r.accountGuid && !i.is_excluded_from_accounts)).filter((r) => h(r.expectedDate, e));
47
47
  };
48
- upcomingExpensesForRange = (e) => this.recurrencesForRange(e).filter((t) => t.type === o.Expense && t.status === n.Upcoming);
49
- incomeForRange = (e) => this.recurrencesForRange(e).filter((t) => t.type === o.Income);
48
+ upcomingExpensesForRange = (e) => this.recurrencesForRange(e).filter((t) => t.type === c.Expense && t.status === n.Upcoming);
49
+ incomeForRange = (e) => this.recurrencesForRange(e).filter((t) => t.type === c.Income);
50
50
  upcomingIncomeForRange = (e) => this.incomeForRange(e).filter((t) => t.status === n.Upcoming);
51
- nextIncomeForRange = (e) => this.upcomingIncomeForRange(e).find((t) => l(t.expectedDate, a()));
51
+ nextIncomeForRange = (e) => this.upcomingIncomeForRange(e).find((t) => p(t.expectedDate, s()));
52
52
  get recurrences() {
53
53
  return this.recurrencesForRange(this.dateRange);
54
54
  }
@@ -56,22 +56,22 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
56
56
  return this.recurrences.filter((e) => e.status === n.Paid || e.status === n.Missed);
57
57
  }
58
58
  get upcomingRecurrences() {
59
- return this.recurrences.filter((e) => l(e.expectedDate, S(a(), 3)) && T(e.expectedDate, this.dateRange.end) && e.status === n.Upcoming);
59
+ return this.recurrences.filter((e) => p(e.expectedDate, y(s(), 3)) && T(e.expectedDate, this.dateRange.end) && e.status === n.Upcoming);
60
60
  }
61
61
  get expenses() {
62
- return this.recurrences.filter((e) => e.type === o.Expense);
62
+ return this.recurrences.filter((e) => e.type === c.Expense);
63
63
  }
64
64
  get upcomingExpenses() {
65
65
  return this.expenses.filter((e) => e.status === n.Upcoming);
66
66
  }
67
67
  get income() {
68
- return this.recurrences.filter((e) => e.type === o.Income);
68
+ return this.recurrences.filter((e) => e.type === c.Income);
69
69
  }
70
70
  get upcomingIncome() {
71
71
  return this.income.filter((e) => e.status === n.Upcoming);
72
72
  }
73
73
  get nextIncomeRecurrence() {
74
- return this.upcomingIncome.find((e) => l(e.expectedDate, a()));
74
+ return this.upcomingIncome.find((e) => p(e.expectedDate, s()));
75
75
  }
76
76
  get currentMonthExpenses() {
77
77
  return this.expenses.filter((e) => d(this.dateRange, e));
@@ -80,25 +80,25 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
80
80
  return this.income.filter((e) => d(this.dateRange, e));
81
81
  }
82
82
  get expenseTotal() {
83
- return this.currentMonthExpenses.reduce(s, 0);
83
+ return this.currentMonthExpenses.reduce(a, 0);
84
84
  }
85
85
  get paidExpenseTotal() {
86
- return this.currentMonthExpenses.filter((e) => e.status === n.Paid).reduce(s, 0);
86
+ return this.currentMonthExpenses.filter((e) => e.status === n.Paid).reduce(a, 0);
87
87
  }
88
88
  get missedExpenseTotal() {
89
- return this.currentMonthExpenses.filter((e) => e.status === n.Missed).reduce(s, 0);
89
+ return this.currentMonthExpenses.filter((e) => e.status === n.Missed).reduce(a, 0);
90
90
  }
91
91
  get upcomingExpenseTotal() {
92
- return this.currentMonthExpenses.filter((e) => e.status === n.Upcoming).reduce(s, 0);
92
+ return this.currentMonthExpenses.filter((e) => e.status === n.Upcoming).reduce(a, 0);
93
93
  }
94
94
  get incomeTotal() {
95
- return this.currentMonthIncome.reduce(s, 0);
95
+ return this.currentMonthIncome.reduce(a, 0);
96
96
  }
97
97
  get paidIncomeTotal() {
98
- return this.currentMonthIncome.filter((e) => e.status === n.Paid).reduce(s, 0);
98
+ return this.currentMonthIncome.filter((e) => e.status === n.Paid).reduce(a, 0);
99
99
  }
100
100
  get upcomingIncomeTotal() {
101
- return this.currentMonthIncome.filter((e) => e.status === n.Upcoming).reduce(s, 0);
101
+ return this.currentMonthIncome.filter((e) => e.status === n.Upcoming).reduce(a, 0);
102
102
  }
103
103
  get selectedDayRecurrences() {
104
104
  return this.selectedDay && this.recurrences.filter((e) => this.selectedDay && g(e.occurredOnDate || e.expectedDate, this.selectedDay));
@@ -127,7 +127,7 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
127
127
  const e = await this.api.getRepeatingTransactions();
128
128
  this.setRepeatingTransactions(e);
129
129
  } catch (e) {
130
- console.error("Error occurred while getting repeating transactions:", e), this.globalStore.captureException(e, { store: "RecurringTransactionsStore" });
130
+ this.captureError("getRepeatingTransactions", e);
131
131
  }
132
132
  };
133
133
  addRepeatingTransaction = async (e, t) => {
@@ -137,19 +137,19 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
137
137
  ...t,
138
138
  repeating_transaction_guid: r.guid
139
139
  }), u(() => {
140
- this.repeatingTransactions = [...this.repeatingTransactions, ...c(this.globalStore.accountStore.visibleAccounts, [r], this.globalStore.transactionStore.transactions)];
140
+ this.repeatingTransactions = [...this.repeatingTransactions, ...o(this.globalStore.accountStore.visibleAccounts, [r], this.globalStore.transactionStore.transactions)];
141
141
  }), this.setAlert(this.copy.add_repeating_transaction_success, "success"), !0;
142
142
  } catch (r) {
143
- return console.error("Error occurred while adding repeating transaction:", r), this.globalStore.captureException(r, { store: "RecurringTransactionsStore" }), this.setAlert(this.copy.add_repeating_transaction_error, "error"), !1;
143
+ return this.captureError("addRepeatingTransaction", r), this.setAlert(this.copy.add_repeating_transaction_error, "error"), !1;
144
144
  }
145
145
  };
146
146
  deleteRepeatingTransaction = async (e) => {
147
147
  try {
148
148
  return await this.api.deleteRepeatingTransaction(e), u(() => {
149
- this.repeatingTransactions = [...this.repeatingTransactions.filter((t) => t.guid !== e)];
149
+ this.repeatingTransactions = this.repeatingTransactions.filter((t) => t.guid !== e);
150
150
  }), this.setAlert(this.copy.remove_repeating_transaction_success, "success"), !0;
151
151
  } catch (t) {
152
- return console.error("Error occurred while deleting repeating transaction:", t), this.globalStore.captureException(t, { store: "RecurringTransactionsStore" }), this.setAlert(this.copy.remove_repeating_transaction_error, "error"), !1;
152
+ return this.captureError("deleteRepeatingTransaction", t), this.setAlert(this.copy.remove_repeating_transaction_error, "error"), !1;
153
153
  }
154
154
  };
155
155
  updateRepeatingTransaction = async (e) => {
@@ -158,12 +158,12 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
158
158
  return r < 0 ? !1 : (u(() => {
159
159
  this.repeatingTransactions = [
160
160
  ...this.repeatingTransactions.slice(0, r),
161
- ...c(this.globalStore.accountStore.visibleAccounts, [t], this.globalStore.transactionStore.transactions),
161
+ ...o(this.globalStore.accountStore.visibleAccounts, [t], this.globalStore.transactionStore.transactions),
162
162
  ...this.repeatingTransactions.slice(r + 1)
163
163
  ];
164
164
  }), this.setAlert(this.copy.update_repeating_transaction_success, "success"), !0);
165
165
  } catch (t) {
166
- return console.error("Error occurred while updating repeating transaction:", t), this.globalStore.captureException(t, { store: "RecurringTransactionsStore" }), this.setAlert(this.copy.update_repeating_transaction_error, "error"), !1;
166
+ return this.captureError("updateRepeatingTransaction", t), this.setAlert(this.copy.update_repeating_transaction_error, "error"), !1;
167
167
  }
168
168
  };
169
169
  markRecurrenceAsPaid = async (e, t) => {
@@ -173,7 +173,7 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
173
173
  repeating_transaction_guid: e
174
174
  }), await this.loadRepeatingTransactions(), this.setSelectedRecurrence(null), this.setAlert(this.copy.link_transaction_success, "success");
175
175
  } catch (r) {
176
- console.error("Error occurred while marking recurrence as paid:", r), this.globalStore.captureException(r, { store: "RecurringTransactionsStore" }), this.setAlert(this.copy.link_transaction_error, "error");
176
+ this.captureError("markRecurrenceAsPaid", r), this.setAlert(this.copy.link_transaction_error, "error");
177
177
  }
178
178
  };
179
179
  markRecurrenceAsUnpaid = async (e) => {
@@ -183,9 +183,13 @@ var d = (e, t) => h(t.expectedDate, e), s = (e, t) => e + t.amount, U = class {
183
183
  repeating_transaction_guid: null
184
184
  }), await this.loadRepeatingTransactions(), this.setSelectedRecurrence(null), this.setAlert(this.copy.unlink_transaction_success, "success");
185
185
  } catch (t) {
186
- console.error("Error occurred while marking recurrence as unpaid:", t), this.globalStore.captureException(t, { store: "RecurringTransactionsStore" }), this.setAlert(this.copy.unlink_transaction_error, "error");
186
+ this.captureError("markRecurrenceAsUnpaid", t), this.setAlert(this.copy.unlink_transaction_error, "error");
187
187
  }
188
188
  };
189
+ captureError = (e, t) => this.globalStore.captureException(t, {
190
+ store: "RecurringTransactionsStore",
191
+ action: e
192
+ });
189
193
  setAlert = (e, t = void 0) => this.alert = {
190
194
  message: e,
191
195
  severity: t
@@ -1 +1 @@
1
- {"version":3,"file":"RecurringTransactionsStore.es.js","names":[],"sources":["../../../src/core/stores/RecurringTransactionsStore.ts"],"sourcesContent":["import { type AlertProps } from '@mui/material'\nimport { makeAutoObservable, runInAction } from 'mobx'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { isAfter } from 'date-fns/isAfter'\nimport { isBefore } from 'date-fns/isBefore'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { isWithinInterval } from 'date-fns/isWithinInterval'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\nimport { subDays } from 'date-fns/subDays'\n\nimport { RepeatingTransactionsApi } from '../api'\nimport {\n type Recurrence,\n type RecurringCopy,\n type RepeatingTransaction,\n type Transaction,\n RecurrenceStatus,\n RecurrenceType,\n type DateRange,\n} from '../types'\nimport {\n augmentRepeatingTransactions,\n buildAllRecurrences,\n} from '../utils/RecurringTransactionsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nconst currentMonthFilter = (date: DateRange, recurrence: Recurrence) =>\n isWithinInterval(recurrence.expectedDate, date)\n\nconst recurrenceTotalReducer = (total: number, recurrence: Recurrence) => total + recurrence.amount\n\ninterface RecurringAlertProps {\n message: string\n severity: AlertProps['severity']\n}\n\nexport class RecurringTransactionsStore {\n globalStore: GlobalStore\n api = new RepeatingTransactionsApi('/', '')\n\n repeatingTransactions: RepeatingTransaction[] = []\n isDataLoaded: boolean = false\n\n selectedDay: Date | undefined\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n selectedRepeatingTransactionGuid: string | null = null\n selectedRecurrence: Recurrence | null = null\n\n alert: RecurringAlertProps = { message: '', severity: undefined }\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new RepeatingTransactionsApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n // The *ForRange helpers are parameterized computeds: they must stay plain\n // methods (not actions) so observable reads inside them remain tracked when\n // invoked from an observer/derivation. makeAutoObservable would otherwise\n // annotate them as actions, which do not track reads.\n makeAutoObservable(this, {\n recurrencesForRange: false,\n upcomingExpensesForRange: false,\n upcomingIncomeForRange: false,\n incomeForRange: false,\n nextIncomeForRange: false,\n })\n }\n\n get copy(): RecurringCopy {\n return this.globalStore.copyStore.copy.recurring\n }\n\n get detailedRepeatingTransactions(): RepeatingTransaction[] {\n return augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n this.repeatingTransactions,\n this.globalStore.transactionStore.transactions,\n )\n }\n\n /**\n * Returns all recurrences built from repeating transactions and filtered by\n * accounts, scoped to the supplied date range. This is the range-parameterized\n * core used by both the shared getters (which pass this.dateRange) and by\n * consumers such as Cash Flow that need their own independent window without\n * mutating the shared dateRange.\n */\n recurrencesForRange = (dateRange: DateRange): Recurrence[] => {\n const accounts = this.globalStore.accountStore.visibleAccounts\n\n return buildAllRecurrences(this.detailedRepeatingTransactions, dateRange)\n .filter((r) => accounts.some((a) => a.guid === r.accountGuid && !a.is_excluded_from_accounts))\n .filter((r) => isWithinInterval(r.expectedDate, dateRange))\n }\n\n /**\n * Returns the upcoming expense recurrences scoped to the supplied date range.\n */\n upcomingExpensesForRange = (dateRange: DateRange): Recurrence[] => {\n return this.recurrencesForRange(dateRange).filter(\n (recurrence: Recurrence) =>\n recurrence.type === RecurrenceType.Expense &&\n recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns the income recurrences scoped to the supplied date range.\n */\n incomeForRange = (dateRange: DateRange): Recurrence[] => {\n return this.recurrencesForRange(dateRange).filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Income,\n )\n }\n\n /**\n * Returns the upcoming income recurrences scoped to the supplied date range.\n */\n upcomingIncomeForRange = (dateRange: DateRange): Recurrence[] => {\n return this.incomeForRange(dateRange).filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns the next upcoming income recurrence scoped to the supplied range.\n */\n nextIncomeForRange = (dateRange: DateRange): Recurrence | undefined => {\n return this.upcomingIncomeForRange(dateRange).find((r) =>\n isAfter(r.expectedDate, startOfToday()),\n )\n }\n\n /**\n * Returns all recurrences built from repeating transactions and filtered by accounts.\n */\n get recurrences(): Recurrence[] {\n return this.recurrencesForRange(this.dateRange)\n }\n\n /**\n * Returns all recurrences that have occurred in the past, including those that are paid or missed\n */\n get pastRecurrences(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) =>\n recurrence.status === RecurrenceStatus.Paid ||\n recurrence.status === RecurrenceStatus.Missed,\n )\n }\n\n /**\n * Returns all recurrences that are expected to occur through the end of the month\n * or should have occurred in the last 3 days.\n */\n get upcomingRecurrences(): Recurrence[] {\n return this.recurrences.filter(\n (r) =>\n isAfter(r.expectedDate, subDays(startOfToday(), 3)) &&\n isBefore(r.expectedDate, this.dateRange.end) &&\n r.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns all expense recurrences.\n */\n get expenses(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Expense,\n )\n }\n\n /**\n * Returns the upcoming expense recurrences.\n */\n get upcomingExpenses(): Recurrence[] {\n return this.expenses.filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns all income recurrences.\n */\n get income(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Income,\n )\n }\n\n /**\n * Returns the upcoming income recurrences.\n */\n get upcomingIncome(): Recurrence[] {\n return this.income.filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n get nextIncomeRecurrence() {\n return this.upcomingIncome.find((r) => isAfter(r.expectedDate, startOfToday()))\n }\n\n /**\n * Returns the expense recurrences for the current month.\n */\n get currentMonthExpenses(): Recurrence[] {\n return this.expenses.filter((recurrence: Recurrence) =>\n currentMonthFilter(this.dateRange, recurrence),\n )\n }\n\n /**\n * Returns the income recurrences for the current month.\n */\n get currentMonthIncome(): Recurrence[] {\n return this.income.filter((recurrence: Recurrence) =>\n currentMonthFilter(this.dateRange, recurrence),\n )\n }\n\n /**\n * Calculates the total amount of all expenses for the current month.\n */\n get expenseTotal(): number {\n return this.currentMonthExpenses.reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all paid expenses for the current month.\n */\n get paidExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Paid)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all missed expenses for the current month.\n */\n get missedExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Missed)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all upcoming expenses for the current month.\n */\n get upcomingExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all income for the current month.\n */\n get incomeTotal(): number {\n return this.currentMonthIncome.reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all paid income for the current month.\n */\n get paidIncomeTotal(): number {\n return this.currentMonthIncome\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Paid)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all upcoming income for the current month.\n */\n get upcomingIncomeTotal(): number {\n return this.currentMonthIncome\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Get the recurrences for the currently selected day.\n */\n get selectedDayRecurrences(): Recurrence[] | undefined {\n return (\n this.selectedDay &&\n this.recurrences.filter(\n (recurrence: Recurrence) =>\n this.selectedDay &&\n isSameDay(recurrence.occurredOnDate || recurrence.expectedDate, this.selectedDay),\n )\n )\n }\n\n get selectedRepeatingTransaction(): RepeatingTransaction | undefined {\n return this.selectedRepeatingTransactionGuid\n ? this.detailedRepeatingTransactions.find(\n (rt) => rt.guid === this.selectedRepeatingTransactionGuid,\n )\n : undefined\n }\n\n setSelectedRepeatingTransactionGuid = (guid: string | null) =>\n (this.selectedRepeatingTransactionGuid = guid)\n\n setSelectedRecurrence = (recurrence: Recurrence | null) => (this.selectedRecurrence = recurrence)\n\n setRepeatingTransactions = (repeating: RepeatingTransaction[]) => {\n this.repeatingTransactions = repeating\n this.isDataLoaded = true\n }\n\n /**\n * Set the date range for filtering recurrences.\n * @param dateRange - The date range to set.\n */\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n /**\n * Set the currently selected day.\n * @param day - The day to select.\n */\n setSelectedDay = (day: Date) => {\n this.selectedDay = this.selectedDay && isSameDay(day, this.selectedDay) ? undefined : day\n }\n\n loadRepeatingTransactionData = async () => {\n await Promise.all([\n this.globalStore.accountStore.loadAccountData(),\n this.globalStore.categoryStore.loadCategories(),\n this.globalStore.transactionStore.loadTransactionData(),\n ])\n await this.loadRepeatingTransactions()\n }\n\n /**\n * Load repeating transactions and augment them with additional data.\n */\n loadRepeatingTransactions = async () => {\n try {\n const repeatingTransactions = await this.api.getRepeatingTransactions()\n this.setRepeatingTransactions(repeatingTransactions)\n } catch (error) {\n console.error('Error occurred while getting repeating transactions:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n }\n }\n\n /**\n * Add a new repeating transaction and link it to the associated transaction.\n * @param repeatingTransaction - The repeating transaction to add.\n * @param transaction - The transaction associated with the repeating transaction.\n */\n addRepeatingTransaction = async (\n repeatingTransaction: RepeatingTransaction,\n transaction: Transaction,\n ): Promise<boolean> => {\n try {\n const newRepeating = await this.api.addRepeatingTransaction(repeatingTransaction)\n\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: newRepeating.guid,\n })\n\n runInAction(() => {\n this.repeatingTransactions = [\n ...this.repeatingTransactions,\n ...augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n [newRepeating],\n this.globalStore.transactionStore.transactions,\n ),\n ]\n })\n\n this.setAlert(this.copy.add_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n console.error('Error occurred while adding repeating transaction:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n this.setAlert(this.copy.add_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Delete a repeating transaction by its GUID.\n * @param guid - The GUID of the repeating transaction to delete.\n */\n deleteRepeatingTransaction = async (guid: string): Promise<boolean> => {\n try {\n await this.api.deleteRepeatingTransaction(guid)\n\n runInAction(() => {\n this.repeatingTransactions = [\n ...this.repeatingTransactions.filter((rt) => rt.guid !== guid),\n ]\n })\n\n this.setAlert(this.copy.remove_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n console.error('Error occurred while deleting repeating transaction:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n this.setAlert(this.copy.remove_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Update an existing repeating transaction.\n * @param transaction - The repeating transaction to update.\n */\n updateRepeatingTransaction = async (transaction: RepeatingTransaction): Promise<boolean> => {\n try {\n const updatedTransaction = await this.api.updateRepeatingTransaction(transaction)\n\n const index = this.repeatingTransactions.findIndex(\n (rt) => rt.guid === updatedTransaction.guid,\n )\n if (index < 0) return false\n\n runInAction(() => {\n this.repeatingTransactions = [\n ...this.repeatingTransactions.slice(0, index),\n ...augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n [updatedTransaction],\n this.globalStore.transactionStore.transactions,\n ),\n ...this.repeatingTransactions.slice(index + 1),\n ]\n })\n\n this.setAlert(this.copy.update_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n console.error('Error occurred while updating repeating transaction:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n this.setAlert(this.copy.update_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Mark a recurrence as paid by linking a transaction to the repeating transaction.\n * @param repeatingTransactionGuid - The GUID of the repeating transaction.\n * @param transaction - The transaction to link.\n */\n markRecurrenceAsPaid = async (repeatingTransactionGuid: string, transaction: Transaction) => {\n try {\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: repeatingTransactionGuid,\n })\n\n await this.loadRepeatingTransactions()\n this.setSelectedRecurrence(null)\n this.setAlert(this.copy.link_transaction_success, 'success')\n } catch (error) {\n console.error('Error occurred while marking recurrence as paid:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n this.setAlert(this.copy.link_transaction_error, 'error')\n }\n }\n\n /**\n * Mark a recurrence as unpaid by unlinking the associated transaction from the repeating transaction.\n * @param transaction - The transaction to unlink.\n */\n markRecurrenceAsUnpaid = async (transaction: Transaction) => {\n try {\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: null,\n })\n\n await this.loadRepeatingTransactions()\n this.setSelectedRecurrence(null)\n this.setAlert(this.copy.unlink_transaction_success, 'success')\n } catch (error) {\n console.error('Error occurred while marking recurrence as unpaid:', error)\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore' })\n this.setAlert(this.copy.unlink_transaction_error, 'error')\n }\n }\n\n setAlert = (message: string, severity: RecurringAlertProps['severity'] = undefined) =>\n (this.alert = { message, severity })\n}\n"],"mappings":";;;;;;;;;;;;AA4BA,IAAM,IAAA,CAAsB,GAAiB,MAC3C,EAAiB,EAAW,cAAc,CAAI,GAE1C,IAAA,CAA0B,GAAe,MAA2B,IAAQ,EAAW,QAOhF,IAAb,MAAwC;AAAA,EACtC;AAAA,EACA,MAAM,IAAI,EAAyB,KAAK,EAAE;AAAA,EAE1C,wBAAgD,CAAC;AAAA,EACjD,eAAwB;AAAA,EAExB;AAAA,EACA,YAAuB;AAAA,IAAE,OAAO,EAAa,EAAa,CAAC;AAAA,IAAG,KAAK,EAAW,EAAa,CAAC;AAAA,EAAE;AAAA,EAC9F,mCAAkD;AAAA,EAClD,qBAAwC;AAAA,EAExC,QAA6B;AAAA,IAAE,SAAS;AAAA,IAAI,UAAU;AAAA,EAAU;AAAA,EAEhE,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EACb,EAAY,UACZ,EAAY,cACZ,EAAY,OACd,GAMA,EAAmB,MAAM;AAAA,MACvB,qBAAqB;AAAA,MACrB,0BAA0B;AAAA,MAC1B,wBAAwB;AAAA,MACxB,gBAAgB;AAAA,MAChB,oBAAoB;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,OAAsB;AACxB,WAAO,KAAK,YAAY,UAAU,KAAK;AAAA,EACzC;AAAA,EAEA,IAAI,gCAAwD;AAC1D,WAAO,EACL,KAAK,YAAY,aAAa,iBAC9B,KAAK,uBACL,KAAK,YAAY,iBAAiB,YACpC;AAAA,EACF;AAAA,EASA,sBAAA,CAAuB,MAAuC;AAC5D,UAAM,IAAW,KAAK,YAAY,aAAa;AAE/C,WAAO,EAAoB,KAAK,+BAA+B,CAAS,EACrE,OAAA,CAAQ,MAAM,EAAS,KAAA,CAAM,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,EAAE,yBAAyB,CAAC,EAC5F,OAAA,CAAQ,MAAM,EAAiB,EAAE,cAAc,CAAS,CAAC;AAAA,EAC9D;AAAA,EAKA,2BAAA,CAA4B,MACnB,KAAK,oBAAoB,CAAS,EAAE,OAAA,CACxC,MACC,EAAW,SAAS,EAAe,WACnC,EAAW,WAAW,EAAiB,QAC3C;AAAA,EAMF,iBAAA,CAAkB,MACT,KAAK,oBAAoB,CAAS,EAAE,OAAA,CACxC,MAA2B,EAAW,SAAS,EAAe,MACjE;AAAA,EAMF,yBAAA,CAA0B,MACjB,KAAK,eAAe,CAAS,EAAE,OAAA,CACnC,MAA2B,EAAW,WAAW,EAAiB,QACrE;AAAA,EAMF,qBAAA,CAAsB,MACb,KAAK,uBAAuB,CAAS,EAAE,KAAA,CAAM,MAClD,EAAQ,EAAE,cAAc,EAAa,CAAC,CACxC;AAAA,EAMF,IAAI,cAA4B;AAC9B,WAAO,KAAK,oBAAoB,KAAK,SAAS;AAAA,EAChD;AAAA,EAKA,IAAI,kBAAgC;AAClC,WAAO,KAAK,YAAY,OAAA,CACrB,MACC,EAAW,WAAW,EAAiB,QACvC,EAAW,WAAW,EAAiB,MAC3C;AAAA,EACF;AAAA,EAMA,IAAI,sBAAoC;AACtC,WAAO,KAAK,YAAY,OAAA,CACrB,MACC,EAAQ,EAAE,cAAc,EAAQ,EAAa,GAAG,CAAC,CAAC,KAClD,EAAS,EAAE,cAAc,KAAK,UAAU,GAAG,KAC3C,EAAE,WAAW,EAAiB,QAClC;AAAA,EACF;AAAA,EAKA,IAAI,WAAyB;AAC3B,WAAO,KAAK,YAAY,OAAA,CACrB,MAA2B,EAAW,SAAS,EAAe,OACjE;AAAA,EACF;AAAA,EAKA,IAAI,mBAAiC;AACnC,WAAO,KAAK,SAAS,OAAA,CAClB,MAA2B,EAAW,WAAW,EAAiB,QACrE;AAAA,EACF;AAAA,EAKA,IAAI,SAAuB;AACzB,WAAO,KAAK,YAAY,OAAA,CACrB,MAA2B,EAAW,SAAS,EAAe,MACjE;AAAA,EACF;AAAA,EAKA,IAAI,iBAA+B;AACjC,WAAO,KAAK,OAAO,OAAA,CAChB,MAA2B,EAAW,WAAW,EAAiB,QACrE;AAAA,EACF;AAAA,EAEA,IAAI,uBAAuB;AACzB,WAAO,KAAK,eAAe,KAAA,CAAM,MAAM,EAAQ,EAAE,cAAc,EAAa,CAAC,CAAC;AAAA,EAChF;AAAA,EAKA,IAAI,uBAAqC;AACvC,WAAO,KAAK,SAAS,OAAA,CAAQ,MAC3B,EAAmB,KAAK,WAAW,CAAU,CAC/C;AAAA,EACF;AAAA,EAKA,IAAI,qBAAmC;AACrC,WAAO,KAAK,OAAO,OAAA,CAAQ,MACzB,EAAmB,KAAK,WAAW,CAAU,CAC/C;AAAA,EACF;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,qBAAqB,OAAO,GAAwB,CAAC;AAAA,EACnE;AAAA,EAKA,IAAI,mBAA2B;AAC7B,WAAO,KAAK,qBACT,OAAA,CAAQ,MAA2B,EAAW,WAAW,EAAiB,IAAI,EAC9E,OAAO,GAAwB,CAAC;AAAA,EACrC;AAAA,EAKA,IAAI,qBAA6B;AAC/B,WAAO,KAAK,qBACT,OAAA,CAAQ,MAA2B,EAAW,WAAW,EAAiB,MAAM,EAChF,OAAO,GAAwB,CAAC;AAAA,EACrC;AAAA,EAKA,IAAI,uBAA+B;AACjC,WAAO,KAAK,qBACT,OAAA,CAAQ,MAA2B,EAAW,WAAW,EAAiB,QAAQ,EAClF,OAAO,GAAwB,CAAC;AAAA,EACrC;AAAA,EAKA,IAAI,cAAsB;AACxB,WAAO,KAAK,mBAAmB,OAAO,GAAwB,CAAC;AAAA,EACjE;AAAA,EAKA,IAAI,kBAA0B;AAC5B,WAAO,KAAK,mBACT,OAAA,CAAQ,MAA2B,EAAW,WAAW,EAAiB,IAAI,EAC9E,OAAO,GAAwB,CAAC;AAAA,EACrC;AAAA,EAKA,IAAI,sBAA8B;AAChC,WAAO,KAAK,mBACT,OAAA,CAAQ,MAA2B,EAAW,WAAW,EAAiB,QAAQ,EAClF,OAAO,GAAwB,CAAC;AAAA,EACrC;AAAA,EAKA,IAAI,yBAAmD;AACrD,WACE,KAAK,eACL,KAAK,YAAY,OAAA,CACd,MACC,KAAK,eACL,EAAU,EAAW,kBAAkB,EAAW,cAAc,KAAK,WAAW,CACpF;AAAA,EAEJ;AAAA,EAEA,IAAI,+BAAiE;AACnE,WAAO,KAAK,mCACR,KAAK,8BAA8B,KAAA,CAChC,MAAO,EAAG,SAAS,KAAK,gCAC3B,IACA;AAAA,EACN;AAAA,EAEA,sCAAA,CAAuC,MACpC,KAAK,mCAAmC;AAAA,EAE3C,wBAAA,CAAyB,MAAmC,KAAK,qBAAqB;AAAA,EAEtF,2BAAA,CAA4B,MAAsC;AAChE,SAAK,wBAAwB,GAC7B,KAAK,eAAe;AAAA,EACtB;AAAA,EAMA,eAAA,CAAgB,MAA0B,KAAK,YAAY;AAAA,EAM3D,iBAAA,CAAkB,MAAc;AAC9B,SAAK,cAAc,KAAK,eAAe,EAAU,GAAK,KAAK,WAAW,IAAI,SAAY;AAAA,EACxF;AAAA,EAEA,+BAA+B,YAAY;AACzC,UAAM,QAAQ,IAAI;AAAA,MAChB,KAAK,YAAY,aAAa,gBAAgB;AAAA,MAC9C,KAAK,YAAY,cAAc,eAAe;AAAA,MAC9C,KAAK,YAAY,iBAAiB,oBAAoB;AAAA,IACxD,CAAC,GACD,MAAM,KAAK,0BAA0B;AAAA,EACvC;AAAA,EAKA,4BAA4B,YAAY;AACtC,QAAI;AACF,YAAM,IAAwB,MAAM,KAAK,IAAI,yBAAyB;AACtE,WAAK,yBAAyB,CAAqB;AAAA,IACrD,SAAS,GAAO;AACd,cAAQ,MAAM,wDAAwD,CAAK,GAC3E,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC;AAAA,IAClF;AAAA,EACF;AAAA,EAOA,0BAA0B,OACxB,GACA,MACqB;AACrB,QAAI;AACF,YAAM,IAAe,MAAM,KAAK,IAAI,wBAAwB,CAAoB;AAEhF,mBAAM,KAAK,YAAY,iBAAiB,kBAAkB;AAAA,QACxD,GAAG;AAAA,QACH,4BAA4B,EAAa;AAAA,MAC3C,CAAC,GAED,EAAA,MAAkB;AAChB,aAAK,wBAAwB,CAC3B,GAAG,KAAK,uBACR,GAAG,EACD,KAAK,YAAY,aAAa,iBAC9B,CAAC,CAAY,GACb,KAAK,YAAY,iBAAiB,YACpC,CACF;AAAA,MACF,CAAC,GAED,KAAK,SAAS,KAAK,KAAK,mCAAmC,SAAS,GAE7D;AAAA,IACT,SAAS,GAAO;AACd,qBAAQ,MAAM,sDAAsD,CAAK,GACzE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC,GAChF,KAAK,SAAS,KAAK,KAAK,iCAAiC,OAAO,GAEzD;AAAA,IACT;AAAA,EACF;AAAA,EAMA,6BAA6B,OAAO,MAAmC;AACrE,QAAI;AACF,mBAAM,KAAK,IAAI,2BAA2B,CAAI,GAE9C,EAAA,MAAkB;AAChB,aAAK,wBAAwB,CAC3B,GAAG,KAAK,sBAAsB,OAAA,CAAQ,MAAO,EAAG,SAAS,CAAI,CAC/D;AAAA,MACF,CAAC,GAED,KAAK,SAAS,KAAK,KAAK,sCAAsC,SAAS,GAEhE;AAAA,IACT,SAAS,GAAO;AACd,qBAAQ,MAAM,wDAAwD,CAAK,GAC3E,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC,GAChF,KAAK,SAAS,KAAK,KAAK,oCAAoC,OAAO,GAE5D;AAAA,IACT;AAAA,EACF;AAAA,EAMA,6BAA6B,OAAO,MAAwD;AAC1F,QAAI;AACF,YAAM,IAAqB,MAAM,KAAK,IAAI,2BAA2B,CAAW,GAE1E,IAAQ,KAAK,sBAAsB,UAAA,CACtC,MAAO,EAAG,SAAS,EAAmB,IACzC;AACA,aAAI,IAAQ,IAAU,MAEtB,EAAA,MAAkB;AAChB,aAAK,wBAAwB;AAAA,UAC3B,GAAG,KAAK,sBAAsB,MAAM,GAAG,CAAK;AAAA,UAC5C,GAAG,EACD,KAAK,YAAY,aAAa,iBAC9B,CAAC,CAAkB,GACnB,KAAK,YAAY,iBAAiB,YACpC;AAAA,UACA,GAAG,KAAK,sBAAsB,MAAM,IAAQ,CAAC;AAAA,QAC/C;AAAA,MACF,CAAC,GAED,KAAK,SAAS,KAAK,KAAK,sCAAsC,SAAS,GAEhE;AAAA,IACT,SAAS,GAAO;AACd,qBAAQ,MAAM,wDAAwD,CAAK,GAC3E,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC,GAChF,KAAK,SAAS,KAAK,KAAK,oCAAoC,OAAO,GAE5D;AAAA,IACT;AAAA,EACF;AAAA,EAOA,uBAAuB,OAAO,GAAkC,MAA6B;AAC3F,QAAI;AACF,YAAM,KAAK,YAAY,iBAAiB,kBAAkB;AAAA,QACxD,GAAG;AAAA,QACH,4BAA4B;AAAA,MAC9B,CAAC,GAED,MAAM,KAAK,0BAA0B,GACrC,KAAK,sBAAsB,IAAI,GAC/B,KAAK,SAAS,KAAK,KAAK,0BAA0B,SAAS;AAAA,IAC7D,SAAS,GAAO;AACd,cAAQ,MAAM,oDAAoD,CAAK,GACvE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC,GAChF,KAAK,SAAS,KAAK,KAAK,wBAAwB,OAAO;AAAA,IACzD;AAAA,EACF;AAAA,EAMA,yBAAyB,OAAO,MAA6B;AAC3D,QAAI;AACF,YAAM,KAAK,YAAY,iBAAiB,kBAAkB;AAAA,QACxD,GAAG;AAAA,QACH,4BAA4B;AAAA,MAC9B,CAAC,GAED,MAAM,KAAK,0BAA0B,GACrC,KAAK,sBAAsB,IAAI,GAC/B,KAAK,SAAS,KAAK,KAAK,4BAA4B,SAAS;AAAA,IAC/D,SAAS,GAAO;AACd,cAAQ,MAAM,sDAAsD,CAAK,GACzE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,6BAA6B,CAAC,GAChF,KAAK,SAAS,KAAK,KAAK,0BAA0B,OAAO;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,WAAA,CAAY,GAAiB,IAA4C,WACtE,KAAK,QAAQ;AAAA,IAAE,SAAA;AAAA,IAAS,UAAA;AAAA,EAAS;AACtC"}
1
+ {"version":3,"file":"RecurringTransactionsStore.es.js","names":[],"sources":["../../../src/core/stores/RecurringTransactionsStore.ts"],"sourcesContent":["import { type AlertProps } from '@mui/material'\nimport { makeAutoObservable, runInAction } from 'mobx'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { isAfter } from 'date-fns/isAfter'\nimport { isBefore } from 'date-fns/isBefore'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { isWithinInterval } from 'date-fns/isWithinInterval'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\nimport { subDays } from 'date-fns/subDays'\n\nimport { RepeatingTransactionsApi } from '../api'\nimport {\n type Recurrence,\n type RecurringCopy,\n type RepeatingTransaction,\n type Transaction,\n RecurrenceStatus,\n RecurrenceType,\n type DateRange,\n} from '../types'\nimport {\n augmentRepeatingTransactions,\n buildAllRecurrences,\n} from '../utils/RecurringTransactionsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nconst currentMonthFilter = (date: DateRange, recurrence: Recurrence) =>\n isWithinInterval(recurrence.expectedDate, date)\n\nconst recurrenceTotalReducer = (total: number, recurrence: Recurrence) => total + recurrence.amount\n\ninterface RecurringAlertProps {\n message: string\n severity: AlertProps['severity']\n}\n\nexport class RecurringTransactionsStore {\n globalStore: GlobalStore\n api = new RepeatingTransactionsApi('/', '')\n\n repeatingTransactions: RepeatingTransaction[] = []\n isDataLoaded: boolean = false\n\n selectedDay: Date | undefined\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n selectedRepeatingTransactionGuid: string | null = null\n selectedRecurrence: Recurrence | null = null\n\n alert: RecurringAlertProps = { message: '', severity: undefined }\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new RepeatingTransactionsApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n // The *ForRange helpers are parameterized computeds: they must stay plain\n // methods (not actions) so observable reads inside them remain tracked when\n // invoked from an observer/derivation. makeAutoObservable would otherwise\n // annotate them as actions, which do not track reads.\n makeAutoObservable(this, {\n recurrencesForRange: false,\n upcomingExpensesForRange: false,\n upcomingIncomeForRange: false,\n incomeForRange: false,\n nextIncomeForRange: false,\n })\n }\n\n get copy(): RecurringCopy {\n return this.globalStore.copyStore.copy.recurring\n }\n\n get detailedRepeatingTransactions(): RepeatingTransaction[] {\n return augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n this.repeatingTransactions,\n this.globalStore.transactionStore.transactions,\n )\n }\n\n /**\n * Returns all recurrences built from repeating transactions and filtered by\n * accounts, scoped to the supplied date range. This is the range-parameterized\n * core used by both the shared getters (which pass this.dateRange) and by\n * consumers such as Cash Flow that need their own independent window without\n * mutating the shared dateRange.\n */\n recurrencesForRange = (dateRange: DateRange): Recurrence[] => {\n const accounts = this.globalStore.accountStore.visibleAccounts\n\n return buildAllRecurrences(this.detailedRepeatingTransactions, dateRange)\n .filter((r) => accounts.some((a) => a.guid === r.accountGuid && !a.is_excluded_from_accounts))\n .filter((r) => isWithinInterval(r.expectedDate, dateRange))\n }\n\n /**\n * Returns the upcoming expense recurrences scoped to the supplied date range.\n */\n upcomingExpensesForRange = (dateRange: DateRange): Recurrence[] => {\n return this.recurrencesForRange(dateRange).filter(\n (recurrence: Recurrence) =>\n recurrence.type === RecurrenceType.Expense &&\n recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns the income recurrences scoped to the supplied date range.\n */\n incomeForRange = (dateRange: DateRange): Recurrence[] => {\n return this.recurrencesForRange(dateRange).filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Income,\n )\n }\n\n /**\n * Returns the upcoming income recurrences scoped to the supplied date range.\n */\n upcomingIncomeForRange = (dateRange: DateRange): Recurrence[] => {\n return this.incomeForRange(dateRange).filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns the next upcoming income recurrence scoped to the supplied range.\n */\n nextIncomeForRange = (dateRange: DateRange): Recurrence | undefined => {\n return this.upcomingIncomeForRange(dateRange).find((r) =>\n isAfter(r.expectedDate, startOfToday()),\n )\n }\n\n /**\n * Returns all recurrences built from repeating transactions and filtered by accounts.\n */\n get recurrences(): Recurrence[] {\n return this.recurrencesForRange(this.dateRange)\n }\n\n /**\n * Returns all recurrences that have occurred in the past, including those that are paid or missed\n */\n get pastRecurrences(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) =>\n recurrence.status === RecurrenceStatus.Paid ||\n recurrence.status === RecurrenceStatus.Missed,\n )\n }\n\n /**\n * Returns all recurrences that are expected to occur through the end of the month\n * or should have occurred in the last 3 days.\n */\n get upcomingRecurrences(): Recurrence[] {\n return this.recurrences.filter(\n (r) =>\n isAfter(r.expectedDate, subDays(startOfToday(), 3)) &&\n isBefore(r.expectedDate, this.dateRange.end) &&\n r.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns all expense recurrences.\n */\n get expenses(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Expense,\n )\n }\n\n /**\n * Returns the upcoming expense recurrences.\n */\n get upcomingExpenses(): Recurrence[] {\n return this.expenses.filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n /**\n * Returns all income recurrences.\n */\n get income(): Recurrence[] {\n return this.recurrences.filter(\n (recurrence: Recurrence) => recurrence.type === RecurrenceType.Income,\n )\n }\n\n /**\n * Returns the upcoming income recurrences.\n */\n get upcomingIncome(): Recurrence[] {\n return this.income.filter(\n (recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming,\n )\n }\n\n get nextIncomeRecurrence() {\n return this.upcomingIncome.find((r) => isAfter(r.expectedDate, startOfToday()))\n }\n\n /**\n * Returns the expense recurrences for the current month.\n */\n get currentMonthExpenses(): Recurrence[] {\n return this.expenses.filter((recurrence: Recurrence) =>\n currentMonthFilter(this.dateRange, recurrence),\n )\n }\n\n /**\n * Returns the income recurrences for the current month.\n */\n get currentMonthIncome(): Recurrence[] {\n return this.income.filter((recurrence: Recurrence) =>\n currentMonthFilter(this.dateRange, recurrence),\n )\n }\n\n /**\n * Calculates the total amount of all expenses for the current month.\n */\n get expenseTotal(): number {\n return this.currentMonthExpenses.reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all paid expenses for the current month.\n */\n get paidExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Paid)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all missed expenses for the current month.\n */\n get missedExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Missed)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all upcoming expenses for the current month.\n */\n get upcomingExpenseTotal(): number {\n return this.currentMonthExpenses\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all income for the current month.\n */\n get incomeTotal(): number {\n return this.currentMonthIncome.reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all paid income for the current month.\n */\n get paidIncomeTotal(): number {\n return this.currentMonthIncome\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Paid)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Calculates the total amount of all upcoming income for the current month.\n */\n get upcomingIncomeTotal(): number {\n return this.currentMonthIncome\n .filter((recurrence: Recurrence) => recurrence.status === RecurrenceStatus.Upcoming)\n .reduce(recurrenceTotalReducer, 0)\n }\n\n /**\n * Get the recurrences for the currently selected day.\n */\n get selectedDayRecurrences(): Recurrence[] | undefined {\n return (\n this.selectedDay &&\n this.recurrences.filter(\n (recurrence: Recurrence) =>\n this.selectedDay &&\n isSameDay(recurrence.occurredOnDate || recurrence.expectedDate, this.selectedDay),\n )\n )\n }\n\n get selectedRepeatingTransaction(): RepeatingTransaction | undefined {\n return this.selectedRepeatingTransactionGuid\n ? this.detailedRepeatingTransactions.find(\n (rt) => rt.guid === this.selectedRepeatingTransactionGuid,\n )\n : undefined\n }\n\n setSelectedRepeatingTransactionGuid = (guid: string | null) =>\n (this.selectedRepeatingTransactionGuid = guid)\n\n setSelectedRecurrence = (recurrence: Recurrence | null) => (this.selectedRecurrence = recurrence)\n\n setRepeatingTransactions = (repeating: RepeatingTransaction[]) => {\n this.repeatingTransactions = repeating\n this.isDataLoaded = true\n }\n\n /**\n * Set the date range for filtering recurrences.\n * @param dateRange - The date range to set.\n */\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n /**\n * Set the currently selected day.\n * @param day - The day to select.\n */\n setSelectedDay = (day: Date) => {\n this.selectedDay = this.selectedDay && isSameDay(day, this.selectedDay) ? undefined : day\n }\n\n loadRepeatingTransactionData = async () => {\n await Promise.all([\n this.globalStore.accountStore.loadAccountData(),\n this.globalStore.categoryStore.loadCategories(),\n this.globalStore.transactionStore.loadTransactionData(),\n ])\n await this.loadRepeatingTransactions()\n }\n\n /**\n * Load repeating transactions and augment them with additional data.\n */\n loadRepeatingTransactions = async () => {\n try {\n const repeatingTransactions = await this.api.getRepeatingTransactions()\n this.setRepeatingTransactions(repeatingTransactions)\n } catch (error) {\n this.captureError('getRepeatingTransactions', error)\n }\n }\n\n /**\n * Add a new repeating transaction and link it to the associated transaction.\n * @param repeatingTransaction - The repeating transaction to add.\n * @param transaction - The transaction associated with the repeating transaction.\n */\n addRepeatingTransaction = async (\n repeatingTransaction: RepeatingTransaction,\n transaction: Transaction,\n ): Promise<boolean> => {\n try {\n const newRepeating = await this.api.addRepeatingTransaction(repeatingTransaction)\n\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: newRepeating.guid,\n })\n\n runInAction(() => {\n this.repeatingTransactions = [\n ...this.repeatingTransactions,\n ...augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n [newRepeating],\n this.globalStore.transactionStore.transactions,\n ),\n ]\n })\n\n this.setAlert(this.copy.add_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n this.captureError('addRepeatingTransaction', error)\n this.setAlert(this.copy.add_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Delete a repeating transaction by its GUID.\n * @param guid - The GUID of the repeating transaction to delete.\n */\n deleteRepeatingTransaction = async (guid: string): Promise<boolean> => {\n try {\n await this.api.deleteRepeatingTransaction(guid)\n\n runInAction(() => {\n this.repeatingTransactions = this.repeatingTransactions.filter((rt) => rt.guid !== guid)\n })\n\n this.setAlert(this.copy.remove_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n this.captureError('deleteRepeatingTransaction', error)\n this.setAlert(this.copy.remove_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Update an existing repeating transaction.\n * @param transaction - The repeating transaction to update.\n */\n updateRepeatingTransaction = async (transaction: RepeatingTransaction): Promise<boolean> => {\n try {\n const updatedTransaction = await this.api.updateRepeatingTransaction(transaction)\n\n const index = this.repeatingTransactions.findIndex(\n (rt) => rt.guid === updatedTransaction.guid,\n )\n if (index < 0) return false\n\n runInAction(() => {\n this.repeatingTransactions = [\n ...this.repeatingTransactions.slice(0, index),\n ...augmentRepeatingTransactions(\n this.globalStore.accountStore.visibleAccounts,\n [updatedTransaction],\n this.globalStore.transactionStore.transactions,\n ),\n ...this.repeatingTransactions.slice(index + 1),\n ]\n })\n\n this.setAlert(this.copy.update_repeating_transaction_success, 'success')\n\n return true\n } catch (error) {\n this.captureError('updateRepeatingTransaction', error)\n this.setAlert(this.copy.update_repeating_transaction_error, 'error')\n\n return false\n }\n }\n\n /**\n * Mark a recurrence as paid by linking a transaction to the repeating transaction.\n * @param repeatingTransactionGuid - The GUID of the repeating transaction.\n * @param transaction - The transaction to link.\n */\n markRecurrenceAsPaid = async (repeatingTransactionGuid: string, transaction: Transaction) => {\n try {\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: repeatingTransactionGuid,\n })\n\n await this.loadRepeatingTransactions()\n this.setSelectedRecurrence(null)\n this.setAlert(this.copy.link_transaction_success, 'success')\n } catch (error) {\n this.captureError('markRecurrenceAsPaid', error)\n this.setAlert(this.copy.link_transaction_error, 'error')\n }\n }\n\n /**\n * Mark a recurrence as unpaid by unlinking the associated transaction from the repeating transaction.\n * @param transaction - The transaction to unlink.\n */\n markRecurrenceAsUnpaid = async (transaction: Transaction) => {\n try {\n await this.globalStore.transactionStore.updateTransaction({\n ...transaction,\n repeating_transaction_guid: null,\n })\n\n await this.loadRepeatingTransactions()\n this.setSelectedRecurrence(null)\n this.setAlert(this.copy.unlink_transaction_success, 'success')\n } catch (error) {\n this.captureError('markRecurrenceAsUnpaid', error)\n this.setAlert(this.copy.unlink_transaction_error, 'error')\n }\n }\n\n private captureError = (action: string, error: unknown) =>\n this.globalStore.captureException(error, { store: 'RecurringTransactionsStore', action })\n\n setAlert = (message: string, severity: RecurringAlertProps['severity'] = undefined) =>\n (this.alert = { message, severity })\n}\n"],"mappings":"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"}
@@ -10,6 +10,8 @@ export declare class TrendsStore {
10
10
  setSelectedDateRange: (dateRange: DateRange) => void;
11
11
  setVisibleListLength: (length: number) => void;
12
12
  get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[];
13
+ get isTransactionStoreIdle(): boolean;
14
+ get isSelectedRangeLoaded(): boolean;
13
15
  get selectedDateRangeMonthCount(): number;
14
16
  get selectedDateRangeMonthRange(): string;
15
17
  get visibleCategories(): DetailedCategoryWithTransactions[];
@@ -1,20 +1,21 @@
1
- import { DATE_FORMATS_INTL as t, formatDate as a } from "../constants/DateFormats.es.js";
2
- import { buildCategoryDetailsChartData as i, filterAndSortCategoriesWithTransactions as r } from "../utils/TrendsUtil.es.js";
3
- import { endOfMonth as s } from "date-fns/endOfMonth";
4
- import { subMonths as o } from "date-fns/subMonths";
5
- import { differenceInCalendarMonths as n } from "date-fns/differenceInCalendarMonths";
6
- import { makeAutoObservable as l } from "mobx";
7
- import { addSeconds as g } from "date-fns/addSeconds";
8
- var u = class {
1
+ import { DATE_FORMATS_INTL as a, formatDate as s } from "../constants/DateFormats.es.js";
2
+ import { buildCategoryDetailsChartData as i, filterAndSortCategoriesWithTransactions as o } from "../utils/TrendsUtil.es.js";
3
+ import { endOfMonth as r } from "date-fns/endOfMonth";
4
+ import { isBefore as n } from "date-fns/isBefore";
5
+ import { subMonths as l } from "date-fns/subMonths";
6
+ import { differenceInCalendarMonths as d } from "date-fns/differenceInCalendarMonths";
7
+ import { makeAutoObservable as g } from "mobx";
8
+ import { addSeconds as c } from "date-fns/addSeconds";
9
+ var R = class {
9
10
  globalStore;
10
11
  selectedCategoryData = null;
11
12
  selectedDateRange;
12
13
  visibleListLength = 5;
13
14
  constructor(e) {
14
15
  this.globalStore = e, this.selectedDateRange = {
15
- start: g(s(o(/* @__PURE__ */ new Date(), 6)), 1),
16
- end: s(/* @__PURE__ */ new Date())
17
- }, l(this);
16
+ start: c(r(l(/* @__PURE__ */ new Date(), 6)), 1),
17
+ end: r(/* @__PURE__ */ new Date())
18
+ }, g(this);
18
19
  }
19
20
  setSelectedCategoryData = (e) => {
20
21
  this.selectedCategoryData = e;
@@ -26,13 +27,21 @@ var u = class {
26
27
  this.visibleListLength = e;
27
28
  };
28
29
  get sortedDetailedCategoriesWithTransactions() {
29
- return r(this.globalStore.categoryStore.detailedCategoriesWithTransactions);
30
+ return o(this.globalStore.categoryStore.detailedCategoriesWithTransactions);
31
+ }
32
+ get isTransactionStoreIdle() {
33
+ const { isTransactionDataLoaded: e, transactionsLoading: t } = this.globalStore.transactionStore;
34
+ return e && !t;
35
+ }
36
+ get isSelectedRangeLoaded() {
37
+ const { isTransactionDataLoaded: e, cachedStartDate: t } = this.globalStore.transactionStore;
38
+ return e && !n(this.selectedDateRange.start, t);
30
39
  }
31
40
  get selectedDateRangeMonthCount() {
32
- return n(this.selectedDateRange.end, this.selectedDateRange.start) + 1;
41
+ return d(this.selectedDateRange.end, this.selectedDateRange.start) + 1;
33
42
  }
34
43
  get selectedDateRangeMonthRange() {
35
- return `${a(this.selectedDateRange.start, t.MONTH_LONG)} - ${a(this.selectedDateRange.end, t.MONTH_LONG)}`;
44
+ return `${s(this.selectedDateRange.start, a.MONTH_LONG)} - ${s(this.selectedDateRange.end, a.MONTH_LONG)}`;
36
45
  }
37
46
  get visibleCategories() {
38
47
  return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength);
@@ -45,7 +54,7 @@ var u = class {
45
54
  }
46
55
  };
47
56
  export {
48
- u as TrendsStore
57
+ R as TrendsStore
49
58
  };
50
59
 
51
60
  //# sourceMappingURL=TrendsStore.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TrendsStore.es.js","names":[],"sources":["../../../src/core/stores/TrendsStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\nimport { addSeconds } from 'date-fns/addSeconds'\nimport { differenceInCalendarMonths } from 'date-fns/differenceInCalendarMonths'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { subMonths } from 'date-fns/subMonths'\n\nimport type { DateRange, DetailedCategoryWithTransactions } from '../types'\nimport { DATE_FORMATS_INTL, formatDate } from '../constants'\nimport {\n buildCategoryDetailsChartData,\n filterAndSortCategoriesWithTransactions,\n} from '../utils/TrendsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class TrendsStore {\n globalStore: GlobalStore\n selectedCategoryData: DetailedCategoryWithTransactions | null = null\n selectedDateRange: DateRange\n visibleListLength: number = 5\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.selectedDateRange = {\n start: addSeconds(endOfMonth(subMonths(new Date(), 6)), 1),\n end: endOfMonth(new Date()),\n }\n makeAutoObservable(this)\n }\n\n setSelectedCategoryData = (data: DetailedCategoryWithTransactions | null) => {\n this.selectedCategoryData = data\n }\n\n setSelectedDateRange = (dateRange: DateRange) => {\n this.selectedDateRange = dateRange\n }\n\n setVisibleListLength = (length: number) => {\n this.visibleListLength = length\n }\n\n get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return filterAndSortCategoriesWithTransactions(\n this.globalStore.categoryStore.detailedCategoriesWithTransactions,\n )\n }\n\n get selectedDateRangeMonthCount(): number {\n return differenceInCalendarMonths(this.selectedDateRange.end, this.selectedDateRange.start) + 1\n }\n\n get selectedDateRangeMonthRange(): string {\n const startMonth = formatDate(this.selectedDateRange.start, DATE_FORMATS_INTL.MONTH_LONG)\n const endMonth = formatDate(this.selectedDateRange.end, DATE_FORMATS_INTL.MONTH_LONG)\n return `${startMonth} - ${endMonth}`\n }\n\n get visibleCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength)\n }\n\n get collapsedCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(this.visibleListLength)\n }\n\n get categoryDetailsChartData() {\n return buildCategoryDetailsChartData(\n this.selectedCategoryData,\n this.selectedDateRangeMonthCount,\n )\n }\n}\n"],"mappings":";;;;;;;AAeA,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,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'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class TrendsStore {\n globalStore: GlobalStore\n selectedCategoryData: DetailedCategoryWithTransactions | null = null\n selectedDateRange: DateRange\n visibleListLength: number = 5\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.selectedDateRange = {\n start: addSeconds(endOfMonth(subMonths(new Date(), 6)), 1),\n end: endOfMonth(new Date()),\n }\n makeAutoObservable(this)\n }\n\n setSelectedCategoryData = (data: DetailedCategoryWithTransactions | null) => {\n this.selectedCategoryData = data\n }\n\n setSelectedDateRange = (dateRange: DateRange) => {\n this.selectedDateRange = dateRange\n }\n\n setVisibleListLength = (length: number) => {\n this.visibleListLength = length\n }\n\n get sortedDetailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return filterAndSortCategoriesWithTransactions(\n this.globalStore.categoryStore.detailedCategoriesWithTransactions,\n )\n }\n\n get isTransactionStoreIdle(): boolean {\n const { isTransactionDataLoaded, transactionsLoading } = this.globalStore.transactionStore\n return isTransactionDataLoaded && !transactionsLoading\n }\n\n get isSelectedRangeLoaded(): boolean {\n const { isTransactionDataLoaded, cachedStartDate } = this.globalStore.transactionStore\n return isTransactionDataLoaded && !isBefore(this.selectedDateRange.start, cachedStartDate)\n }\n\n get selectedDateRangeMonthCount(): number {\n return differenceInCalendarMonths(this.selectedDateRange.end, this.selectedDateRange.start) + 1\n }\n\n get selectedDateRangeMonthRange(): string {\n const startMonth = formatDate(this.selectedDateRange.start, DATE_FORMATS_INTL.MONTH_LONG)\n const endMonth = formatDate(this.selectedDateRange.end, DATE_FORMATS_INTL.MONTH_LONG)\n return `${startMonth} - ${endMonth}`\n }\n\n get visibleCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(0, this.visibleListLength)\n }\n\n get collapsedCategories(): DetailedCategoryWithTransactions[] {\n return this.sortedDetailedCategoriesWithTransactions.slice(this.visibleListLength)\n }\n\n get categoryDetailsChartData() {\n return buildCategoryDetailsChartData(\n this.selectedCategoryData,\n this.selectedDateRangeMonthCount,\n )\n }\n}\n"],"mappings":";;;;;;;;AAgBA,IAAa,IAAb,MAAyB;AAAA,EACvB;AAAA,EACA,uBAAgE;AAAA,EAChE;AAAA,EACA,oBAA4B;AAAA,EAE5B,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,oBAAoB;AAAA,MACvB,OAAO,EAAW,EAAW,EAAU,oBAAI,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;AAAA,MACzD,KAAK,EAAW,oBAAI,KAAK,CAAC;AAAA,IAC5B,GACA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,0BAAA,CAA2B,MAAkD;AAC3E,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEA,uBAAA,CAAwB,MAAyB;AAC/C,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,uBAAA,CAAwB,MAAmB;AACzC,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,IAAI,2CAA+E;AACjF,WAAO,EACL,KAAK,YAAY,cAAc,kCACjC;AAAA,EACF;AAAA,EAEA,IAAI,yBAAkC;AACpC,UAAM,EAAE,yBAAA,GAAyB,qBAAA,EAAA,IAAwB,KAAK,YAAY;AAC1E,WAAO,KAA2B,CAAC;AAAA,EACrC;AAAA,EAEA,IAAI,wBAAiC;AACnC,UAAM,EAAE,yBAAA,GAAyB,iBAAA,EAAA,IAAoB,KAAK,YAAY;AACtE,WAAO,KAA2B,CAAC,EAAS,KAAK,kBAAkB,OAAO,CAAe;AAAA,EAC3F;AAAA,EAEA,IAAI,8BAAsC;AACxC,WAAO,EAA2B,KAAK,kBAAkB,KAAK,KAAK,kBAAkB,KAAK,IAAI;AAAA,EAChG;AAAA,EAEA,IAAI,8BAAsC;AAGxC,WAAO,GAFY,EAAW,KAAK,kBAAkB,OAAO,EAAkB,UAEpE,CAAA,MADO,EAAW,KAAK,kBAAkB,KAAK,EAAkB,UAChD,CAAA;AAAA,EAC5B;AAAA,EAEA,IAAI,oBAAwD;AAC1D,WAAO,KAAK,yCAAyC,MAAM,GAAG,KAAK,iBAAiB;AAAA,EACtF;AAAA,EAEA,IAAI,sBAA0D;AAC5D,WAAO,KAAK,yCAAyC,MAAM,KAAK,iBAAiB;AAAA,EACnF;AAAA,EAEA,IAAI,2BAA2B;AAC7B,WAAO,EACL,KAAK,sBACL,KAAK,2BACP;AAAA,EACF;AACF"}
@@ -1,133 +1,136 @@
1
- import { useAccountStore as 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,EAAE,sBAAA,GAAsB,mBAAA,GAAmB,yBAAA,GAAyB,sBAAA,EAAA,IACxE,GAAe,GACX,EAAE,eAAA,GAAe,kBAAA,GAAkB,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,GACA,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,GACD,EAAM,UAAA,MAAgB;AAEpB,QAAI,EAAsB,WAAW,GAAG;AACtC,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,CAAqB,CAAC;AAE1B,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,EAAqB;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 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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.4.38",
3
+ "version": "9.4.40",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",