@mx-cartographer/experiences 9.1.0-alpha.bb1 → 9.1.0
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 +75 -0
- package/README.md +10 -10
- package/dist/Account-DR7Plrqy.mjs +119 -0
- package/dist/Account-DR7Plrqy.mjs.map +1 -0
- package/dist/AccountDetailsDrawer-CZPeLsCq.mjs +922 -0
- package/dist/AccountDetailsDrawer-CZPeLsCq.mjs.map +1 -0
- package/dist/AccountDetailsHeader-BvbCUQSS.mjs +231 -0
- package/dist/AccountDetailsHeader-BvbCUQSS.mjs.map +1 -0
- package/dist/AccountUtils-B8ZzWI-d.mjs +28 -0
- package/dist/AccountUtils-B8ZzWI-d.mjs.map +1 -0
- package/dist/Analytics-CkYXKvco.mjs +54 -0
- package/dist/Analytics-CkYXKvco.mjs.map +1 -0
- package/dist/Analytics-WeZYytR0.mjs +140 -0
- package/dist/Analytics-WeZYytR0.mjs.map +1 -0
- package/dist/ApiEndpoints-DXwIYNUV.mjs +50 -0
- package/dist/ApiEndpoints-DXwIYNUV.mjs.map +1 -0
- package/dist/BeatMaterialIcon-1KOfRZrA.mjs +27 -0
- package/dist/BeatMaterialIcon-1KOfRZrA.mjs.map +1 -0
- package/dist/BudgetUtil-Bg2AQJpQ.mjs +75 -0
- package/dist/BudgetUtil-Bg2AQJpQ.mjs.map +1 -0
- package/dist/Category-DEKZGLYe.mjs +302 -0
- package/dist/Category-DEKZGLYe.mjs.map +1 -0
- package/dist/CategorySelectorDrawer-NJsFsKP1.mjs +431 -0
- package/dist/CategorySelectorDrawer-NJsFsKP1.mjs.map +1 -0
- package/dist/Connect-BH0Pt6zc.mjs +43 -0
- package/dist/Connect-BH0Pt6zc.mjs.map +1 -0
- package/dist/ConnectCard-D7uxoH5Y.mjs +55 -0
- package/dist/ConnectCard-D7uxoH5Y.mjs.map +1 -0
- package/dist/ConnectDrawer-CW4LA3H3.mjs +58 -0
- package/dist/ConnectDrawer-CW4LA3H3.mjs.map +1 -0
- package/dist/ConnectionsDrawer-CZU9ku-k.mjs +54 -0
- package/dist/ConnectionsDrawer-CZU9ku-k.mjs.map +1 -0
- package/dist/CurrencyDialog-DumQCTPO.mjs +374 -0
- package/dist/CurrencyDialog-DumQCTPO.mjs.map +1 -0
- package/dist/CurrencyInput-DaGEQaLW.mjs +88 -0
- package/dist/CurrencyInput-DaGEQaLW.mjs.map +1 -0
- package/dist/CurrencyText-CCbE6MmF.mjs +21 -0
- package/dist/CurrencyText-CCbE6MmF.mjs.map +1 -0
- package/dist/DateFormats-HudZ3Bjs.mjs +65 -0
- package/dist/DateFormats-HudZ3Bjs.mjs.map +1 -0
- package/dist/DateUtil-CzBmbjmA.mjs +75 -0
- package/dist/DateUtil-CzBmbjmA.mjs.map +1 -0
- package/dist/DebtUtils-i4pI2Uoe.mjs +154 -0
- package/dist/DebtUtils-i4pI2Uoe.mjs.map +1 -0
- package/dist/Dialog-Bvd2n8hz.mjs +67 -0
- package/dist/Dialog-Bvd2n8hz.mjs.map +1 -0
- package/dist/Donut-SzzfZDHF.mjs +89 -0
- package/dist/Donut-SzzfZDHF.mjs.map +1 -0
- package/dist/Drawer-DsnW2o0v.mjs +175 -0
- package/dist/Drawer-DsnW2o0v.mjs.map +1 -0
- package/dist/EmbeddedCard-DH8vQ3qN.mjs +859 -0
- package/dist/EmbeddedCard-DH8vQ3qN.mjs.map +1 -0
- package/dist/EmptyState-CJUDc3kD.mjs +85 -0
- package/dist/EmptyState-CJUDc3kD.mjs.map +1 -0
- package/dist/Error-Dtw6yxkf.mjs +85 -0
- package/dist/Error-Dtw6yxkf.mjs.map +1 -0
- package/dist/ErrorBoundary-CsdOcnJ9.mjs +24 -0
- package/dist/ErrorBoundary-CsdOcnJ9.mjs.map +1 -0
- package/dist/ExportCsvAction-C9KWH3Az.mjs +25 -0
- package/dist/ExportCsvAction-C9KWH3Az.mjs.map +1 -0
- package/dist/GlobalAccountFilter-BhzR5Vb1.mjs +230 -0
- package/dist/GlobalAccountFilter-BhzR5Vb1.mjs.map +1 -0
- package/dist/GlobalCopyApi-wcnDUzMV.mjs +129 -0
- package/dist/GlobalCopyApi-wcnDUzMV.mjs.map +1 -0
- package/dist/GoalsUtil-C9EnLWvC.mjs +108 -0
- package/dist/GoalsUtil-C9EnLWvC.mjs.map +1 -0
- package/dist/HeaderCell-P8w6CmfO.mjs +7 -0
- package/dist/HeaderCell-P8w6CmfO.mjs.map +1 -0
- package/dist/Help-CkQTjORd.mjs +300 -0
- package/dist/Help-CkQTjORd.mjs.map +1 -0
- package/dist/Help-aERwhajy.mjs +3210 -0
- package/dist/Help-aERwhajy.mjs.map +1 -0
- package/dist/IconBacking-DgT8DCeh.mjs +40 -0
- package/dist/IconBacking-DgT8DCeh.mjs.map +1 -0
- package/dist/InformationTooltip-4su8bn1e.mjs +42 -0
- package/dist/InformationTooltip-4su8bn1e.mjs.map +1 -0
- package/dist/InvestmentUtil-BItV7uEs.mjs +135 -0
- package/dist/InvestmentUtil-BItV7uEs.mjs.map +1 -0
- package/dist/LineChart-CUfiH86G.mjs +613 -0
- package/dist/LineChart-CUfiH86G.mjs.map +1 -0
- package/dist/ListItemAction-BqUCLj_w.mjs +70 -0
- package/dist/ListItemAction-BqUCLj_w.mjs.map +1 -0
- package/dist/ListItemRow-kH1rn8Xu.mjs +68 -0
- package/dist/ListItemRow-kH1rn8Xu.mjs.map +1 -0
- package/dist/ListItemWrapper-DRse79Iu.mjs +44 -0
- package/dist/ListItemWrapper-DRse79Iu.mjs.map +1 -0
- package/dist/Loader-CxeBwuPG.mjs +22 -0
- package/dist/Loader-CxeBwuPG.mjs.map +1 -0
- package/dist/Localization-DnoVyBNK.mjs +39 -0
- package/dist/Localization-DnoVyBNK.mjs.map +1 -0
- package/dist/ManageIncome-Dcsnnz86.mjs +906 -0
- package/dist/ManageIncome-Dcsnnz86.mjs.map +1 -0
- package/dist/MicroWidgetContainer-B2NnKBgW.mjs +46 -0
- package/dist/MicroWidgetContainer-B2NnKBgW.mjs.map +1 -0
- package/dist/MiniWidgetContainer-Bmv_WeUd.mjs +67 -0
- package/dist/MiniWidgetContainer-Bmv_WeUd.mjs.map +1 -0
- package/dist/NetWorthUtils-DfSH3z70.mjs +96 -0
- package/dist/NetWorthUtils-DfSH3z70.mjs.map +1 -0
- package/dist/Notification-DTNYSd8P.mjs +8 -0
- package/dist/Notification-DTNYSd8P.mjs.map +1 -0
- package/dist/NotificationSettings-CW7okUrk.mjs +678 -0
- package/dist/NotificationSettings-CW7okUrk.mjs.map +1 -0
- package/dist/NotificationUtils-BRGFTePr.mjs +24 -0
- package/dist/NotificationUtils-BRGFTePr.mjs.map +1 -0
- package/dist/NumberFormatting--XMeeBfr.mjs +50 -0
- package/dist/NumberFormatting--XMeeBfr.mjs.map +1 -0
- package/dist/OriginalBalanceAction-YrvxBYAl.mjs +115 -0
- package/dist/OriginalBalanceAction-YrvxBYAl.mjs.map +1 -0
- package/dist/RecurringSettings-D8hBbXV_.mjs +89 -0
- package/dist/RecurringSettings-D8hBbXV_.mjs.map +1 -0
- package/dist/RecurringTransactionsUtil-CHWmqvW5.mjs +299 -0
- package/dist/RecurringTransactionsUtil-CHWmqvW5.mjs.map +1 -0
- package/dist/ResponsiveButton-CC9F_Ezk.mjs +46 -0
- package/dist/ResponsiveButton-CC9F_Ezk.mjs.map +1 -0
- package/dist/SearchBox-Cpgu_gdO.mjs +51 -0
- package/dist/SearchBox-Cpgu_gdO.mjs.map +1 -0
- package/dist/Select-CSpkK5cR.mjs +62 -0
- package/dist/Select-CSpkK5cR.mjs.map +1 -0
- package/dist/SelectionBox-B4xELRgp.mjs +49 -0
- package/dist/SelectionBox-B4xELRgp.mjs.map +1 -0
- package/dist/SingleSegmentDonut-7Uy6VEld.mjs +70 -0
- package/dist/SingleSegmentDonut-7Uy6VEld.mjs.map +1 -0
- package/dist/Sizes-DISGrlUg.mjs +7 -0
- package/dist/Sizes-DISGrlUg.mjs.map +1 -0
- package/dist/SkeletonLoader-BaNboJjD.mjs +39 -0
- package/dist/SkeletonLoader-BaNboJjD.mjs.map +1 -0
- package/dist/SpendingData-Fii_xATx.mjs +54 -0
- package/dist/SpendingData-Fii_xATx.mjs.map +1 -0
- package/dist/SpendingLegend-CxvNOg3c.mjs +204 -0
- package/dist/SpendingLegend-CxvNOg3c.mjs.map +1 -0
- package/dist/StatusBar-CPfSXe80.mjs +31 -0
- package/dist/StatusBar-CPfSXe80.mjs.map +1 -0
- package/dist/TabContentContainer-B0eYJP5p.mjs +49 -0
- package/dist/TabContentContainer-B0eYJP5p.mjs.map +1 -0
- package/dist/ToggleListItem-Dl1lXNwj.mjs +92 -0
- package/dist/ToggleListItem-Dl1lXNwj.mjs.map +1 -0
- package/dist/TransactionDetails-roZ5xLq8.mjs +1708 -0
- package/dist/TransactionDetails-roZ5xLq8.mjs.map +1 -0
- package/dist/TransactionUtils-BphBJBbU.mjs +235 -0
- package/dist/TransactionUtils-BphBJBbU.mjs.map +1 -0
- package/dist/TrendsUtil-D9z3kIj_.mjs +70 -0
- package/dist/TrendsUtil-D9z3kIj_.mjs.map +1 -0
- package/dist/UserStore-C1fdL3Iu.mjs +3054 -0
- package/dist/UserStore-C1fdL3Iu.mjs.map +1 -0
- package/dist/ViewMoreMicroCard-fnwE0hqd.mjs +1280 -0
- package/dist/ViewMoreMicroCard-fnwE0hqd.mjs.map +1 -0
- package/dist/WidgetContainer-DJnp6t6c.mjs +483 -0
- package/dist/WidgetContainer-DJnp6t6c.mjs.map +1 -0
- package/dist/accounts/components/detailsdrawer/Accounts/AccountDetailsDrawer.d.ts +6 -0
- package/dist/accounts/index.d.ts +1 -0
- package/dist/accounts/index.es.js +784 -12
- package/dist/accounts/index.es.js.map +1 -0
- package/dist/analytics/index.es.js +140 -155
- package/dist/analytics/index.es.js.map +1 -0
- package/dist/budgets/index.es.js +1267 -1317
- package/dist/budgets/index.es.js.map +1 -0
- package/dist/cashflow/index.es.js +943 -1047
- package/dist/cashflow/index.es.js.map +1 -0
- package/dist/categories/index.es.js +5 -4
- package/dist/categories/index.es.js.map +1 -0
- package/dist/common/components/DataRow.d.ts +1 -0
- package/dist/common/components/ListItemWrapper.d.ts +2 -1
- package/dist/common/constants/Analytics.d.ts +3 -0
- package/dist/common/index.es.js +310 -101
- package/dist/common/index.es.js.map +1 -0
- package/dist/core/index.es.js +105 -80
- package/dist/core/index.es.js.map +1 -0
- package/dist/core/stores/RecurringTransactionsStore.d.ts +29 -1
- package/dist/core/stores/TransactionStore.d.ts +1 -0
- package/dist/core/types/localization/RecurringCopy.d.ts +14 -1
- package/dist/core/types/localization/SpendingCopy.d.ts +1 -0
- package/dist/core/utils/DateUtil.d.ts +2 -0
- package/dist/core/utils/RecurringTransactionsUtil.d.ts +2 -1
- package/dist/dashboard/index.es.js +142 -185
- package/dist/dashboard/index.es.js.map +1 -0
- package/dist/debts/index.es.js +1273 -1384
- package/dist/debts/index.es.js.map +1 -0
- package/dist/finstrong/index.es.js +3473 -3367
- package/dist/finstrong/index.es.js.map +1 -0
- package/dist/goals/index.es.js +984 -1103
- package/dist/goals/index.es.js.map +1 -0
- package/dist/help/index.es.js +26 -3
- package/dist/help/index.es.js.map +1 -0
- package/dist/hooks-97sNJ_lf.mjs +78 -0
- package/dist/hooks-97sNJ_lf.mjs.map +1 -0
- package/dist/insights/components/insights/WeeklyNoSpendDays/BubbleWeek.d.ts +4 -1
- package/dist/insights/components/insights/WeeklyNoSpendDays/WeeklyNoSpendDays.d.ts +4 -2
- package/dist/insights/index.es.js +4871 -93
- package/dist/insights/index.es.js.map +1 -0
- package/dist/investments/index.es.js +1523 -1533
- package/dist/investments/index.es.js.map +1 -0
- package/dist/merchants/index.es.js +65 -75
- package/dist/merchants/index.es.js.map +1 -0
- package/dist/microinsights/index.es.js +826 -15
- package/dist/microinsights/index.es.js.map +1 -0
- package/dist/networth/index.es.js +504 -550
- package/dist/networth/index.es.js.map +1 -0
- package/dist/notifications/index.es.js +162 -169
- package/dist/notifications/index.es.js.map +1 -0
- package/dist/recurringtransactions/components/RecurringTransactionDetails.d.ts +3 -2
- package/dist/recurringtransactions/components/RecurringTransactionDetailsDrawer.d.ts +3 -0
- package/dist/recurringtransactions/components/RecurringTransactionList.d.ts +11 -0
- package/dist/recurringtransactions/components/UpcomingRecurrenceCard.d.ts +8 -0
- package/dist/recurringtransactions/components/actions/LinkTransactionDrawer.d.ts +10 -0
- package/dist/recurringtransactions/components/actions/MarkAsPaidDialog.d.ts +7 -0
- package/dist/recurringtransactions/components/actions/MarkAsUnpaidDialog.d.ts +7 -0
- package/dist/recurringtransactions/index.es.js +1012 -10
- package/dist/recurringtransactions/index.es.js.map +1 -0
- package/dist/settings/index.es.js +892 -13
- package/dist/settings/index.es.js.map +1 -0
- package/dist/spending/index.es.js +457 -400
- package/dist/spending/index.es.js.map +1 -0
- package/dist/transactions/components/shared/transactionlist/TransactionRow.d.ts +1 -0
- package/dist/transactions/index.es.js +604 -10
- package/dist/transactions/index.es.js.map +1 -0
- package/dist/trends/index.es.js +1408 -1268
- package/dist/trends/index.es.js.map +1 -0
- package/dist/useAccountDisplayName-BsiXA0qf.mjs +24 -0
- package/dist/useAccountDisplayName-BsiXA0qf.mjs.map +1 -0
- package/dist/useAriaLive-MkYebyUR.mjs +36 -0
- package/dist/useAriaLive-MkYebyUR.mjs.map +1 -0
- package/dist/useDimensions-CeDR9V8N.mjs +37 -0
- package/dist/useDimensions-CeDR9V8N.mjs.map +1 -0
- package/dist/useInsightsEnabled-D5Sdm0TJ.mjs +12 -0
- package/dist/useInsightsEnabled-D5Sdm0TJ.mjs.map +1 -0
- package/dist/useScreenSize-mWpmnh5w.mjs +37 -0
- package/dist/useScreenSize-mWpmnh5w.mjs.map +1 -0
- package/dist/useWidgetLoadTimer-B0tB-yzL.mjs +20 -0
- package/dist/useWidgetLoadTimer-B0tB-yzL.mjs.map +1 -0
- package/package.json +30 -30
- package/dist/Analytics-BKzTPees.mjs +0 -61
- package/dist/GlobalCopyApi-BeXzaDH9.mjs +0 -487
- package/dist/HeaderCell-EhCUSjvj.mjs +0 -10
- package/dist/Loader-BlVzRtUd.mjs +0 -73
- package/dist/MiniWidgetContainer-COwnjfy7.mjs +0 -110
- package/dist/OriginalBalanceAction-sbiqaxok.mjs +0 -110
- package/dist/SpendingLegend-D15ixlQ1.mjs +0 -222
- package/dist/accounts-DkyAiLpg.mjs +0 -15632
- package/dist/core-BexP5oiV.mjs +0 -4047
- package/dist/help-CctDYrAH.mjs +0 -2308
- package/dist/insights/components/insights/P2pCategorization/_tests_/P2pCategorizationMultipleTransaction.test.d.ts +0 -0
- package/dist/insights/components/insights/P2pCategorization/_tests_/P2pCategorizationSingleTransaction.test.d.ts +0 -0
- package/dist/microinsights-CRf3ChsJ.mjs +0 -1814
- package/dist/recurringtransactions-gbJ_NA8u.mjs +0 -1564
- package/dist/settings-ZMHe439l.mjs +0 -1526
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { format as h } from "date-fns/format";
|
|
2
|
+
import { startOfMonth as M } from "date-fns/startOfMonth";
|
|
3
|
+
import { startOfToday as N } from "date-fns/startOfToday";
|
|
4
|
+
import { subMonths as L } from "date-fns/subMonths";
|
|
5
|
+
import { CategoryIconList as P } from "@mxenabled/mxui";
|
|
6
|
+
import { c as U, a as G, C as S, b as w } from "./Category-DEKZGLYe.mjs";
|
|
7
|
+
import { f as _, D as m, O as H } from "./DateFormats-HudZ3Bjs.mjs";
|
|
8
|
+
import { endOfToday as B } from "date-fns/endOfToday";
|
|
9
|
+
import { fromUnixTime as I } from "date-fns/fromUnixTime";
|
|
10
|
+
import { getUnixTime as y } from "date-fns/getUnixTime";
|
|
11
|
+
import { f as F } from "./NumberFormatting--XMeeBfr.mjs";
|
|
12
|
+
var A = /* @__PURE__ */ ((e) => (e[e.CREDIT = 1] = "CREDIT", e[e.DEBIT = 2] = "DEBIT", e))(A || {}), C = /* @__PURE__ */ ((e) => (e[e.POSTED = 1] = "POSTED", e[e.PENDING = 2] = "PENDING", e))(C || {});
|
|
13
|
+
const j = 3, D = 12, ue = (e, t, n, o) => e.filter((r) => !r.parent_guid).map(
|
|
14
|
+
(r) => v(
|
|
15
|
+
r,
|
|
16
|
+
t,
|
|
17
|
+
n,
|
|
18
|
+
o,
|
|
19
|
+
e.filter((d) => d.parent_guid === r.guid)
|
|
20
|
+
)
|
|
21
|
+
), ce = (e, t) => {
|
|
22
|
+
const n = P.find((o) => o.guid === e);
|
|
23
|
+
return n ? t.palette.categories[n.colorName] || "" : t.palette.categories.uncategorized || "";
|
|
24
|
+
}, v = (e, t, n, o, r = []) => {
|
|
25
|
+
const d = e.guid, i = e.parent_guid || d, a = d === i, s = n.find((f) => f.category_guid === d)?.total || 0, u = b(
|
|
26
|
+
o.filter((f) => f.category_guid === d)
|
|
27
|
+
), g = b(
|
|
28
|
+
o.filter(
|
|
29
|
+
(f) => f.category_guid === d || f.top_level_category_guid === d
|
|
30
|
+
)
|
|
31
|
+
), c = r.map(
|
|
32
|
+
(f) => v(f, t, n, o)
|
|
33
|
+
), p = c.reduce(
|
|
34
|
+
(f, R) => f + R.currentAmount,
|
|
35
|
+
s
|
|
36
|
+
), T = t.default_categories[e.guid] ? t.default_categories[e.guid].replace(/&/g, "&") : e.name;
|
|
37
|
+
return {
|
|
38
|
+
...e,
|
|
39
|
+
currentAmount: s,
|
|
40
|
+
averageAmount: E(u),
|
|
41
|
+
color: G[i],
|
|
42
|
+
icon: U[i],
|
|
43
|
+
isTransfer: i === S.TRANSFER,
|
|
44
|
+
monthlyAmounts: u,
|
|
45
|
+
name: T,
|
|
46
|
+
subCategories: c,
|
|
47
|
+
totalAmount: a ? p : 0,
|
|
48
|
+
totalAverageAmount: E(g),
|
|
49
|
+
totalMonthlyAmounts: a ? g : []
|
|
50
|
+
};
|
|
51
|
+
}, le = (e, t) => e.map((n) => {
|
|
52
|
+
const o = t.filter(
|
|
53
|
+
(r) => r.category_guid === n.guid || r.top_level_category_guid === n.guid
|
|
54
|
+
);
|
|
55
|
+
return {
|
|
56
|
+
...n,
|
|
57
|
+
transactions: o
|
|
58
|
+
};
|
|
59
|
+
}), E = (e, t = j) => {
|
|
60
|
+
const n = t > history.length ? history.length : t;
|
|
61
|
+
return Math.ceil(
|
|
62
|
+
Math.max(
|
|
63
|
+
0,
|
|
64
|
+
e.slice(-n).reduce((o, r) => o + r.amount, 0) / n
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
}, b = (e) => {
|
|
68
|
+
const t = [], n = N();
|
|
69
|
+
for (let o = 0; o <= D; o++) {
|
|
70
|
+
const r = M(L(n, D - o)), i = e.filter(
|
|
71
|
+
(a) => a.year_month === Number(h(r, "yyyyMM"))
|
|
72
|
+
).reduce((a, s) => a + s.total, 0);
|
|
73
|
+
t.push({
|
|
74
|
+
amount: i,
|
|
75
|
+
isoDate: h(r, "yyyy-MM-dd"),
|
|
76
|
+
label: _(r, m.MONTH_YEAR)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return t;
|
|
80
|
+
}, ge = (e, t) => e.find((n) => n.guid === t), fe = (e, t) => {
|
|
81
|
+
const n = e.find((o) => o.subCategories.find((r) => r.guid === t));
|
|
82
|
+
if (n)
|
|
83
|
+
return n.subCategories.find((o) => o.guid === t);
|
|
84
|
+
}, Y = {
|
|
85
|
+
ASC: "ASC",
|
|
86
|
+
DESC: "DESC"
|
|
87
|
+
}, _e = {
|
|
88
|
+
account_guid: "",
|
|
89
|
+
amount: 0,
|
|
90
|
+
currency_code: "",
|
|
91
|
+
date: 0,
|
|
92
|
+
description: "",
|
|
93
|
+
duplicate: !1,
|
|
94
|
+
feed_description: "",
|
|
95
|
+
feed_status: C.POSTED,
|
|
96
|
+
feed_transaction_date: 0,
|
|
97
|
+
has_been_split: !1,
|
|
98
|
+
has_been_viewed: !1,
|
|
99
|
+
is_cleared: !1,
|
|
100
|
+
is_flagged: !1,
|
|
101
|
+
is_hidden: !1,
|
|
102
|
+
is_manual: !0,
|
|
103
|
+
is_personal: !0,
|
|
104
|
+
is_reimbursable: !1,
|
|
105
|
+
is_subscription: !1,
|
|
106
|
+
is_void: !1,
|
|
107
|
+
revision: 1,
|
|
108
|
+
transaction_type: A.DEBIT,
|
|
109
|
+
user_guid: "",
|
|
110
|
+
is_duplicate: !1,
|
|
111
|
+
feed_transacted_at: 0,
|
|
112
|
+
guid: "",
|
|
113
|
+
memo: void 0,
|
|
114
|
+
tags: []
|
|
115
|
+
}, O = {
|
|
116
|
+
DATE: "date",
|
|
117
|
+
AMOUNT: "amount"
|
|
118
|
+
}, me = (e, t, n, o = []) => {
|
|
119
|
+
const r = t.reduce((a, s) => ({ ...a, [s.guid]: s }), {}), d = n.reduce((a, s) => ({ ...a, [s.guid]: s }), {}), i = o.reduce((a, s) => {
|
|
120
|
+
const { transaction_guid: u, tag_guid: g } = s;
|
|
121
|
+
if (!a[u])
|
|
122
|
+
return {
|
|
123
|
+
...a,
|
|
124
|
+
[u]: [g]
|
|
125
|
+
};
|
|
126
|
+
const c = [...a[u], g];
|
|
127
|
+
return {
|
|
128
|
+
...a,
|
|
129
|
+
[u]: c
|
|
130
|
+
};
|
|
131
|
+
}, {});
|
|
132
|
+
return e.map((a) => {
|
|
133
|
+
const s = r[a.account_guid], u = a.category_guid ? d[a.category_guid] : null, g = i[a.guid] ?? [];
|
|
134
|
+
return {
|
|
135
|
+
...a,
|
|
136
|
+
account: s?.user_name || "Unknown",
|
|
137
|
+
accountIsClosed: s?.is_closed,
|
|
138
|
+
accountIsHidden: s?.is_hidden,
|
|
139
|
+
category: u?.name || "Uncategorized",
|
|
140
|
+
isIncome: a.top_level_category_guid === S.INCOME,
|
|
141
|
+
isPending: a.feed_status === C.PENDING,
|
|
142
|
+
number: s?.account_number || "",
|
|
143
|
+
payee: a.description,
|
|
144
|
+
tags: g
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}, x = "uncategorized", pe = (e, t, n, o, r, d) => {
|
|
148
|
+
const i = k(e, r, d), a = V(i, n, o);
|
|
149
|
+
return t.forEach((s) => {
|
|
150
|
+
const u = a.findIndex((c) => c.guid === s), g = d.filter((c) => c.parent_guid === s);
|
|
151
|
+
a.splice(u + 1, 0, ...g);
|
|
152
|
+
}), a;
|
|
153
|
+
}, k = (e, t, n) => {
|
|
154
|
+
const {
|
|
155
|
+
accounts: o = [],
|
|
156
|
+
dateRange: r = { start: M(N()), end: B() },
|
|
157
|
+
custom: d = () => !0,
|
|
158
|
+
searchTerm: i = "",
|
|
159
|
+
showSplits: a = !1
|
|
160
|
+
} = e;
|
|
161
|
+
return n.filter((s) => a ? !s.has_been_split : !s.parent_guid).filter((s) => !!o.find((u) => u === s.account_guid)).filter((s) => s.date >= y(r.start) && s.date <= y(r.end)).filter(d).filter((s) => {
|
|
162
|
+
if (i === x && s.has_been_split)
|
|
163
|
+
return !1;
|
|
164
|
+
if (/^spl/i.test(i) && (s.has_been_split || s.parent_guid))
|
|
165
|
+
return !0;
|
|
166
|
+
const g = s.tags.some(
|
|
167
|
+
(p) => l(i, t.find((T) => T.guid === p)?.name)
|
|
168
|
+
), c = I(s.date);
|
|
169
|
+
return l(i, s.payee) || l(i, s.feed_description) || l(i, s.category) || l(i, _(c, m.MONTH)) || l(i, _(c, m.DAY)) || l(i, _(c, m.FULL_MONTH_DAY)) || l(i, _(c, m.MONTH_DAY_YEAR)) || l(i, h(c, H)) || l(i, s.account) || l(i, F(s.amount, "0,0.00")) || l(i, s.memo) || g;
|
|
170
|
+
});
|
|
171
|
+
}, V = (e, t, n) => [...e].sort((o, r) => {
|
|
172
|
+
const d = t, i = (o[d] || "") > (r[d] || "");
|
|
173
|
+
let a = i ? -1 : 1, s = i ? 1 : -1;
|
|
174
|
+
return (t === O.DATE || t === O.AMOUNT) && (a = i ? 1 : -1, s = i ? -1 : 1), n === Y.ASC ? a : s;
|
|
175
|
+
}), l = (e, t) => {
|
|
176
|
+
const n = e.toLowerCase().split(" "), o = t?.toString().toLowerCase() ?? "";
|
|
177
|
+
return n.every((r) => o.indexOf(r) > -1);
|
|
178
|
+
};
|
|
179
|
+
function z(e) {
|
|
180
|
+
return new Set(
|
|
181
|
+
e.filter((t) => t.parent_guid !== void 0).map((t) => t.parent_guid)
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
function W(e) {
|
|
185
|
+
return e.reduce((t, n) => (n.parent_guid && (t[n.parent_guid] || (t[n.parent_guid] = []), t[n.parent_guid].push(n)), t), {});
|
|
186
|
+
}
|
|
187
|
+
function Te(e, t) {
|
|
188
|
+
const n = z(t), o = W(t), r = /* @__PURE__ */ new Set(), d = [];
|
|
189
|
+
for (const i of e)
|
|
190
|
+
n.has(i.guid) ? (o[i.guid] ?? []).slice().sort((s, u) => Math.abs(u.amount) - Math.abs(s.amount)).forEach((s) => {
|
|
191
|
+
r.has(s.guid) || (d.push(s), r.add(s.guid));
|
|
192
|
+
}) : r.has(i.guid) || (d.push(i), r.add(i.guid));
|
|
193
|
+
return d;
|
|
194
|
+
}
|
|
195
|
+
const he = (e, t) => {
|
|
196
|
+
const n = q($(e, t)), o = new Blob([n], { type: "text/csv;charset=utf-8;" }), r = document.createElement("a");
|
|
197
|
+
r.href = URL.createObjectURL(o), r.setAttribute("download", "transactions.csv"), document.body.appendChild(r), r.click(), document.body.removeChild(r), URL.revokeObjectURL(r.href);
|
|
198
|
+
}, $ = (e, t) => e.map((n) => ({
|
|
199
|
+
Date: _(I(n.date), m.YEAR_MONTH_DAY),
|
|
200
|
+
Description: J(n),
|
|
201
|
+
"Original Description": n.feed_description,
|
|
202
|
+
Amount: `${n.amount}`,
|
|
203
|
+
Type: n.transaction_type === A.CREDIT ? "Credit" : "Debit",
|
|
204
|
+
"Parent Category": w[n.top_level_category_guid || ""],
|
|
205
|
+
Category: n.category,
|
|
206
|
+
Account: n.account,
|
|
207
|
+
Tags: K(n, t),
|
|
208
|
+
Memo: n.memo,
|
|
209
|
+
Pending: n.isPending ? "TRUE" : "FALSE"
|
|
210
|
+
})), Z = (e) => e ? /[,"\n\r]/.test(e) ? `"${e.replace(/"/g, '""')}"` : e : "", q = (e) => {
|
|
211
|
+
const t = Object.keys(e[0]).join(",").concat(`\r
|
|
212
|
+
`), n = e.map((o) => Object.values(o).map(Z).join(",")).join(`\r
|
|
213
|
+
`);
|
|
214
|
+
return t + n;
|
|
215
|
+
}, J = (e) => {
|
|
216
|
+
let t = e.parent_guid ? "Split: " : "";
|
|
217
|
+
return t += e.is_hidden ? "(Excluded) " : "", t += e.description, t;
|
|
218
|
+
}, K = (e, t) => e.tags.map((n) => t.filter((r) => r.guid === n)[0]?.name ?? "").join(" ");
|
|
219
|
+
export {
|
|
220
|
+
O as C,
|
|
221
|
+
_e as D,
|
|
222
|
+
A as T,
|
|
223
|
+
fe as a,
|
|
224
|
+
C as b,
|
|
225
|
+
ue as c,
|
|
226
|
+
le as d,
|
|
227
|
+
he as e,
|
|
228
|
+
ge as f,
|
|
229
|
+
ce as g,
|
|
230
|
+
Y as h,
|
|
231
|
+
me as i,
|
|
232
|
+
Te as j,
|
|
233
|
+
pe as s
|
|
234
|
+
};
|
|
235
|
+
//# sourceMappingURL=TransactionUtils-BphBJBbU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransactionUtils-BphBJBbU.mjs","sources":["../src/core/types/Transaction.ts","../src/core/utils/CategoryUtil.ts","../src/core/constants/Table.ts","../src/core/constants/Transaction.ts","../src/core/utils/TransactionUtils.ts"],"sourcesContent":["export interface Transaction {\n guid: string\n account_guid: string\n amount: number\n attachment_guid?: string | null\n category_guid?: string\n check_number?: string | null\n currency_code: string | null\n date: number\n description: string\n duplicate: boolean\n external_guid?: string | null\n feed_attachment_guid?: string | null\n feed_description: string\n feed_localized_description?: string | null\n feed_posted_date?: number | null\n feed_status: TransactionStatus | null\n feed_transaction_date: number | null\n flags?: number | null\n has_been_split: boolean\n has_been_viewed: boolean\n is_cleared: boolean\n is_flagged: boolean\n is_hidden: boolean\n is_international?: boolean | null\n is_manual: boolean\n is_personal: boolean\n is_reimbursable: boolean\n is_subscription: boolean\n is_void: boolean\n localized_description?: string | null\n localized_memo?: string | null\n memo?: string | null\n metadata?: string | null\n merchant_guid?: string | null\n parent_guid?: string | null\n posted_date?: number | null\n reference?: string | null\n revision: number\n repeating_transaction_guid?: string | null\n scheduled_payment_guid?: string | null\n top_level_category_guid?: string\n transaction_type: TransactionType\n user_date?: number | null\n user_guid: string\n user_transaction_rule_guid?: string | null\n is_duplicate: boolean\n tags: string[]\n feed_transacted_at: number | null\n\n // Detailed Transaction fields\n account?: string\n accountIsClosed?: boolean\n accountIsHidden?: boolean\n category?: string\n isIncome?: boolean\n isPending?: boolean\n number?: string\n payee?: string\n}\n\nexport enum TransactionType {\n CREDIT = 1,\n DEBIT = 2,\n}\n\nexport enum TransactionStatus {\n POSTED = 1,\n PENDING = 2,\n}\n\nexport interface Tag {\n guid: string\n is_default_tag: boolean\n name: string\n user_guid: string\n}\n\nexport interface Tagging {\n guid: string\n user_guid: string\n tag_guid: string\n transaction_guid: string\n}\n\nexport interface TransactionRule {\n guid: string\n user_guid: string\n category_guid: string | null\n match_description: string\n description: string | null\n}\n","import { format } from 'date-fns/format'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\nimport { subMonths } from 'date-fns/subMonths'\n\nimport type { Palette, Theme } from '@mui/material'\n\nimport { CategoryIconList } from '@mxenabled/mxui'\n\nimport {\n CategoryColors,\n CategoryGuids,\n CategoryIcon,\n DATE_FORMATS_INTL,\n formatDate,\n} from '../constants'\n\nimport type {\n Category,\n DateRangeCategoryTotals,\n DetailedCategory,\n DetailedCategoryWithTransactions,\n MonthlyAmount,\n MonthlyCategoryTotals,\n Transaction,\n CategoryCopy,\n CategoryTotal,\n} from '../types'\n\nconst MONTHLY_AVERAGE_LENGTH = 3\nconst MONTHS_OF_HISTORY = 12\n\n/**\n * Augment categories\n * @param categories - Categories to augment\n * @param monthlyCategoryTotals - Monthly category totals\n * @param currentCategoryTotals - Current month category totals\n * @param copy - Category copy\n */\nexport const augmentCategories = (\n categories: Category[],\n copy: CategoryCopy,\n currentCategoryTotals: DateRangeCategoryTotals[],\n monthlyCategoryTotals: MonthlyCategoryTotals[],\n): DetailedCategory[] => {\n return categories\n .filter((category) => !category.parent_guid)\n .map((category) =>\n getDetailedCategory(\n category,\n copy,\n currentCategoryTotals,\n monthlyCategoryTotals,\n categories.filter((c) => c.parent_guid === category.guid),\n ),\n )\n}\n\nexport const getCategoryColor = (guid: string, theme: Theme) => {\n const categoryInfo = CategoryIconList.find((c) => c.guid === guid)\n if (!categoryInfo) return theme.palette.categories.uncategorized || ''\n\n return theme.palette.categories[categoryInfo.colorName as keyof Palette['categories']] || ''\n}\n\nexport const getCategoryIcon = (guid: string) => {\n return CategoryIconList.find((c) => c.guid === guid)?.icon\n}\n\n/**\n * Get an augmented category with additional details\n * @param category - The category to augment\n * @param copy - Category copy\n * @param currentCategoryTotals - Current month category totals\n * @param monthlyCategoryTotals - Past monthly category totals\n * @param subCategories - Subcategories for the specified category (If applicable)\n */\nconst getDetailedCategory = (\n category: Category,\n copy: CategoryCopy,\n currentCategoryTotals: DateRangeCategoryTotals[],\n monthlyCategoryTotals: MonthlyCategoryTotals[],\n subCategories: Category[] = [],\n): DetailedCategory => {\n const guid = category.guid\n const parentGuid = category.parent_guid || guid\n const isParent = guid === parentGuid\n\n const currentAmount = currentCategoryTotals.find((t) => t.category_guid === guid)?.total || 0\n const monthlyAmounts = getMonthlyAmounts(\n monthlyCategoryTotals.filter((total) => total.category_guid === guid),\n )\n const totalMonthlyAmounts = getMonthlyAmounts(\n monthlyCategoryTotals.filter(\n (total) => total.category_guid === guid || total.top_level_category_guid === guid,\n ),\n )\n const detailedSubCategories = subCategories.map((subCategory) =>\n getDetailedCategory(subCategory, copy, currentCategoryTotals, monthlyCategoryTotals),\n )\n const totalAmount = detailedSubCategories.reduce(\n (total, current) => total + current.currentAmount,\n currentAmount,\n )\n\n const name = copy.default_categories[category.guid]\n ? copy.default_categories[category.guid].replace(/&/g, '&')\n : category.name\n\n return {\n ...category,\n currentAmount,\n averageAmount: getAverage(monthlyAmounts),\n color: CategoryColors[parentGuid],\n icon: CategoryIcon[parentGuid],\n isTransfer: parentGuid === CategoryGuids.TRANSFER,\n monthlyAmounts,\n name,\n subCategories: detailedSubCategories,\n totalAmount: isParent ? totalAmount : 0,\n totalAverageAmount: getAverage(totalMonthlyAmounts),\n totalMonthlyAmounts: isParent ? totalMonthlyAmounts : [],\n }\n}\n/**\n * get the transactions belonging to parent categories\n * @param detailedCategories - detailed categories from the category store\n * @param transactions - sortedTransactions from the transaction store\n */\nexport const getDetailedCategoryTransactions = (\n detailedCategories: DetailedCategory[],\n transactions: Transaction[],\n): DetailedCategoryWithTransactions[] => {\n return detailedCategories.map((category) => {\n const categoryTransactions = transactions.filter(\n (transaction) =>\n transaction.category_guid === category.guid ||\n transaction.top_level_category_guid === category.guid,\n )\n\n return {\n ...category,\n transactions: categoryTransactions,\n }\n })\n}\n\n/**\n * Get the average amount based on the number of months (numMonths) requested\n * @param monthlyAmounts - Monthly amounts to calculate and average from\n * @param numMonths - Number of months to base the average on (DEFAULT: 3)\n */\nconst getAverage = (\n monthlyAmounts: MonthlyAmount[],\n numMonths: number = MONTHLY_AVERAGE_LENGTH,\n): number => {\n const monthsBack = numMonths > history.length ? history.length : numMonths\n\n return Math.ceil(\n Math.max(\n 0,\n monthlyAmounts.slice(-monthsBack).reduce((total, current) => total + current.amount, 0) /\n monthsBack,\n ),\n )\n}\n\n/**\n * Get the last 12 months of amounts for a category\n * @param categoryTotals - Monthly category totals\n */\nconst getMonthlyAmounts = (categoryTotals: MonthlyCategoryTotals[]): MonthlyAmount[] => {\n const monthlyAmounts: MonthlyAmount[] = []\n const today = startOfToday()\n for (let i = 0; i <= MONTHS_OF_HISTORY; i++) {\n const historyDate = startOfMonth(subMonths(today, MONTHS_OF_HISTORY - i))\n const monthlyTotals = categoryTotals.filter(\n (total) => total.year_month === Number(format(historyDate, 'yyyyMM')),\n )\n const totalAmount = monthlyTotals.reduce((acc, curr) => acc + curr.total, 0)\n\n monthlyAmounts.push({\n amount: totalAmount,\n isoDate: format(historyDate, 'yyyy-MM-dd'),\n label: formatDate(historyDate, DATE_FORMATS_INTL.MONTH_YEAR),\n })\n }\n\n return monthlyAmounts\n}\n\nexport const findCategory = (\n categories: Category[],\n categoryGuid: string | undefined,\n): Category | undefined => {\n return categories.find((c) => c.guid === categoryGuid)\n}\n\nexport const findDetailedCategory = (\n detailedCategories: DetailedCategory[],\n guid: string | undefined,\n): DetailedCategory | undefined => {\n return detailedCategories.find((dc) => dc.guid === guid)\n}\n\nexport const findDetailedSubCategory = (\n detailedCategories: DetailedCategory[],\n guid: string | undefined,\n): DetailedCategory | undefined => {\n const parent = detailedCategories.find((dc) => dc.subCategories.find((sc) => sc.guid === guid))\n if (!parent) return undefined\n\n return parent.subCategories.find((sc) => sc.guid === guid)\n}\n\nexport const findCategoryTotalsByParent = (\n categories: Category[],\n dateRangeTotals: DateRangeCategoryTotals[],\n): CategoryTotal[] => {\n const categoryTotals = [] as CategoryTotal[]\n\n // Iterate over the category data from BE and roll up all categories into parent categories\n // acc is the accumulated category totals of type CategoryTotal that is initialized as an empty []\n // curr is the current DateRangeCategoryTotal\n\n for (const dateRangeTotal of dateRangeTotals) {\n const category = findCategory(categories, dateRangeTotal.category_guid)\n if (!category) continue\n\n const parentGuid = category.parent_guid ?? category.guid\n const parentCategory = findCategory(categories, parentGuid)\n if (!parentCategory) continue\n\n const categoryTotal = {\n amount: dateRangeTotal.total,\n category,\n guid: category.guid,\n subCategoryTotals: [],\n }\n\n const parentCategoryTotal = categoryTotals.find((ct) => ct.guid === parentGuid)\n if (parentCategoryTotal) {\n parentCategoryTotal.amount += dateRangeTotal.total\n parentCategoryTotal.subCategoryTotals.push(categoryTotal)\n } else {\n categoryTotals.push({\n amount: dateRangeTotal.total,\n category: parentCategory,\n guid: parentGuid,\n subCategoryTotals: [categoryTotal],\n })\n }\n }\n\n return categoryTotals\n}\n\nexport const isIncome = (categories: Category[], guid: string) => {\n const category = categories.find((c) => c.guid === guid)\n if (!category) return false\n\n return category.guid === CategoryGuids.INCOME || category.parent_guid === CategoryGuids.INCOME\n}\n","export const TABLE_CONST = {\n ASC: 'ASC',\n DESC: 'DESC',\n DIRECTION: {\n ASC: 'ascending',\n DESC: 'descending',\n },\n ALIGN: {\n center: 'center',\n left: 'flex-start',\n right: 'flex-end',\n },\n}\n","import type { Transaction } from '../types'\nimport { TransactionStatus, TransactionType } from '../types'\n\nexport const DEFAULT_TRANSACTION = {\n account_guid: '',\n amount: 0,\n currency_code: '',\n date: 0,\n description: '',\n duplicate: false,\n feed_description: '',\n feed_status: TransactionStatus.POSTED,\n feed_transaction_date: 0,\n has_been_split: false,\n has_been_viewed: false,\n is_cleared: false,\n is_flagged: false,\n is_hidden: false,\n is_manual: true,\n is_personal: true,\n is_reimbursable: false,\n is_subscription: false,\n is_void: false,\n revision: 1,\n transaction_type: TransactionType.DEBIT,\n user_guid: '',\n is_duplicate: false,\n feed_transacted_at: 0,\n guid: '',\n memo: undefined,\n tags: [],\n} as Transaction\n\nexport const COLUMN_NAMES = {\n FLAG: 'flag',\n DATE: 'date',\n PAYEE: 'payee',\n CATEGORY: 'category',\n ACCOUNT: 'account',\n AMOUNT: 'amount',\n}\n","import { endOfToday } from 'date-fns/endOfToday'\nimport { format } from 'date-fns/format'\nimport { fromUnixTime } from 'date-fns/fromUnixTime'\nimport { getUnixTime } from 'date-fns/getUnixTime'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { TABLE_CONST } from '../constants/Table'\nimport {\n CategoryGuids,\n CategoryGuidToName,\n DATE_FORMATS_INTL,\n formatDate,\n ORDINAL_DATE_FORMAT,\n} from '../constants'\nimport { COLUMN_NAMES } from '../constants/Transaction'\nimport { TransactionStatus, TransactionType } from '../types'\nimport type { Account, Category, Tag, Tagging, Transaction } from '../types'\n\nimport { type TransactionFilter } from '../stores/TransactionStore'\n\nimport { formatCurrency } from './NumberFormatting'\n\ninterface AccountsMap {\n [key: string]: Account\n}\n\ninterface CategoriesMap {\n [key: string]: Category\n}\n\ninterface TaggingsMap {\n [key: string]: string[]\n}\n\nexport const buildDetailedTransactions = (\n transactions: Transaction[],\n accounts: Account[],\n categories: Category[],\n taggings: Tagging[] = [],\n) => {\n const accountsMap = accounts.reduce((acc: AccountsMap, account: Account) => {\n return { ...acc, [account.guid]: account }\n }, {})\n\n const categoriesMap = categories.reduce((acc: CategoriesMap, category: Category) => {\n return { ...acc, [category.guid]: category }\n }, {})\n\n const taggingsMap = taggings.reduce((acc: TaggingsMap, tagging: Tagging) => {\n const { transaction_guid, tag_guid } = tagging\n\n if (!acc[transaction_guid]) {\n return {\n ...acc,\n [transaction_guid]: [tag_guid],\n }\n }\n const tags = [...acc[transaction_guid], tag_guid] as string[]\n\n return {\n ...acc,\n [transaction_guid]: tags,\n }\n }, {})\n\n return transactions.map((transaction: Transaction) => {\n const account = accountsMap[transaction.account_guid]\n const category = transaction.category_guid ? categoriesMap[transaction.category_guid] : null\n const tags = taggingsMap[transaction.guid] ?? []\n\n return {\n ...transaction,\n account: account?.user_name || 'Unknown',\n accountIsClosed: account?.is_closed,\n accountIsHidden: account?.is_hidden,\n category: category?.name || 'Uncategorized',\n isIncome: transaction.top_level_category_guid === CategoryGuids.INCOME,\n isPending: transaction.feed_status === TransactionStatus.PENDING,\n number: account?.account_number || '',\n payee: transaction.description,\n tags,\n }\n })\n}\n\nconst UNCATEGORIZED_TERM = 'uncategorized'\n\nexport const sortAndFilterTransactions = (\n filter: TransactionFilter,\n expandedSplits: string[],\n sortColumn: string,\n sortDirection: string,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const filteredTransactions = filterTransactions(filter, tags, transactions)\n\n const sortedTransactions = sortTransactions(filteredTransactions, sortColumn, sortDirection)\n\n expandedSplits.forEach((guid) => {\n const index = sortedTransactions.findIndex((t) => t.guid === guid)\n const children = transactions.filter((t) => t.parent_guid === guid)\n sortedTransactions.splice(index + 1, 0, ...children)\n })\n return sortedTransactions\n}\n\nconst filterTransactions = (\n filter: TransactionFilter,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const {\n accounts = [],\n dateRange = { start: startOfMonth(startOfToday()), end: endOfToday() },\n custom = () => true,\n searchTerm: searchFilter = '',\n showSplits = false,\n } = filter\n\n return (\n transactions\n // Filters out parent of split transactions when showSplits is true and filters out split\n // transaction children when showSplits is false\n .filter((t) => (showSplits ? !t.has_been_split : !t.parent_guid))\n // Filter for selected accounts\n .filter((t) => Boolean(accounts.find((guid) => guid === t.account_guid)))\n // Filter for Date Range\n .filter((t) => t.date >= getUnixTime(dateRange.start) && t.date <= getUnixTime(dateRange.end))\n // Custom filter\n .filter(custom)\n // Search filter\n .filter((transaction) => {\n // Don't return uncategorized split transactions\n if (searchFilter === UNCATEGORIZED_TERM && transaction.has_been_split) {\n return false\n }\n\n // Split check - When searching for \"Splits\" and transaction is a split or is a parent of a split(s)\n const splitPattern = /^spl/i\n if (\n splitPattern.test(searchFilter) &&\n (transaction.has_been_split || Boolean(transaction.parent_guid))\n ) {\n return true\n }\n\n // Check transactions tags\n const isTagIncludedInSearch = transaction.tags.some((guid) =>\n isIncludedInSearch(searchFilter, tags.find((tag) => tag.guid === guid)?.name),\n )\n const date = fromUnixTime(transaction.date)\n return (\n isIncludedInSearch(searchFilter, transaction.payee) ||\n isIncludedInSearch(searchFilter, transaction.feed_description) ||\n isIncludedInSearch(searchFilter, transaction.category) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.FULL_MONTH_DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH_DAY_YEAR)) ||\n isIncludedInSearch(searchFilter, format(date, ORDINAL_DATE_FORMAT)) ||\n isIncludedInSearch(searchFilter, transaction.account) ||\n isIncludedInSearch(searchFilter, formatCurrency(transaction.amount, '0,0.00')) ||\n isIncludedInSearch(searchFilter, transaction.memo) ||\n isTagIncludedInSearch\n )\n })\n )\n}\n\nconst sortTransactions = (\n transactions: Transaction[],\n sortColumn: string,\n sortDirection: string,\n) => {\n return [...transactions].sort((a: Transaction, b: Transaction) => {\n const column = sortColumn as keyof Transaction\n const sortCompare = (a[column] || '') > (b[column] || '')\n\n let sortASC = sortCompare ? -1 : 1\n let sortDESC = sortCompare ? 1 : -1\n\n if (sortColumn === COLUMN_NAMES.DATE || sortColumn === COLUMN_NAMES.AMOUNT) {\n sortASC = sortCompare ? 1 : -1\n sortDESC = sortCompare ? -1 : 1\n }\n\n return sortDirection === TABLE_CONST.ASC ? sortASC : sortDESC\n })\n}\n\n/**\n * Determines if a value is included within the terms set in the search bar\n */\nconst isIncludedInSearch = (searchFilter: string, value: string | null | undefined) => {\n const lowerCasedTerms = searchFilter.toLowerCase().split(' ')\n const lowerCasedValue = value?.toString().toLowerCase() ?? ''\n\n return lowerCasedTerms.every((filter) => lowerCasedValue.indexOf(filter) > -1)\n}\n\n// TODO: Change the way formatting data is exported in order to handle localization\ntype FormattedTransaction = {\n Date: string\n Description: string\n 'Original Description': string\n Amount: string\n Type: string\n 'Parent Category': string\n Category: string\n Account: string\n Tags: string\n Memo: string\n Pending: string\n}\n\n/**\n * Collects the GUIDs of all transactions that act as parents\n * to one or more split (child) transactions.\n */\nfunction extractParentTransactionGuids(transactions: Transaction[]): Set<string> {\n return new Set(\n transactions.filter((tx) => tx.parent_guid !== undefined).map((tx) => tx.parent_guid!),\n )\n}\n\n/**\n * Organizes child transactions by their parent transaction GUID.\n * Returns a map from parent GUID to an array of its child transactions.\n */\nfunction mapChildTransactionsByParent(transactions: Transaction[]): Record<string, Transaction[]> {\n return transactions.reduce<Record<string, Transaction[]>>((accumulator, tx) => {\n if (tx.parent_guid) {\n if (!accumulator[tx.parent_guid]) accumulator[tx.parent_guid] = []\n accumulator[tx.parent_guid].push(tx)\n }\n return accumulator\n }, {})\n}\n\n/**\n * Produces a list of transactions based on the given sorted transactions,\n * where parent transactions that have split children are replaced by those\n * children sorted by descending absolute amount. All other transactions\n * are included as-is, with duplicates removed.\n */\nexport function flattenTransactionsWithSplits(\n sortedTransactions: Transaction[],\n allTransactions: Transaction[],\n): Transaction[] {\n // Set of parent transaction GUIDs that have split child transactions\n const parentTransactionGuidsWithSplits = extractParentTransactionGuids(allTransactions)\n\n // Map from parent GUID to array of its child split transactions\n const childTransactionsGroupedByParent = mapChildTransactionsByParent(allTransactions)\n\n // Track GUIDs of transactions already included in the result to avoid duplicates\n const processedTransactionGuids = new Set<string>()\n\n // Resulting list of transactions with parents replaced by their split children\n const flattenedTransactionList: Transaction[] = []\n\n for (const transaction of sortedTransactions) {\n if (parentTransactionGuidsWithSplits.has(transaction.guid)) {\n // This transaction is a parent with splits, so replace it with its children\n const splitChildTransactions = childTransactionsGroupedByParent[transaction.guid] ?? []\n\n splitChildTransactions\n .slice()\n .sort((a, b) => Math.abs(b.amount) - Math.abs(a.amount))\n .forEach((childTransaction) => {\n if (!processedTransactionGuids.has(childTransaction.guid)) {\n flattenedTransactionList.push(childTransaction)\n processedTransactionGuids.add(childTransaction.guid)\n }\n })\n } else if (!processedTransactionGuids.has(transaction.guid)) {\n // Normal transaction (no splits), add as-is if not already added\n flattenedTransactionList.push(transaction)\n processedTransactionGuids.add(transaction.guid)\n }\n }\n\n return flattenedTransactionList\n}\n\nexport const exportTransactionsToCSV = (transactions: Transaction[], tags: Tag[]) => {\n const csvContent = structureCSVData(formatTransactions(transactions, tags))\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const link = document.createElement('a')\n link.href = URL.createObjectURL(blob)\n link.setAttribute('download', 'transactions.csv')\n\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(link.href)\n}\n\n/**\n * Formats a list of transactions into a list that will be used when\n * downloaded to a CSV file.\n */\nconst formatTransactions = (transactions: Transaction[], tags: Tag[]) => {\n return transactions.map((transaction) => ({\n Date: formatDate(fromUnixTime(transaction.date), DATE_FORMATS_INTL.YEAR_MONTH_DAY),\n Description: getDescription(transaction),\n 'Original Description': transaction.feed_description,\n Amount: `${transaction.amount}`,\n Type: transaction.transaction_type === TransactionType.CREDIT ? 'Credit' : 'Debit',\n 'Parent Category': CategoryGuidToName[transaction.top_level_category_guid || ''],\n Category: transaction.category,\n Account: transaction.account,\n Tags: getTags(transaction, tags),\n Memo: transaction.memo,\n Pending: transaction.isPending ? 'TRUE' : 'FALSE',\n })) as FormattedTransaction[]\n}\n\n/**\n * Escapes a value for safe CSV output\n */\nconst escapeCsvField = (field?: string | null): string => {\n if (!field) return ''\n return /[,\"\\n\\r]/.test(field) ? `\"${field.replace(/\"/g, '\"\"')}\"` : field\n}\n\n/**\n * Structures the CSV file data using the formatted transactions\n */\nconst structureCSVData = (formattedTransactions: FormattedTransaction[]) => {\n const csvHeader = Object.keys(formattedTransactions[0]).join(',').concat('\\r\\n')\n const csvRows = formattedTransactions\n .map((transaction) => Object.values(transaction).map(escapeCsvField).join(','))\n .join('\\r\\n')\n\n return csvHeader + csvRows\n}\n\n/**\n * Get the description for a transaction that will be used within the CSV copy.\n * We want to highlight that split transactions are a split as well as\n * hidden transactions are hidden.\n */\nconst getDescription = (transaction: Transaction) => {\n let description = transaction.parent_guid ? 'Split: ' : ''\n description += transaction.is_hidden ? '(Excluded) ' : ''\n description += transaction.description\n\n return description\n}\n\nconst getTags = (transaction: Transaction, tags: Tag[]) => {\n return transaction.tags\n .map((tagGuid) => {\n const tag = tags.filter((t) => t.guid === tagGuid)[0]\n\n return tag?.name ?? ''\n })\n .join(' ')\n}\n"],"names":["TransactionType","TransactionStatus","MONTHLY_AVERAGE_LENGTH","MONTHS_OF_HISTORY","augmentCategories","categories","copy","currentCategoryTotals","monthlyCategoryTotals","category","getDetailedCategory","c","getCategoryColor","guid","theme","categoryInfo","CategoryIconList","subCategories","parentGuid","isParent","currentAmount","t","monthlyAmounts","getMonthlyAmounts","total","totalMonthlyAmounts","detailedSubCategories","subCategory","totalAmount","current","name","getAverage","CategoryColors","CategoryIcon","CategoryGuids","getDetailedCategoryTransactions","detailedCategories","transactions","categoryTransactions","transaction","numMonths","monthsBack","categoryTotals","today","startOfToday","i","historyDate","startOfMonth","subMonths","format","acc","curr","formatDate","DATE_FORMATS_INTL","findDetailedCategory","dc","findDetailedSubCategory","parent","sc","TABLE_CONST","DEFAULT_TRANSACTION","COLUMN_NAMES","buildDetailedTransactions","accounts","taggings","accountsMap","account","categoriesMap","taggingsMap","tagging","transaction_guid","tag_guid","tags","UNCATEGORIZED_TERM","sortAndFilterTransactions","filter","expandedSplits","sortColumn","sortDirection","filteredTransactions","filterTransactions","sortedTransactions","sortTransactions","index","children","dateRange","endOfToday","custom","searchFilter","showSplits","getUnixTime","isTagIncludedInSearch","isIncludedInSearch","tag","date","fromUnixTime","ORDINAL_DATE_FORMAT","formatCurrency","a","b","column","sortCompare","sortASC","sortDESC","value","lowerCasedTerms","lowerCasedValue","extractParentTransactionGuids","tx","mapChildTransactionsByParent","accumulator","flattenTransactionsWithSplits","allTransactions","parentTransactionGuidsWithSplits","childTransactionsGroupedByParent","processedTransactionGuids","flattenedTransactionList","childTransaction","exportTransactionsToCSV","csvContent","structureCSVData","formatTransactions","blob","link","getDescription","CategoryGuidToName","getTags","escapeCsvField","field","formattedTransactions","csvHeader","csvRows","description","tagGuid"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { C as b, a as p, b as d } from "./Category-DEKZGLYe.mjs";
|
|
2
|
+
const _ = (e) => p[e] ?? p.default, f = (e) => d[e];
|
|
3
|
+
function C(e, t) {
|
|
4
|
+
const o = [], a = new Date(e);
|
|
5
|
+
for (; a <= t; ) {
|
|
6
|
+
const r = a.getFullYear(), n = String(a.getMonth() + 1).padStart(2, "0");
|
|
7
|
+
o.push(+`${r}${n}`), a.setMonth(a.getMonth() + 1);
|
|
8
|
+
}
|
|
9
|
+
return o;
|
|
10
|
+
}
|
|
11
|
+
const M = (e) => e.reduce((t, o) => {
|
|
12
|
+
const a = {
|
|
13
|
+
top_level_category_guid: o.top_level_category_guid,
|
|
14
|
+
category_guid: o.category_guid,
|
|
15
|
+
amount: o.total,
|
|
16
|
+
year_month: o.year_month
|
|
17
|
+
}, { top_level_category_guid: r, category_guid: n } = a;
|
|
18
|
+
return t[n] || (t[n] = []), t[n].push(a), r !== n && (t[r] || (t[r] = []), t[r].push(a)), t;
|
|
19
|
+
}, {}), E = (e, t, o) => {
|
|
20
|
+
const a = M(e), r = C(t, o);
|
|
21
|
+
return Object.entries(a).map(([n, c]) => {
|
|
22
|
+
const i = c[0].top_level_category_guid, g = r.map((l) => {
|
|
23
|
+
const s = c.filter((y) => y.year_month === l).reduce((y, h) => y + Math.abs(h.amount), 0), u = Number(String(l).slice(0, 4)), m = Number(String(l).slice(4));
|
|
24
|
+
return { x: new Date(u, m - 1), y: s };
|
|
25
|
+
}).sort((l, s) => l.x.getTime() - s.x.getTime());
|
|
26
|
+
return {
|
|
27
|
+
top_level_category_guid: i,
|
|
28
|
+
category_guid: n,
|
|
29
|
+
category_name: f(n),
|
|
30
|
+
category_color: _(i),
|
|
31
|
+
dataset: g
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}, N = (e, t) => {
|
|
35
|
+
const o = typeof e == "string" ? parseFloat(e.replace(/[^0-9.-]+/g, "")) : e, a = typeof t == "string" ? parseFloat(t.replace(/[^0-9.-]+/g, "")) : t;
|
|
36
|
+
return (o || 0) - (a || 0);
|
|
37
|
+
}, x = (e, t) => e.indexOf("General") >= 0 ? 1 : e.localeCompare(t), T = (e, t) => {
|
|
38
|
+
const o = e.subCategories.filter((n) => n.currentAmount !== 0), a = e.totalMonthlyAmounts.slice(-t), r = (n) => n.substring(0, 3) + " " + n.slice(-4);
|
|
39
|
+
return a.map((n) => {
|
|
40
|
+
const c = r(n.label), i = o.map((s) => {
|
|
41
|
+
const u = s.monthlyAmounts.slice(-t).find((m) => r(m.label) === c);
|
|
42
|
+
return {
|
|
43
|
+
label: s.name,
|
|
44
|
+
amount: Math.abs(u?.amount || 0),
|
|
45
|
+
header: c
|
|
46
|
+
};
|
|
47
|
+
}), g = e.monthlyAmounts.slice(-t).find((s) => r(s.label) === c);
|
|
48
|
+
return [{
|
|
49
|
+
label: e.name,
|
|
50
|
+
amount: Math.abs(g?.amount || 0),
|
|
51
|
+
header: c
|
|
52
|
+
}, ...i].sort((s, u) => u.amount - s.amount);
|
|
53
|
+
});
|
|
54
|
+
}, D = (e, t) => {
|
|
55
|
+
const o = e ? e.totalMonthlyAmounts.slice(-t).map((r) => ({
|
|
56
|
+
x: r.label.substring(0, 3),
|
|
57
|
+
y: Math.abs(r.amount)
|
|
58
|
+
})) : [], a = e ? T(e, t) : [];
|
|
59
|
+
return { monthlyAmounts: o, tooltipLabels: a };
|
|
60
|
+
}, L = (e) => e.slice().filter(
|
|
61
|
+
(t) => t.totalAmount !== 0 && !t.isTransfer && t.guid !== b.INVESTMENTS
|
|
62
|
+
).sort((t, o) => Math.abs(o.totalAmount) - Math.abs(t.totalAmount));
|
|
63
|
+
export {
|
|
64
|
+
N as a,
|
|
65
|
+
D as b,
|
|
66
|
+
x as c,
|
|
67
|
+
L as f,
|
|
68
|
+
E as g
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=TrendsUtil-D9z3kIj_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TrendsUtil-D9z3kIj_.mjs","sources":["../src/core/utils/TrendsUtil.ts"],"sourcesContent":["import { GridComparatorFn } from '@mui/x-data-grid-pro'\n\nimport { CategoryColors, CategoryGuids, CategoryGuidToName } from '../constants'\nimport { DetailedCategoryWithTransactions, MonthlyCategoryTotals } from '../types'\n\ntype DataPoint = { x: Date; y: number }\ntype Dataset = DataPoint[]\n\ntype CategoryTotalData = {\n top_level_category_guid: string\n category_guid: string\n amount: number\n year_month: number // e.g. 202409\n}\n\ntype GroupedCategoryTotalData = {\n [categoryGuid: string]: CategoryTotalData[]\n}\n\nexport interface StackedLineChartData {\n top_level_category_guid: string\n category_guid: string\n category_name: string\n category_color: string\n dataset: Dataset\n}\n\nconst getCategoryColor = (categoryGuid: string): string => {\n return CategoryColors[categoryGuid] ?? CategoryColors.default\n}\n\nconst getCategoryName = (categoryGuid: string): string => {\n return CategoryGuidToName[categoryGuid]\n}\n\nfunction createYearMonthRange(start: Date, end: Date): number[] {\n const result = []\n const current = new Date(start)\n\n while (current <= end) {\n const year = current.getFullYear()\n const month = String(current.getMonth() + 1).padStart(2, '0')\n result.push(Number(`${year}${month}`))\n current.setMonth(current.getMonth() + 1)\n }\n\n return result\n}\n\nconst createGroupedCategoryTotals = (totals: MonthlyCategoryTotals[]): GroupedCategoryTotalData => {\n return totals.reduce((result, item) => {\n const totalData: CategoryTotalData = {\n top_level_category_guid: item.top_level_category_guid,\n category_guid: item.category_guid,\n amount: item.total,\n year_month: item.year_month,\n }\n\n const { top_level_category_guid, category_guid } = totalData\n\n // Ensure category bucket exists\n if (!result[category_guid]) {\n result[category_guid] = []\n }\n result[category_guid].push(totalData)\n\n // Ensure top-level category bucket exists (if different than category)\n if (top_level_category_guid !== category_guid) {\n if (!result[top_level_category_guid]) {\n result[top_level_category_guid] = []\n }\n result[top_level_category_guid].push(totalData)\n }\n\n return result\n }, {} as GroupedCategoryTotalData)\n}\n\nexport const getStackedLineChartData = (\n totals: MonthlyCategoryTotals[],\n start: Date,\n end: Date,\n): StackedLineChartData[] => {\n const groupedTotals = createGroupedCategoryTotals(totals)\n const yearMonths = createYearMonthRange(start, end)\n\n return Object.entries(groupedTotals).map(([categoryGuid, totals]) => {\n const topLevelCategoryGuid = totals[0].top_level_category_guid\n // Build dataset for current category\n const dataset: Dataset = yearMonths\n // Build chart coordinates and fill missing totals with 0\n .map((yearMonth) => {\n // Sum category totals for same month\n // (totals with same top_level_category_guid but different category_guid)\n // And fill missing totals with 0\n // (necessary for StackedLineChart lines to be smooth)\n const sumTotal = totals\n .filter((total) => total.year_month === yearMonth)\n .reduce((sum, total) => sum + Math.abs(total.amount), 0)\n\n const year = Number(String(yearMonth).slice(0, 4))\n const month = Number(String(yearMonth).slice(4))\n const date = new Date(year, month - 1)\n\n return { x: date, y: sumTotal }\n })\n .sort((a, b) => a.x.getTime() - b.x.getTime())\n\n return {\n top_level_category_guid: topLevelCategoryGuid,\n category_guid: categoryGuid,\n category_name: getCategoryName(categoryGuid),\n category_color: getCategoryColor(topLevelCategoryGuid),\n dataset: dataset,\n }\n })\n}\n\nexport const amountComparator: GridComparatorFn<string | number> = (v1, v2) => {\n const num1 = typeof v1 === 'string' ? parseFloat(v1.replace(/[^0-9.-]+/g, '')) : v1\n const num2 = typeof v2 === 'string' ? parseFloat(v2.replace(/[^0-9.-]+/g, '')) : v2\n\n return (num1 || 0) - (num2 || 0)\n}\n\nexport const categoryComparator: GridComparatorFn<string> = (cat1, cat2) => {\n // Always keep \"General\" categories at the bottom of the list\n return cat1.indexOf('General') >= 0 ? 1 : cat1.localeCompare(cat2)\n}\n\nconst buildTooltipLabels = (data: DetailedCategoryWithTransactions, monthsCount: number) => {\n const subcategories = data.subCategories.filter((subcategory) => subcategory.currentAmount !== 0)\n const monthsData = data.totalMonthlyAmounts.slice(-monthsCount)\n\n const formatMonthLabel = (label: string) => label.substring(0, 3) + ' ' + label.slice(-4)\n\n return monthsData.map((monthData) => {\n const monthLabel = formatMonthLabel(monthData.label)\n\n const subcategoryEntries = subcategories.map((subcategory) => {\n const monthEntry = subcategory.monthlyAmounts\n .slice(-monthsCount)\n .find((entry) => formatMonthLabel(entry.label) === monthLabel)\n\n return {\n label: subcategory.name,\n amount: Math.abs(monthEntry?.amount || 0),\n header: monthLabel,\n }\n })\n\n const parentMonthEntry = data.monthlyAmounts\n .slice(-monthsCount)\n .find((entry) => formatMonthLabel(entry.label) === monthLabel)\n\n const parentEntry = {\n label: data.name,\n amount: Math.abs(parentMonthEntry?.amount || 0),\n header: monthLabel,\n }\n\n return [parentEntry, ...subcategoryEntries].sort((a, b) => b.amount - a.amount)\n })\n}\n\nexport const buildCategoryDetailsChartData = (\n data: DetailedCategoryWithTransactions | null,\n monthsCount: number,\n) => {\n const monthlyAmounts = data\n ? data.totalMonthlyAmounts.slice(-monthsCount).map((monthData) => ({\n x: monthData.label.substring(0, 3),\n y: Math.abs(monthData.amount),\n }))\n : []\n\n const tooltipLabels = data ? buildTooltipLabels(data, monthsCount) : []\n\n return { monthlyAmounts, tooltipLabels }\n}\n\nexport const filterAndSortCategoriesWithTransactions = (\n categories: DetailedCategoryWithTransactions[],\n): DetailedCategoryWithTransactions[] => {\n return categories\n .slice()\n .filter(\n (category) =>\n category.totalAmount !== 0 &&\n !category.isTransfer &&\n category.guid !== CategoryGuids.INVESTMENTS,\n )\n .sort((a, b) => Math.abs(b.totalAmount) - Math.abs(a.totalAmount))\n}\n"],"names":["getCategoryColor","categoryGuid","CategoryColors","getCategoryName","CategoryGuidToName","createYearMonthRange","start","end","result","current","year","month","createGroupedCategoryTotals","totals","item","totalData","top_level_category_guid","category_guid","getStackedLineChartData","groupedTotals","yearMonths","topLevelCategoryGuid","dataset","yearMonth","sumTotal","total","sum","a","b","amountComparator","v1","v2","num1","num2","categoryComparator","cat1","cat2","buildTooltipLabels","data","monthsCount","subcategories","subcategory","monthsData","formatMonthLabel","label","monthData","monthLabel","subcategoryEntries","monthEntry","entry","parentMonthEntry","buildCategoryDetailsChartData","monthlyAmounts","tooltipLabels","filterAndSortCategoriesWithTransactions","categories","category","CategoryGuids"],"mappings":"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"}
|