@mx-cartographer/experiences 9.4.42 → 9.4.44
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 +12 -0
- package/dist/budgets/components/BudgetsEmptyState.es.js +50 -44
- package/dist/budgets/components/BudgetsEmptyState.es.js.map +1 -1
- package/dist/categories/components/CategoryList.es.js +34 -27
- package/dist/categories/components/CategoryList.es.js.map +1 -1
- package/dist/common/components/listitems/CollapseExpandListItem.es.js +26 -25
- package/dist/common/components/listitems/CollapseExpandListItem.es.js.map +1 -1
- package/dist/core/stores/TransactionStore.es.js +1 -1
- package/dist/core/stores/TransactionStore.es.js.map +1 -1
- package/dist/core/types/localization/CommonCopy.d.ts +2 -0
- package/dist/core/types/localization/TrendsCopy.d.ts +0 -1
- package/dist/core/utils/CategoryUtil.d.ts +11 -0
- package/dist/core/utils/CategoryUtil.es.js +36 -32
- package/dist/core/utils/CategoryUtil.es.js.map +1 -1
- package/dist/core/utils/NetWorthUtils.d.ts +2 -2
- package/dist/core/utils/NetWorthUtils.es.js +64 -64
- package/dist/core/utils/NetWorthUtils.es.js.map +1 -1
- package/dist/core/utils/TransactionUtils.d.ts +2 -2
- package/dist/core/utils/TransactionUtils.es.js +93 -92
- package/dist/core/utils/TransactionUtils.es.js.map +1 -1
- package/dist/debts/components/debtstable/AccountCell.es.js +13 -13
- package/dist/debts/components/debtstable/AccountCell.es.js.map +1 -1
- package/dist/finstrong/components/SpendLessThanYouMake/SpendLessThanYouMakeComponent.es.js +40 -36
- package/dist/finstrong/components/SpendLessThanYouMake/SpendLessThanYouMakeComponent.es.js.map +1 -1
- package/dist/networth/components/AssetsLiabilitiesDetail.es.js +47 -47
- package/dist/networth/components/AssetsLiabilitiesDetail.es.js.map +1 -1
- package/dist/spending/components/MiniSpendingChart.es.js +52 -47
- package/dist/spending/components/MiniSpendingChart.es.js.map +1 -1
- package/dist/spending/components/Spending.es.js +82 -74
- package/dist/spending/components/Spending.es.js.map +1 -1
- package/dist/spending/utils/SpendingData.d.ts +7 -5
- package/dist/spending/utils/SpendingData.es.js +34 -31
- package/dist/spending/utils/SpendingData.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [9.4.44] - 09-25-2026
|
|
2
|
+
|
|
3
|
+
- **FIXED** - Budgets zero-state buttons now wrap and grow to fit longer localized copy instead of cropping or overflowing the text (MEW-4167)
|
|
4
|
+
|
|
5
|
+
## [9.4.43] - 09-25-2026
|
|
6
|
+
|
|
7
|
+
- **FIXED** - Category names now render localized copy instead of the raw API value in the Spending widget (main view list, drawer, donut legend), the Spending mini widget, the Finstrong spend-less-than-you-make chart, and the Transactions table Category column. (MEW-4166)
|
|
8
|
+
- **FIXED** - Trends category list "View more"/"View less" toggle is now localized and moved to common copy (MEW-4166)
|
|
9
|
+
- **FIXED** - Account type labels (e.g. Checking, Savings, Investment) in the Net Worth "Assets & Liabilities" drawer accordion and the Debts table account cell now use localized copy instead of hardcoded English (MEW-4166)
|
|
10
|
+
- **FIXED** - Category names in the shared category selection drawer (used by the transaction category-edit and split actions, and transaction-rule category edit) now render localized copy instead of the raw API value, and the search filter matches on the localized name (MEW-4166)
|
|
11
|
+
- **CHANGED** - Copy contract: added required `common.view_more` and `common.view_less` keys and removed the unused `trends.view_more` key; the component falls back to English if they are absent (MEW-4166)
|
|
12
|
+
|
|
1
13
|
## [9.4.42] - 09-24-2026
|
|
2
14
|
|
|
3
15
|
- **CHANGED** - insights-v2 Save an Extra beat UI polish: `SaveAnExtraCard` now uses mxui `P`/`Text` semantic typography (logo `boxShadow` removed), `BaseLayout` renders the beat description via mxui `P` (`subtitle2`), and `SaveExtraBlock` uses horizontal-only padding (WEC-1851)
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { useAppConfig as
|
|
1
|
+
import { useAppConfig as S, useBudgetsStore as B, useCategoryStore as v, useGlobalCopyStore as z, useWidgetContainerProvider as A } from "../../common/context/hooks.es.js";
|
|
2
2
|
import { useScreenSize as D } from "../../common/hooks/useScreenSize.es.js";
|
|
3
3
|
import E from "../../common/components/Loader.es.js";
|
|
4
4
|
import { EmptyState as u } from "../../common/components/EmptyState.es.js";
|
|
5
|
-
import
|
|
6
|
-
import { Fragment as j, jsx as
|
|
7
|
-
var
|
|
8
|
-
const { config:
|
|
9
|
-
|
|
10
|
-
const { data: e, isSuccess:
|
|
11
|
-
|
|
5
|
+
import s from "react";
|
|
6
|
+
import { Fragment as j, jsx as a } from "react/jsx-runtime";
|
|
7
|
+
var R = ({ isMiniWidget: r = !1, onConnectAccountsClick: _, createBudgetOnClick: n }) => {
|
|
8
|
+
const { config: h } = S(), { recalculateBudgets: g } = B(), { spendCategories: i } = v(), { budgets: t } = z(), { availableWidth: p } = A(), { isMobile: b } = D(p), o = r && b, [l, d] = s.useState(!1), [y, f] = s.useState(!1), [x, m] = s.useState(!1), w = s.useMemo(() => i.filter((e) => e.totalAverageAmount > 0), [i]), c = async () => {
|
|
9
|
+
m(!0);
|
|
10
|
+
const { data: e, isSuccess: C } = await g(w);
|
|
11
|
+
m(!1), C ? (e.length === 0 && f(!0), d(!1)) : d(!0);
|
|
12
12
|
};
|
|
13
|
-
return
|
|
13
|
+
return x ? /* @__PURE__ */ a(E, {}) : l ? /* @__PURE__ */ a(u, {
|
|
14
14
|
header: t.autogenerate_budgets_error_header,
|
|
15
15
|
icon: "error",
|
|
16
16
|
iconColor: "#4D4D4D",
|
|
17
17
|
onClick: (e) => {
|
|
18
|
-
e === "primary" ?
|
|
18
|
+
e === "primary" ? c() : n();
|
|
19
19
|
},
|
|
20
20
|
primaryButton: t.autogenerate_budgets_error_primary_button,
|
|
21
21
|
secondaryButton: t.zero_state_generate_budgets_secondary_button,
|
|
@@ -23,13 +23,15 @@ var P = ({ isMiniWidget: o = !1, onConnectAccountsClick: _, createBudgetOnClick:
|
|
|
23
23
|
sx: {
|
|
24
24
|
width: { sm: 468 },
|
|
25
25
|
".buttons-footer": {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
minWidth: 208,
|
|
27
|
+
maxWidth: "100%",
|
|
28
|
+
button: {
|
|
29
|
+
textWrap: "wrap",
|
|
30
|
+
height: "max-content"
|
|
31
|
+
},
|
|
32
|
+
...o && { mt: 16 }
|
|
31
33
|
},
|
|
32
|
-
...
|
|
34
|
+
...o && {
|
|
33
35
|
justifyContent: "center",
|
|
34
36
|
mt: 0,
|
|
35
37
|
svg: {
|
|
@@ -38,30 +40,32 @@ var P = ({ isMiniWidget: o = !1, onConnectAccountsClick: _, createBudgetOnClick:
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
|
-
}) : /* @__PURE__ */
|
|
43
|
+
}) : /* @__PURE__ */ a(j, { children: y ? /* @__PURE__ */ a(u, {
|
|
42
44
|
header: t.zero_state_generate_budgets_header,
|
|
43
45
|
icon: "error",
|
|
44
46
|
iconColor: "#4D4D4D",
|
|
45
47
|
onClick: (e) => {
|
|
46
48
|
e === "primary" ? _() : n();
|
|
47
49
|
},
|
|
48
|
-
primaryButton:
|
|
50
|
+
primaryButton: h.show_connections_widget_in_master ? t.zero_state_generate_budgets_primary_button : void 0,
|
|
49
51
|
secondaryButton: t.zero_state_generate_budgets_secondary_button,
|
|
50
52
|
subText: t.zero_state_generate_budgets_subheader,
|
|
51
53
|
sx: {
|
|
52
|
-
width:
|
|
53
|
-
height:
|
|
54
|
-
mt:
|
|
54
|
+
width: r ? "100%" : { sm: 500 },
|
|
55
|
+
height: r ? "100%" : { sm: 468 },
|
|
56
|
+
mt: o ? 0 : 50,
|
|
55
57
|
".buttons-footer": {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
minWidth: 208,
|
|
59
|
+
maxWidth: "100%",
|
|
60
|
+
minHeight: 100,
|
|
61
|
+
button: {
|
|
62
|
+
textWrap: "wrap",
|
|
63
|
+
height: "max-content"
|
|
64
|
+
},
|
|
65
|
+
...o && { mt: 16 }
|
|
62
66
|
},
|
|
63
|
-
padding:
|
|
64
|
-
...
|
|
67
|
+
padding: r ? 5 : 0,
|
|
68
|
+
...o && {
|
|
65
69
|
justifyContent: "center",
|
|
66
70
|
svg: {
|
|
67
71
|
height: 32,
|
|
@@ -69,30 +73,32 @@ var P = ({ isMiniWidget: o = !1, onConnectAccountsClick: _, createBudgetOnClick:
|
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
|
-
}) : /* @__PURE__ */
|
|
76
|
+
}) : /* @__PURE__ */ a(u, {
|
|
73
77
|
header: t.create_budgets_title,
|
|
74
78
|
icon: "bubble_chart",
|
|
75
79
|
iconColor: "#1A1A1A",
|
|
76
80
|
onClick: (e) => {
|
|
77
|
-
e === "primary" ?
|
|
81
|
+
e === "primary" ? c() : n();
|
|
78
82
|
},
|
|
79
83
|
primaryButton: t.empty_state_primary_button,
|
|
80
|
-
secondaryButton:
|
|
84
|
+
secondaryButton: r ? void 0 : t.empty_state_secondary_button,
|
|
81
85
|
subText: t.empty_state_subheader,
|
|
82
86
|
sx: {
|
|
83
|
-
width:
|
|
84
|
-
height:
|
|
85
|
-
mt:
|
|
87
|
+
width: r ? "100%" : { sm: 432 },
|
|
88
|
+
height: r ? "100%" : { sm: 468 },
|
|
89
|
+
mt: o ? 0 : 50,
|
|
86
90
|
".buttons-footer": {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
minWidth: 208,
|
|
92
|
+
maxWidth: "100%",
|
|
93
|
+
minHeight: 100,
|
|
94
|
+
button: {
|
|
95
|
+
textWrap: "wrap",
|
|
96
|
+
height: "max-content"
|
|
97
|
+
},
|
|
98
|
+
...o && { mt: 24 }
|
|
93
99
|
},
|
|
94
|
-
padding:
|
|
95
|
-
...
|
|
100
|
+
padding: r ? 4 : 0,
|
|
101
|
+
...o && {
|
|
96
102
|
justifyContent: "center",
|
|
97
103
|
svg: {
|
|
98
104
|
height: 32,
|
|
@@ -103,7 +109,7 @@ var P = ({ isMiniWidget: o = !1, onConnectAccountsClick: _, createBudgetOnClick:
|
|
|
103
109
|
}) });
|
|
104
110
|
};
|
|
105
111
|
export {
|
|
106
|
-
|
|
112
|
+
R as BudgetsEmptyState
|
|
107
113
|
};
|
|
108
114
|
|
|
109
115
|
//# sourceMappingURL=BudgetsEmptyState.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BudgetsEmptyState.es.js","names":[],"sources":["../../../src/budgets/components/BudgetsEmptyState.tsx"],"sourcesContent":["import React from 'react'\n\nimport {\n useAppConfig,\n EmptyState,\n Loader,\n useBudgetsStore,\n useCategoryStore,\n useGlobalCopyStore,\n useScreenSize,\n useWidgetContainerProvider,\n} from '../../common'\n\ninterface BudgetsEmptyStateProps {\n isMiniWidget?: boolean\n onConnectAccountsClick: () => void\n createBudgetOnClick: () => void\n}\nexport const BudgetsEmptyState: React.FC<BudgetsEmptyStateProps> = ({\n isMiniWidget = false,\n onConnectAccountsClick,\n createBudgetOnClick,\n}) => {\n const { config } = useAppConfig()\n const { recalculateBudgets } = useBudgetsStore()\n const { spendCategories } = useCategoryStore()\n const { budgets: copy } = useGlobalCopyStore()\n const { availableWidth } = useWidgetContainerProvider()\n const { isMobile } = useScreenSize(availableWidth)\n\n const isCompact = isMiniWidget && isMobile\n\n const [isError, setError] = React.useState(false)\n const [shouldShowEmptyGeneratedBudgets, setShouldShowEmptyGeneratedBudgets] =\n React.useState(false)\n const [recalculateBudgetsLoading, setRecalculateBudgetsLoading] = React.useState(false)\n\n const newBudgetCategories = React.useMemo(() => {\n return
|
|
1
|
+
{"version":3,"file":"BudgetsEmptyState.es.js","names":[],"sources":["../../../src/budgets/components/BudgetsEmptyState.tsx"],"sourcesContent":["import React from 'react'\n\nimport {\n useAppConfig,\n EmptyState,\n Loader,\n useBudgetsStore,\n useCategoryStore,\n useGlobalCopyStore,\n useScreenSize,\n useWidgetContainerProvider,\n} from '../../common'\n\ninterface BudgetsEmptyStateProps {\n isMiniWidget?: boolean\n onConnectAccountsClick: () => void\n createBudgetOnClick: () => void\n}\nexport const BudgetsEmptyState: React.FC<BudgetsEmptyStateProps> = ({\n isMiniWidget = false,\n onConnectAccountsClick,\n createBudgetOnClick,\n}) => {\n const { config } = useAppConfig()\n const { recalculateBudgets } = useBudgetsStore()\n const { spendCategories } = useCategoryStore()\n const { budgets: copy } = useGlobalCopyStore()\n const { availableWidth } = useWidgetContainerProvider()\n const { isMobile } = useScreenSize(availableWidth)\n\n const isCompact = isMiniWidget && isMobile\n\n const [isError, setError] = React.useState(false)\n const [shouldShowEmptyGeneratedBudgets, setShouldShowEmptyGeneratedBudgets] =\n React.useState(false)\n const [recalculateBudgetsLoading, setRecalculateBudgetsLoading] = React.useState(false)\n\n const newBudgetCategories = React.useMemo(() => {\n return spendCategories.filter((category) => category.totalAverageAmount > 0)\n }, [spendCategories])\n\n const autoGenerateBudgets = async () => {\n setRecalculateBudgetsLoading(true)\n const { data, isSuccess } = await recalculateBudgets(newBudgetCategories)\n setRecalculateBudgetsLoading(false)\n if (isSuccess) {\n if (data.length === 0) {\n setShouldShowEmptyGeneratedBudgets(true)\n }\n setError(false)\n } else {\n setError(true)\n }\n }\n\n if (recalculateBudgetsLoading) {\n return <Loader />\n }\n if (isError) {\n return (\n <EmptyState\n header={copy.autogenerate_budgets_error_header}\n icon={'error'}\n iconColor=\"#4D4D4D\"\n onClick={(buttonType) => {\n if (buttonType === 'primary') {\n autoGenerateBudgets()\n } else {\n createBudgetOnClick()\n }\n }}\n primaryButton={copy.autogenerate_budgets_error_primary_button}\n secondaryButton={copy.zero_state_generate_budgets_secondary_button}\n subText={copy.autogenerate_budgets_error_subheader}\n sx={{\n width: { sm: 468 },\n '.buttons-footer': {\n minWidth: 208,\n maxWidth: '100%',\n button: { textWrap: 'wrap', height: 'max-content' },\n ...(isCompact && { mt: 16 }),\n },\n ...(isCompact && { justifyContent: 'center', mt: 0, svg: { height: 32, width: 32 } }),\n }}\n />\n )\n }\n\n return (\n <>\n {shouldShowEmptyGeneratedBudgets ? (\n <EmptyState\n header={copy.zero_state_generate_budgets_header}\n icon=\"error\"\n iconColor=\"#4D4D4D\"\n onClick={(buttonType: string) => {\n if (buttonType === 'primary') {\n onConnectAccountsClick()\n } else {\n createBudgetOnClick()\n }\n }}\n primaryButton={\n config.show_connections_widget_in_master\n ? copy.zero_state_generate_budgets_primary_button\n : undefined\n }\n secondaryButton={copy.zero_state_generate_budgets_secondary_button}\n subText={copy.zero_state_generate_budgets_subheader}\n sx={{\n width: isMiniWidget ? '100%' : { sm: 500 },\n height: isMiniWidget ? '100%' : { sm: 468 },\n mt: isCompact ? 0 : 50,\n '.buttons-footer': {\n minWidth: 208,\n maxWidth: '100%',\n minHeight: 100,\n button: { textWrap: 'wrap', height: 'max-content' },\n ...(isCompact && { mt: 16 }),\n },\n padding: isMiniWidget ? 5 : 0,\n ...(isCompact && { justifyContent: 'center', svg: { height: 32, width: 32 } }),\n }}\n />\n ) : (\n <EmptyState\n header={copy.create_budgets_title}\n icon=\"bubble_chart\"\n iconColor=\"#1A1A1A\"\n onClick={(buttonType: string) => {\n if (buttonType === 'primary') {\n autoGenerateBudgets()\n } else {\n createBudgetOnClick()\n }\n }}\n primaryButton={copy.empty_state_primary_button}\n secondaryButton={!isMiniWidget ? copy.empty_state_secondary_button : undefined}\n subText={copy.empty_state_subheader}\n sx={{\n width: isMiniWidget ? '100%' : { sm: 432 },\n height: isMiniWidget ? '100%' : { sm: 468 },\n mt: isCompact ? 0 : 50,\n '.buttons-footer': {\n minWidth: 208,\n maxWidth: '100%',\n minHeight: 100,\n button: { textWrap: 'wrap', height: 'max-content' },\n ...(isCompact && { mt: 24 }),\n },\n padding: isMiniWidget ? 4 : 0,\n ...(isCompact && { justifyContent: 'center', svg: { height: 32, width: 32 } }),\n }}\n />\n )}\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,38 +1,45 @@
|
|
|
1
|
-
import { buildDynamicCopy as
|
|
2
|
-
import { useCategoryStore as
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { buildDynamicCopy as c } from "../../core/utils/Localization.es.js";
|
|
2
|
+
import { useCategoryStore as g, useGlobalCopyStore as u } from "../../common/context/hooks.es.js";
|
|
3
|
+
import { getLocalizedCategoryName as f } from "../../core/utils/CategoryUtil.es.js";
|
|
4
|
+
import { useCategoryUiStore as C } from "../context/hooks.es.js";
|
|
5
|
+
import y from "./CategoryRow.es.js";
|
|
5
6
|
import "react";
|
|
6
|
-
import { observer as
|
|
7
|
-
import
|
|
8
|
-
import { jsx as
|
|
9
|
-
import
|
|
10
|
-
var
|
|
11
|
-
const { categories:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
import { observer as L } from "mobx-react-lite";
|
|
8
|
+
import b from "@mui/material/Paper";
|
|
9
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
10
|
+
import h from "@mui/material/List";
|
|
11
|
+
var _ = () => {
|
|
12
|
+
const { categories: l } = g(), { searchValue: d } = C(), { categories: a } = u(), p = ((o, i = "") => {
|
|
13
|
+
const s = o.map((t) => ({
|
|
14
|
+
...t,
|
|
15
|
+
name: f(t, a)
|
|
16
|
+
}));
|
|
17
|
+
return s.reduce((t, e) => {
|
|
18
|
+
if (e.parent_guid === null) {
|
|
19
|
+
const m = [{
|
|
20
|
+
...e,
|
|
21
|
+
name: c(a.all_parent_category, e.name),
|
|
22
|
+
parent_guid: e.guid
|
|
23
|
+
}, ...s].filter((n) => n.parent_guid === e.guid && n.name.toLowerCase().includes(i.toLowerCase()));
|
|
24
|
+
if (e.name.toLowerCase().includes(i.toLowerCase()) || m.length > 0) return [...t, {
|
|
25
|
+
category: { ...e },
|
|
26
|
+
children: m
|
|
27
|
+
}];
|
|
28
|
+
}
|
|
29
|
+
return t;
|
|
30
|
+
}, []);
|
|
31
|
+
})(l, d);
|
|
32
|
+
return /* @__PURE__ */ r(b, {
|
|
26
33
|
className: "mx-cat-category-list",
|
|
27
34
|
sx: { boxShadow: "none" },
|
|
28
|
-
children: /* @__PURE__ */
|
|
35
|
+
children: /* @__PURE__ */ r(h, { children: p.map((o) => /* @__PURE__ */ r(y, {
|
|
29
36
|
category: o.category,
|
|
30
37
|
subCategories: o.children
|
|
31
38
|
}, o.category.guid)) })
|
|
32
39
|
});
|
|
33
|
-
},
|
|
40
|
+
}, V = L(_);
|
|
34
41
|
export {
|
|
35
|
-
|
|
42
|
+
V as default
|
|
36
43
|
};
|
|
37
44
|
|
|
38
45
|
//# sourceMappingURL=CategoryList.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoryList.es.js","names":[],"sources":["../../../src/categories/components/CategoryList.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\nimport List from '@mui/material/List'\nimport Paper from '@mui/material/Paper'\n\nimport { useCategoryStore, useGlobalCopyStore } from '../../common'\nimport type { Category } from '../../core'\n\nimport { useCategoryUiStore } from '../context/hooks'\nimport CategoryRow from './CategoryRow'\nimport { buildDynamicCopy } from '../../core/utils/Localization'\n\ninterface NestedCategory {\n category: Category\n children: Category[]\n}\n\nconst CategoryList: React.FC = () => {\n const { categories } = useCategoryStore()\n const { searchValue } = useCategoryUiStore()\n const { categories: copy } = useGlobalCopyStore()\n\n const buildNestedCategories = (categories: Category[], filter = ''): NestedCategory[] => {\n
|
|
1
|
+
{"version":3,"file":"CategoryList.es.js","names":[],"sources":["../../../src/categories/components/CategoryList.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\nimport List from '@mui/material/List'\nimport Paper from '@mui/material/Paper'\n\nimport { useCategoryStore, useGlobalCopyStore } from '../../common'\nimport type { Category } from '../../core'\n\nimport { useCategoryUiStore } from '../context/hooks'\nimport CategoryRow from './CategoryRow'\nimport { buildDynamicCopy } from '../../core/utils/Localization'\nimport { getLocalizedCategoryName } from '../../core/utils/CategoryUtil'\n\ninterface NestedCategory {\n category: Category\n children: Category[]\n}\n\nconst CategoryList: React.FC = () => {\n const { categories } = useCategoryStore()\n const { searchValue } = useCategoryUiStore()\n const { categories: copy } = useGlobalCopyStore()\n\n const buildNestedCategories = (categories: Category[], filter = ''): NestedCategory[] => {\n const localizedCategories = categories.map((category) => ({\n ...category,\n name: getLocalizedCategoryName(category, copy),\n }))\n\n return localizedCategories.reduce((acc, currCategory) => {\n if (currCategory.parent_guid === null) {\n const categoriesWithParent = [\n {\n ...currCategory,\n name: buildDynamicCopy(copy.all_parent_category, currCategory.name) as string,\n parent_guid: currCategory.guid,\n },\n ...localizedCategories,\n ]\n const children = categoriesWithParent.filter(\n (category) =>\n category.parent_guid === currCategory.guid &&\n category.name.toLowerCase().includes(filter.toLowerCase()),\n )\n\n if (currCategory.name.toLowerCase().includes(filter.toLowerCase()) || children.length > 0) {\n return [...acc, { category: { ...currCategory }, children }]\n }\n }\n return acc\n }, [] as NestedCategory[])\n }\n\n const nestedCategories = buildNestedCategories(categories, searchValue)\n\n return (\n <Paper className=\"mx-cat-category-list\" sx={{ boxShadow: 'none' }}>\n <List>\n {nestedCategories.map((nested: NestedCategory) => (\n <CategoryRow\n category={nested.category}\n key={nested.category.guid}\n subCategories={nested.children}\n />\n ))}\n </List>\n </Paper>\n )\n}\n\nexport default observer(CategoryList)\n"],"mappings":";;;;;;;;;;AAkBA,IAAM,IAAA,MAA+B;AACnC,QAAM,EAAE,YAAA,EAAA,IAAe,EAAiB,GAClC,EAAE,aAAA,EAAA,IAAgB,EAAmB,GACrC,EAAE,YAAY,EAAA,IAAS,EAAmB,GAgC1C,KA9BA,CAAyB,GAAwB,IAAS,OAAyB;AACvF,UAAM,IAAsB,EAAW,IAAA,CAAK,OAAc;AAAA,MACxD,GAAG;AAAA,MACH,MAAM,EAAyB,GAAU,CAAI;AAAA,IAC/C,EAAE;AAEF,WAAO,EAAoB,OAAA,CAAQ,GAAK,MAAiB;AACvD,UAAI,EAAa,gBAAgB,MAAM;AASrC,cAAM,IAAW,CAPf;AAAA,UACE,GAAG;AAAA,UACH,MAAM,EAAiB,EAAK,qBAAqB,EAAa,IAAI;AAAA,UAClE,aAAa,EAAa;AAAA,QAC5B,GACA,GAAG,CAEY,EAAqB,OAAA,CACnC,MACC,EAAS,gBAAgB,EAAa,QACtC,EAAS,KAAK,YAAY,EAAE,SAAS,EAAO,YAAY,CAAC,CAC7D;AAEA,YAAI,EAAa,KAAK,YAAY,EAAE,SAAS,EAAO,YAAY,CAAC,KAAK,EAAS,SAAS,EACtF,QAAO,CAAC,GAAG,GAAK;AAAA,UAAE,UAAU,EAAE,GAAG,EAAa;AAAA,UAAG,UAAA;AAAA,QAAS,CAAC;AAAA,MAE/D;AACA,aAAO;AAAA,IACT,GAAG,CAAC,CAAqB;AAAA,EAC3B,GAE+C,GAAY,CAAW;AAEtE,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,WAAU;AAAA,IAAuB,IAAI,EAAE,WAAW,OAAO;AAAA,IAC9D,UAAA,gBAAA,EAAC,GAAD,EAAA,UACG,EAAiB,IAAA,CAAK,MACrB,gBAAA,EAAC,GAAD;AAAA,MACE,UAAU,EAAO;AAAA,MAEjB,eAAe,EAAO;AAAA,IACvB,GAFM,EAAO,SAAS,IAEtB,CACF,EACG,CAAA;AAAA,EACD,CAAA;AAEX,GAEA,IAAe,EAAS,CAAY"}
|
|
@@ -1,42 +1,43 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import I from "@mui/material/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { useGlobalCopyStore as s } from "../../context/hooks.es.js";
|
|
2
|
+
import n from "react";
|
|
3
|
+
import { observer as a } from "mobx-react-lite";
|
|
4
|
+
import p from "@mui/material/Stack";
|
|
5
|
+
import { Text as l } from "@mxenabled/mxui";
|
|
6
|
+
import { ExpandLess as c, ExpandMore as f } from "@mxenabled/mx-icons";
|
|
7
|
+
import { jsx as r, jsxs as x } from "react/jsx-runtime";
|
|
8
|
+
import { useTheme as d } from "@mui/material/styles";
|
|
9
|
+
import h from "@mui/material/ListItem";
|
|
10
|
+
import u from "@mui/material/ListItemButton";
|
|
11
|
+
import I from "@mui/material/ListItemIcon";
|
|
12
|
+
import w from "@mui/material/ListItemText";
|
|
13
|
+
var k = a(n.forwardRef(({ isExpanded: o, onClick: m }, i) => {
|
|
14
|
+
const t = d(), { common: e } = s();
|
|
15
|
+
return /* @__PURE__ */ r(h, { children: /* @__PURE__ */ r(u, {
|
|
16
|
+
ref: i,
|
|
17
|
+
onClick: m,
|
|
17
18
|
sx: { justifyContent: "center" },
|
|
18
|
-
children: /* @__PURE__ */
|
|
19
|
+
children: /* @__PURE__ */ x(p, {
|
|
19
20
|
sx: {
|
|
20
|
-
color:
|
|
21
|
+
color: t.palette.primary.main,
|
|
21
22
|
flexDirection: "row",
|
|
22
23
|
alignItems: "center"
|
|
23
24
|
},
|
|
24
|
-
children: [/* @__PURE__ */ r(
|
|
25
|
+
children: [/* @__PURE__ */ r(w, { children: /* @__PURE__ */ r(l, {
|
|
25
26
|
bold: !0,
|
|
26
27
|
variant: "body2",
|
|
27
|
-
children:
|
|
28
|
-
}) }), /* @__PURE__ */ r(
|
|
29
|
-
sx: { color:
|
|
30
|
-
children:
|
|
28
|
+
children: o ? e.view_less ?? "View less" : e.view_more ?? "View more"
|
|
29
|
+
}) }), /* @__PURE__ */ r(I, {
|
|
30
|
+
sx: { color: t.palette.primary.main },
|
|
31
|
+
children: o ? /* @__PURE__ */ r(c, {}) : /* @__PURE__ */ r(f, { sx: {
|
|
31
32
|
transition: "transform 0.3s ease-in-out",
|
|
32
|
-
transform:
|
|
33
|
+
transform: o ? "rotate(180deg)" : "rotate(0deg)"
|
|
33
34
|
} })
|
|
34
35
|
})]
|
|
35
36
|
})
|
|
36
37
|
}) });
|
|
37
38
|
}));
|
|
38
39
|
export {
|
|
39
|
-
|
|
40
|
+
k as CollapseExpandListItem
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
//# sourceMappingURL=CollapseExpandListItem.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollapseExpandListItem.es.js","names":[],"sources":["../../../../src/common/components/listitems/CollapseExpandListItem.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport 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'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ExpandLess, ExpandMore } from '@mxenabled/mx-icons'\nimport { Text } from '@mxenabled/mxui'\n\ninterface CollapseExpandListItemProps {\n isExpanded: boolean\n onClick: () => void\n}\n\nexport const CollapseExpandListItem = observer(\n React.forwardRef<HTMLDivElement, CollapseExpandListItemProps>(({ isExpanded, onClick }, ref) => {\n const theme = useTheme()\n return (\n <ListItem>\n <ListItemButton ref={ref} onClick={onClick} sx={{ justifyContent: 'center' }}>\n <Stack\n sx={{ color: theme.palette.primary.main, flexDirection: 'row', alignItems: 'center' }}\n >\n <ListItemText>\n <Text bold={true} variant=\"body2\">\n {isExpanded ?
|
|
1
|
+
{"version":3,"file":"CollapseExpandListItem.es.js","names":[],"sources":["../../../../src/common/components/listitems/CollapseExpandListItem.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\nimport 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'\nimport { useTheme } from '@mui/material/styles'\n\nimport { ExpandLess, ExpandMore } from '@mxenabled/mx-icons'\nimport { Text } from '@mxenabled/mxui'\n\nimport { useGlobalCopyStore } from '../../context'\n\ninterface CollapseExpandListItemProps {\n isExpanded: boolean\n onClick: () => void\n}\n\nexport const CollapseExpandListItem = observer(\n React.forwardRef<HTMLDivElement, CollapseExpandListItemProps>(({ isExpanded, onClick }, ref) => {\n const theme = useTheme()\n const { common: copy } = useGlobalCopyStore()\n return (\n <ListItem>\n <ListItemButton ref={ref} onClick={onClick} sx={{ justifyContent: 'center' }}>\n <Stack\n sx={{ color: theme.palette.primary.main, flexDirection: 'row', alignItems: 'center' }}\n >\n <ListItemText>\n <Text bold={true} variant=\"body2\">\n {isExpanded ? (copy.view_less ?? 'View less') : (copy.view_more ?? 'View more')}\n </Text>\n </ListItemText>\n <ListItemIcon sx={{ color: theme.palette.primary.main }}>\n {isExpanded ? (\n <ExpandLess />\n ) : (\n <ExpandMore\n sx={{\n transition: 'transform 0.3s ease-in-out',\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n />\n )}\n </ListItemIcon>\n </Stack>\n </ListItemButton>\n </ListItem>\n )\n }),\n)\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAa,IAAyB,EACpC,EAAM,WAAA,CAAyD,EAAE,YAAA,GAAY,SAAA,EAAA,GAAW,MAAQ;AAC9F,QAAM,IAAQ,EAAS,GACjB,EAAE,QAAQ,EAAA,IAAS,EAAmB;AAC5C,SACE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,IAAqB,KAAA;AAAA,IAAc,SAAA;AAAA,IAAS,IAAI,EAAE,gBAAgB,SAAS;AAAA,IACzE,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,IAAI;AAAA,QAAE,OAAO,EAAM,QAAQ,QAAQ;AAAA,QAAM,eAAe;AAAA,QAAO,YAAY;AAAA,MAAS;AAAA,MADtF,UAAA,CAGE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAM,SAAQ;AAAA,QACvB,UAAA,IAAc,EAAK,aAAa,cAAgB,EAAK,aAAa;AAAA,MAC/D,CAAA,EACM,CAAA,GACd,gBAAA,EAAC,GAAD;AAAA,QAAc,IAAI,EAAE,OAAO,EAAM,QAAQ,QAAQ,KAAK;AAAA,QACnD,UAAA,IACC,gBAAA,EAAC,GAAD,CAAa,CAAA,IAEb,gBAAA,EAAC,GAAD,EACE,IAAI;AAAA,UACF,YAAY;AAAA,UACZ,WAAW,IAAa,mBAAmB;AAAA,QAC7C,EACD,CAAA;AAAA,MAES,CAAA,CACT;AAAA;EACO,CAAA,EACR,CAAA;AAEd,CAAC,CACH"}
|
|
@@ -57,7 +57,7 @@ var j = class {
|
|
|
57
57
|
return this.associatedBeatsLoaded && this.tagsLoaded && this.taggingsLoaded && this.transactionRulesLoaded && this.transactionsLoaded;
|
|
58
58
|
}
|
|
59
59
|
get detailedTransactions() {
|
|
60
|
-
return this.isTransactionDataLoaded ? m(this.transactions, this.globalStore.accountStore.visibleAccounts, this.globalStore.categoryStore.categories, this.taggings) : [];
|
|
60
|
+
return this.isTransactionDataLoaded ? m(this.transactions, this.globalStore.accountStore.visibleAccounts, this.globalStore.categoryStore.categories, this.taggings, this.globalStore.copyStore.copy.categories) : [];
|
|
61
61
|
}
|
|
62
62
|
get sortedTransactions() {
|
|
63
63
|
return L(this.filter, this.uiStore.expandedSplits, this.sortColumn, this.sortDirection, this.tags, this.detailedTransactions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionStore.es.js","names":[],"sources":["../../../src/core/stores/TransactionStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { endOfToday } from 'date-fns/endOfToday'\nimport { formatISO } from 'date-fns/formatISO'\nimport { getUnixTime } from 'date-fns/getUnixTime'\nimport { isBefore } from 'date-fns/isBefore'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\nimport { subDays } from 'date-fns/subDays'\n\nimport { BeatApi, TransactionApi } from '../api'\nimport { TABLE_CONST } from '../constants/Table'\nimport { COLUMN_NAMES, DEFAULT_TRANSACTION } from '../constants/Transaction'\nimport { TransactionType } from '../types'\nimport type { Beat, Tag, Tagging, Transaction, TransactionRule } from '../types'\nimport {\n buildDetailedTransactions,\n flattenTransactionsWithSplits,\n sortAndFilterTransactions,\n} from '../utils/TransactionUtils'\n\nimport { GlobalStore } from './GlobalStore'\nimport { upsertByGuid } from '../utils/upsertByGuid'\n\nexport type TransactionFilter = {\n accounts?: string[]\n dateRange?: { start: Date; end: Date }\n custom?: (value: Transaction) => boolean\n searchTerm?: string\n showSplits?: boolean\n}\n\nexport class TransactionStore {\n globalStore: GlobalStore\n uiStore: UiStore\n api = new TransactionApi('/', '')\n beatApi = new BeatApi('/', '')\n\n associatedBeats: Beat[] = []\n associatedBeatsLoaded: boolean = false\n associatedBeatsLoading: boolean = false\n transactions: Transaction[] = []\n transactionsLoaded: boolean = false\n transactionsLoading: boolean = false\n taggings: Tagging[] = []\n taggingsLoaded: boolean = false\n taggingsLoading: boolean = false\n tags: Tag[] = []\n tagsLoaded: boolean = false\n tagsLoading: boolean = false\n transactionRules: TransactionRule[] = []\n transactionRulesLoaded: boolean = false\n transactionRulesLoading: boolean = false\n transactionSplitting: boolean = false\n\n cachedStartDate: Date = subDays(startOfToday(), 90)\n filter: TransactionFilter = {}\n isLoading = true\n\n alert = ''\n\n sortColumn = COLUMN_NAMES.DATE\n sortDirection = TABLE_CONST.DESC\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new TransactionApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n this.beatApi = new BeatApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadTransactionData = async () => {\n if (!this.globalStore.accountStore.isAccountDataLoaded) {\n await this.globalStore.accountStore.loadAccountData()\n }\n if (!this.globalStore.categoryStore.categoriesLoaded) {\n await this.globalStore.categoryStore.loadCategories()\n }\n await Promise.all([\n this.loadAssociatedBeats(startOfMonth(new Date())),\n this.loadTags(),\n this.loadTaggings(),\n this.loadTransactionRules(),\n // By default loads 90 days of transactions\n this.loadTransactions(this.cachedStartDate),\n ])\n }\n\n get isTransactionDataLoaded(): boolean {\n return (\n this.associatedBeatsLoaded &&\n this.tagsLoaded &&\n this.taggingsLoaded &&\n this.transactionRulesLoaded &&\n this.transactionsLoaded\n )\n }\n\n get detailedTransactions(): Transaction[] {\n return this.isTransactionDataLoaded\n ? buildDetailedTransactions(\n this.transactions,\n this.globalStore.accountStore.visibleAccounts,\n this.globalStore.categoryStore.categories,\n this.taggings,\n )\n : []\n }\n\n get sortedTransactions(): Transaction[] {\n return sortAndFilterTransactions(\n this.filter,\n this.uiStore.expandedSplits,\n this.sortColumn,\n this.sortDirection,\n this.tags,\n this.detailedTransactions,\n )\n }\n\n get sortedTransactionsWithSplits(): Transaction[] {\n return flattenTransactionsWithSplits(this.sortedTransactions, this.detailedTransactions)\n }\n\n setAssociatedBeats = (beats: Beat[]) => {\n this.associatedBeats = beats\n this.associatedBeatsLoading = false\n this.associatedBeatsLoaded = true\n }\n\n setTaggings = (taggings: Tagging[]) => {\n this.taggings = taggings\n this.taggingsLoading = false\n this.taggingsLoaded = true\n }\n\n setTags = (tags: Tag[]) => {\n this.tags = tags\n this.tagsLoading = false\n this.tagsLoaded = true\n }\n\n setTransactionRules = (transactionRules: TransactionRule[]) => {\n this.transactionRules = transactionRules\n this.transactionRulesLoading = false\n this.transactionRulesLoaded = true\n }\n\n setTransactions = (transactions: Transaction[]) => {\n this.transactions = transactions\n this.transactionsLoading = false\n this.transactionsLoaded = true\n }\n\n setAlert = (alert: string) => {\n this.alert = alert\n }\n\n addTag = async (name: string) => {\n try {\n await this.api.addTag({ name } as Tag)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while adding tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addTagging = async (tagGuid: string, transactionGuid: string) => {\n try {\n await this.api.addTagging({\n tag_guid: tagGuid,\n transaction_guid: transactionGuid,\n } as Tagging)\n } catch (error) {\n console.error('Error occurred while adding tagging:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addOrUpdateTransactionRule = async (categoryGuid: string, transaction: Transaction) => {\n try {\n const existingRule = this.transactionRules.find(\n (rule: TransactionRule) => rule.guid === transaction.user_transaction_rule_guid,\n ) as TransactionRule | undefined\n\n if (existingRule) {\n await this.api.updateTransactionRule({\n ...existingRule,\n category_guid: categoryGuid,\n description: transaction.description,\n } as TransactionRule)\n } else {\n await this.api.addTransactionRule({\n category_guid: categoryGuid,\n description: transaction.description,\n match_description: transaction.description,\n } as TransactionRule)\n }\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error occurred while adding/updating transaction rule:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addTransaction = async (transaction: Transaction) => {\n try {\n const newTransaction = await this.api.addTransaction(transaction)\n\n if (newTransaction) {\n runInAction(() => {\n this.setTransactions(upsertByGuid(this.transactions, newTransaction, true))\n\n // Brokaw may insert the transaction via WebSocket, but it never\n // updates the account balance — that only happens here.\n // See: money-dashboard/src/util/BrokawClient.ts::handleTransactionEvents (search \"setTransactions\")\n // If that handler ever calls updateAccountBalance, remove this call or guard on !existing.\n const balanceChange =\n newTransaction.transaction_type === TransactionType.CREDIT\n ? newTransaction.amount\n : -newTransaction.amount\n\n this.globalStore.accountStore.updateAccountBalance(\n newTransaction.account_guid,\n balanceChange,\n )\n })\n }\n } catch (error) {\n console.error('Error occurred while adding transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n loadAssociatedBeats = async (fromDate?: Date) => {\n if (this.associatedBeatsLoading) return\n\n this.associatedBeatsLoading = true\n const fromDateISO = fromDate ? formatISO(fromDate, { representation: 'date' }) : undefined\n try {\n const beats = await this.beatApi.getBeatsWithAssociatedTransaction(fromDateISO)\n this.setAssociatedBeats(beats)\n } catch (error) {\n console.error('Error occurred while loading associated beats:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setAssociatedBeats([])\n } finally {\n // Clear the in-flight flag even on failure so a later load (e.g. a widget\n // remount) can retry instead of being no-oped by the guard above, which would\n // leave isTransactionDataLoaded false and the list empty until a hard refresh.\n runInAction(() => {\n this.associatedBeatsLoading = false\n })\n }\n }\n\n loadTags = async () => {\n if (this.tagsLoading) return\n\n this.tagsLoading = true\n try {\n const tags = await this.api.getTags()\n this.setTags(tags)\n } catch (error) {\n console.error('Error occurred while loading tags:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n } finally {\n runInAction(() => {\n this.tagsLoading = false\n })\n }\n }\n\n loadTaggings = async () => {\n if (this.taggingsLoading) return\n\n this.taggingsLoading = true\n try {\n const taggings = await this.api.getTaggings()\n this.setTaggings(taggings)\n } catch (error) {\n console.error('Error occurred while loading taggings:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setTaggings([])\n } finally {\n runInAction(() => {\n this.taggingsLoading = false\n })\n }\n }\n\n loadTransactionRules = async () => {\n if (this.transactionRulesLoading) return\n\n this.transactionRulesLoading = true\n try {\n const transactionRules = await this.api.getTransactionRules()\n this.setTransactionRules(transactionRules)\n } catch (error) {\n // Catch so a rejection can't abort the Promise.all in loadTransactionData.\n console.error('Error occurred while loading transaction rules:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setTransactionRules([])\n } finally {\n runInAction(() => {\n this.transactionRulesLoading = false\n })\n }\n }\n\n loadTransactions = async (startDate: Date = this.cachedStartDate) => {\n if (this.transactionsLoading) return\n\n this.setIsLoading(true)\n this.transactionsLoading = true\n\n try {\n const transactions = await this.api.getTransactionsByDateRange(\n getUnixTime(startDate),\n getUnixTime(endOfToday()),\n )\n this.setTransactions(transactions)\n // Advance the cache only after the range is actually loaded, so the invariant\n // \"we hold transactions back to cachedStartDate\" always holds.\n runInAction(() => {\n this.cachedStartDate = startDate\n })\n } catch (error) {\n console.error('Error occurred while loading transactions:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n } finally {\n // See loadAssociatedBeats: clear the flag on failure so retries aren't no-oped.\n runInAction(() => {\n this.transactionsLoading = false\n })\n this.setIsLoading(false)\n }\n }\n\n modifyTransactionByAccountGuid = (guid: string, updates: Partial<Transaction>) => {\n this.transactions = this.transactions.map((txn) =>\n txn.account_guid === guid ? { ...txn, ...updates } : txn,\n )\n }\n\n removeTag = async (tagGuid: string) => {\n try {\n await this.api.removeTag(tagGuid)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while removing tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n removeTagging = async (taggingGuid: string) => {\n try {\n await this.api.removeTagging(taggingGuid)\n } catch (error) {\n console.error('Error occurred while removing tagging:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n removeTransaction = async (transactionGuid: string) => {\n try {\n await this.api.removeTransaction(transactionGuid)\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transactionGuid)\n\n if (index >= 0) {\n const updatedTransactions = [...this.transactions]\n updatedTransactions.splice(index, 1)\n this.setTransactions(updatedTransactions)\n }\n } catch (error) {\n console.error('Error occurred while removing transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n setFilter = (filter: TransactionFilter) => {\n this.filter = filter\n\n // Only reload if the new start date is prior to the cached start date; end date\n // is always today. loadTransactions advances cachedStartDate on success, so we\n // must not advance it here (a skipped/failed load would leave the list empty).\n if (filter.dateRange && isBefore(filter.dateRange.start, this.cachedStartDate)) {\n this.loadTransactions(filter.dateRange.start)\n }\n }\n\n setIsLoading = (isLoading: boolean) => (this.isLoading = isLoading)\n\n splitTransaction = async (transaction: Transaction, splits: Transaction[]) => {\n if (this.transactionSplitting) return\n this.transactionSplitting = true\n\n try {\n const updatedTransaction = await this.api.updateTransaction(transaction)\n const children = [] as Transaction[]\n\n for (let i = 0; i < splits.length; i++) {\n const child = await this.api.addTransaction(splits[i])\n children.push(child)\n }\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transaction.guid)\n\n if (index >= 0) {\n // Remove old parent and any existing children\n const filtered = this.transactions.filter(\n (t) => t.guid !== transaction.guid && t.parent_guid !== transaction.guid,\n )\n\n // Insert updated parent + new children at original position\n this.setTransactions([\n ...filtered.slice(0, index),\n updatedTransaction,\n ...children,\n ...filtered.slice(index),\n ])\n }\n } catch (error) {\n console.error('Error occurred while splitting transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n throw error\n } finally {\n this.transactionSplitting = false\n }\n }\n\n unSplitTransaction = async (guid: string) => {\n try {\n const children = this.transactions.filter((t) => t.parent_guid === guid)\n\n await this.api.removeTransactionSplit(guid)\n\n // Remove children\n const transactions = [...this.transactions]\n children.forEach((child) => {\n const index = transactions.findIndex((t) => t.guid === child.guid)\n\n if (index >= 0) {\n transactions.splice(index, 1)\n }\n })\n\n // Update parent\n const index = transactions.findIndex((t) => t.guid === guid)\n\n runInAction(() => {\n const transaction = transactions[index]\n if (transaction) {\n transaction.has_been_split = false\n }\n\n if (index >= 0) {\n this.setTransactions([\n ...transactions.slice(0, index),\n transaction,\n ...transactions.slice(index + 1),\n ])\n }\n })\n } catch (error) {\n console.error('Error occurred while unsplitting transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTaggings = async (tagGuids: string[], transactionGuid: string) => {\n try {\n const currentTaggings = this.taggings.filter((t) => t.transaction_guid === transactionGuid)\n\n const currentTagGuids = new Set(currentTaggings.map((t) => t.tag_guid))\n const incomingTagGuids = new Set(tagGuids)\n\n // Add new taggings that don't already exist\n for (const tagGuid of tagGuids) {\n if (!currentTagGuids.has(tagGuid)) {\n await this.addTagging(tagGuid, transactionGuid)\n }\n }\n\n // Remove taggings that are no longer needed\n for (const tagging of currentTaggings) {\n if (!incomingTagGuids.has(tagging.tag_guid)) {\n await this.removeTagging(tagging.guid)\n }\n }\n\n await this.loadTaggings()\n } catch (error) {\n console.error('Error occurred while updating taggings:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTag = async (tag: Tag) => {\n try {\n await this.api.updateTag(tag)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while updating tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTransaction = async (transaction: Transaction) => {\n try {\n const updatedTransaction = await this.api.updateTransaction(transaction)\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transaction.guid)\n\n if (index >= 0) {\n this.setTransactions([\n ...this.transactions.slice(0, index),\n updatedTransaction,\n ...this.transactions.slice(index + 1),\n ])\n }\n } catch (error) {\n console.error('Error occurred while updating transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n // This is used for loading the transactions list on demand, on clicking the different transactions of the insightful beats.\n loadEmbeddedInstanceTransactions = async (fromDate: Date) => {\n try {\n const transactions = await this.api.getTransactionsByDateRange(\n getUnixTime(fromDate),\n getUnixTime(endOfToday()),\n )\n this.cachedStartDate = fromDate\n this.transactions = transactions\n } catch (error) {\n console.error('Error occurred while loading embedded instance transactions:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n}\n\nexport class UiStore {\n beginDate = startOfMonth(new Date())\n endDate = endOfMonth(new Date())\n\n expandedSplits = [] as string[]\n height = 550\n width = 1000\n shouldDisableDrawerScroll = false\n\n searchValue = ''\n selectedAccountGuids = [] as string[]\n\n manualTransaction: Transaction = DEFAULT_TRANSACTION\n isAmountValid = false\n\n showInsights = false\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setDateRange = (beginDate: Date, endDate: Date) => {\n this.beginDate = beginDate\n this.endDate = endDate\n }\n\n setIsAmountValid = (valid: boolean) => (this.isAmountValid = valid)\n\n setSearchValue = (searchValue: string) => (this.searchValue = searchValue)\n\n setSelectedAccountGuids = (accountGuids: string[]) => (this.selectedAccountGuids = accountGuids)\n\n setShouldDisableDrawerScroll = (shouldDisable: boolean) =>\n (this.shouldDisableDrawerScroll = shouldDisable)\n\n setShowInsights = (showInsights: boolean) => {\n this.showInsights = showInsights\n }\n\n setSize = (height: number, width: number) => {\n this.height = height\n this.width = width\n }\n\n toggleSplit = (guid: string) => {\n const expandedSplits = [...this.expandedSplits]\n const index = this.expandedSplits.findIndex((splitGuid) => splitGuid === guid)\n\n if (index >= 0) {\n expandedSplits.splice(index, 1)\n } else {\n expandedSplits.push(guid)\n }\n\n this.expandedSplits = expandedSplits\n }\n\n clearExpandedSplits = () => {\n if (this.expandedSplits.length === 0) return\n this.expandedSplits = []\n }\n\n updateManualTransaction = (manualTransaction: Transaction) => {\n this.manualTransaction = manualTransaction\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TransactionStore.es.js","names":[],"sources":["../../../src/core/stores/TransactionStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { endOfToday } from 'date-fns/endOfToday'\nimport { formatISO } from 'date-fns/formatISO'\nimport { getUnixTime } from 'date-fns/getUnixTime'\nimport { isBefore } from 'date-fns/isBefore'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\nimport { subDays } from 'date-fns/subDays'\n\nimport { BeatApi, TransactionApi } from '../api'\nimport { TABLE_CONST } from '../constants/Table'\nimport { COLUMN_NAMES, DEFAULT_TRANSACTION } from '../constants/Transaction'\nimport { TransactionType } from '../types'\nimport type { Beat, Tag, Tagging, Transaction, TransactionRule } from '../types'\nimport {\n buildDetailedTransactions,\n flattenTransactionsWithSplits,\n sortAndFilterTransactions,\n} from '../utils/TransactionUtils'\n\nimport { GlobalStore } from './GlobalStore'\nimport { upsertByGuid } from '../utils/upsertByGuid'\n\nexport type TransactionFilter = {\n accounts?: string[]\n dateRange?: { start: Date; end: Date }\n custom?: (value: Transaction) => boolean\n searchTerm?: string\n showSplits?: boolean\n}\n\nexport class TransactionStore {\n globalStore: GlobalStore\n uiStore: UiStore\n api = new TransactionApi('/', '')\n beatApi = new BeatApi('/', '')\n\n associatedBeats: Beat[] = []\n associatedBeatsLoaded: boolean = false\n associatedBeatsLoading: boolean = false\n transactions: Transaction[] = []\n transactionsLoaded: boolean = false\n transactionsLoading: boolean = false\n taggings: Tagging[] = []\n taggingsLoaded: boolean = false\n taggingsLoading: boolean = false\n tags: Tag[] = []\n tagsLoaded: boolean = false\n tagsLoading: boolean = false\n transactionRules: TransactionRule[] = []\n transactionRulesLoaded: boolean = false\n transactionRulesLoading: boolean = false\n transactionSplitting: boolean = false\n\n cachedStartDate: Date = subDays(startOfToday(), 90)\n filter: TransactionFilter = {}\n isLoading = true\n\n alert = ''\n\n sortColumn = COLUMN_NAMES.DATE\n sortDirection = TABLE_CONST.DESC\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new TransactionApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n this.beatApi = new BeatApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadTransactionData = async () => {\n if (!this.globalStore.accountStore.isAccountDataLoaded) {\n await this.globalStore.accountStore.loadAccountData()\n }\n if (!this.globalStore.categoryStore.categoriesLoaded) {\n await this.globalStore.categoryStore.loadCategories()\n }\n await Promise.all([\n this.loadAssociatedBeats(startOfMonth(new Date())),\n this.loadTags(),\n this.loadTaggings(),\n this.loadTransactionRules(),\n // By default loads 90 days of transactions\n this.loadTransactions(this.cachedStartDate),\n ])\n }\n\n get isTransactionDataLoaded(): boolean {\n return (\n this.associatedBeatsLoaded &&\n this.tagsLoaded &&\n this.taggingsLoaded &&\n this.transactionRulesLoaded &&\n this.transactionsLoaded\n )\n }\n\n get detailedTransactions(): Transaction[] {\n return this.isTransactionDataLoaded\n ? buildDetailedTransactions(\n this.transactions,\n this.globalStore.accountStore.visibleAccounts,\n this.globalStore.categoryStore.categories,\n this.taggings,\n this.globalStore.copyStore.copy.categories,\n )\n : []\n }\n\n get sortedTransactions(): Transaction[] {\n return sortAndFilterTransactions(\n this.filter,\n this.uiStore.expandedSplits,\n this.sortColumn,\n this.sortDirection,\n this.tags,\n this.detailedTransactions,\n )\n }\n\n get sortedTransactionsWithSplits(): Transaction[] {\n return flattenTransactionsWithSplits(this.sortedTransactions, this.detailedTransactions)\n }\n\n setAssociatedBeats = (beats: Beat[]) => {\n this.associatedBeats = beats\n this.associatedBeatsLoading = false\n this.associatedBeatsLoaded = true\n }\n\n setTaggings = (taggings: Tagging[]) => {\n this.taggings = taggings\n this.taggingsLoading = false\n this.taggingsLoaded = true\n }\n\n setTags = (tags: Tag[]) => {\n this.tags = tags\n this.tagsLoading = false\n this.tagsLoaded = true\n }\n\n setTransactionRules = (transactionRules: TransactionRule[]) => {\n this.transactionRules = transactionRules\n this.transactionRulesLoading = false\n this.transactionRulesLoaded = true\n }\n\n setTransactions = (transactions: Transaction[]) => {\n this.transactions = transactions\n this.transactionsLoading = false\n this.transactionsLoaded = true\n }\n\n setAlert = (alert: string) => {\n this.alert = alert\n }\n\n addTag = async (name: string) => {\n try {\n await this.api.addTag({ name } as Tag)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while adding tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addTagging = async (tagGuid: string, transactionGuid: string) => {\n try {\n await this.api.addTagging({\n tag_guid: tagGuid,\n transaction_guid: transactionGuid,\n } as Tagging)\n } catch (error) {\n console.error('Error occurred while adding tagging:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addOrUpdateTransactionRule = async (categoryGuid: string, transaction: Transaction) => {\n try {\n const existingRule = this.transactionRules.find(\n (rule: TransactionRule) => rule.guid === transaction.user_transaction_rule_guid,\n ) as TransactionRule | undefined\n\n if (existingRule) {\n await this.api.updateTransactionRule({\n ...existingRule,\n category_guid: categoryGuid,\n description: transaction.description,\n } as TransactionRule)\n } else {\n await this.api.addTransactionRule({\n category_guid: categoryGuid,\n description: transaction.description,\n match_description: transaction.description,\n } as TransactionRule)\n }\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error occurred while adding/updating transaction rule:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n addTransaction = async (transaction: Transaction) => {\n try {\n const newTransaction = await this.api.addTransaction(transaction)\n\n if (newTransaction) {\n runInAction(() => {\n this.setTransactions(upsertByGuid(this.transactions, newTransaction, true))\n\n // Brokaw may insert the transaction via WebSocket, but it never\n // updates the account balance — that only happens here.\n // See: money-dashboard/src/util/BrokawClient.ts::handleTransactionEvents (search \"setTransactions\")\n // If that handler ever calls updateAccountBalance, remove this call or guard on !existing.\n const balanceChange =\n newTransaction.transaction_type === TransactionType.CREDIT\n ? newTransaction.amount\n : -newTransaction.amount\n\n this.globalStore.accountStore.updateAccountBalance(\n newTransaction.account_guid,\n balanceChange,\n )\n })\n }\n } catch (error) {\n console.error('Error occurred while adding transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n loadAssociatedBeats = async (fromDate?: Date) => {\n if (this.associatedBeatsLoading) return\n\n this.associatedBeatsLoading = true\n const fromDateISO = fromDate ? formatISO(fromDate, { representation: 'date' }) : undefined\n try {\n const beats = await this.beatApi.getBeatsWithAssociatedTransaction(fromDateISO)\n this.setAssociatedBeats(beats)\n } catch (error) {\n console.error('Error occurred while loading associated beats:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setAssociatedBeats([])\n } finally {\n // Clear the in-flight flag even on failure so a later load (e.g. a widget\n // remount) can retry instead of being no-oped by the guard above, which would\n // leave isTransactionDataLoaded false and the list empty until a hard refresh.\n runInAction(() => {\n this.associatedBeatsLoading = false\n })\n }\n }\n\n loadTags = async () => {\n if (this.tagsLoading) return\n\n this.tagsLoading = true\n try {\n const tags = await this.api.getTags()\n this.setTags(tags)\n } catch (error) {\n console.error('Error occurred while loading tags:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n } finally {\n runInAction(() => {\n this.tagsLoading = false\n })\n }\n }\n\n loadTaggings = async () => {\n if (this.taggingsLoading) return\n\n this.taggingsLoading = true\n try {\n const taggings = await this.api.getTaggings()\n this.setTaggings(taggings)\n } catch (error) {\n console.error('Error occurred while loading taggings:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setTaggings([])\n } finally {\n runInAction(() => {\n this.taggingsLoading = false\n })\n }\n }\n\n loadTransactionRules = async () => {\n if (this.transactionRulesLoading) return\n\n this.transactionRulesLoading = true\n try {\n const transactionRules = await this.api.getTransactionRules()\n this.setTransactionRules(transactionRules)\n } catch (error) {\n // Catch so a rejection can't abort the Promise.all in loadTransactionData.\n console.error('Error occurred while loading transaction rules:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n this.setTransactionRules([])\n } finally {\n runInAction(() => {\n this.transactionRulesLoading = false\n })\n }\n }\n\n loadTransactions = async (startDate: Date = this.cachedStartDate) => {\n if (this.transactionsLoading) return\n\n this.setIsLoading(true)\n this.transactionsLoading = true\n\n try {\n const transactions = await this.api.getTransactionsByDateRange(\n getUnixTime(startDate),\n getUnixTime(endOfToday()),\n )\n this.setTransactions(transactions)\n // Advance the cache only after the range is actually loaded, so the invariant\n // \"we hold transactions back to cachedStartDate\" always holds.\n runInAction(() => {\n this.cachedStartDate = startDate\n })\n } catch (error) {\n console.error('Error occurred while loading transactions:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n } finally {\n // See loadAssociatedBeats: clear the flag on failure so retries aren't no-oped.\n runInAction(() => {\n this.transactionsLoading = false\n })\n this.setIsLoading(false)\n }\n }\n\n modifyTransactionByAccountGuid = (guid: string, updates: Partial<Transaction>) => {\n this.transactions = this.transactions.map((txn) =>\n txn.account_guid === guid ? { ...txn, ...updates } : txn,\n )\n }\n\n removeTag = async (tagGuid: string) => {\n try {\n await this.api.removeTag(tagGuid)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while removing tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n removeTagging = async (taggingGuid: string) => {\n try {\n await this.api.removeTagging(taggingGuid)\n } catch (error) {\n console.error('Error occurred while removing tagging:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n removeTransaction = async (transactionGuid: string) => {\n try {\n await this.api.removeTransaction(transactionGuid)\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transactionGuid)\n\n if (index >= 0) {\n const updatedTransactions = [...this.transactions]\n updatedTransactions.splice(index, 1)\n this.setTransactions(updatedTransactions)\n }\n } catch (error) {\n console.error('Error occurred while removing transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n setFilter = (filter: TransactionFilter) => {\n this.filter = filter\n\n // Only reload if the new start date is prior to the cached start date; end date\n // is always today. loadTransactions advances cachedStartDate on success, so we\n // must not advance it here (a skipped/failed load would leave the list empty).\n if (filter.dateRange && isBefore(filter.dateRange.start, this.cachedStartDate)) {\n this.loadTransactions(filter.dateRange.start)\n }\n }\n\n setIsLoading = (isLoading: boolean) => (this.isLoading = isLoading)\n\n splitTransaction = async (transaction: Transaction, splits: Transaction[]) => {\n if (this.transactionSplitting) return\n this.transactionSplitting = true\n\n try {\n const updatedTransaction = await this.api.updateTransaction(transaction)\n const children = [] as Transaction[]\n\n for (let i = 0; i < splits.length; i++) {\n const child = await this.api.addTransaction(splits[i])\n children.push(child)\n }\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transaction.guid)\n\n if (index >= 0) {\n // Remove old parent and any existing children\n const filtered = this.transactions.filter(\n (t) => t.guid !== transaction.guid && t.parent_guid !== transaction.guid,\n )\n\n // Insert updated parent + new children at original position\n this.setTransactions([\n ...filtered.slice(0, index),\n updatedTransaction,\n ...children,\n ...filtered.slice(index),\n ])\n }\n } catch (error) {\n console.error('Error occurred while splitting transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n throw error\n } finally {\n this.transactionSplitting = false\n }\n }\n\n unSplitTransaction = async (guid: string) => {\n try {\n const children = this.transactions.filter((t) => t.parent_guid === guid)\n\n await this.api.removeTransactionSplit(guid)\n\n // Remove children\n const transactions = [...this.transactions]\n children.forEach((child) => {\n const index = transactions.findIndex((t) => t.guid === child.guid)\n\n if (index >= 0) {\n transactions.splice(index, 1)\n }\n })\n\n // Update parent\n const index = transactions.findIndex((t) => t.guid === guid)\n\n runInAction(() => {\n const transaction = transactions[index]\n if (transaction) {\n transaction.has_been_split = false\n }\n\n if (index >= 0) {\n this.setTransactions([\n ...transactions.slice(0, index),\n transaction,\n ...transactions.slice(index + 1),\n ])\n }\n })\n } catch (error) {\n console.error('Error occurred while unsplitting transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTaggings = async (tagGuids: string[], transactionGuid: string) => {\n try {\n const currentTaggings = this.taggings.filter((t) => t.transaction_guid === transactionGuid)\n\n const currentTagGuids = new Set(currentTaggings.map((t) => t.tag_guid))\n const incomingTagGuids = new Set(tagGuids)\n\n // Add new taggings that don't already exist\n for (const tagGuid of tagGuids) {\n if (!currentTagGuids.has(tagGuid)) {\n await this.addTagging(tagGuid, transactionGuid)\n }\n }\n\n // Remove taggings that are no longer needed\n for (const tagging of currentTaggings) {\n if (!incomingTagGuids.has(tagging.tag_guid)) {\n await this.removeTagging(tagging.guid)\n }\n }\n\n await this.loadTaggings()\n } catch (error) {\n console.error('Error occurred while updating taggings:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTag = async (tag: Tag) => {\n try {\n await this.api.updateTag(tag)\n await this.loadTags()\n } catch (error) {\n console.error('Error occurred while updating tag:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n updateTransaction = async (transaction: Transaction) => {\n try {\n const updatedTransaction = await this.api.updateTransaction(transaction)\n\n const index = this.transactions.findIndex((t: Transaction) => t.guid === transaction.guid)\n\n if (index >= 0) {\n this.setTransactions([\n ...this.transactions.slice(0, index),\n updatedTransaction,\n ...this.transactions.slice(index + 1),\n ])\n }\n } catch (error) {\n console.error('Error occurred while updating transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n\n // This is used for loading the transactions list on demand, on clicking the different transactions of the insightful beats.\n loadEmbeddedInstanceTransactions = async (fromDate: Date) => {\n try {\n const transactions = await this.api.getTransactionsByDateRange(\n getUnixTime(fromDate),\n getUnixTime(endOfToday()),\n )\n this.cachedStartDate = fromDate\n this.transactions = transactions\n } catch (error) {\n console.error('Error occurred while loading embedded instance transactions:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n }\n }\n}\n\nexport class UiStore {\n beginDate = startOfMonth(new Date())\n endDate = endOfMonth(new Date())\n\n expandedSplits = [] as string[]\n height = 550\n width = 1000\n shouldDisableDrawerScroll = false\n\n searchValue = ''\n selectedAccountGuids = [] as string[]\n\n manualTransaction: Transaction = DEFAULT_TRANSACTION\n isAmountValid = false\n\n showInsights = false\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setDateRange = (beginDate: Date, endDate: Date) => {\n this.beginDate = beginDate\n this.endDate = endDate\n }\n\n setIsAmountValid = (valid: boolean) => (this.isAmountValid = valid)\n\n setSearchValue = (searchValue: string) => (this.searchValue = searchValue)\n\n setSelectedAccountGuids = (accountGuids: string[]) => (this.selectedAccountGuids = accountGuids)\n\n setShouldDisableDrawerScroll = (shouldDisable: boolean) =>\n (this.shouldDisableDrawerScroll = shouldDisable)\n\n setShowInsights = (showInsights: boolean) => {\n this.showInsights = showInsights\n }\n\n setSize = (height: number, width: number) => {\n this.height = height\n this.width = width\n }\n\n toggleSplit = (guid: string) => {\n const expandedSplits = [...this.expandedSplits]\n const index = this.expandedSplits.findIndex((splitGuid) => splitGuid === guid)\n\n if (index >= 0) {\n expandedSplits.splice(index, 1)\n } else {\n expandedSplits.push(guid)\n }\n\n this.expandedSplits = expandedSplits\n }\n\n clearExpandedSplits = () => {\n if (this.expandedSplits.length === 0) return\n this.expandedSplits = []\n }\n\n updateManualTransaction = (manualTransaction: Transaction) => {\n this.manualTransaction = manualTransaction\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { Theme } from '@mui/material';
|
|
2
2
|
import { Category, DateRangeCategoryTotals, DetailedCategory, DetailedCategoryWithTransactions, MonthlyCategoryTotals, Transaction, CategoryCopy, CategoryTotal } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the localized display name for a category.
|
|
5
|
+
*
|
|
6
|
+
* Default (MX-supplied) categories arrive from the API with fixed English
|
|
7
|
+
* names, but localized copy for them is delivered via CategoryCopy
|
|
8
|
+
* `default_categories` (keyed by category guid). User-created categories have no
|
|
9
|
+
* localized copy and legitimately fall back to their API name.
|
|
10
|
+
* @param category - The category to resolve a name for
|
|
11
|
+
* @param copy - Category copy containing localized default category names
|
|
12
|
+
*/
|
|
13
|
+
export declare const getLocalizedCategoryName: (category: Category, copy: CategoryCopy) => string;
|
|
3
14
|
/**
|
|
4
15
|
* Augment categories
|
|
5
16
|
* @param categories - Categories to augment
|