@mx-cartographer/experiences 9.6.8 → 9.6.10

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/core/stores/AccountStore.d.ts +1 -0
  3. package/dist/core/stores/AccountStore.es.js +47 -42
  4. package/dist/core/stores/AccountStore.es.js.map +1 -1
  5. package/dist/core/stores/AppDataStore.d.ts +1 -0
  6. package/dist/core/stores/AppDataStore.es.js +15 -11
  7. package/dist/core/stores/AppDataStore.es.js.map +1 -1
  8. package/dist/core/stores/BeatStore.d.ts +1 -0
  9. package/dist/core/stores/BeatStore.es.js +10 -6
  10. package/dist/core/stores/BeatStore.es.js.map +1 -1
  11. package/dist/core/stores/BudgetsStore.d.ts +1 -0
  12. package/dist/core/stores/BudgetsStore.es.js +37 -35
  13. package/dist/core/stores/BudgetsStore.es.js.map +1 -1
  14. package/dist/core/stores/CategoryStore.d.ts +1 -0
  15. package/dist/core/stores/CategoryStore.es.js +36 -32
  16. package/dist/core/stores/CategoryStore.es.js.map +1 -1
  17. package/dist/core/stores/GlobalCopyStore.d.ts +1 -0
  18. package/dist/core/stores/GlobalCopyStore.es.js +17 -13
  19. package/dist/core/stores/GlobalCopyStore.es.js.map +1 -1
  20. package/dist/core/stores/HoldingStore.d.ts +1 -0
  21. package/dist/core/stores/HoldingStore.es.js +6 -2
  22. package/dist/core/stores/HoldingStore.es.js.map +1 -1
  23. package/dist/core/stores/TransactionStore.d.ts +1 -0
  24. package/dist/core/stores/TransactionStore.es.js +71 -67
  25. package/dist/core/stores/TransactionStore.es.js.map +1 -1
  26. package/dist/core/types/localization/InsightsFeedCopy.d.ts +1 -1
  27. package/dist/insights-v2/actionBlocks/MakeTransferActionBlock/layout.es.js +6 -6
  28. package/dist/insights-v2/actionBlocks/MakeTransferActionBlock/layout.es.js.map +1 -1
  29. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +2 -2
  30. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js +15 -15
  31. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -1
  32. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.d.ts +1 -1
  33. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js +1 -1
  34. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js.map +1 -1
  35. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.d.ts +1 -1
  36. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js +16 -16
  37. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js.map +1 -1
  38. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js +6 -7
  39. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js.map +1 -1
  40. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.d.ts +1 -1
  41. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.es.js +14 -30
  42. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.es.js.map +1 -1
  43. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.d.ts +8 -8
  44. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js +14 -14
  45. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js.map +1 -1
  46. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js +1 -1
  47. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js.map +1 -1
  48. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.d.ts +4 -3
  49. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js +2 -2
  50. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js.map +1 -1
  51. package/package.json +1 -1
@@ -1,18 +1,18 @@
1
- import { CategoryGuids as o } from "../constants/Category.es.js";
2
- import { BudgetsApi as g } from "../api/BudgetsApi.es.js";
1
+ import { CategoryGuids as g } from "../constants/Category.es.js";
2
+ import { BudgetsApi as o } from "../api/BudgetsApi.es.js";
3
3
  import { upsertByGuid as n } from "../utils/upsertByGuid.es.js";
4
- import { augmentBudgets as c, findBudget as h, findSubBudget as p } from "../utils/BudgetUtil.es.js";
5
- import { endOfMonth as B } from "date-fns/endOfMonth";
4
+ import { augmentBudgets as c, findBudget as l, findSubBudget as B } from "../utils/BudgetUtil.es.js";
5
+ import { endOfMonth as p } from "date-fns/endOfMonth";
6
6
  import { startOfMonth as f } from "date-fns/startOfMonth";
7
- import { startOfToday as l } from "date-fns/startOfToday";
8
- import { makeAutoObservable as S, reaction as b, runInAction as i } from "mobx";
9
- var A = class {
10
- api = new g("/", "");
7
+ import { startOfToday as h } from "date-fns/startOfToday";
8
+ import { makeAutoObservable as m, reaction as S, runInAction as u } from "mobx";
9
+ var D = class {
10
+ api = new o("/", "");
11
11
  globalStore;
12
12
  alert = null;
13
13
  dateRange = {
14
- start: f(l()),
15
- end: B(l())
14
+ start: f(h()),
15
+ end: p(h())
16
16
  };
17
17
  budgets = [];
18
18
  selectedBudget;
@@ -21,23 +21,23 @@ var A = class {
21
21
  theme = {};
22
22
  merchantBudgets = [];
23
23
  constructor(t) {
24
- this.globalStore = t, this.api = new g(t.endpoint, t.sessionToken, t.onError), S(this);
24
+ this.globalStore = t, this.api = new o(t.endpoint, t.sessionToken, t.onError), m(this);
25
25
  }
26
26
  loadBudgetData = async () => {
27
- this.globalStore.recurringTransactionsStore.isDataLoaded || await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData(), await this.loadBudgets(), b(() => this.detailedBudgets, (t) => {
27
+ this.globalStore.recurringTransactionsStore.isDataLoaded || await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData(), await this.loadBudgets(), S(() => this.detailedBudgets, (t) => {
28
28
  if (t) {
29
29
  const e = this.selectedBudget;
30
- e && (this.selectedBudget = h(t, e.guid));
30
+ e && (this.selectedBudget = l(t, e.guid));
31
31
  const r = this.selectedSubBudget;
32
- r && r.parent_guid && (this.selectedSubBudget = p(t, r.guid, r.parent_guid));
32
+ r && r.parent_guid && (this.selectedSubBudget = B(t, r.guid, r.parent_guid));
33
33
  }
34
34
  });
35
35
  };
36
36
  get detailedBudgets() {
37
- return c(this.budgets.filter((t) => t.category_guid !== o.INCOME && t.category_guid !== o.TRANSFER && t.category_guid !== o.INVESTMENTS), this.globalStore.categoryStore.detailedCategories, this.globalStore.copyStore.copy.budgets, this.theme).sort((t, e) => t.percentage > e.percentage ? -1 : t.percentage < e.percentage ? 1 : 0);
37
+ return c(this.budgets.filter((t) => t.category_guid !== g.INCOME && t.category_guid !== g.TRANSFER && t.category_guid !== g.INVESTMENTS), this.globalStore.categoryStore.detailedCategories, this.globalStore.copyStore.copy.budgets, this.theme).sort((t, e) => t.percentage > e.percentage ? -1 : t.percentage < e.percentage ? 1 : 0);
38
38
  }
39
39
  get incomeBudget() {
40
- return c(this.budgets.filter((t) => !t.parent_guid), this.globalStore.categoryStore.detailedCategories, this.globalStore.copyStore.copy.budgets, this.theme).reduce((t, e) => e.category_guid !== o.INCOME ? t : !t || e.percentage > t.percentage ? e : t, void 0)?.amount;
40
+ return c(this.budgets.filter((t) => !t.parent_guid), this.globalStore.categoryStore.detailedCategories, this.globalStore.copyStore.copy.budgets, this.theme).reduce((t, e) => e.category_guid !== g.INCOME ? t : !t || e.percentage > t.percentage ? e : t, void 0)?.amount;
41
41
  }
42
42
  get unbudgetedCategories() {
43
43
  return this.globalStore.categoryStore.spendCategories.filter((t) => !this.detailedBudgets.find((e) => e.category_guid === t.guid));
@@ -48,23 +48,20 @@ var A = class {
48
48
  addBudget = async (t, e, r = null) => {
49
49
  try {
50
50
  const s = await this.api.addBudget(t, e, r);
51
- return i(() => {
51
+ return u(() => {
52
52
  this.budgets = n(this.budgets, s);
53
53
  }), !0;
54
54
  } catch (s) {
55
- return console.error("Error adding budget:", s), this.globalStore.captureException(s, { store: "BudgetsStore" }), !1;
55
+ return this.captureError("addBudget", s), !1;
56
56
  }
57
57
  };
58
58
  deleteBudget = async (t) => {
59
- const e = [t, ...this.budgets.filter((a) => a.parent_guid === t).map((a) => a.guid)], r = await Promise.allSettled(e.map((a) => this.api.deleteBudget(a))), s = new Set(e.filter((a, u) => r[u].status === "fulfilled"));
60
- i(() => {
59
+ const e = [t, ...this.budgets.filter((a) => a.parent_guid === t).map((a) => a.guid)], r = await Promise.allSettled(e.map((a) => this.api.deleteBudget(a))), s = new Set(e.filter((a, i) => r[i].status === "fulfilled"));
60
+ u(() => {
61
61
  this.budgets = this.budgets.filter((a) => !s.has(a.guid));
62
62
  });
63
63
  let d = !1;
64
- for (const [a, u] of r.entries()) u.status === "rejected" && (d = !0, console.error("Error deleting budget:", u.reason), this.globalStore.captureException(u.reason, {
65
- store: "BudgetsStore",
66
- guid: e[a]
67
- }));
64
+ for (const [a, i] of r.entries()) i.status === "rejected" && (d = !0, this.captureError("deleteBudget", i.reason, { guid: e[a] }));
68
65
  return !d;
69
66
  };
70
67
  loadBudgets = async () => {
@@ -72,7 +69,7 @@ var A = class {
72
69
  const t = await this.api.getBudgets();
73
70
  this.setBudgets(t);
74
71
  } catch (t) {
75
- throw console.error("Error occurred while loading budgets:", t), this.globalStore.captureException(t, { store: "BudgetsStore" }), t;
72
+ throw this.captureError("loadBudgets", t), t;
76
73
  }
77
74
  };
78
75
  setAlert = (t) => this.alert = t;
@@ -99,7 +96,7 @@ var A = class {
99
96
  isSuccess: !0
100
97
  };
101
98
  } catch (e) {
102
- return console.error("Error recalculating budgets:", e), this.globalStore.captureException(e, { store: "BudgetsStore" }), await this.loadBudgets().catch(() => {
99
+ return this.captureError("recalculateBudgets", e), await this.loadBudgets().catch(() => {
103
100
  }), {
104
101
  data: [],
105
102
  isSuccess: !1
@@ -109,12 +106,12 @@ var A = class {
109
106
  updateBudget = async (t) => {
110
107
  try {
111
108
  const e = await this.api.updateBudget(t);
112
- return i(() => {
109
+ return u(() => {
113
110
  const r = this.budgets.findIndex((s) => s.guid === t.guid);
114
111
  r >= 0 && (this.budgets[r] = e);
115
112
  }), !0;
116
113
  } catch (e) {
117
- return console.error("Error updating budget:", e), this.globalStore.captureException(e, { store: "BudgetsStore" }), !1;
114
+ return this.captureError("updateBudget", e), !1;
118
115
  }
119
116
  };
120
117
  getMerchantBudgetByMerchantGuid = (t) => this.merchantBudgets.find((e) => e?.merchant_guid === t);
@@ -124,36 +121,41 @@ var A = class {
124
121
  addMerchantBudget = async (t, e) => {
125
122
  try {
126
123
  const r = await this.api.addMerchantBudget(t, e);
127
- return i(() => {
124
+ return u(() => {
128
125
  this.merchantBudgets = n(this.merchantBudgets, r);
129
126
  }), { isSuccess: !0 };
130
127
  } catch (r) {
131
- return console.error("Error adding merchant budget:", r), this.globalStore.captureException(r, { store: "BudgetsStore" }), { isSuccess: !1 };
128
+ return this.captureError("addMerchantBudget", r), { isSuccess: !1 };
132
129
  }
133
130
  };
134
131
  updateMerchantBudget = async (t) => {
135
132
  try {
136
133
  const { guid: e, amount: r } = t, s = await this.api.updateMerchantBudget(e, r);
137
- return i(() => {
134
+ return u(() => {
138
135
  const d = this.merchantBudgets.findIndex((a) => a.guid === t.guid);
139
136
  d >= 0 && (this.merchantBudgets[d] = s);
140
137
  }), { isSuccess: !0 };
141
138
  } catch (e) {
142
- return console.error("Error updating merchant budget:", e), this.globalStore.captureException(e, { store: "BudgetsStore" }), { isSuccess: !1 };
139
+ return this.captureError("updateMerchantBudget", e), { isSuccess: !1 };
143
140
  }
144
141
  };
145
142
  deleteMerchantBudget = async (t) => {
146
143
  try {
147
- return await this.api.deleteMerchantBudget(t), i(() => {
144
+ return await this.api.deleteMerchantBudget(t), u(() => {
148
145
  this.merchantBudgets = this.merchantBudgets.filter((e) => e.guid !== t);
149
146
  }), { isSuccess: !0 };
150
147
  } catch (e) {
151
- return console.error("Error deleting merchant budget:", e), this.globalStore.captureException(e, { store: "BudgetsStore" }), { isSuccess: !1 };
148
+ return this.captureError("deleteMerchantBudget", e), { isSuccess: !1 };
152
149
  }
153
150
  };
151
+ captureError = (t, e, r) => this.globalStore.captureException(e, {
152
+ store: "BudgetsStore",
153
+ action: t,
154
+ ...r
155
+ });
154
156
  };
155
157
  export {
156
- A as BudgetsStore
158
+ D as BudgetsStore
157
159
  };
158
160
 
159
161
  //# sourceMappingURL=BudgetsStore.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BudgetsStore.es.js","names":[],"sources":["../../../src/core/stores/BudgetsStore.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from 'mobx'\n\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { Theme } from '@mui/system'\n\nimport { BudgetsApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport { CategoryGuids } from '../constants'\nimport { augmentBudgets, findBudget, findSubBudget } from '../utils/BudgetUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Budget,\n Category,\n DateRange,\n DetailedBudget,\n DetailedCategory,\n MerchantBudget,\n} from '../types'\n\nexport class BudgetsStore {\n api: BudgetsApi = new BudgetsApi('/', '')\n\n globalStore: GlobalStore\n\n alert: { msg: string; severity: 'success' | 'error' } | null = null\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n budgets: Budget[] = []\n selectedBudget: DetailedBudget | undefined\n selectedSubBudget: DetailedBudget | undefined\n isDataLoaded = false\n theme = {} as Theme\n merchantBudgets: MerchantBudget[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BudgetsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBudgetData = async () => {\n if (!this.globalStore.recurringTransactionsStore.isDataLoaded) {\n await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData()\n }\n await this.loadBudgets()\n\n /** Reaction to update the selected budget/sub-budget if detailedBudgets is updated **/\n reaction(\n () => this.detailedBudgets,\n (detailedBudgets) => {\n if (detailedBudgets) {\n const budget = this.selectedBudget\n if (budget) {\n this.selectedBudget = findBudget(detailedBudgets, budget.guid)\n }\n\n const subBudget = this.selectedSubBudget\n if (subBudget && subBudget.parent_guid) {\n this.selectedSubBudget = findSubBudget(\n detailedBudgets,\n subBudget.guid,\n subBudget.parent_guid,\n )\n }\n }\n },\n )\n }\n\n get detailedBudgets(): DetailedBudget[] {\n return augmentBudgets(\n this.budgets.filter(\n (budget: Budget) =>\n budget.category_guid !== CategoryGuids.INCOME &&\n budget.category_guid !== CategoryGuids.TRANSFER &&\n budget.category_guid !== CategoryGuids.INVESTMENTS,\n ),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n ).sort((a, b) => {\n if (a.percentage > b.percentage) return -1\n if (a.percentage < b.percentage) return 1\n return 0\n })\n }\n\n // TODO: Replace this with income from recurring transactions. Income budgets are deprecated.\n get incomeBudget(): number | undefined {\n const filteredBudgets = augmentBudgets(\n this.budgets.filter((budget: Budget) => !budget.parent_guid),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n )\n\n const incomeBudget = filteredBudgets.reduce(\n (acc, curr) => {\n if (curr.category_guid !== CategoryGuids.INCOME) return acc\n if (!acc || curr.percentage > acc.percentage) return curr\n return acc\n },\n undefined as DetailedBudget | undefined,\n )\n\n return incomeBudget?.amount\n }\n\n get unbudgetedCategories(): DetailedCategory[] {\n return this.globalStore.categoryStore.spendCategories.filter(\n (category) => !this.detailedBudgets.find((budget) => budget.category_guid === category.guid),\n )\n }\n\n get totalBudgeted(): number {\n return this.detailedBudgets.reduce((total, budget) => total + budget.amount, 0)\n }\n\n /** Resolves `true` when the budget was created, `false` when the API call failed. */\n addBudget = async (\n category: Category,\n amount: number,\n parentGuid: string | null = null,\n ): Promise<boolean> => {\n try {\n const budget = await this.api.addBudget(category, amount, parentGuid)\n runInAction(() => {\n this.budgets = upsertByGuid(this.budgets, budget)\n })\n return true\n } catch (error) {\n console.error('Error adding budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return false\n }\n }\n\n deleteBudget = async (guid: string): Promise<boolean> => {\n const guids = [guid, ...this.budgets.filter((b) => b.parent_guid === guid).map((b) => b.guid)]\n const results = await Promise.allSettled(guids.map((g) => this.api.deleteBudget(g)))\n const deleted = new Set(guids.filter((_, i) => results[i].status === 'fulfilled'))\n runInAction(() => {\n this.budgets = this.budgets.filter((b) => !deleted.has(b.guid))\n })\n let failed = false\n for (const [i, r] of results.entries()) {\n if (r.status === 'rejected') {\n failed = true\n console.error('Error deleting budget:', r.reason)\n this.globalStore.captureException(r.reason, { store: 'BudgetsStore', guid: guids[i] })\n }\n }\n return !failed\n }\n\n loadBudgets = async () => {\n try {\n const budgets = await this.api.getBudgets()\n this.setBudgets(budgets)\n } catch (error) {\n console.error('Error occurred while loading budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n throw error\n }\n }\n\n setAlert = (alert: { msg: string; severity: 'success' | 'error' } | null) => (this.alert = alert)\n\n setBudgets = (budgets: Budget[]) => {\n this.budgets = budgets\n this.isDataLoaded = true\n }\n\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n setSelectedBudget = (budget: DetailedBudget | undefined) => (this.selectedBudget = budget)\n\n setSelectedSubBudget = (budget: DetailedBudget | undefined) => (this.selectedSubBudget = budget)\n\n setTheme = (theme: Theme) => (this.theme = theme)\n\n /**\n * Recalculate budget by using the average amount from top-level categories\n * @param categories Detailed categories\n */\n recalculateBudgets = async (categories: DetailedCategory[]) => {\n try {\n for (const category of categories) {\n const budget = this.budgets.find((budget) => budget.category_guid === category.guid)\n if (budget) {\n await this.api.updateBudget({\n ...budget,\n amount: category.totalAverageAmount,\n })\n } else {\n await this.api.addBudget(category, category.totalAverageAmount)\n }\n }\n const budgetsToDelete = this.budgets.filter(\n (budget) => !categories.find((c) => c.guid === budget.category_guid),\n )\n\n for (const budgetToDelete of budgetsToDelete) {\n await this.api.deleteBudget(budgetToDelete.guid)\n }\n\n await this.loadBudgets()\n\n return { data: this.budgets, isSuccess: true }\n } catch (error) {\n console.error('Error recalculating budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n // Some budgets may have saved before the failure; reload so a retry updates them.\n await this.loadBudgets().catch(() => undefined)\n return { data: [], isSuccess: false }\n }\n }\n\n updateBudget = async (budget: Budget): Promise<boolean> => {\n try {\n const updatedBudget = await this.api.updateBudget(budget)\n\n runInAction(() => {\n const index = this.budgets.findIndex((b) => b.guid === budget.guid)\n if (index >= 0) {\n this.budgets[index] = updatedBudget\n }\n })\n return true\n } catch (error) {\n console.error('Error updating budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return false\n }\n }\n\n getMerchantBudgetByMerchantGuid = (merchantGuid: string): MerchantBudget | undefined => {\n return this.merchantBudgets.find(\n (eachMerchantBudget) => eachMerchantBudget?.merchant_guid === merchantGuid,\n )\n }\n\n setMerchantBudgets = (merchantBudgets: MerchantBudget[]) => {\n this.merchantBudgets = merchantBudgets\n }\n\n addMerchantBudget = async (merchantGuid: string, amount: number) => {\n try {\n const newMerchantBudget = await this.api.addMerchantBudget(merchantGuid, amount)\n\n runInAction(() => {\n this.merchantBudgets = upsertByGuid(this.merchantBudgets, newMerchantBudget)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error adding merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n updateMerchantBudget = async (merchantBudget: MerchantBudget) => {\n try {\n const { guid: merchantBudgetGuid, amount } = merchantBudget\n const updatedMerchantBudget = await this.api.updateMerchantBudget(merchantBudgetGuid, amount)\n\n runInAction(() => {\n const index = this.merchantBudgets.findIndex((b) => b.guid === merchantBudget.guid)\n if (index >= 0) {\n this.merchantBudgets[index] = updatedMerchantBudget\n }\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error updating merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n deleteMerchantBudget = async (merchantBudgetGuid: string) => {\n try {\n await this.api.deleteMerchantBudget(merchantBudgetGuid)\n\n runInAction(() => {\n this.merchantBudgets = this.merchantBudgets.filter((b) => b.guid !== merchantBudgetGuid)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error deleting merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BudgetsStore.es.js","names":[],"sources":["../../../src/core/stores/BudgetsStore.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from 'mobx'\n\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { Theme } from '@mui/system'\n\nimport { BudgetsApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport { CategoryGuids } from '../constants'\nimport { augmentBudgets, findBudget, findSubBudget } from '../utils/BudgetUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Budget,\n Category,\n DateRange,\n DetailedBudget,\n DetailedCategory,\n MerchantBudget,\n} from '../types'\n\nexport class BudgetsStore {\n api: BudgetsApi = new BudgetsApi('/', '')\n\n globalStore: GlobalStore\n\n alert: { msg: string; severity: 'success' | 'error' } | null = null\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n budgets: Budget[] = []\n selectedBudget: DetailedBudget | undefined\n selectedSubBudget: DetailedBudget | undefined\n isDataLoaded = false\n theme = {} as Theme\n merchantBudgets: MerchantBudget[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BudgetsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBudgetData = async () => {\n if (!this.globalStore.recurringTransactionsStore.isDataLoaded) {\n await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData()\n }\n await this.loadBudgets()\n\n /** Reaction to update the selected budget/sub-budget if detailedBudgets is updated **/\n reaction(\n () => this.detailedBudgets,\n (detailedBudgets) => {\n if (detailedBudgets) {\n const budget = this.selectedBudget\n if (budget) {\n this.selectedBudget = findBudget(detailedBudgets, budget.guid)\n }\n\n const subBudget = this.selectedSubBudget\n if (subBudget && subBudget.parent_guid) {\n this.selectedSubBudget = findSubBudget(\n detailedBudgets,\n subBudget.guid,\n subBudget.parent_guid,\n )\n }\n }\n },\n )\n }\n\n get detailedBudgets(): DetailedBudget[] {\n return augmentBudgets(\n this.budgets.filter(\n (budget: Budget) =>\n budget.category_guid !== CategoryGuids.INCOME &&\n budget.category_guid !== CategoryGuids.TRANSFER &&\n budget.category_guid !== CategoryGuids.INVESTMENTS,\n ),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n ).sort((a, b) => {\n if (a.percentage > b.percentage) return -1\n if (a.percentage < b.percentage) return 1\n return 0\n })\n }\n\n // TODO: Replace this with income from recurring transactions. Income budgets are deprecated.\n get incomeBudget(): number | undefined {\n const filteredBudgets = augmentBudgets(\n this.budgets.filter((budget: Budget) => !budget.parent_guid),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n )\n\n const incomeBudget = filteredBudgets.reduce(\n (acc, curr) => {\n if (curr.category_guid !== CategoryGuids.INCOME) return acc\n if (!acc || curr.percentage > acc.percentage) return curr\n return acc\n },\n undefined as DetailedBudget | undefined,\n )\n\n return incomeBudget?.amount\n }\n\n get unbudgetedCategories(): DetailedCategory[] {\n return this.globalStore.categoryStore.spendCategories.filter(\n (category) => !this.detailedBudgets.find((budget) => budget.category_guid === category.guid),\n )\n }\n\n get totalBudgeted(): number {\n return this.detailedBudgets.reduce((total, budget) => total + budget.amount, 0)\n }\n\n /** Resolves `true` when the budget was created, `false` when the API call failed. */\n addBudget = async (\n category: Category,\n amount: number,\n parentGuid: string | null = null,\n ): Promise<boolean> => {\n try {\n const budget = await this.api.addBudget(category, amount, parentGuid)\n runInAction(() => {\n this.budgets = upsertByGuid(this.budgets, budget)\n })\n return true\n } catch (error) {\n this.captureError('addBudget', error)\n return false\n }\n }\n\n deleteBudget = async (guid: string): Promise<boolean> => {\n const guids = [guid, ...this.budgets.filter((b) => b.parent_guid === guid).map((b) => b.guid)]\n const results = await Promise.allSettled(guids.map((g) => this.api.deleteBudget(g)))\n const deleted = new Set(guids.filter((_, i) => results[i].status === 'fulfilled'))\n runInAction(() => {\n this.budgets = this.budgets.filter((b) => !deleted.has(b.guid))\n })\n let failed = false\n for (const [i, r] of results.entries()) {\n if (r.status === 'rejected') {\n failed = true\n this.captureError('deleteBudget', r.reason, { guid: guids[i] })\n }\n }\n return !failed\n }\n\n loadBudgets = async () => {\n try {\n const budgets = await this.api.getBudgets()\n this.setBudgets(budgets)\n } catch (error) {\n this.captureError('loadBudgets', error)\n throw error\n }\n }\n\n setAlert = (alert: { msg: string; severity: 'success' | 'error' } | null) => (this.alert = alert)\n\n setBudgets = (budgets: Budget[]) => {\n this.budgets = budgets\n this.isDataLoaded = true\n }\n\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n setSelectedBudget = (budget: DetailedBudget | undefined) => (this.selectedBudget = budget)\n\n setSelectedSubBudget = (budget: DetailedBudget | undefined) => (this.selectedSubBudget = budget)\n\n setTheme = (theme: Theme) => (this.theme = theme)\n\n /**\n * Recalculate budget by using the average amount from top-level categories\n * @param categories Detailed categories\n */\n recalculateBudgets = async (categories: DetailedCategory[]) => {\n try {\n for (const category of categories) {\n const budget = this.budgets.find((budget) => budget.category_guid === category.guid)\n if (budget) {\n await this.api.updateBudget({\n ...budget,\n amount: category.totalAverageAmount,\n })\n } else {\n await this.api.addBudget(category, category.totalAverageAmount)\n }\n }\n const budgetsToDelete = this.budgets.filter(\n (budget) => !categories.find((c) => c.guid === budget.category_guid),\n )\n\n for (const budgetToDelete of budgetsToDelete) {\n await this.api.deleteBudget(budgetToDelete.guid)\n }\n\n await this.loadBudgets()\n\n return { data: this.budgets, isSuccess: true }\n } catch (error) {\n this.captureError('recalculateBudgets', error)\n // Some budgets may have saved before the failure; reload so a retry updates them.\n await this.loadBudgets().catch(() => undefined)\n return { data: [], isSuccess: false }\n }\n }\n\n updateBudget = async (budget: Budget): Promise<boolean> => {\n try {\n const updatedBudget = await this.api.updateBudget(budget)\n\n runInAction(() => {\n const index = this.budgets.findIndex((b) => b.guid === budget.guid)\n if (index >= 0) {\n this.budgets[index] = updatedBudget\n }\n })\n return true\n } catch (error) {\n this.captureError('updateBudget', error)\n return false\n }\n }\n\n getMerchantBudgetByMerchantGuid = (merchantGuid: string): MerchantBudget | undefined => {\n return this.merchantBudgets.find(\n (eachMerchantBudget) => eachMerchantBudget?.merchant_guid === merchantGuid,\n )\n }\n\n setMerchantBudgets = (merchantBudgets: MerchantBudget[]) => {\n this.merchantBudgets = merchantBudgets\n }\n\n addMerchantBudget = async (merchantGuid: string, amount: number) => {\n try {\n const newMerchantBudget = await this.api.addMerchantBudget(merchantGuid, amount)\n\n runInAction(() => {\n this.merchantBudgets = upsertByGuid(this.merchantBudgets, newMerchantBudget)\n })\n return { isSuccess: true }\n } catch (error) {\n this.captureError('addMerchantBudget', error)\n return { isSuccess: false }\n }\n }\n\n updateMerchantBudget = async (merchantBudget: MerchantBudget) => {\n try {\n const { guid: merchantBudgetGuid, amount } = merchantBudget\n const updatedMerchantBudget = await this.api.updateMerchantBudget(merchantBudgetGuid, amount)\n\n runInAction(() => {\n const index = this.merchantBudgets.findIndex((b) => b.guid === merchantBudget.guid)\n if (index >= 0) {\n this.merchantBudgets[index] = updatedMerchantBudget\n }\n })\n return { isSuccess: true }\n } catch (error) {\n this.captureError('updateMerchantBudget', error)\n return { isSuccess: false }\n }\n }\n\n deleteMerchantBudget = async (merchantBudgetGuid: string) => {\n try {\n await this.api.deleteMerchantBudget(merchantBudgetGuid)\n\n runInAction(() => {\n this.merchantBudgets = this.merchantBudgets.filter((b) => b.guid !== merchantBudgetGuid)\n })\n return { isSuccess: true }\n } catch (error) {\n this.captureError('deleteMerchantBudget', error)\n return { isSuccess: false }\n }\n }\n\n private captureError = (action: string, error: unknown, extra?: Record<string, string>) =>\n this.globalStore.captureException(error, { store: 'BudgetsStore', action, ...extra })\n}\n"],"mappings":"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"}
@@ -44,6 +44,7 @@ export declare class CategoryStore {
44
44
  */
45
45
  getTopLevelCategoryGuid: (guid: string) => string;
46
46
  getCategoryName: (guid: string) => string;
47
+ private captureError;
47
48
  }
48
49
  declare class UiStore {
49
50
  expandedGuid: string | null;
@@ -1,12 +1,12 @@
1
1
  import { CategoryGuidToName as T, CategoryGuids as n } from "../constants/Category.es.js";
2
- import { toUnixUTC as l } from "../utils/DateUtil.es.js";
2
+ import { toUnixUTC as i } from "../utils/DateUtil.es.js";
3
3
  import { CategoryApi as d } from "../api/CategoryApi.es.js";
4
4
  import { augmentCategories as C, getDetailedCategoryTransactions as f } from "../utils/CategoryUtil.es.js";
5
5
  import { endOfMonth as h } from "date-fns/endOfMonth";
6
6
  import { startOfMonth as p } from "date-fns/startOfMonth";
7
7
  import { subMonths as c } from "date-fns/subMonths";
8
8
  import { makeAutoObservable as u, runInAction as g } from "mobx";
9
- var A = class {
9
+ var E = class {
10
10
  globalStore;
11
11
  uiStore;
12
12
  api = new d("/", "");
@@ -24,7 +24,7 @@ var A = class {
24
24
  lastDateRangeTotalsArgs = null;
25
25
  lastMonthlyTotalsArgs = null;
26
26
  constructor(t) {
27
- this.globalStore = t, this.uiStore = new S(), this.api = new d(t.endpoint, t.sessionToken, t.onError), u(this, {
27
+ this.globalStore = t, this.uiStore = new m(), this.api = new d(t.endpoint, t.sessionToken, t.onError), u(this, {
28
28
  dateRangeTotalsRequestId: !1,
29
29
  monthlyTotalsRequestId: !1,
30
30
  lastDateRangeTotalsArgs: !1,
@@ -65,8 +65,8 @@ var A = class {
65
65
  };
66
66
  try {
67
67
  await this.api.addCategory(a), await this.loadCategories();
68
- } catch (o) {
69
- console.error("Error occurred while adding category:", o), this.globalStore.captureException(o, { store: "CategoryStore" });
68
+ } catch (s) {
69
+ this.captureError("addCategory", s);
70
70
  }
71
71
  };
72
72
  loadCategories = async () => {
@@ -76,14 +76,14 @@ var A = class {
76
76
  const t = await this.api.getCategories();
77
77
  this.setCategories(t);
78
78
  } catch (t) {
79
- console.error("Error occurred while getting categories:", t), this.globalStore.captureException(t, { store: "CategoryStore" }), g(() => {
79
+ this.captureError("loadCategories", t), g(() => {
80
80
  this.categoriesLoading = !1;
81
81
  });
82
82
  }
83
83
  }
84
84
  };
85
85
  loadDateRangeCategoryTotals = async (t, e, a) => {
86
- const o = ++this.dateRangeTotalsRequestId, s = () => o !== this.dateRangeTotalsRequestId;
86
+ const s = ++this.dateRangeTotalsRequestId, o = () => s !== this.dateRangeTotalsRequestId;
87
87
  this.lastDateRangeTotalsArgs = {
88
88
  accounts: t,
89
89
  startDate: e,
@@ -92,16 +92,16 @@ var A = class {
92
92
  this.dateRangeTotalsLoading = !0;
93
93
  });
94
94
  try {
95
- const r = await this.api.getDateRangeCategoryTotals(l(e), l(a), t);
96
- if (s()) return;
95
+ const r = await this.api.getDateRangeCategoryTotals(i(e), i(a), t);
96
+ if (o()) return;
97
97
  this.setDateRangeCategoryTotals(r);
98
98
  } catch (r) {
99
- if (s()) return;
100
- console.error("Error occurred while getting date range category totals:", r), this.globalStore.captureException(r, { store: "CategoryStore" }), this.setDateRangeCategoryTotals([]);
99
+ if (o()) return;
100
+ this.captureError("loadDateRangeCategoryTotals", r), this.setDateRangeCategoryTotals([]);
101
101
  }
102
102
  };
103
103
  loadMonthlyCategoryTotals = async (t = this.globalStore.globalUiStore.selectedAccounts, e, a) => {
104
- const o = ++this.monthlyTotalsRequestId, s = () => o !== this.monthlyTotalsRequestId;
104
+ const s = ++this.monthlyTotalsRequestId, o = () => s !== this.monthlyTotalsRequestId;
105
105
  this.lastMonthlyTotalsArgs = {
106
106
  accounts: t,
107
107
  startDate: e,
@@ -109,29 +109,29 @@ var A = class {
109
109
  }, g(() => {
110
110
  this.monthlyTotalsLoading = !0;
111
111
  });
112
- const r = l(p(e ?? c(/* @__PURE__ */ new Date(), 11))), y = l(h(a ?? /* @__PURE__ */ new Date()));
112
+ const r = i(p(e ?? c(/* @__PURE__ */ new Date(), 11))), y = i(h(a ?? /* @__PURE__ */ new Date()));
113
113
  try {
114
- const i = await this.api.getMonthlyCategoryTotals(r, y, t);
115
- if (s()) return;
116
- this.setMonthlyCategoryTotals(i);
117
- } catch (i) {
118
- if (s()) return;
119
- console.error("Error occurred while getting monthly category totals:", i), this.globalStore.captureException(i, { store: "CategoryStore" }), this.setMonthlyCategoryTotals([]);
114
+ const l = await this.api.getMonthlyCategoryTotals(r, y, t);
115
+ if (o()) return;
116
+ this.setMonthlyCategoryTotals(l);
117
+ } catch (l) {
118
+ if (o()) return;
119
+ this.captureError("loadMonthlyCategoryTotals", l), this.setMonthlyCategoryTotals([]);
120
120
  }
121
121
  };
122
122
  reloadCategoryTotals = async (t, e, a) => {
123
- const o = e ?? c(/* @__PURE__ */ new Date(), 11), s = a ?? h(/* @__PURE__ */ new Date());
124
- await Promise.all([this.loadMonthlyCategoryTotals(t, o, s), this.loadDateRangeCategoryTotals(t, o, s)]);
123
+ const s = e ?? c(/* @__PURE__ */ new Date(), 11), o = a ?? h(/* @__PURE__ */ new Date());
124
+ await Promise.all([this.loadMonthlyCategoryTotals(t, s, o), this.loadDateRangeCategoryTotals(t, s, o)]);
125
125
  };
126
126
  refreshLoadedCategoryTotals = async () => {
127
127
  const t = [];
128
128
  if (this.lastDateRangeTotalsArgs) {
129
- const { accounts: e, startDate: a, endDate: o } = this.lastDateRangeTotalsArgs;
130
- t.push(this.loadDateRangeCategoryTotals(e, a, o));
129
+ const { accounts: e, startDate: a, endDate: s } = this.lastDateRangeTotalsArgs;
130
+ t.push(this.loadDateRangeCategoryTotals(e, a, s));
131
131
  }
132
132
  if (this.lastMonthlyTotalsArgs) {
133
- const { accounts: e, startDate: a, endDate: o } = this.lastMonthlyTotalsArgs;
134
- t.push(this.loadMonthlyCategoryTotals(e, a, o));
133
+ const { accounts: e, startDate: a, endDate: s } = this.lastMonthlyTotalsArgs;
134
+ t.push(this.loadMonthlyCategoryTotals(e, a, s));
135
135
  }
136
136
  await Promise.all(t);
137
137
  };
@@ -139,14 +139,14 @@ var A = class {
139
139
  try {
140
140
  await this.api.removeCategory(t), await this.loadCategories();
141
141
  } catch (e) {
142
- console.error("Error occurred while removing category:", e), this.globalStore.captureException(e, { store: "CategoryStore" });
142
+ this.captureError("removeCategory", e);
143
143
  }
144
144
  };
145
145
  updateCategory = async (t) => {
146
146
  try {
147
147
  await this.api.updateCategory(t), await this.loadCategories();
148
148
  } catch (e) {
149
- console.error("Error occurred while updating category:", e), this.globalStore.captureException(e, { store: "CategoryStore" });
149
+ this.captureError("updateCategory", e);
150
150
  }
151
151
  };
152
152
  getTopLevelCategoryGuid = (t) => {
@@ -154,14 +154,18 @@ var A = class {
154
154
  let a = t;
155
155
  for (; !e.has(a); ) {
156
156
  e.add(a);
157
- const o = this.categories.find((s) => s.guid === a)?.parent_guid;
158
- if (!o) return a;
159
- a = o;
157
+ const s = this.categories.find((o) => o.guid === a)?.parent_guid;
158
+ if (!s) return a;
159
+ a = s;
160
160
  }
161
161
  return a;
162
162
  };
163
163
  getCategoryName = (t) => this.categories.find((e) => e.guid === t)?.name ?? T[t];
164
- }, S = class {
164
+ captureError = (t, e) => this.globalStore.captureException(e, {
165
+ store: "CategoryStore",
166
+ action: t
167
+ });
168
+ }, m = class {
165
169
  expandedGuid = null;
166
170
  selectedGuid = null;
167
171
  searchValue = "";
@@ -184,7 +188,7 @@ var A = class {
184
188
  setOnSelect = (t) => this.savedOnSelect = t;
185
189
  };
186
190
  export {
187
- A as CategoryStore
191
+ E as CategoryStore
188
192
  };
189
193
 
190
194
  //# sourceMappingURL=CategoryStore.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CategoryStore.es.js","names":[],"sources":["../../../src/core/stores/CategoryStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\nimport { subMonths } from 'date-fns/subMonths'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { endOfMonth } from 'date-fns/endOfMonth'\n\nimport { CategoryGuids, CategoryGuidToName } from '../constants'\nimport { CategoryApi } from '../api'\nimport { toUnixUTC } from '../utils/DateUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Account,\n Category,\n DetailedCategory,\n DetailedCategoryWithTransactions,\n DateRangeCategoryTotals,\n MonthlyCategoryTotals,\n} from '../types'\n\nimport { augmentCategories, getDetailedCategoryTransactions } from '../utils/CategoryUtil'\n\nexport class CategoryStore {\n globalStore: GlobalStore\n uiStore: UiStore\n api = new CategoryApi('/', '')\n\n categories: Category[] = []\n categoriesLoaded: boolean = false\n categoriesLoading: boolean = false\n dateRangeCategoryTotals: DateRangeCategoryTotals[] = []\n monthlyCategoryTotals: MonthlyCategoryTotals[] = []\n\n dateRangeTotalsLoaded = false\n dateRangeTotalsLoading = false\n monthlyTotalsLoaded = false\n monthlyTotalsLoading = false\n\n // Monotonic request tokens, one per totals endpoint. A newer request\n // supersedes an older in-flight one: the stale response is discarded rather\n // than the newer request being dropped. These loaders used to early-return\n // while a request was in flight, which silently swallowed date-range/account\n // changes made mid-flight. (MEW-3910)\n //\n // Deliberately per-endpoint rather than one shared counter: several callers\n // (BubbleBudgetsWidget, BubbleBudgetsMiniWidget) fire the two loaders\n // independently and concurrently, and a shared counter would make the second\n // call supersede — and silently drop — the first.\n //\n // Kept out of the observable graph — internal concurrency bookkeeping, not\n // renderable state.\n dateRangeTotalsRequestId = 0\n monthlyTotalsRequestId = 0\n\n // Args each loader was last requested with; refreshLoadedCategoryTotals replays them.\n private lastDateRangeTotalsArgs: {\n accounts: Account[]\n startDate: Date\n endDate: Date\n } | null = null\n private lastMonthlyTotalsArgs: {\n accounts: Account[]\n startDate?: Date\n endDate?: Date\n } | null = null\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new CategoryApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable<CategoryStore, 'lastDateRangeTotalsArgs' | 'lastMonthlyTotalsArgs'>(this, {\n dateRangeTotalsRequestId: false,\n monthlyTotalsRequestId: false,\n lastDateRangeTotalsArgs: false,\n lastMonthlyTotalsArgs: false,\n })\n }\n\n get detailedCategories(): DetailedCategory[] {\n if (!this.globalStore.isInitialized) return []\n return augmentCategories(\n this.categories,\n this.globalStore.copyStore.copy.categories,\n this.dateRangeCategoryTotals,\n this.monthlyCategoryTotals,\n )\n }\n\n get detailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return getDetailedCategoryTransactions(\n this.detailedCategories,\n this.globalStore.transactionStore.sortedTransactions,\n )\n }\n\n get incomeCategories(): DetailedCategory[] {\n return this.detailedCategories.filter((c) => c.is_income)\n }\n\n get spendCategories(): DetailedCategory[] {\n return this.detailedCategories.filter(\n (c) => !c.is_income && !c.isTransfer && c.guid !== CategoryGuids.INVESTMENTS,\n )\n }\n\n get transferCategories(): DetailedCategory[] {\n return this.detailedCategories.filter((c) => c.isTransfer)\n }\n\n setCategories = (categories: Category[]) => {\n this.categories = categories\n this.categoriesLoading = false\n this.categoriesLoaded = true\n }\n\n setMonthlyCategoryTotals = (totals: MonthlyCategoryTotals[]) => {\n this.monthlyCategoryTotals = totals\n this.monthlyTotalsLoading = false\n this.monthlyTotalsLoaded = true\n }\n\n setDateRangeCategoryTotals = (totals: DateRangeCategoryTotals[]) => {\n this.dateRangeCategoryTotals = totals\n this.dateRangeTotalsLoading = false\n this.dateRangeTotalsLoaded = true\n }\n\n get trendsCategories(): DetailedCategory[] {\n return this.detailedCategories\n .filter((c) => c.totalAmount !== 0)\n .filter((c) => c.guid !== CategoryGuids.INVESTMENTS && c.guid !== CategoryGuids.TRANSFER)\n }\n\n addCategory = async (name: string, parentGuid: string) => {\n const category = { name, parent_guid: parentGuid } as Category\n\n try {\n await this.api.addCategory(category)\n await this.loadCategories()\n } catch (error) {\n console.error('Error occurred while adding category:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n }\n }\n\n loadCategories = async () => {\n if (this.categoriesLoading) return\n\n this.categoriesLoading = true\n try {\n const categories = await this.api.getCategories()\n this.setCategories(categories)\n } catch (error) {\n console.error('Error occurred while getting categories:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n runInAction(() => {\n this.categoriesLoading = false\n })\n }\n }\n\n loadDateRangeCategoryTotals = async (accounts: Account[], startDate: Date, endDate: Date) => {\n // Claim this request. Any request started later wins, so a date-range or\n // account change made while a request is in flight is no longer dropped.\n const requestId = ++this.dateRangeTotalsRequestId\n const isStale = () => requestId !== this.dateRangeTotalsRequestId\n this.lastDateRangeTotalsArgs = { accounts, startDate, endDate }\n\n runInAction(() => {\n this.dateRangeTotalsLoading = true\n })\n\n try {\n // UTC-midnight boundaries so the window matches the absolute post dates the\n // API keys on; local Dates would shift it by the viewer's timezone offset.\n const totals = await this.api.getDateRangeCategoryTotals(\n toUnixUTC(startDate),\n toUnixUTC(endDate),\n accounts,\n )\n // A newer request superseded this one; its response is authoritative.\n // Leave the loading flag alone: the newest request still owns it.\n if (isStale()) return\n this.setDateRangeCategoryTotals(totals)\n } catch (error) {\n // Don't report deliberately superseded requests — rapid date scrubbing\n // would otherwise spam the error backend. (MEW-3910)\n if (isStale()) return\n console.error('Error occurred while getting date range category totals:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n this.setDateRangeCategoryTotals([])\n }\n }\n\n loadMonthlyCategoryTotals = async (\n accounts: Account[] = this.globalStore.globalUiStore.selectedAccounts,\n startDate?: Date,\n endDate?: Date,\n ) => {\n // See loadDateRangeCategoryTotals: newest request wins. (MEW-3910)\n const requestId = ++this.monthlyTotalsRequestId\n const isStale = () => requestId !== this.monthlyTotalsRequestId\n this.lastMonthlyTotalsArgs = { accounts, startDate, endDate }\n runInAction(() => {\n this.monthlyTotalsLoading = true\n })\n\n // UTC-midnight boundaries; see loadDateRangeCategoryTotals.\n const start = toUnixUTC(startOfMonth(startDate ?? subMonths(new Date(), 11)))\n const end = toUnixUTC(endOfMonth(endDate ?? new Date()))\n\n try {\n const totals = await this.api.getMonthlyCategoryTotals(start, end, accounts)\n if (isStale()) return\n this.setMonthlyCategoryTotals(totals)\n } catch (error) {\n // Superseded requests are not reported. (MEW-3910)\n if (isStale()) return\n console.error('Error occurred while getting monthly category totals:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n // Setter clears monthlyTotalsLoading and marks loaded so the UI recovers\n // and retries aren't blocked. (MEW-3538)\n this.setMonthlyCategoryTotals([])\n }\n }\n\n reloadCategoryTotals = async (accounts: Account[], startDate?: Date, endDate?: Date) => {\n const start = startDate ?? subMonths(new Date(), 11)\n const end = endDate ?? endOfMonth(new Date())\n // Each loader claims its own token, so the pair does not invalidate itself.\n // No try/catch: both loaders handle and report their own errors and always\n // resolve, so nothing can reject here.\n await Promise.all([\n this.loadMonthlyCategoryTotals(accounts, start, end),\n this.loadDateRangeCategoryTotals(accounts, start, end),\n ])\n }\n\n // Re-issues each loader's last request; a replay supersedes an in-flight\n // request via the request-id guard, so the replayed response wins.\n refreshLoadedCategoryTotals = async () => {\n const refreshes: Promise<void>[] = []\n\n if (this.lastDateRangeTotalsArgs) {\n const { accounts, startDate, endDate } = this.lastDateRangeTotalsArgs\n refreshes.push(this.loadDateRangeCategoryTotals(accounts, startDate, endDate))\n }\n if (this.lastMonthlyTotalsArgs) {\n const { accounts, startDate, endDate } = this.lastMonthlyTotalsArgs\n refreshes.push(this.loadMonthlyCategoryTotals(accounts, startDate, endDate))\n }\n\n await Promise.all(refreshes)\n }\n\n removeCategory = async (guid: string) => {\n try {\n await this.api.removeCategory(guid)\n await this.loadCategories()\n } catch (error) {\n console.error('Error occurred while removing category:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n }\n }\n\n updateCategory = async (category: Category) => {\n try {\n await this.api.updateCategory(category)\n await this.loadCategories()\n } catch (error) {\n console.error('Error occurred while updating category:', error)\n this.globalStore.captureException(error, { store: 'CategoryStore' })\n }\n }\n\n /**\n * Walks a category guid up to its top-level parent. mxui's `CategoryIcon` only knows the\n * top-level guids and falls back to the Uncategorized icon for anything else, so callers that\n * only have a (possibly sub-) category guid must resolve it before rendering an icon. Returns\n * the guid unchanged when categories are not loaded yet or the guid is unknown.\n */\n getTopLevelCategoryGuid = (guid: string): string => {\n const seen = new Set<string>()\n let current = guid\n while (!seen.has(current)) {\n seen.add(current)\n const parent = this.categories.find((c) => c.guid === current)?.parent_guid\n if (!parent) return current\n current = parent\n }\n return current\n }\n\n // TODO: Remove this after refactoring Trends components to use detailedCategories\n getCategoryName = (guid: string) => {\n const category = this.categories.find((c) => c.guid === guid)\n return category?.name ?? CategoryGuidToName[guid]\n }\n}\n\n// TODO: Move into CategoryStore\nclass UiStore {\n expandedGuid: string | null = null\n selectedGuid: string | null = null\n searchValue = ''\n showSelected = true\n shouldDisableDrawerScroll = false\n unselectable: string[] = []\n unselectableText = ''\n\n savedOnSelect: any // todo\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setExpandedGuid = (guid: string | null) => (this.expandedGuid = guid)\n\n setSelectedGuid = (guid: string | null) => (this.selectedGuid = guid)\n\n setSearchValue = (value: string) => (this.searchValue = value)\n\n setShouldDisableDrawerScroll = (shouldDisable: boolean) =>\n (this.shouldDisableDrawerScroll = shouldDisable)\n\n setShowSelected = (showSelected: boolean) => (this.showSelected = showSelected)\n\n setUnselectable = (unselectable: string[]) => (this.unselectable = unselectable)\n\n setUnselectableText = (text: string) => (this.unselectableText = text)\n\n onSelect = (guid: string) => this.savedOnSelect(guid)\n\n setOnSelect = (callback: any) => (this.savedOnSelect = callback)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CategoryStore.es.js","names":[],"sources":["../../../src/core/stores/CategoryStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\nimport { subMonths } from 'date-fns/subMonths'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { endOfMonth } from 'date-fns/endOfMonth'\n\nimport { CategoryGuids, CategoryGuidToName } from '../constants'\nimport { CategoryApi } from '../api'\nimport { toUnixUTC } from '../utils/DateUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Account,\n Category,\n DetailedCategory,\n DetailedCategoryWithTransactions,\n DateRangeCategoryTotals,\n MonthlyCategoryTotals,\n} from '../types'\n\nimport { augmentCategories, getDetailedCategoryTransactions } from '../utils/CategoryUtil'\n\nexport class CategoryStore {\n globalStore: GlobalStore\n uiStore: UiStore\n api = new CategoryApi('/', '')\n\n categories: Category[] = []\n categoriesLoaded: boolean = false\n categoriesLoading: boolean = false\n dateRangeCategoryTotals: DateRangeCategoryTotals[] = []\n monthlyCategoryTotals: MonthlyCategoryTotals[] = []\n\n dateRangeTotalsLoaded = false\n dateRangeTotalsLoading = false\n monthlyTotalsLoaded = false\n monthlyTotalsLoading = false\n\n // Monotonic request tokens, one per totals endpoint. A newer request\n // supersedes an older in-flight one: the stale response is discarded rather\n // than the newer request being dropped. These loaders used to early-return\n // while a request was in flight, which silently swallowed date-range/account\n // changes made mid-flight. (MEW-3910)\n //\n // Deliberately per-endpoint rather than one shared counter: several callers\n // (BubbleBudgetsWidget, BubbleBudgetsMiniWidget) fire the two loaders\n // independently and concurrently, and a shared counter would make the second\n // call supersede — and silently drop — the first.\n //\n // Kept out of the observable graph — internal concurrency bookkeeping, not\n // renderable state.\n dateRangeTotalsRequestId = 0\n monthlyTotalsRequestId = 0\n\n // Args each loader was last requested with; refreshLoadedCategoryTotals replays them.\n private lastDateRangeTotalsArgs: {\n accounts: Account[]\n startDate: Date\n endDate: Date\n } | null = null\n private lastMonthlyTotalsArgs: {\n accounts: Account[]\n startDate?: Date\n endDate?: Date\n } | null = null\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new CategoryApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable<CategoryStore, 'lastDateRangeTotalsArgs' | 'lastMonthlyTotalsArgs'>(this, {\n dateRangeTotalsRequestId: false,\n monthlyTotalsRequestId: false,\n lastDateRangeTotalsArgs: false,\n lastMonthlyTotalsArgs: false,\n })\n }\n\n get detailedCategories(): DetailedCategory[] {\n if (!this.globalStore.isInitialized) return []\n return augmentCategories(\n this.categories,\n this.globalStore.copyStore.copy.categories,\n this.dateRangeCategoryTotals,\n this.monthlyCategoryTotals,\n )\n }\n\n get detailedCategoriesWithTransactions(): DetailedCategoryWithTransactions[] {\n return getDetailedCategoryTransactions(\n this.detailedCategories,\n this.globalStore.transactionStore.sortedTransactions,\n )\n }\n\n get incomeCategories(): DetailedCategory[] {\n return this.detailedCategories.filter((c) => c.is_income)\n }\n\n get spendCategories(): DetailedCategory[] {\n return this.detailedCategories.filter(\n (c) => !c.is_income && !c.isTransfer && c.guid !== CategoryGuids.INVESTMENTS,\n )\n }\n\n get transferCategories(): DetailedCategory[] {\n return this.detailedCategories.filter((c) => c.isTransfer)\n }\n\n setCategories = (categories: Category[]) => {\n this.categories = categories\n this.categoriesLoading = false\n this.categoriesLoaded = true\n }\n\n setMonthlyCategoryTotals = (totals: MonthlyCategoryTotals[]) => {\n this.monthlyCategoryTotals = totals\n this.monthlyTotalsLoading = false\n this.monthlyTotalsLoaded = true\n }\n\n setDateRangeCategoryTotals = (totals: DateRangeCategoryTotals[]) => {\n this.dateRangeCategoryTotals = totals\n this.dateRangeTotalsLoading = false\n this.dateRangeTotalsLoaded = true\n }\n\n get trendsCategories(): DetailedCategory[] {\n return this.detailedCategories\n .filter((c) => c.totalAmount !== 0)\n .filter((c) => c.guid !== CategoryGuids.INVESTMENTS && c.guid !== CategoryGuids.TRANSFER)\n }\n\n addCategory = async (name: string, parentGuid: string) => {\n const category = { name, parent_guid: parentGuid } as Category\n\n try {\n await this.api.addCategory(category)\n await this.loadCategories()\n } catch (error) {\n this.captureError('addCategory', error)\n }\n }\n\n loadCategories = async () => {\n if (this.categoriesLoading) return\n\n this.categoriesLoading = true\n try {\n const categories = await this.api.getCategories()\n this.setCategories(categories)\n } catch (error) {\n this.captureError('loadCategories', error)\n runInAction(() => {\n this.categoriesLoading = false\n })\n }\n }\n\n loadDateRangeCategoryTotals = async (accounts: Account[], startDate: Date, endDate: Date) => {\n // Claim this request. Any request started later wins, so a date-range or\n // account change made while a request is in flight is no longer dropped.\n const requestId = ++this.dateRangeTotalsRequestId\n const isStale = () => requestId !== this.dateRangeTotalsRequestId\n this.lastDateRangeTotalsArgs = { accounts, startDate, endDate }\n\n runInAction(() => {\n this.dateRangeTotalsLoading = true\n })\n\n try {\n // UTC-midnight boundaries so the window matches the absolute post dates the\n // API keys on; local Dates would shift it by the viewer's timezone offset.\n const totals = await this.api.getDateRangeCategoryTotals(\n toUnixUTC(startDate),\n toUnixUTC(endDate),\n accounts,\n )\n // A newer request superseded this one; its response is authoritative.\n // Leave the loading flag alone: the newest request still owns it.\n if (isStale()) return\n this.setDateRangeCategoryTotals(totals)\n } catch (error) {\n // Don't report deliberately superseded requests — rapid date scrubbing\n // would otherwise spam the error backend. (MEW-3910)\n if (isStale()) return\n this.captureError('loadDateRangeCategoryTotals', error)\n this.setDateRangeCategoryTotals([])\n }\n }\n\n loadMonthlyCategoryTotals = async (\n accounts: Account[] = this.globalStore.globalUiStore.selectedAccounts,\n startDate?: Date,\n endDate?: Date,\n ) => {\n // See loadDateRangeCategoryTotals: newest request wins. (MEW-3910)\n const requestId = ++this.monthlyTotalsRequestId\n const isStale = () => requestId !== this.monthlyTotalsRequestId\n this.lastMonthlyTotalsArgs = { accounts, startDate, endDate }\n runInAction(() => {\n this.monthlyTotalsLoading = true\n })\n\n // UTC-midnight boundaries; see loadDateRangeCategoryTotals.\n const start = toUnixUTC(startOfMonth(startDate ?? subMonths(new Date(), 11)))\n const end = toUnixUTC(endOfMonth(endDate ?? new Date()))\n\n try {\n const totals = await this.api.getMonthlyCategoryTotals(start, end, accounts)\n if (isStale()) return\n this.setMonthlyCategoryTotals(totals)\n } catch (error) {\n // Superseded requests are not reported. (MEW-3910)\n if (isStale()) return\n this.captureError('loadMonthlyCategoryTotals', error)\n // Setter clears monthlyTotalsLoading and marks loaded so the UI recovers\n // and retries aren't blocked. (MEW-3538)\n this.setMonthlyCategoryTotals([])\n }\n }\n\n reloadCategoryTotals = async (accounts: Account[], startDate?: Date, endDate?: Date) => {\n const start = startDate ?? subMonths(new Date(), 11)\n const end = endDate ?? endOfMonth(new Date())\n // Each loader claims its own token, so the pair does not invalidate itself.\n // No try/catch: both loaders handle and report their own errors and always\n // resolve, so nothing can reject here.\n await Promise.all([\n this.loadMonthlyCategoryTotals(accounts, start, end),\n this.loadDateRangeCategoryTotals(accounts, start, end),\n ])\n }\n\n // Re-issues each loader's last request; a replay supersedes an in-flight\n // request via the request-id guard, so the replayed response wins.\n refreshLoadedCategoryTotals = async () => {\n const refreshes: Promise<void>[] = []\n\n if (this.lastDateRangeTotalsArgs) {\n const { accounts, startDate, endDate } = this.lastDateRangeTotalsArgs\n refreshes.push(this.loadDateRangeCategoryTotals(accounts, startDate, endDate))\n }\n if (this.lastMonthlyTotalsArgs) {\n const { accounts, startDate, endDate } = this.lastMonthlyTotalsArgs\n refreshes.push(this.loadMonthlyCategoryTotals(accounts, startDate, endDate))\n }\n\n await Promise.all(refreshes)\n }\n\n removeCategory = async (guid: string) => {\n try {\n await this.api.removeCategory(guid)\n await this.loadCategories()\n } catch (error) {\n this.captureError('removeCategory', error)\n }\n }\n\n updateCategory = async (category: Category) => {\n try {\n await this.api.updateCategory(category)\n await this.loadCategories()\n } catch (error) {\n this.captureError('updateCategory', error)\n }\n }\n\n /**\n * Walks a category guid up to its top-level parent. mxui's `CategoryIcon` only knows the\n * top-level guids and falls back to the Uncategorized icon for anything else, so callers that\n * only have a (possibly sub-) category guid must resolve it before rendering an icon. Returns\n * the guid unchanged when categories are not loaded yet or the guid is unknown.\n */\n getTopLevelCategoryGuid = (guid: string): string => {\n const seen = new Set<string>()\n let current = guid\n while (!seen.has(current)) {\n seen.add(current)\n const parent = this.categories.find((c) => c.guid === current)?.parent_guid\n if (!parent) return current\n current = parent\n }\n return current\n }\n\n // TODO: Remove this after refactoring Trends components to use detailedCategories\n getCategoryName = (guid: string) => {\n const category = this.categories.find((c) => c.guid === guid)\n return category?.name ?? CategoryGuidToName[guid]\n }\n\n private captureError = (action: string, error: unknown) =>\n this.globalStore.captureException(error, { store: 'CategoryStore', action })\n}\n\n// TODO: Move into CategoryStore\nclass UiStore {\n expandedGuid: string | null = null\n selectedGuid: string | null = null\n searchValue = ''\n showSelected = true\n shouldDisableDrawerScroll = false\n unselectable: string[] = []\n unselectableText = ''\n\n savedOnSelect: any // todo\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setExpandedGuid = (guid: string | null) => (this.expandedGuid = guid)\n\n setSelectedGuid = (guid: string | null) => (this.selectedGuid = guid)\n\n setSearchValue = (value: string) => (this.searchValue = value)\n\n setShouldDisableDrawerScroll = (shouldDisable: boolean) =>\n (this.shouldDisableDrawerScroll = shouldDisable)\n\n setShowSelected = (showSelected: boolean) => (this.showSelected = showSelected)\n\n setUnselectable = (unselectable: string[]) => (this.unselectable = unselectable)\n\n setUnselectableText = (text: string) => (this.unselectableText = text)\n\n onSelect = (guid: string) => this.savedOnSelect(guid)\n\n setOnSelect = (callback: any) => (this.savedOnSelect = callback)\n}\n"],"mappings":";;;;;;;;AAsBA,IAAa,IAAb,MAA2B;AAAA,EACzB;AAAA,EACA;AAAA,EACA,MAAM,IAAI,EAAY,KAAK,EAAE;AAAA,EAE7B,aAAyB,CAAC;AAAA,EAC1B,mBAA4B;AAAA,EAC5B,oBAA6B;AAAA,EAC7B,0BAAqD,CAAC;AAAA,EACtD,wBAAiD,CAAC;AAAA,EAElD,wBAAwB;AAAA,EACxB,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EAevB,2BAA2B;AAAA,EAC3B,yBAAyB;AAAA,EAGzB,0BAIW;AAAA,EACX,wBAIW;AAAA,EAEX,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,UAAU,IAAI,EAAQ,GAC3B,KAAK,MAAM,IAAI,EAAY,EAAY,UAAU,EAAY,cAAc,EAAY,OAAO,GAE9F,EAAuF,MAAM;AAAA,MAC3F,0BAA0B;AAAA,MAC1B,wBAAwB;AAAA,MACxB,yBAAyB;AAAA,MACzB,uBAAuB;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,qBAAyC;AAC3C,WAAK,KAAK,YAAY,gBACf,EACL,KAAK,YACL,KAAK,YAAY,UAAU,KAAK,YAChC,KAAK,yBACL,KAAK,qBACP,IAN4C,CAAC;AAAA,EAO/C;AAAA,EAEA,IAAI,qCAAyE;AAC3E,WAAO,EACL,KAAK,oBACL,KAAK,YAAY,iBAAiB,kBACpC;AAAA,EACF;AAAA,EAEA,IAAI,mBAAuC;AACzC,WAAO,KAAK,mBAAmB,OAAA,CAAQ,MAAM,EAAE,SAAS;AAAA,EAC1D;AAAA,EAEA,IAAI,kBAAsC;AACxC,WAAO,KAAK,mBAAmB,OAAA,CAC5B,MAAM,CAAC,EAAE,aAAa,CAAC,EAAE,cAAc,EAAE,SAAS,EAAc,WACnE;AAAA,EACF;AAAA,EAEA,IAAI,qBAAyC;AAC3C,WAAO,KAAK,mBAAmB,OAAA,CAAQ,MAAM,EAAE,UAAU;AAAA,EAC3D;AAAA,EAEA,gBAAA,CAAiB,MAA2B;AAC1C,SAAK,aAAa,GAClB,KAAK,oBAAoB,IACzB,KAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,2BAAA,CAA4B,MAAoC;AAC9D,SAAK,wBAAwB,GAC7B,KAAK,uBAAuB,IAC5B,KAAK,sBAAsB;AAAA,EAC7B;AAAA,EAEA,6BAAA,CAA8B,MAAsC;AAClE,SAAK,0BAA0B,GAC/B,KAAK,yBAAyB,IAC9B,KAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEA,IAAI,mBAAuC;AACzC,WAAO,KAAK,mBACT,OAAA,CAAQ,MAAM,EAAE,gBAAgB,CAAC,EACjC,OAAA,CAAQ,MAAM,EAAE,SAAS,EAAc,eAAe,EAAE,SAAS,EAAc,QAAQ;AAAA,EAC5F;AAAA,EAEA,cAAc,OAAO,GAAc,MAAuB;AACxD,UAAM,IAAW;AAAA,MAAE,MAAA;AAAA,MAAM,aAAa;AAAA,IAAW;AAEjD,QAAI;AACF,YAAM,KAAK,IAAI,YAAY,CAAQ,GACnC,MAAM,KAAK,eAAe;AAAA,IAC5B,SAAS,GAAO;AACd,WAAK,aAAa,eAAe,CAAK;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,iBAAiB,YAAY;AAC3B,QAAI,MAAK,mBAET;AAAA,WAAK,oBAAoB;AACzB,UAAI;AACF,cAAM,IAAa,MAAM,KAAK,IAAI,cAAc;AAChD,aAAK,cAAc,CAAU;AAAA,MAC/B,SAAS,GAAO;AACd,aAAK,aAAa,kBAAkB,CAAK,GACzC,EAAA,MAAkB;AAChB,eAAK,oBAAoB;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAAA,EAEA,8BAA8B,OAAO,GAAqB,GAAiB,MAAkB;AAG3F,UAAM,IAAY,EAAE,KAAK,0BACnB,IAAA,MAAgB,MAAc,KAAK;AACzC,SAAK,0BAA0B;AAAA,MAAE,UAAA;AAAA,MAAU,WAAA;AAAA,MAAW,SAAA;AAAA,IAAQ,GAE9D,EAAA,MAAkB;AAChB,WAAK,yBAAyB;AAAA,IAChC,CAAC;AAED,QAAI;AAGF,YAAM,IAAS,MAAM,KAAK,IAAI,2BAC5B,EAAU,CAAS,GACnB,EAAU,CAAO,GACjB,CACF;AAGA,UAAI,EAAQ,EAAG;AACf,WAAK,2BAA2B,CAAM;AAAA,IACxC,SAAS,GAAO;AAGd,UAAI,EAAQ,EAAG;AACf,WAAK,aAAa,+BAA+B,CAAK,GACtD,KAAK,2BAA2B,CAAC,CAAC;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,4BAA4B,OAC1B,IAAsB,KAAK,YAAY,cAAc,kBACrD,GACA,MACG;AAEH,UAAM,IAAY,EAAE,KAAK,wBACnB,IAAA,MAAgB,MAAc,KAAK;AACzC,SAAK,wBAAwB;AAAA,MAAE,UAAA;AAAA,MAAU,WAAA;AAAA,MAAW,SAAA;AAAA,IAAQ,GAC5D,EAAA,MAAkB;AAChB,WAAK,uBAAuB;AAAA,IAC9B,CAAC;AAGD,UAAM,IAAQ,EAAU,EAAa,KAAa,EAAU,oBAAI,KAAK,GAAG,EAAE,CAAC,CAAC,GACtE,IAAM,EAAU,EAAW,KAAW,oBAAI,KAAK,CAAC,CAAC;AAEvD,QAAI;AACF,YAAM,IAAS,MAAM,KAAK,IAAI,yBAAyB,GAAO,GAAK,CAAQ;AAC3E,UAAI,EAAQ,EAAG;AACf,WAAK,yBAAyB,CAAM;AAAA,IACtC,SAAS,GAAO;AAEd,UAAI,EAAQ,EAAG;AACf,WAAK,aAAa,6BAA6B,CAAK,GAGpD,KAAK,yBAAyB,CAAC,CAAC;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,uBAAuB,OAAO,GAAqB,GAAkB,MAAmB;AACtF,UAAM,IAAQ,KAAa,EAAU,oBAAI,KAAK,GAAG,EAAE,GAC7C,IAAM,KAAW,EAAW,oBAAI,KAAK,CAAC;AAI5C,UAAM,QAAQ,IAAI,CAChB,KAAK,0BAA0B,GAAU,GAAO,CAAG,GACnD,KAAK,4BAA4B,GAAU,GAAO,CAAG,CACvD,CAAC;AAAA,EACH;AAAA,EAIA,8BAA8B,YAAY;AACxC,UAAM,IAA6B,CAAC;AAEpC,QAAI,KAAK,yBAAyB;AAChC,YAAM,EAAE,UAAA,GAAU,WAAA,GAAW,SAAA,EAAA,IAAY,KAAK;AAC9C,MAAA,EAAU,KAAK,KAAK,4BAA4B,GAAU,GAAW,CAAO,CAAC;AAAA,IAC/E;AACA,QAAI,KAAK,uBAAuB;AAC9B,YAAM,EAAE,UAAA,GAAU,WAAA,GAAW,SAAA,EAAA,IAAY,KAAK;AAC9C,MAAA,EAAU,KAAK,KAAK,0BAA0B,GAAU,GAAW,CAAO,CAAC;AAAA,IAC7E;AAEA,UAAM,QAAQ,IAAI,CAAS;AAAA,EAC7B;AAAA,EAEA,iBAAiB,OAAO,MAAiB;AACvC,QAAI;AACF,YAAM,KAAK,IAAI,eAAe,CAAI,GAClC,MAAM,KAAK,eAAe;AAAA,IAC5B,SAAS,GAAO;AACd,WAAK,aAAa,kBAAkB,CAAK;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,iBAAiB,OAAO,MAAuB;AAC7C,QAAI;AACF,YAAM,KAAK,IAAI,eAAe,CAAQ,GACtC,MAAM,KAAK,eAAe;AAAA,IAC5B,SAAS,GAAO;AACd,WAAK,aAAa,kBAAkB,CAAK;AAAA,IAC3C;AAAA,EACF;AAAA,EAQA,0BAAA,CAA2B,MAAyB;AAClD,UAAM,IAAO,oBAAI,IAAY;AAC7B,QAAI,IAAU;AACd,WAAO,CAAC,EAAK,IAAI,CAAO,KAAG;AACzB,MAAA,EAAK,IAAI,CAAO;AAChB,YAAM,IAAS,KAAK,WAAW,KAAA,CAAM,MAAM,EAAE,SAAS,CAAO,GAAG;AAChE,UAAI,CAAC,EAAQ,QAAO;AACpB,MAAA,IAAU;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA,EAGA,kBAAA,CAAmB,MACA,KAAK,WAAW,KAAA,CAAM,MAAM,EAAE,SAAS,CACjD,GAAU,QAAQ,EAAmB,CAAA;AAAA,EAG9C,eAAA,CAAwB,GAAgB,MACtC,KAAK,YAAY,iBAAiB,GAAO;AAAA,IAAE,OAAO;AAAA,IAAiB,QAAA;AAAA,EAAO,CAAC;AAC/E,GAGM,IAAN,MAAc;AAAA,EACZ,eAA8B;AAAA,EAC9B,eAA8B;AAAA,EAC9B,cAAc;AAAA,EACd,eAAe;AAAA,EACf,4BAA4B;AAAA,EAC5B,eAAyB,CAAC;AAAA,EAC1B,mBAAmB;AAAA,EAEnB;AAAA,EAEA,cAAc;AACZ,IAAA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,kBAAA,CAAmB,MAAyB,KAAK,eAAe;AAAA,EAEhE,kBAAA,CAAmB,MAAyB,KAAK,eAAe;AAAA,EAEhE,iBAAA,CAAkB,MAAmB,KAAK,cAAc;AAAA,EAExD,+BAAA,CAAgC,MAC7B,KAAK,4BAA4B;AAAA,EAEpC,kBAAA,CAAmB,MAA2B,KAAK,eAAe;AAAA,EAElE,kBAAA,CAAmB,MAA4B,KAAK,eAAe;AAAA,EAEnE,sBAAA,CAAuB,MAAkB,KAAK,mBAAmB;AAAA,EAEjE,WAAA,CAAY,MAAiB,KAAK,cAAc,CAAI;AAAA,EAEpD,cAAA,CAAe,MAAmB,KAAK,gBAAgB;AACzD"}
@@ -10,4 +10,5 @@ export declare class GlobalCopyStore {
10
10
  constructor(globalStore: GlobalStore);
11
11
  loadCopy: () => Promise<void>;
12
12
  getCopy: (namespace: string, translationKey?: string) => Promise<void>;
13
+ private captureError;
13
14
  }
@@ -1,32 +1,36 @@
1
- import { GlobalCopyApi as t } from "../api/GlobalCopyApi.es.js";
2
- import { makeAutoObservable as a, runInAction as r } from "mobx";
3
- var c = class {
1
+ import { GlobalCopyApi as r } from "../api/GlobalCopyApi.es.js";
2
+ import { makeAutoObservable as a, runInAction as i } from "mobx";
3
+ var n = class {
4
4
  globalStore;
5
- api = new t("/", "");
5
+ api = new r("/", "");
6
6
  copy = {};
7
7
  featureNamespace = "experiences";
8
8
  isInitialized = !1;
9
- constructor(o) {
10
- this.globalStore = o, this.api = new t(o.endpoint, o.sessionToken, o.onError), a(this);
9
+ constructor(t) {
10
+ this.globalStore = t, this.api = new r(t.endpoint, t.sessionToken, t.onError), a(this);
11
11
  }
12
12
  loadCopy = async () => {
13
- await this.getCopy(this.featureNamespace), r(() => {
13
+ await this.getCopy(this.featureNamespace), i(() => {
14
14
  this.isInitialized = !0;
15
15
  });
16
16
  };
17
- getCopy = async (o, i = "") => {
17
+ getCopy = async (t, o = "") => {
18
18
  try {
19
- const e = await this.api.getGlobalCopy(o, i);
20
- r(() => {
21
- this.copy = e[o];
19
+ const e = await this.api.getGlobalCopy(t, o);
20
+ i(() => {
21
+ this.copy = e[t];
22
22
  });
23
23
  } catch (e) {
24
- console.error("Error occurred while fetching copy:", e), this.globalStore.captureException(e, { store: "GlobalCopyStore" });
24
+ this.captureError("getCopy", e);
25
25
  }
26
26
  };
27
+ captureError = (t, o) => this.globalStore.captureException(o, {
28
+ store: "GlobalCopyStore",
29
+ action: t
30
+ });
27
31
  };
28
32
  export {
29
- c as GlobalCopyStore
33
+ n as GlobalCopyStore
30
34
  };
31
35
 
32
36
  //# sourceMappingURL=GlobalCopyStore.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalCopyStore.es.js","names":[],"sources":["../../../src/core/stores/GlobalCopyStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { GlobalCopyApi } from '../api'\nimport { GlobalCopy } from '../types'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class GlobalCopyStore {\n globalStore: GlobalStore\n api: GlobalCopyApi = new GlobalCopyApi('/', '')\n\n copy: GlobalCopy = {} as GlobalCopy\n featureNamespace = 'experiences'\n\n isInitialized = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new GlobalCopyApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n makeAutoObservable(this)\n }\n\n loadCopy = async () => {\n await this.getCopy(this.featureNamespace)\n\n runInAction(() => {\n this.isInitialized = true\n })\n }\n\n getCopy = async (namespace: string, translationKey: string = '') => {\n try {\n const newCopy = await this.api.getGlobalCopy(namespace, translationKey)\n\n runInAction(() => {\n this.copy = newCopy[namespace]\n })\n } catch (error) {\n console.error('Error occurred while fetching copy:', error)\n this.globalStore.captureException(error, { store: 'GlobalCopyStore' })\n }\n }\n}\n"],"mappings":";;AAOA,IAAa,IAAb,MAA6B;AAAA,EAC3B;AAAA,EACA,MAAqB,IAAI,EAAc,KAAK,EAAE;AAAA,EAE9C,OAAmB,CAAC;AAAA,EACpB,mBAAmB;AAAA,EAEnB,gBAAgB;AAAA,EAEhB,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EACb,EAAY,UACZ,EAAY,cACZ,EAAY,OACd,GAEA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,WAAW,YAAY;AACrB,UAAM,KAAK,QAAQ,KAAK,gBAAgB,GAExC,EAAA,MAAkB;AAChB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAO,GAAmB,IAAyB,OAAO;AAClE,QAAI;AACF,YAAM,IAAU,MAAM,KAAK,IAAI,cAAc,GAAW,CAAc;AAEtE,MAAA,EAAA,MAAkB;AAChB,aAAK,OAAO,EAAQ,CAAA;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,GAAO;AACd,cAAQ,MAAM,uCAAuC,CAAK,GAC1D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,kBAAkB,CAAC;AAAA,IACvE;AAAA,EACF;AACF"}
1
+ {"version":3,"file":"GlobalCopyStore.es.js","names":[],"sources":["../../../src/core/stores/GlobalCopyStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { GlobalCopyApi } from '../api'\nimport { GlobalCopy } from '../types'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class GlobalCopyStore {\n globalStore: GlobalStore\n api: GlobalCopyApi = new GlobalCopyApi('/', '')\n\n copy: GlobalCopy = {} as GlobalCopy\n featureNamespace = 'experiences'\n\n isInitialized = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new GlobalCopyApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n makeAutoObservable(this)\n }\n\n loadCopy = async () => {\n await this.getCopy(this.featureNamespace)\n\n runInAction(() => {\n this.isInitialized = true\n })\n }\n\n getCopy = async (namespace: string, translationKey: string = '') => {\n try {\n const newCopy = await this.api.getGlobalCopy(namespace, translationKey)\n\n runInAction(() => {\n this.copy = newCopy[namespace]\n })\n } catch (error) {\n this.captureError('getCopy', error)\n }\n }\n\n private captureError = (action: string, error: unknown) =>\n this.globalStore.captureException(error, { store: 'GlobalCopyStore', action })\n}\n"],"mappings":";;AAOA,IAAa,IAAb,MAA6B;AAAA,EAC3B;AAAA,EACA,MAAqB,IAAI,EAAc,KAAK,EAAE;AAAA,EAE9C,OAAmB,CAAC;AAAA,EACpB,mBAAmB;AAAA,EAEnB,gBAAgB;AAAA,EAEhB,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EACb,EAAY,UACZ,EAAY,cACZ,EAAY,OACd,GAEA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,WAAW,YAAY;AACrB,UAAM,KAAK,QAAQ,KAAK,gBAAgB,GAExC,EAAA,MAAkB;AAChB,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAO,GAAmB,IAAyB,OAAO;AAClE,QAAI;AACF,YAAM,IAAU,MAAM,KAAK,IAAI,cAAc,GAAW,CAAc;AAEtE,MAAA,EAAA,MAAkB;AAChB,aAAK,OAAO,EAAQ,CAAA;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,GAAO;AACd,WAAK,aAAa,WAAW,CAAK;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,eAAA,CAAwB,GAAgB,MACtC,KAAK,YAAY,iBAAiB,GAAO;AAAA,IAAE,OAAO;AAAA,IAAmB,QAAA;AAAA,EAAO,CAAC;AACjF"}
@@ -23,4 +23,5 @@ export declare class HoldingStore {
23
23
  loadHoldings: () => Promise<void>;
24
24
  setAnalysisType: (analysisType: AnalysisType) => void;
25
25
  updateHoldings: (holding: Holding) => Promise<void>;
26
+ private captureError;
26
27
  }
@@ -42,7 +42,7 @@ var m = class {
42
42
  const s = await this.api.getHoldings();
43
43
  this.setHoldings(s);
44
44
  } catch (s) {
45
- console.error("Error occurred while getting holdings:", s), this.globalStore.captureException(s, { store: "HoldingStore" });
45
+ this.captureError("loadHoldings", s);
46
46
  }
47
47
  };
48
48
  setAnalysisType = (s) => {
@@ -59,9 +59,13 @@ var m = class {
59
59
  });
60
60
  }
61
61
  } catch (t) {
62
- console.error("Error occurred while updating holding:", t), this.globalStore.captureException(t, { store: "HoldingStore" });
62
+ this.captureError("updateHoldings", t);
63
63
  }
64
64
  };
65
+ captureError = (s, t) => this.globalStore.captureException(t, {
66
+ store: "HoldingStore",
67
+ action: s
68
+ });
65
69
  };
66
70
  export {
67
71
  m as HoldingStore