@mx-cartographer/experiences 9.4.58 → 9.4.59
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 +8 -0
- package/dist/core/api/UserApi.d.ts +2 -1
- package/dist/core/api/UserApi.es.js +6 -5
- package/dist/core/api/UserApi.es.js.map +1 -1
- package/dist/core/constants/ApiEndpoints.d.ts +1 -0
- package/dist/core/constants/ApiEndpoints.es.js +1 -0
- package/dist/core/constants/ApiEndpoints.es.js.map +1 -1
- package/dist/core/stores/AccountStore.d.ts +2 -1
- package/dist/core/stores/AccountStore.es.js +16 -16
- package/dist/core/stores/AccountStore.es.js.map +1 -1
- package/dist/core/stores/BeatStore.d.ts +6 -0
- package/dist/core/stores/BeatStore.es.js +30 -17
- package/dist/core/stores/BeatStore.es.js.map +1 -1
- package/dist/core/stores/BudgetsStore.d.ts +2 -1
- package/dist/core/stores/BudgetsStore.es.js +8 -8
- package/dist/core/stores/BudgetsStore.es.js.map +1 -1
- package/dist/core/stores/InsightsV2Store.es.js.map +1 -1
- package/dist/core/stores/SettingsStore.d.ts +2 -1
- package/dist/core/stores/SettingsStore.es.js +11 -11
- package/dist/core/stores/SettingsStore.es.js.map +1 -1
- package/dist/core/stores/TransactionStore.d.ts +4 -2
- package/dist/core/stores/TransactionStore.es.js +6 -6
- package/dist/core/stores/TransactionStore.es.js.map +1 -1
- package/dist/core/stores/UserStore.d.ts +15 -1
- package/dist/core/stores/UserStore.es.js +21 -3
- package/dist/core/stores/UserStore.es.js.map +1 -1
- package/dist/core/types/RepeatingTransaction.d.ts +2 -0
- package/dist/core/types/RepeatingTransaction.es.js.map +1 -1
- package/dist/core/types/User.d.ts +11 -0
- package/dist/core/types/index.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [9.4.59] - 10-07-2026
|
|
2
|
+
|
|
3
|
+
- **ADDED** - `UserInsightProfile` type, `ApiEndpoints.USER_INSIGHT_PROFILE`, `UserApi.updateUserInsightProfile` (`PUT user_insight_profile`) and `UserStore.userInsightProfile` with `setUserInsightProfile` (the host seeds the profile it loaded) and `updateUserInsightProfile`, which merges the changed fields over the seeded profile and PUTs the whole profile (the endpoint upserts every field, so a partial body would null the rest), refuses to PUT before the profile is seeded, and rethrows so a caller can surface a failed save (WEC-1852)
|
|
4
|
+
- **ADDED** - `BeatStore.updateOffer` (`PUT offers/:guid`) to flag a marketing offer as clicked; rethrows on failure (WEC-1852)
|
|
5
|
+
- **ADDED** - `RepeatingTransaction.user_response` field (WEC-1852)
|
|
6
|
+
- **CHANGED** - `AccountStore.updateAccount`, `SettingsStore.updateNotificationProfile`, `TransactionStore.updateTransaction`, `TransactionStore.addOrUpdateTransactionRule` and `BudgetsStore.addBudget` now resolve `true` on success and `false` when the API call fails, instead of resolving `undefined` either way. They still catch and report their own errors and never throw, so existing callers are unaffected; the flag lets a caller distinguish a failed write (WEC-1852)
|
|
7
|
+
- **ADDED** - MSW handlers and mock data for `PUT user_insight_profile` and `PUT offers/:guid` (WEC-1852)
|
|
8
|
+
|
|
1
9
|
## [9.4.58] - 10-07-2026
|
|
2
10
|
|
|
3
11
|
- **ADDED** - Insights V2 `ErrorCard` and `LoadingCard` components, plus `isError`/`isLoading` props on `BaseLayout`: `isError` replaces the entire card with the `ErrorCard` (heading, message, and a "Try Again" retry button that reloads by default), while `isLoading` swaps only the block slot for the `LoadingCard`. `ErrorCard` derives the CIBC illustration variant from the app's `custom_copy_namespace`. Added `error_heading`, `error_message`, `loading`, and `try_again` copy keys under `insights_feed.general`, with stories for all three states (WEC-1854)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Fetch } from '../utils';
|
|
2
|
-
import { GlobalErrorHandler, User, UserProfile } from '..';
|
|
2
|
+
import { GlobalErrorHandler, User, UserInsightProfile, UserProfile } from '..';
|
|
3
3
|
export declare class UserApi {
|
|
4
4
|
fetchInstance: Fetch;
|
|
5
5
|
constructor(endpoint: string, token: string, onError?: GlobalErrorHandler);
|
|
6
6
|
getUserFeatures: () => Promise<any>;
|
|
7
7
|
updateUser: (user: User) => Promise<any>;
|
|
8
8
|
updateUserProfile: (userProfile: UserProfile) => Promise<any>;
|
|
9
|
+
updateUserInsightProfile: (profile: Partial<UserInsightProfile>) => Promise<UserInsightProfile>;
|
|
9
10
|
}
|
|
@@ -2,12 +2,13 @@ import { ApiEndpoints as s } from "../constants/ApiEndpoints.es.js";
|
|
|
2
2
|
import { Fetch as r } from "../utils/Fetch.es.js";
|
|
3
3
|
var h = class {
|
|
4
4
|
fetchInstance;
|
|
5
|
-
constructor(
|
|
6
|
-
this.fetchInstance = new r(
|
|
5
|
+
constructor(e, t, n) {
|
|
6
|
+
this.fetchInstance = new r(e, t, void 0, n);
|
|
7
7
|
}
|
|
8
|
-
getUserFeatures = async () => this.fetchInstance.get(s.USER_FEATURES).then((
|
|
9
|
-
updateUser = async (
|
|
10
|
-
updateUserProfile = async (
|
|
8
|
+
getUserFeatures = async () => this.fetchInstance.get(s.USER_FEATURES).then((e) => e.user_features);
|
|
9
|
+
updateUser = async (e) => this.fetchInstance.put(s.USER, e).then((t) => t.user);
|
|
10
|
+
updateUserProfile = async (e) => this.fetchInstance.put(`${s.USER_PROFILES}/${e.guid}`, e).then((t) => t.user_profile);
|
|
11
|
+
updateUserInsightProfile = async (e) => this.fetchInstance.put(s.USER_INSIGHT_PROFILE, { user_insight_profile: e }).then((t) => t.user_insight_profile);
|
|
11
12
|
};
|
|
12
13
|
export {
|
|
13
14
|
h as UserApi
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserApi.es.js","names":[],"sources":["../../../src/core/api/UserApi.ts"],"sourcesContent":["import { Fetch } from '../utils'\nimport { ApiEndpoints } from '../constants'\nimport type { GlobalErrorHandler, User, UserProfile } from '..'\n\nexport class UserApi {\n fetchInstance: Fetch\n\n constructor(endpoint: string, token: string, onError?: GlobalErrorHandler) {\n this.fetchInstance = new Fetch(endpoint, token, undefined, onError)\n }\n\n getUserFeatures = async () => {\n return this.fetchInstance.get(ApiEndpoints.USER_FEATURES).then((data) => data.user_features)\n }\n\n updateUser = async (user: User) => {\n return this.fetchInstance.put(ApiEndpoints.USER, user).then((data) => data.user)\n }\n\n updateUserProfile = async (userProfile: UserProfile) => {\n return this.fetchInstance\n .put(`${ApiEndpoints.USER_PROFILES}/${userProfile.guid}`, userProfile)\n .then((data) => data.user_profile)\n }\n}\n"],"mappings":";;AAIA,IAAa,IAAb,MAAqB;AAAA,EACnB;AAAA,EAEA,YAAY,GAAkB,GAAe,GAA8B;AACzE,SAAK,gBAAgB,IAAI,EAAM,GAAU,GAAO,QAAW,CAAO;AAAA,EACpE;AAAA,EAEA,kBAAkB,YACT,KAAK,cAAc,IAAI,EAAa,aAAa,EAAE,KAAA,CAAM,MAAS,EAAK,aAAa;AAAA,EAG7F,aAAa,OAAO,MACX,KAAK,cAAc,IAAI,EAAa,MAAM,CAAI,EAAE,KAAA,CAAM,MAAS,EAAK,IAAI;AAAA,EAGjF,oBAAoB,OAAO,MAClB,KAAK,cACT,IAAI,GAAG,EAAa,aAAA,IAAiB,EAAY,IAAA,IAAQ,CAAW,EACpE,KAAA,CAAM,MAAS,EAAK,YAAY;
|
|
1
|
+
{"version":3,"file":"UserApi.es.js","names":[],"sources":["../../../src/core/api/UserApi.ts"],"sourcesContent":["import { Fetch } from '../utils'\nimport { ApiEndpoints } from '../constants'\nimport type { GlobalErrorHandler, User, UserInsightProfile, UserProfile } from '..'\n\nexport class UserApi {\n fetchInstance: Fetch\n\n constructor(endpoint: string, token: string, onError?: GlobalErrorHandler) {\n this.fetchInstance = new Fetch(endpoint, token, undefined, onError)\n }\n\n getUserFeatures = async () => {\n return this.fetchInstance.get(ApiEndpoints.USER_FEATURES).then((data) => data.user_features)\n }\n\n updateUser = async (user: User) => {\n return this.fetchInstance.put(ApiEndpoints.USER, user).then((data) => data.user)\n }\n\n updateUserProfile = async (userProfile: UserProfile) => {\n return this.fetchInstance\n .put(`${ApiEndpoints.USER_PROFILES}/${userProfile.guid}`, userProfile)\n .then((data) => data.user_profile)\n }\n\n // The endpoint is singular per user, so no guid in the path (mirrors pulse FireflyAPI).\n updateUserInsightProfile = async (\n profile: Partial<UserInsightProfile>,\n ): Promise<UserInsightProfile> => {\n return this.fetchInstance\n .put(ApiEndpoints.USER_INSIGHT_PROFILE, { user_insight_profile: profile })\n .then((data) => data.user_insight_profile)\n }\n}\n"],"mappings":";;AAIA,IAAa,IAAb,MAAqB;AAAA,EACnB;AAAA,EAEA,YAAY,GAAkB,GAAe,GAA8B;AACzE,SAAK,gBAAgB,IAAI,EAAM,GAAU,GAAO,QAAW,CAAO;AAAA,EACpE;AAAA,EAEA,kBAAkB,YACT,KAAK,cAAc,IAAI,EAAa,aAAa,EAAE,KAAA,CAAM,MAAS,EAAK,aAAa;AAAA,EAG7F,aAAa,OAAO,MACX,KAAK,cAAc,IAAI,EAAa,MAAM,CAAI,EAAE,KAAA,CAAM,MAAS,EAAK,IAAI;AAAA,EAGjF,oBAAoB,OAAO,MAClB,KAAK,cACT,IAAI,GAAG,EAAa,aAAA,IAAiB,EAAY,IAAA,IAAQ,CAAW,EACpE,KAAA,CAAM,MAAS,EAAK,YAAY;AAAA,EAIrC,2BAA2B,OACzB,MAEO,KAAK,cACT,IAAI,EAAa,sBAAsB,EAAE,sBAAsB,EAAQ,CAAC,EACxE,KAAA,CAAM,MAAS,EAAK,oBAAoB;AAE/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiEndpoints.es.js","names":[],"sources":["../../../src/core/constants/ApiEndpoints.ts"],"sourcesContent":["export const ApiEndpoints = {\n ACCOUNTS: 'accounts',\n ANALYTICS_EVENTS: 'analytics_events',\n ANALYTICS_FEATURE_VISITS: 'feature_visits',\n ANALYTICS_PAGEVIEWS: 'analytics_pageviews',\n ANALYTICS_SESSION: 'analytics_sessions',\n APP_DATA: 'raja/data?type=master',\n BEATS: 'beats',\n BUDGETS: 'budgets',\n CATEGORIES: 'categories',\n CHANGE_PASSWORD: 'user/change_password',\n DATE_RANGE_CATEGORY_TOTALS: 'date_range_category_totals',\n DEVICES: 'devices',\n EMAIL_VERIFICATIONS: 'email_verifications',\n GOALS: 'goals',\n HEALTH_SCORES: 'health_scores',\n HOLDINGS: 'holdings',\n INSTITUTIONS: 'institutions',\n INSIGHTS_NOTIFICATION_PROFILES: 'insight_notification_profiles',\n LOCALIZED_COPY: 'localized_copies',\n LOCALIZED_CONTENT: 'localized_content',\n MEMBERS: 'members',\n MERCHANTS: 'merchants',\n MERCHANT_BUDGETS: 'merchant_budgets',\n MONTHLY_CASH_FLOW_PROFILE: 'monthly_cash_flow_profile',\n MONTHLY_CATEGORY_TOTALS: 'monthly_category_totals',\n OFFERS: 'offers',\n NOTIFICATION_PROFILES: 'notification_profiles',\n NOTIFICATIONS: 'notifications',\n PHONE_VERIFICATIONS: 'sms_verification',\n PULSE_COMMUNICATIONS: 'pulse_communications',\n REPEATING_TRANSACTIONS: 'repeating_transactions',\n RETIREMENT_GOALS: 'retirement_goals',\n RETIREMENT_GOAL_ACCOUNTS: 'retirement_goal_accounts',\n SCHEDULED_PAYMENTS: 'scheduled_payments',\n SPENDING_PLANS: 'spending_plans',\n SUPPORT_TICKETS: 'support_tickets',\n TAGGINGS: 'taggings',\n TAGS: 'tags',\n TRANSACTION_RULES: 'transaction_rules',\n TRANSACTIONS: 'transactions',\n USER: 'user',\n USER_COMMUNICATION_PROFILE: 'user_communication_profile',\n USER_FEATURES: 'user_features',\n USER_PROFILES: 'user_profiles',\n WIDGET_URLS: 'widget_urls',\n}\n"],"mappings":"AAAA,IAAa,IAAe;AAAA,EAC1B,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,4BAA4B;AAAA,EAC5B,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,OAAO;AAAA,EACP,eAAe;AAAA,EACf,UAAU;AAAA,EACV,cAAc;AAAA,EACd,gCAAgC;AAAA,EAChC,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,2BAA2B;AAAA,EAC3B,yBAAyB;AAAA,EACzB,QAAQ;AAAA,EACR,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,MAAM;AAAA,EACN,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,MAAM;AAAA,EACN,4BAA4B;AAAA,EAC5B,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AACf"}
|
|
1
|
+
{"version":3,"file":"ApiEndpoints.es.js","names":[],"sources":["../../../src/core/constants/ApiEndpoints.ts"],"sourcesContent":["export const ApiEndpoints = {\n ACCOUNTS: 'accounts',\n ANALYTICS_EVENTS: 'analytics_events',\n ANALYTICS_FEATURE_VISITS: 'feature_visits',\n ANALYTICS_PAGEVIEWS: 'analytics_pageviews',\n ANALYTICS_SESSION: 'analytics_sessions',\n APP_DATA: 'raja/data?type=master',\n BEATS: 'beats',\n BUDGETS: 'budgets',\n CATEGORIES: 'categories',\n CHANGE_PASSWORD: 'user/change_password',\n DATE_RANGE_CATEGORY_TOTALS: 'date_range_category_totals',\n DEVICES: 'devices',\n EMAIL_VERIFICATIONS: 'email_verifications',\n GOALS: 'goals',\n HEALTH_SCORES: 'health_scores',\n HOLDINGS: 'holdings',\n INSTITUTIONS: 'institutions',\n INSIGHTS_NOTIFICATION_PROFILES: 'insight_notification_profiles',\n LOCALIZED_COPY: 'localized_copies',\n LOCALIZED_CONTENT: 'localized_content',\n MEMBERS: 'members',\n MERCHANTS: 'merchants',\n MERCHANT_BUDGETS: 'merchant_budgets',\n MONTHLY_CASH_FLOW_PROFILE: 'monthly_cash_flow_profile',\n MONTHLY_CATEGORY_TOTALS: 'monthly_category_totals',\n OFFERS: 'offers',\n NOTIFICATION_PROFILES: 'notification_profiles',\n NOTIFICATIONS: 'notifications',\n PHONE_VERIFICATIONS: 'sms_verification',\n PULSE_COMMUNICATIONS: 'pulse_communications',\n REPEATING_TRANSACTIONS: 'repeating_transactions',\n RETIREMENT_GOALS: 'retirement_goals',\n RETIREMENT_GOAL_ACCOUNTS: 'retirement_goal_accounts',\n SCHEDULED_PAYMENTS: 'scheduled_payments',\n SPENDING_PLANS: 'spending_plans',\n SUPPORT_TICKETS: 'support_tickets',\n TAGGINGS: 'taggings',\n TAGS: 'tags',\n TRANSACTION_RULES: 'transaction_rules',\n TRANSACTIONS: 'transactions',\n USER: 'user',\n USER_COMMUNICATION_PROFILE: 'user_communication_profile',\n USER_FEATURES: 'user_features',\n USER_INSIGHT_PROFILE: 'user_insight_profile',\n USER_PROFILES: 'user_profiles',\n WIDGET_URLS: 'widget_urls',\n}\n"],"mappings":"AAAA,IAAa,IAAe;AAAA,EAC1B,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,4BAA4B;AAAA,EAC5B,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,OAAO;AAAA,EACP,eAAe;AAAA,EACf,UAAU;AAAA,EACV,cAAc;AAAA,EACd,gCAAgC;AAAA,EAChC,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,2BAA2B;AAAA,EAC3B,yBAAyB;AAAA,EACzB,QAAQ;AAAA,EACR,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,MAAM;AAAA,EACN,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,MAAM;AAAA,EACN,4BAA4B;AAAA,EAC5B,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,aAAa;AACf"}
|
|
@@ -53,7 +53,8 @@ export declare class AccountStore {
|
|
|
53
53
|
refreshAccounts: () => Promise<void>;
|
|
54
54
|
refreshMembers: () => Promise<void>;
|
|
55
55
|
removeAccount: (accountGuid: string) => Promise<void>;
|
|
56
|
-
|
|
56
|
+
/** Resolves `true` when the account was saved, `false` when the API call failed. */
|
|
57
|
+
updateAccount: (account: Account) => Promise<boolean>;
|
|
57
58
|
updateAccountBalance: (accountGuid: string, balanceChange: number) => void;
|
|
58
59
|
updateAccountFilter: (accountMap: Map<string, boolean>) => Promise<void>;
|
|
59
60
|
}
|
|
@@ -37,8 +37,8 @@ var C = class {
|
|
|
37
37
|
get accountsByTypeMap() {
|
|
38
38
|
return this.detailedAccounts.reduce((t, e) => {
|
|
39
39
|
const s = e.account_type;
|
|
40
|
-
let
|
|
41
|
-
return
|
|
40
|
+
let n = t.get(s);
|
|
41
|
+
return n || (n = []), n.push(e), t.set(s, n), t;
|
|
42
42
|
}, /* @__PURE__ */ new Map());
|
|
43
43
|
}
|
|
44
44
|
get cashAccounts() {
|
|
@@ -163,9 +163,9 @@ var C = class {
|
|
|
163
163
|
try {
|
|
164
164
|
const e = await this.api.mergeAccounts(t), s = e[Object.keys(e)[0]];
|
|
165
165
|
d(() => {
|
|
166
|
-
const
|
|
167
|
-
this.accounts.splice(
|
|
168
|
-
const i = this.accounts.findIndex((
|
|
166
|
+
const n = this.accounts.findIndex((o) => o.guid === t[1]);
|
|
167
|
+
this.accounts.splice(n, 1);
|
|
168
|
+
const i = this.accounts.findIndex((o) => o.guid === t[0]);
|
|
169
169
|
this.accounts.splice(i, 1, s);
|
|
170
170
|
});
|
|
171
171
|
} catch (e) {
|
|
@@ -197,14 +197,14 @@ var C = class {
|
|
|
197
197
|
};
|
|
198
198
|
updateAccount = async (t) => {
|
|
199
199
|
try {
|
|
200
|
-
const e = await this.api.updateAccount(t), s = this.accounts.findIndex((
|
|
201
|
-
this.accounts.splice(s, 1, e);
|
|
200
|
+
const e = await this.api.updateAccount(t), s = this.accounts.findIndex((n) => n.guid === e.guid);
|
|
201
|
+
return this.accounts.splice(s, 1, e), !0;
|
|
202
202
|
} catch (e) {
|
|
203
|
-
console.error("Error occurred while updating account:", e), this.globalStore.captureException(e, { store: "AccountStore" });
|
|
203
|
+
return console.error("Error occurred while updating account:", e), this.globalStore.captureException(e, { store: "AccountStore" }), !1;
|
|
204
204
|
}
|
|
205
205
|
};
|
|
206
206
|
updateAccountBalance = (t, e) => {
|
|
207
|
-
const s = this.accounts.find((
|
|
207
|
+
const s = this.accounts.find((n) => n.guid === t);
|
|
208
208
|
s && d(() => {
|
|
209
209
|
s.balance = (s.balance || 0) + e;
|
|
210
210
|
});
|
|
@@ -212,22 +212,22 @@ var C = class {
|
|
|
212
212
|
updateAccountFilter = async (t) => {
|
|
213
213
|
try {
|
|
214
214
|
const e = [];
|
|
215
|
-
for (const [i,
|
|
215
|
+
for (const [i, o] of t.entries()) {
|
|
216
216
|
const r = this.accounts.find((u) => u.guid === i);
|
|
217
|
-
if (r && r.is_excluded_from_accounts ===
|
|
217
|
+
if (r && r.is_excluded_from_accounts === o) {
|
|
218
218
|
const u = {
|
|
219
219
|
...r,
|
|
220
|
-
is_excluded_from_accounts: !
|
|
220
|
+
is_excluded_from_accounts: !o
|
|
221
221
|
};
|
|
222
222
|
e.push(this.api.updateAccount(u).catch((l) => (console.error("Error occurred while updating account filter:", l), this.globalStore.captureException(l, { store: "AccountStore" }), null)));
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
const s = (await Promise.all(e)).filter((i) => i !== null),
|
|
225
|
+
const s = (await Promise.all(e)).filter((i) => i !== null), n = [...this.accounts];
|
|
226
226
|
for (const i of s) {
|
|
227
|
-
const
|
|
228
|
-
|
|
227
|
+
const o = n.findIndex((r) => r.guid === i.guid);
|
|
228
|
+
o !== -1 && n.splice(o, 1, i);
|
|
229
229
|
}
|
|
230
|
-
this.setAccounts(
|
|
230
|
+
this.setAccounts(n);
|
|
231
231
|
} catch (e) {
|
|
232
232
|
console.error("Error occurred while updating account filter:", e), this.globalStore.captureException(e, { store: "AccountStore" });
|
|
233
233
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountStore.es.js","names":[],"sources":["../../../src/core/stores/AccountStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { AccountApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport {\n type Account,\n type DetailedAccount,\n type Institution,\n type Member,\n AccountType,\n AccountSubType,\n} from '../types'\nimport { augmentAccounts } from '../utils/AccountUtils'\nimport { isFeatureEnabled } from '../utils/UserUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class AccountStore {\n globalStore: GlobalStore\n api: AccountApi = new AccountApi('/', '')\n\n accounts: Account[] = []\n accountsLoaded: boolean = false\n accountsLoading: boolean = false\n institutions: Institution[] = []\n institutionsLoaded: boolean = false\n institutionsLoading: boolean = false\n members: Member[] = []\n membersLoaded: boolean = false\n membersLoading: boolean = false\n uiStore: UiStore\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new AccountApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadAccountData = async () => {\n await Promise.all([this.loadAccounts(), this.loadMembers(), this.loadInstitutions()])\n }\n\n get isAccountDataLoaded(): boolean {\n return this.accountsLoaded && this.membersLoaded && this.institutionsLoaded\n }\n\n get detailedAccounts(): DetailedAccount[] {\n const userFeatures = this.globalStore.userStore.userFeatures\n const excludeExternal = isFeatureEnabled(userFeatures, 'MD_EXCLUDE_EXTERNAL_ACCOUNTS')\n\n // Hide held account when this flag is toggled and this is the individual accounts widget\n const excludeHeld =\n this.globalStore.appConfig.config.display_only_external_accounts_in_accounts &&\n this.globalStore.appConfig.options.subtype === 'accounts' // Indicates this is an individual widget\n\n return augmentAccounts(\n this.accounts,\n this.institutions,\n this.members,\n excludeExternal,\n excludeHeld,\n )\n }\n\n get accountsByTypeMap(): Map<AccountType, DetailedAccount[]> {\n return this.detailedAccounts.reduce((typeMap: Map<AccountType, DetailedAccount[]>, account) => {\n const accountType = account.account_type\n\n let accounts = typeMap.get(accountType)\n if (!accounts) {\n accounts = []\n }\n accounts.push(account)\n typeMap.set(accountType, accounts)\n\n return typeMap\n }, new Map<AccountType, DetailedAccount[]>())\n }\n\n get cashAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.CASH ||\n account.account_type === AccountType.CHECKING ||\n account.account_type === AccountType.PREPAID ||\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING_LINE_OF_CREDIT,\n )\n }\n\n get cashBalance(): number {\n return this.cashAccounts.reduce((total, account) => total + (account?.balance || 0), 0)\n }\n\n get checkingAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => a.account_type === AccountType.CHECKING)\n }\n\n get debtAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.CREDIT_CARD ||\n account.account_type === AccountType.LOAN ||\n account.account_type === AccountType.MORTGAGE ||\n account.account_type === AccountType.LINE_OF_CREDIT ||\n account.account_type === AccountType.CHECKING_LINE_OF_CREDIT,\n )\n }\n\n get finstrongAccounts(): DetailedAccount[] {\n const eligibleTypes = new Set([\n AccountType.CHECKING,\n AccountType.SAVINGS,\n AccountType.CREDIT_CARD,\n AccountType.INVESTMENT,\n ])\n\n return this.detailedAccounts.filter((account) => eligibleTypes.has(account.account_type))\n }\n\n get investmentAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) => account.account_type === AccountType.INVESTMENT,\n )\n }\n\n get manualAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((account) => account.is_manual)\n }\n\n get savingsAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => a.account_type === AccountType.SAVINGS)\n }\n\n get retirementAccounts(): Account[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.INVESTMENT ||\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING ||\n account.account_type === AccountType.CASH ||\n account.account_type === AccountType.PROPERTY ||\n (account.account_type === AccountType.INSURANCE &&\n (account.account_subtype === AccountSubType.WHOLE_LIFE ||\n account.account_subtype === AccountSubType.UNIVERSAL_LIFE ||\n account.account_subtype === AccountSubType.VARIABLE_UNIVERSAL_LIFE)),\n )\n }\n\n get visibleAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => !a.is_hidden && !a.is_closed)\n }\n\n get visibleCashAccounts(): DetailedAccount[] {\n return this.cashAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleCashBalance(): number {\n return this.visibleCashAccounts.reduce((total, account) => total + (account?.balance || 0), 0)\n }\n\n get visibleCheckingAccounts(): DetailedAccount[] {\n return this.checkingAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleDebtAccounts(): DetailedAccount[] {\n return this.debtAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleFinstrongAccounts(): DetailedAccount[] {\n return this.finstrongAccounts.filter(\n (account: Account) => !(account.is_closed || account.is_deleted || account.is_hidden),\n )\n }\n\n get visibleRetirementAccounts(): Account[] {\n return this.retirementAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleInvestmentAccounts(): DetailedAccount[] {\n return this.investmentAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleSavingsAccounts(): DetailedAccount[] {\n return this.savingsAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get savingsAndCheckingAccountsBalance(): number {\n const savingsAndCheckingAccountsList = this.savingsAndCheckingAccounts\n\n return savingsAndCheckingAccountsList.reduce(\n (total, account) => total + (account?.balance || 0),\n 0,\n )\n }\n\n get savingsAndCheckingAccounts(): Account[] {\n const savingsAndCheckingAccounts = this.accounts.filter(\n (account: Account) =>\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING,\n )\n\n return savingsAndCheckingAccounts\n }\n\n setAccounts = (accounts: Account[]) => {\n this.accounts = accounts\n this.accountsLoading = false\n this.accountsLoaded = true\n }\n\n setMembers = (members: Member[]) => {\n this.members = members\n this.membersLoading = false\n this.membersLoaded = true\n }\n\n setInstitutions = (institutions: Institution[]) => {\n this.institutions = institutions\n this.institutionsLoading = false\n this.institutionsLoaded = true\n }\n\n addAccount = async (account: Account) => {\n try {\n const newAccount = await this.api.createAccount(account)\n\n runInAction(() => {\n this.accounts = upsertByGuid(this.accounts, newAccount)\n })\n } catch (error) {\n console.error('Error occurred while adding an account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n loadAccounts = async () => {\n if (this.accountsLoading) return\n\n this.accountsLoading = true\n try {\n const accounts = await this.api.getAccounts()\n this.setAccounts(accounts)\n } catch (error) {\n console.error('Error occurred while loading accounts:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setAccounts([])\n }\n }\n\n loadInstitutions = async () => {\n if (this.institutionsLoading) return\n\n this.institutionsLoading = true\n try {\n const institutions = await this.api.getInstitutions()\n this.setInstitutions(institutions)\n } catch (error) {\n console.error('Error occurred while loading institutions:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setInstitutions([])\n }\n }\n\n loadMembers = async () => {\n if (this.membersLoading) return\n\n this.membersLoading = true\n try {\n const members = await this.api.getMembers()\n this.setMembers(members)\n } catch (error) {\n console.error('Error occurred while loading members:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setMembers([])\n }\n }\n\n mergeAccounts = async (accountGuids: string[]) => {\n try {\n const response = await this.api.mergeAccounts(accountGuids)\n // the response from the api is a funky database key here, so this is essentially just getting the first item in the returned object\n // to prevent making multiple api calls here\n const mergedAccount = response[Object.keys(response)[0]]\n\n runInAction(() => {\n const account2Index = this.accounts.findIndex((account) => account.guid === accountGuids[1])\n this.accounts.splice(account2Index, 1)\n\n const account1Index = this.accounts.findIndex((account) => account.guid === accountGuids[0])\n this.accounts.splice(account1Index, 1, mergedAccount)\n })\n } catch (error) {\n console.error('Error occurred while merging accounts:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n /**\n * DEPRECATED: Use loadAccountData instead\n */\n refreshAccounts = async () => {\n await Promise.all([this.loadAccounts(), this.loadInstitutions(), this.loadMembers()])\n }\n\n refreshMembers = async () => {\n try {\n await this.api.refreshAllMembers()\n } catch (error) {\n console.error('Error occurred while refreshing members:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n removeAccount = async (accountGuid: string) => {\n try {\n await this.api.deleteAccount(accountGuid)\n\n const deletedIndex = this.accounts.findIndex((account) => account.guid === accountGuid)\n this.accounts.splice(deletedIndex, 1)\n } catch (error) {\n console.error('Error occurred while removing an account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n updateAccount = async (account: Account) => {\n try {\n const updatedAccount = await this.api.updateAccount(account)\n\n const updatedAccountIndex = this.accounts.findIndex(\n (account) => account.guid === updatedAccount.guid,\n )\n\n this.accounts.splice(updatedAccountIndex, 1, updatedAccount)\n } catch (error) {\n console.error('Error occurred while updating account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n updateAccountBalance = (accountGuid: string, balanceChange: number) => {\n const account = this.accounts.find((a) => a.guid === accountGuid)\n\n if (account) {\n runInAction(() => {\n account.balance = (account.balance || 0) + balanceChange\n })\n }\n }\n\n updateAccountFilter = async (accountMap: Map<string, boolean>) => {\n try {\n const accountUpdates: Promise<Account | null>[] = []\n for (const [guid, isSelected] of accountMap.entries()) {\n const account = this.accounts.find((acc) => acc.guid === guid)\n\n if (account && account.is_excluded_from_accounts === isSelected) {\n const updatedPayload = { ...account, is_excluded_from_accounts: !isSelected }\n accountUpdates.push(\n this.api.updateAccount(updatedPayload).catch((error) => {\n console.error('Error occurred while updating account filter:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n return null\n }),\n )\n }\n }\n\n const results = await Promise.all(accountUpdates)\n const updatedAccounts: Account[] = results.filter((acc): acc is Account => acc !== null)\n\n const accounts = [...this.accounts]\n for (const updatedAccount of updatedAccounts) {\n const index = accounts.findIndex((acc) => acc.guid === updatedAccount.guid)\n if (index !== -1) {\n accounts.splice(index, 1, updatedAccount)\n }\n }\n this.setAccounts(accounts)\n } catch (error) {\n console.error('Error occurred while updating account filter:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n}\n\n// TODO: Move into AccountStore\nclass UiStore {\n selectedAccount: Account = {} as Account\n selectedMember: Member = {} as Member\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setSelectedAccount = (account: Account) => (this.selectedAccount = account)\n setSelectedMember = (member: Member) => (this.selectedMember = member)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AccountStore.es.js","names":[],"sources":["../../../src/core/stores/AccountStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { AccountApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport {\n type Account,\n type DetailedAccount,\n type Institution,\n type Member,\n AccountType,\n AccountSubType,\n} from '../types'\nimport { augmentAccounts } from '../utils/AccountUtils'\nimport { isFeatureEnabled } from '../utils/UserUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class AccountStore {\n globalStore: GlobalStore\n api: AccountApi = new AccountApi('/', '')\n\n accounts: Account[] = []\n accountsLoaded: boolean = false\n accountsLoading: boolean = false\n institutions: Institution[] = []\n institutionsLoaded: boolean = false\n institutionsLoading: boolean = false\n members: Member[] = []\n membersLoaded: boolean = false\n membersLoading: boolean = false\n uiStore: UiStore\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore()\n this.api = new AccountApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadAccountData = async () => {\n await Promise.all([this.loadAccounts(), this.loadMembers(), this.loadInstitutions()])\n }\n\n get isAccountDataLoaded(): boolean {\n return this.accountsLoaded && this.membersLoaded && this.institutionsLoaded\n }\n\n get detailedAccounts(): DetailedAccount[] {\n const userFeatures = this.globalStore.userStore.userFeatures\n const excludeExternal = isFeatureEnabled(userFeatures, 'MD_EXCLUDE_EXTERNAL_ACCOUNTS')\n\n // Hide held account when this flag is toggled and this is the individual accounts widget\n const excludeHeld =\n this.globalStore.appConfig.config.display_only_external_accounts_in_accounts &&\n this.globalStore.appConfig.options.subtype === 'accounts' // Indicates this is an individual widget\n\n return augmentAccounts(\n this.accounts,\n this.institutions,\n this.members,\n excludeExternal,\n excludeHeld,\n )\n }\n\n get accountsByTypeMap(): Map<AccountType, DetailedAccount[]> {\n return this.detailedAccounts.reduce((typeMap: Map<AccountType, DetailedAccount[]>, account) => {\n const accountType = account.account_type\n\n let accounts = typeMap.get(accountType)\n if (!accounts) {\n accounts = []\n }\n accounts.push(account)\n typeMap.set(accountType, accounts)\n\n return typeMap\n }, new Map<AccountType, DetailedAccount[]>())\n }\n\n get cashAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.CASH ||\n account.account_type === AccountType.CHECKING ||\n account.account_type === AccountType.PREPAID ||\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING_LINE_OF_CREDIT,\n )\n }\n\n get cashBalance(): number {\n return this.cashAccounts.reduce((total, account) => total + (account?.balance || 0), 0)\n }\n\n get checkingAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => a.account_type === AccountType.CHECKING)\n }\n\n get debtAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.CREDIT_CARD ||\n account.account_type === AccountType.LOAN ||\n account.account_type === AccountType.MORTGAGE ||\n account.account_type === AccountType.LINE_OF_CREDIT ||\n account.account_type === AccountType.CHECKING_LINE_OF_CREDIT,\n )\n }\n\n get finstrongAccounts(): DetailedAccount[] {\n const eligibleTypes = new Set([\n AccountType.CHECKING,\n AccountType.SAVINGS,\n AccountType.CREDIT_CARD,\n AccountType.INVESTMENT,\n ])\n\n return this.detailedAccounts.filter((account) => eligibleTypes.has(account.account_type))\n }\n\n get investmentAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter(\n (account: Account) => account.account_type === AccountType.INVESTMENT,\n )\n }\n\n get manualAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((account) => account.is_manual)\n }\n\n get savingsAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => a.account_type === AccountType.SAVINGS)\n }\n\n get retirementAccounts(): Account[] {\n return this.detailedAccounts.filter(\n (account: Account) =>\n account.account_type === AccountType.INVESTMENT ||\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING ||\n account.account_type === AccountType.CASH ||\n account.account_type === AccountType.PROPERTY ||\n (account.account_type === AccountType.INSURANCE &&\n (account.account_subtype === AccountSubType.WHOLE_LIFE ||\n account.account_subtype === AccountSubType.UNIVERSAL_LIFE ||\n account.account_subtype === AccountSubType.VARIABLE_UNIVERSAL_LIFE)),\n )\n }\n\n get visibleAccounts(): DetailedAccount[] {\n return this.detailedAccounts.filter((a: Account) => !a.is_hidden && !a.is_closed)\n }\n\n get visibleCashAccounts(): DetailedAccount[] {\n return this.cashAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleCashBalance(): number {\n return this.visibleCashAccounts.reduce((total, account) => total + (account?.balance || 0), 0)\n }\n\n get visibleCheckingAccounts(): DetailedAccount[] {\n return this.checkingAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleDebtAccounts(): DetailedAccount[] {\n return this.debtAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleFinstrongAccounts(): DetailedAccount[] {\n return this.finstrongAccounts.filter(\n (account: Account) => !(account.is_closed || account.is_deleted || account.is_hidden),\n )\n }\n\n get visibleRetirementAccounts(): Account[] {\n return this.retirementAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleInvestmentAccounts(): DetailedAccount[] {\n return this.investmentAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get visibleSavingsAccounts(): DetailedAccount[] {\n return this.savingsAccounts.filter((account: Account) => !account.is_hidden)\n }\n\n get savingsAndCheckingAccountsBalance(): number {\n const savingsAndCheckingAccountsList = this.savingsAndCheckingAccounts\n\n return savingsAndCheckingAccountsList.reduce(\n (total, account) => total + (account?.balance || 0),\n 0,\n )\n }\n\n get savingsAndCheckingAccounts(): Account[] {\n const savingsAndCheckingAccounts = this.accounts.filter(\n (account: Account) =>\n account.account_type === AccountType.SAVINGS ||\n account.account_type === AccountType.CHECKING,\n )\n\n return savingsAndCheckingAccounts\n }\n\n setAccounts = (accounts: Account[]) => {\n this.accounts = accounts\n this.accountsLoading = false\n this.accountsLoaded = true\n }\n\n setMembers = (members: Member[]) => {\n this.members = members\n this.membersLoading = false\n this.membersLoaded = true\n }\n\n setInstitutions = (institutions: Institution[]) => {\n this.institutions = institutions\n this.institutionsLoading = false\n this.institutionsLoaded = true\n }\n\n addAccount = async (account: Account) => {\n try {\n const newAccount = await this.api.createAccount(account)\n\n runInAction(() => {\n this.accounts = upsertByGuid(this.accounts, newAccount)\n })\n } catch (error) {\n console.error('Error occurred while adding an account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n loadAccounts = async () => {\n if (this.accountsLoading) return\n\n this.accountsLoading = true\n try {\n const accounts = await this.api.getAccounts()\n this.setAccounts(accounts)\n } catch (error) {\n console.error('Error occurred while loading accounts:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setAccounts([])\n }\n }\n\n loadInstitutions = async () => {\n if (this.institutionsLoading) return\n\n this.institutionsLoading = true\n try {\n const institutions = await this.api.getInstitutions()\n this.setInstitutions(institutions)\n } catch (error) {\n console.error('Error occurred while loading institutions:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setInstitutions([])\n }\n }\n\n loadMembers = async () => {\n if (this.membersLoading) return\n\n this.membersLoading = true\n try {\n const members = await this.api.getMembers()\n this.setMembers(members)\n } catch (error) {\n console.error('Error occurred while loading members:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n this.setMembers([])\n }\n }\n\n mergeAccounts = async (accountGuids: string[]) => {\n try {\n const response = await this.api.mergeAccounts(accountGuids)\n // the response from the api is a funky database key here, so this is essentially just getting the first item in the returned object\n // to prevent making multiple api calls here\n const mergedAccount = response[Object.keys(response)[0]]\n\n runInAction(() => {\n const account2Index = this.accounts.findIndex((account) => account.guid === accountGuids[1])\n this.accounts.splice(account2Index, 1)\n\n const account1Index = this.accounts.findIndex((account) => account.guid === accountGuids[0])\n this.accounts.splice(account1Index, 1, mergedAccount)\n })\n } catch (error) {\n console.error('Error occurred while merging accounts:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n /**\n * DEPRECATED: Use loadAccountData instead\n */\n refreshAccounts = async () => {\n await Promise.all([this.loadAccounts(), this.loadInstitutions(), this.loadMembers()])\n }\n\n refreshMembers = async () => {\n try {\n await this.api.refreshAllMembers()\n } catch (error) {\n console.error('Error occurred while refreshing members:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n removeAccount = async (accountGuid: string) => {\n try {\n await this.api.deleteAccount(accountGuid)\n\n const deletedIndex = this.accounts.findIndex((account) => account.guid === accountGuid)\n this.accounts.splice(deletedIndex, 1)\n } catch (error) {\n console.error('Error occurred while removing an account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n\n /** Resolves `true` when the account was saved, `false` when the API call failed. */\n updateAccount = async (account: Account): Promise<boolean> => {\n try {\n const updatedAccount = await this.api.updateAccount(account)\n\n const updatedAccountIndex = this.accounts.findIndex(\n (account) => account.guid === updatedAccount.guid,\n )\n\n this.accounts.splice(updatedAccountIndex, 1, updatedAccount)\n return true\n } catch (error) {\n console.error('Error occurred while updating account:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n return false\n }\n }\n\n updateAccountBalance = (accountGuid: string, balanceChange: number) => {\n const account = this.accounts.find((a) => a.guid === accountGuid)\n\n if (account) {\n runInAction(() => {\n account.balance = (account.balance || 0) + balanceChange\n })\n }\n }\n\n updateAccountFilter = async (accountMap: Map<string, boolean>) => {\n try {\n const accountUpdates: Promise<Account | null>[] = []\n for (const [guid, isSelected] of accountMap.entries()) {\n const account = this.accounts.find((acc) => acc.guid === guid)\n\n if (account && account.is_excluded_from_accounts === isSelected) {\n const updatedPayload = { ...account, is_excluded_from_accounts: !isSelected }\n accountUpdates.push(\n this.api.updateAccount(updatedPayload).catch((error) => {\n console.error('Error occurred while updating account filter:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n return null\n }),\n )\n }\n }\n\n const results = await Promise.all(accountUpdates)\n const updatedAccounts: Account[] = results.filter((acc): acc is Account => acc !== null)\n\n const accounts = [...this.accounts]\n for (const updatedAccount of updatedAccounts) {\n const index = accounts.findIndex((acc) => acc.guid === updatedAccount.guid)\n if (index !== -1) {\n accounts.splice(index, 1, updatedAccount)\n }\n }\n this.setAccounts(accounts)\n } catch (error) {\n console.error('Error occurred while updating account filter:', error)\n this.globalStore.captureException(error, { store: 'AccountStore' })\n }\n }\n}\n\n// TODO: Move into AccountStore\nclass UiStore {\n selectedAccount: Account = {} as Account\n selectedMember: Member = {} as Member\n\n constructor() {\n makeAutoObservable(this)\n }\n\n setSelectedAccount = (account: Account) => (this.selectedAccount = account)\n setSelectedMember = (member: Member) => (this.selectedMember = member)\n}\n"],"mappings":";;;;;;AAiBA,IAAa,IAAb,MAA0B;AAAA,EACxB;AAAA,EACA,MAAkB,IAAI,EAAW,KAAK,EAAE;AAAA,EAExC,WAAsB,CAAC;AAAA,EACvB,iBAA0B;AAAA,EAC1B,kBAA2B;AAAA,EAC3B,eAA8B,CAAC;AAAA,EAC/B,qBAA8B;AAAA,EAC9B,sBAA+B;AAAA,EAC/B,UAAoB,CAAC;AAAA,EACrB,gBAAyB;AAAA,EACzB,iBAA0B;AAAA,EAC1B;AAAA,EAEA,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,UAAU,IAAI,EAAQ,GAC3B,KAAK,MAAM,IAAI,EAAW,EAAY,UAAU,EAAY,cAAc,EAAY,OAAO,GAE7F,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,kBAAkB,YAAY;AAC5B,UAAM,QAAQ,IAAI;AAAA,MAAC,KAAK,aAAa;AAAA,MAAG,KAAK,YAAY;AAAA,MAAG,KAAK,iBAAiB;AAAA,IAAC,CAAC;AAAA,EACtF;AAAA,EAEA,IAAI,sBAA+B;AACjC,WAAO,KAAK,kBAAkB,KAAK,iBAAiB,KAAK;AAAA,EAC3D;AAAA,EAEA,IAAI,mBAAsC;AACxC,UAAM,IAAe,KAAK,YAAY,UAAU,cAC1C,IAAkB,EAAiB,GAAc,8BAA8B,GAG/E,IACJ,KAAK,YAAY,UAAU,OAAO,8CAClC,KAAK,YAAY,UAAU,QAAQ,YAAY;AAEjD,WAAO,EACL,KAAK,UACL,KAAK,cACL,KAAK,SACL,GACA,CACF;AAAA,EACF;AAAA,EAEA,IAAI,oBAAyD;AAC3D,WAAO,KAAK,iBAAiB,OAAA,CAAQ,GAA8C,MAAY;AAC7F,YAAM,IAAc,EAAQ;AAE5B,UAAI,IAAW,EAAQ,IAAI,CAAW;AACtC,aAAK,MACH,IAAW,CAAC,IAEd,EAAS,KAAK,CAAO,GACrB,EAAQ,IAAI,GAAa,CAAQ,GAE1B;AAAA,IACT,GAAG,oBAAI,IAAoC,CAAC;AAAA,EAC9C;AAAA,EAEA,IAAI,eAAkC;AACpC,WAAO,KAAK,iBAAiB,OAAA,CAC1B,MACC,EAAQ,iBAAiB,EAAY,QACrC,EAAQ,iBAAiB,EAAY,YACrC,EAAQ,iBAAiB,EAAY,WACrC,EAAQ,iBAAiB,EAAY,WACrC,EAAQ,iBAAiB,EAAY,uBACzC;AAAA,EACF;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,KAAK,aAAa,OAAA,CAAQ,GAAO,MAAY,KAAS,GAAS,WAAW,IAAI,CAAC;AAAA,EACxF;AAAA,EAEA,IAAI,mBAAsC;AACxC,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAe,EAAE,iBAAiB,EAAY,QAAQ;AAAA,EAC7F;AAAA,EAEA,IAAI,eAAkC;AACpC,WAAO,KAAK,iBAAiB,OAAA,CAC1B,MACC,EAAQ,iBAAiB,EAAY,eACrC,EAAQ,iBAAiB,EAAY,QACrC,EAAQ,iBAAiB,EAAY,YACrC,EAAQ,iBAAiB,EAAY,kBACrC,EAAQ,iBAAiB,EAAY,uBACzC;AAAA,EACF;AAAA,EAEA,IAAI,oBAAuC;AACzC,UAAM,IAAgB,oBAAI,IAAI;AAAA,MAC5B,EAAY;AAAA,MACZ,EAAY;AAAA,MACZ,EAAY;AAAA,MACZ,EAAY;AAAA,IACd,CAAC;AAED,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAY,EAAc,IAAI,EAAQ,YAAY,CAAC;AAAA,EAC1F;AAAA,EAEA,IAAI,qBAAwC;AAC1C,WAAO,KAAK,iBAAiB,OAAA,CAC1B,MAAqB,EAAQ,iBAAiB,EAAY,UAC7D;AAAA,EACF;AAAA,EAEA,IAAI,iBAAoC;AACtC,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAY,EAAQ,SAAS;AAAA,EACpE;AAAA,EAEA,IAAI,kBAAqC;AACvC,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAe,EAAE,iBAAiB,EAAY,OAAO;AAAA,EAC5F;AAAA,EAEA,IAAI,qBAAgC;AAClC,WAAO,KAAK,iBAAiB,OAAA,CAC1B,MACC,EAAQ,iBAAiB,EAAY,cACrC,EAAQ,iBAAiB,EAAY,WACrC,EAAQ,iBAAiB,EAAY,YACrC,EAAQ,iBAAiB,EAAY,QACrC,EAAQ,iBAAiB,EAAY,YACpC,EAAQ,iBAAiB,EAAY,cACnC,EAAQ,oBAAoB,EAAe,cAC1C,EAAQ,oBAAoB,EAAe,kBAC3C,EAAQ,oBAAoB,EAAe,wBACnD;AAAA,EACF;AAAA,EAEA,IAAI,kBAAqC;AACvC,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAe,CAAC,EAAE,aAAa,CAAC,EAAE,SAAS;AAAA,EAClF;AAAA,EAEA,IAAI,sBAAyC;AAC3C,WAAO,KAAK,aAAa,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAC1E;AAAA,EAEA,IAAI,qBAA6B;AAC/B,WAAO,KAAK,oBAAoB,OAAA,CAAQ,GAAO,MAAY,KAAS,GAAS,WAAW,IAAI,CAAC;AAAA,EAC/F;AAAA,EAEA,IAAI,0BAA6C;AAC/C,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAC9E;AAAA,EAEA,IAAI,sBAAyC;AAC3C,WAAO,KAAK,aAAa,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAC1E;AAAA,EAEA,IAAI,2BAA8C;AAChD,WAAO,KAAK,kBAAkB,OAAA,CAC3B,MAAqB,EAAE,EAAQ,aAAa,EAAQ,cAAc,EAAQ,UAC7E;AAAA,EACF;AAAA,EAEA,IAAI,4BAAuC;AACzC,WAAO,KAAK,mBAAmB,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAChF;AAAA,EAEA,IAAI,4BAA+C;AACjD,WAAO,KAAK,mBAAmB,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAChF;AAAA,EAEA,IAAI,yBAA4C;AAC9C,WAAO,KAAK,gBAAgB,OAAA,CAAQ,MAAqB,CAAC,EAAQ,SAAS;AAAA,EAC7E;AAAA,EAEA,IAAI,oCAA4C;AAG9C,WAFuC,KAAK,2BAEN,OAAA,CACnC,GAAO,MAAY,KAAS,GAAS,WAAW,IACjD,CACF;AAAA,EACF;AAAA,EAEA,IAAI,6BAAwC;AAO1C,WANmC,KAAK,SAAS,OAAA,CAC9C,MACC,EAAQ,iBAAiB,EAAY,WACrC,EAAQ,iBAAiB,EAAY,QAGlC;AAAA,EACT;AAAA,EAEA,cAAA,CAAe,MAAwB;AACrC,SAAK,WAAW,GAChB,KAAK,kBAAkB,IACvB,KAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,aAAA,CAAc,MAAsB;AAClC,SAAK,UAAU,GACf,KAAK,iBAAiB,IACtB,KAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,kBAAA,CAAmB,MAAgC;AACjD,SAAK,eAAe,GACpB,KAAK,sBAAsB,IAC3B,KAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,aAAa,OAAO,MAAqB;AACvC,QAAI;AACF,YAAM,IAAa,MAAM,KAAK,IAAI,cAAc,CAAO;AAEvD,MAAA,EAAA,MAAkB;AAChB,aAAK,WAAW,EAAa,KAAK,UAAU,CAAU;AAAA,MACxD,CAAC;AAAA,IACH,SAAS,GAAO;AACd,cAAQ,MAAM,2CAA2C,CAAK,GAC9D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AAAA,EAEA,eAAe,YAAY;AACzB,QAAI,MAAK,iBAET;AAAA,WAAK,kBAAkB;AACvB,UAAI;AACF,cAAM,IAAW,MAAM,KAAK,IAAI,YAAY;AAC5C,aAAK,YAAY,CAAQ;AAAA,MAC3B,SAAS,GAAO;AACd,gBAAQ,MAAM,0CAA0C,CAAK,GAC7D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC,GAClE,KAAK,YAAY,CAAC,CAAC;AAAA,MACrB;AAAA;AAAA,EACF;AAAA,EAEA,mBAAmB,YAAY;AAC7B,QAAI,MAAK,qBAET;AAAA,WAAK,sBAAsB;AAC3B,UAAI;AACF,cAAM,IAAe,MAAM,KAAK,IAAI,gBAAgB;AACpD,aAAK,gBAAgB,CAAY;AAAA,MACnC,SAAS,GAAO;AACd,gBAAQ,MAAM,8CAA8C,CAAK,GACjE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC,GAClE,KAAK,gBAAgB,CAAC,CAAC;AAAA,MACzB;AAAA;AAAA,EACF;AAAA,EAEA,cAAc,YAAY;AACxB,QAAI,MAAK,gBAET;AAAA,WAAK,iBAAiB;AACtB,UAAI;AACF,cAAM,IAAU,MAAM,KAAK,IAAI,WAAW;AAC1C,aAAK,WAAW,CAAO;AAAA,MACzB,SAAS,GAAO;AACd,gBAAQ,MAAM,yCAAyC,CAAK,GAC5D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC,GAClE,KAAK,WAAW,CAAC,CAAC;AAAA,MACpB;AAAA;AAAA,EACF;AAAA,EAEA,gBAAgB,OAAO,MAA2B;AAChD,QAAI;AACF,YAAM,IAAW,MAAM,KAAK,IAAI,cAAc,CAAY,GAGpD,IAAgB,EAAS,OAAO,KAAK,CAAQ,EAAE,CAAA,CAAA;AAErD,MAAA,EAAA,MAAkB;AAChB,cAAM,IAAgB,KAAK,SAAS,UAAA,CAAW,MAAY,EAAQ,SAAS,EAAa,CAAA,CAAE;AAC3F,aAAK,SAAS,OAAO,GAAe,CAAC;AAErC,cAAM,IAAgB,KAAK,SAAS,UAAA,CAAW,MAAY,EAAQ,SAAS,EAAa,CAAA,CAAE;AAC3F,aAAK,SAAS,OAAO,GAAe,GAAG,CAAa;AAAA,MACtD,CAAC;AAAA,IACH,SAAS,GAAO;AACd,cAAQ,MAAM,0CAA0C,CAAK,GAC7D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AAAA,EAKA,kBAAkB,YAAY;AAC5B,UAAM,QAAQ,IAAI;AAAA,MAAC,KAAK,aAAa;AAAA,MAAG,KAAK,iBAAiB;AAAA,MAAG,KAAK,YAAY;AAAA,IAAC,CAAC;AAAA,EACtF;AAAA,EAEA,iBAAiB,YAAY;AAC3B,QAAI;AACF,YAAM,KAAK,IAAI,kBAAkB;AAAA,IACnC,SAAS,GAAO;AACd,cAAQ,MAAM,4CAA4C,CAAK,GAC/D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AAAA,EAEA,gBAAgB,OAAO,MAAwB;AAC7C,QAAI;AACF,YAAM,KAAK,IAAI,cAAc,CAAW;AAExC,YAAM,IAAe,KAAK,SAAS,UAAA,CAAW,MAAY,EAAQ,SAAS,CAAW;AACtF,WAAK,SAAS,OAAO,GAAc,CAAC;AAAA,IACtC,SAAS,GAAO;AACd,cAAQ,MAAM,6CAA6C,CAAK,GAChE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AAAA,EAGA,gBAAgB,OAAO,MAAuC;AAC5D,QAAI;AACF,YAAM,IAAiB,MAAM,KAAK,IAAI,cAAc,CAAO,GAErD,IAAsB,KAAK,SAAS,UAAA,CACvC,MAAY,EAAQ,SAAS,EAAe,IAC/C;AAEA,kBAAK,SAAS,OAAO,GAAqB,GAAG,CAAc,GACpD;AAAA,IACT,SAAS,GAAO;AACd,qBAAQ,MAAM,0CAA0C,CAAK,GAC7D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC,GAC3D;AAAA,IACT;AAAA,EACF;AAAA,EAEA,uBAAA,CAAwB,GAAqB,MAA0B;AACrE,UAAM,IAAU,KAAK,SAAS,KAAA,CAAM,MAAM,EAAE,SAAS,CAAW;AAEhE,IAAI,KACF,EAAA,MAAkB;AAChB,MAAA,EAAQ,WAAW,EAAQ,WAAW,KAAK;AAAA,IAC7C,CAAC;AAAA,EAEL;AAAA,EAEA,sBAAsB,OAAO,MAAqC;AAChE,QAAI;AACF,YAAM,IAA4C,CAAC;AACnD,iBAAW,CAAC,GAAM,CAAA,KAAe,EAAW,QAAQ,GAAG;AACrD,cAAM,IAAU,KAAK,SAAS,KAAA,CAAM,MAAQ,EAAI,SAAS,CAAI;AAE7D,YAAI,KAAW,EAAQ,8BAA8B,GAAY;AAC/D,gBAAM,IAAiB;AAAA,YAAE,GAAG;AAAA,YAAS,2BAA2B,CAAC;AAAA,UAAW;AAC5E,UAAA,EAAe,KACb,KAAK,IAAI,cAAc,CAAc,EAAE,MAAA,CAAO,OAC5C,QAAQ,MAAM,iDAAiD,CAAK,GACpE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC,GAC3D,KACR,CACH;AAAA,QACF;AAAA,MACF;AAGA,YAAM,KAA6B,MADb,QAAQ,IAAI,CAAc,GACL,OAAA,CAAQ,MAAwB,MAAQ,IAAI,GAEjF,IAAW,CAAC,GAAG,KAAK,QAAQ;AAClC,iBAAW,KAAkB,GAAiB;AAC5C,cAAM,IAAQ,EAAS,UAAA,CAAW,MAAQ,EAAI,SAAS,EAAe,IAAI;AAC1E,QAAI,MAAU,MACZ,EAAS,OAAO,GAAO,GAAG,CAAc;AAAA,MAE5C;AACA,WAAK,YAAY,CAAQ;AAAA,IAC3B,SAAS,GAAO;AACd,cAAQ,MAAM,iDAAiD,CAAK,GACpE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AACF,GAGM,IAAN,MAAc;AAAA,EACZ,kBAA2B,CAAC;AAAA,EAC5B,iBAAyB,CAAC;AAAA,EAE1B,cAAc;AACZ,IAAA,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,qBAAA,CAAsB,MAAsB,KAAK,kBAAkB;AAAA,EACnE,oBAAA,CAAqB,MAAoB,KAAK,iBAAiB;AACjE"}
|
|
@@ -8,6 +8,12 @@ export declare class BeatStore {
|
|
|
8
8
|
isLoading: boolean;
|
|
9
9
|
constructor(globalStore: GlobalStore);
|
|
10
10
|
loadBeats: () => Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Persists changes to an offer-backed beat (pulse marketing offers, `PUT offers/:guid`),
|
|
13
|
+
* e.g. flagging `has_been_clicked` when its CTA is pressed. Rethrows so callers driving
|
|
14
|
+
* UI state can surface the failure.
|
|
15
|
+
*/
|
|
16
|
+
updateOffer: (beat: Beat) => Promise<any>;
|
|
11
17
|
getFilteredBeats(filter: {
|
|
12
18
|
categoryGuids?: string[];
|
|
13
19
|
templates?: string[];
|
|
@@ -1,43 +1,56 @@
|
|
|
1
|
-
import { BeatApi as
|
|
1
|
+
import { BeatApi as i } from "../api/BeatApi.es.js";
|
|
2
2
|
import { orderArray as o, transformOfferIntoBeatLikeObject as n } from "../utils/BeatUtils.es.js";
|
|
3
|
-
import { makeAutoObservable as
|
|
4
|
-
var
|
|
3
|
+
import { makeAutoObservable as c, runInAction as s } from "mobx";
|
|
4
|
+
var u = class {
|
|
5
5
|
globalStore;
|
|
6
|
-
api = new
|
|
6
|
+
api = new i("/", "");
|
|
7
7
|
beats = [];
|
|
8
8
|
isLoading = !1;
|
|
9
9
|
constructor(t) {
|
|
10
|
-
this.globalStore = t, this.api = new
|
|
10
|
+
this.globalStore = t, this.api = new i(t.endpoint, t.sessionToken, t.onError), c(this);
|
|
11
11
|
}
|
|
12
12
|
loadBeats = async () => {
|
|
13
13
|
this.isLoading = !0;
|
|
14
14
|
try {
|
|
15
|
-
const t = await this.api.getBeats(),
|
|
16
|
-
|
|
17
|
-
this.beats = o(t,
|
|
15
|
+
const t = await this.api.getBeats(), e = (await this.api.getOffers()).map((r) => n(r));
|
|
16
|
+
s(() => {
|
|
17
|
+
this.beats = o(t, e, "active_at", "desc");
|
|
18
18
|
});
|
|
19
19
|
} catch (t) {
|
|
20
20
|
console.error("Error occurred while loading beats:", t), this.globalStore.captureException(t, { store: "BeatStore" });
|
|
21
21
|
} finally {
|
|
22
|
-
|
|
22
|
+
s(() => {
|
|
23
23
|
this.isLoading = !1;
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
+
updateOffer = async (t) => {
|
|
28
|
+
try {
|
|
29
|
+
const e = await this.api.updateOffer(t);
|
|
30
|
+
return s(() => {
|
|
31
|
+
this.beats = this.beats.map((r) => r.guid === t.guid ? {
|
|
32
|
+
...r,
|
|
33
|
+
...e
|
|
34
|
+
} : r);
|
|
35
|
+
}), e;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
throw console.error("Error occurred while updating offer:", e), this.globalStore.captureException(e, { store: "BeatStore" }), e;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
27
40
|
getFilteredBeats(t) {
|
|
28
|
-
const { categoryGuids:
|
|
29
|
-
let
|
|
30
|
-
return
|
|
41
|
+
const { categoryGuids: e, templates: r } = t;
|
|
42
|
+
let a = this.beats;
|
|
43
|
+
return e && (a = this.filterBeatsByCategory(a, e)), r && (a = this.filterBeatsByTemplate(a, r)), a;
|
|
31
44
|
}
|
|
32
|
-
filterBeatsByCategory(t,
|
|
33
|
-
return t.filter((
|
|
45
|
+
filterBeatsByCategory(t, e) {
|
|
46
|
+
return t.filter((r) => r.category_guids?.some((a) => e.includes(a)));
|
|
34
47
|
}
|
|
35
|
-
filterBeatsByTemplate(t,
|
|
36
|
-
return t.filter((
|
|
48
|
+
filterBeatsByTemplate(t, e) {
|
|
49
|
+
return t.filter((r) => e.some((a) => r.template === a));
|
|
37
50
|
}
|
|
38
51
|
};
|
|
39
52
|
export {
|
|
40
|
-
|
|
53
|
+
u as BeatStore
|
|
41
54
|
};
|
|
42
55
|
|
|
43
56
|
//# sourceMappingURL=BeatStore.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BeatStore.es.js","names":[],"sources":["../../../src/core/stores/BeatStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { BeatApi } from '../api'\nimport type { Beat, Offer } from '../types'\nimport { orderArray, transformOfferIntoBeatLikeObject } from '../utils/BeatUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class BeatStore {\n globalStore: GlobalStore\n api: BeatApi = new BeatApi('/', '')\n beats: Beat[] = []\n isLoading = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BeatApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBeats = async () => {\n this.isLoading = true\n try {\n const beats = await this.api.getBeats()\n const offers = await this.api.getOffers()\n const beatLikeOffers = offers.map((o: Offer) => transformOfferIntoBeatLikeObject(o))\n\n runInAction(() => {\n this.beats = orderArray(beats, beatLikeOffers, 'active_at', 'desc')\n })\n } catch (error) {\n console.error('Error occurred while loading beats:', error)\n this.globalStore.captureException(error, { store: 'BeatStore' })\n } finally {\n runInAction(() => {\n this.isLoading = false\n })\n }\n }\n\n getFilteredBeats(filter: { categoryGuids?: string[]; templates?: string[] }): Beat[] {\n const { categoryGuids, templates } = filter\n let filteredBeats = this.beats\n if (categoryGuids) filteredBeats = this.filterBeatsByCategory(filteredBeats, categoryGuids)\n if (templates) filteredBeats = this.filterBeatsByTemplate(filteredBeats, templates)\n return filteredBeats\n }\n\n // Return beats with any beat.category_guids that are in categoryGuids\n filterBeatsByCategory(beats: Beat[], categoryGuids: string[]): Beat[] {\n return beats.filter((beat) => {\n return beat.category_guids?.some((guid) => categoryGuids.includes(guid))\n })\n }\n\n // Return beats with a beat.template that is in templates\n filterBeatsByTemplate(beats: Beat[], templates: string[]): Beat[] {\n return beats.filter((beat) => {\n return templates.some((template) => beat.template === template)\n })\n }\n}\n"],"mappings":";;;AAQA,IAAa,IAAb,MAAuB;AAAA,EACrB;AAAA,EACA,MAAe,IAAI,EAAQ,KAAK,EAAE;AAAA,EAClC,QAAgB,CAAC;AAAA,EACjB,YAAY;AAAA,EAEZ,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EAAQ,EAAY,UAAU,EAAY,cAAc,EAAY,OAAO,GAE1F,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,YAAY,YAAY;AACtB,SAAK,YAAY;AACjB,QAAI;AACF,YAAM,IAAQ,MAAM,KAAK,IAAI,SAAS,GAEhC,KAAiB,MADF,KAAK,IAAI,UAAU,GACV,IAAA,CAAK,MAAa,EAAiC,CAAC,CAAC;AAEnF,MAAA,EAAA,MAAkB;AAChB,aAAK,QAAQ,EAAW,GAAO,GAAgB,aAAa,MAAM;AAAA,MACpE,CAAC;AAAA,IACH,SAAS,GAAO;AACd,cAAQ,MAAM,uCAAuC,CAAK,GAC1D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC;AAAA,IACjE,UAAA;AACE,MAAA,EAAA,MAAkB;AAChB,aAAK,YAAY;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,iBAAiB,GAAoE;AACnF,UAAM,EAAE,eAAA,GAAe,WAAA,EAAA,IAAc;AACrC,QAAI,IAAgB,KAAK;AACzB,WAAI,MAAe,IAAgB,KAAK,sBAAsB,GAAe,CAAa,IACtF,MAAW,IAAgB,KAAK,sBAAsB,GAAe,CAAS,IAC3E;AAAA,EACT;AAAA,EAGA,sBAAsB,GAAe,GAAiC;AACpE,WAAO,EAAM,OAAA,CAAQ,MACZ,EAAK,gBAAgB,KAAA,CAAM,MAAS,EAAc,SAAS,CAAI,CAAC,CACxE;AAAA,EACH;AAAA,EAGA,sBAAsB,GAAe,GAA6B;AAChE,WAAO,EAAM,OAAA,CAAQ,MACZ,EAAU,KAAA,CAAM,MAAa,EAAK,aAAa,CAAQ,CAC/D;AAAA,EACH;AACF"}
|
|
1
|
+
{"version":3,"file":"BeatStore.es.js","names":[],"sources":["../../../src/core/stores/BeatStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { BeatApi } from '../api'\nimport type { Beat, Offer } from '../types'\nimport { orderArray, transformOfferIntoBeatLikeObject } from '../utils/BeatUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class BeatStore {\n globalStore: GlobalStore\n api: BeatApi = new BeatApi('/', '')\n beats: Beat[] = []\n isLoading = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BeatApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBeats = async () => {\n this.isLoading = true\n try {\n const beats = await this.api.getBeats()\n const offers = await this.api.getOffers()\n const beatLikeOffers = offers.map((o: Offer) => transformOfferIntoBeatLikeObject(o))\n\n runInAction(() => {\n this.beats = orderArray(beats, beatLikeOffers, 'active_at', 'desc')\n })\n } catch (error) {\n console.error('Error occurred while loading beats:', error)\n this.globalStore.captureException(error, { store: 'BeatStore' })\n } finally {\n runInAction(() => {\n this.isLoading = false\n })\n }\n }\n\n /**\n * Persists changes to an offer-backed beat (pulse marketing offers, `PUT offers/:guid`),\n * e.g. flagging `has_been_clicked` when its CTA is pressed. Rethrows so callers driving\n * UI state can surface the failure.\n */\n updateOffer = async (beat: Beat) => {\n try {\n const updated = await this.api.updateOffer(beat)\n\n runInAction(() => {\n this.beats = this.beats.map((b) => (b.guid === beat.guid ? { ...b, ...updated } : b))\n })\n\n return updated\n } catch (error) {\n console.error('Error occurred while updating offer:', error)\n this.globalStore.captureException(error, { store: 'BeatStore' })\n throw error\n }\n }\n\n getFilteredBeats(filter: { categoryGuids?: string[]; templates?: string[] }): Beat[] {\n const { categoryGuids, templates } = filter\n let filteredBeats = this.beats\n if (categoryGuids) filteredBeats = this.filterBeatsByCategory(filteredBeats, categoryGuids)\n if (templates) filteredBeats = this.filterBeatsByTemplate(filteredBeats, templates)\n return filteredBeats\n }\n\n // Return beats with any beat.category_guids that are in categoryGuids\n filterBeatsByCategory(beats: Beat[], categoryGuids: string[]): Beat[] {\n return beats.filter((beat) => {\n return beat.category_guids?.some((guid) => categoryGuids.includes(guid))\n })\n }\n\n // Return beats with a beat.template that is in templates\n filterBeatsByTemplate(beats: Beat[], templates: string[]): Beat[] {\n return beats.filter((beat) => {\n return templates.some((template) => beat.template === template)\n })\n }\n}\n"],"mappings":";;;AAQA,IAAa,IAAb,MAAuB;AAAA,EACrB;AAAA,EACA,MAAe,IAAI,EAAQ,KAAK,EAAE;AAAA,EAClC,QAAgB,CAAC;AAAA,EACjB,YAAY;AAAA,EAEZ,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EAAQ,EAAY,UAAU,EAAY,cAAc,EAAY,OAAO,GAE1F,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,YAAY,YAAY;AACtB,SAAK,YAAY;AACjB,QAAI;AACF,YAAM,IAAQ,MAAM,KAAK,IAAI,SAAS,GAEhC,KAAiB,MADF,KAAK,IAAI,UAAU,GACV,IAAA,CAAK,MAAa,EAAiC,CAAC,CAAC;AAEnF,MAAA,EAAA,MAAkB;AAChB,aAAK,QAAQ,EAAW,GAAO,GAAgB,aAAa,MAAM;AAAA,MACpE,CAAC;AAAA,IACH,SAAS,GAAO;AACd,cAAQ,MAAM,uCAAuC,CAAK,GAC1D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC;AAAA,IACjE,UAAA;AACE,MAAA,EAAA,MAAkB;AAChB,aAAK,YAAY;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAOA,cAAc,OAAO,MAAe;AAClC,QAAI;AACF,YAAM,IAAU,MAAM,KAAK,IAAI,YAAY,CAAI;AAE/C,aAAA,EAAA,MAAkB;AAChB,aAAK,QAAQ,KAAK,MAAM,IAAA,CAAK,MAAO,EAAE,SAAS,EAAK,OAAO;AAAA,UAAE,GAAG;AAAA,UAAG,GAAG;AAAA,QAAQ,IAAI,CAAE;AAAA,MACtF,CAAC,GAEM;AAAA,IACT,SAAS,GAAO;AACd,oBAAQ,MAAM,wCAAwC,CAAK,GAC3D,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC,GACzD;AAAA,IACR;AAAA,EACF;AAAA,EAEA,iBAAiB,GAAoE;AACnF,UAAM,EAAE,eAAA,GAAe,WAAA,EAAA,IAAc;AACrC,QAAI,IAAgB,KAAK;AACzB,WAAI,MAAe,IAAgB,KAAK,sBAAsB,GAAe,CAAa,IACtF,MAAW,IAAgB,KAAK,sBAAsB,GAAe,CAAS,IAC3E;AAAA,EACT;AAAA,EAGA,sBAAsB,GAAe,GAAiC;AACpE,WAAO,EAAM,OAAA,CAAQ,MACZ,EAAK,gBAAgB,KAAA,CAAM,MAAS,EAAc,SAAS,CAAI,CAAC,CACxE;AAAA,EACH;AAAA,EAGA,sBAAsB,GAAe,GAA6B;AAChE,WAAO,EAAM,OAAA,CAAQ,MACZ,EAAU,KAAA,CAAM,MAAa,EAAK,aAAa,CAAQ,CAC/D;AAAA,EACH;AACF"}
|
|
@@ -22,7 +22,8 @@ export declare class BudgetsStore {
|
|
|
22
22
|
get incomeBudget(): number | undefined;
|
|
23
23
|
get unbudgetedCategories(): DetailedCategory[];
|
|
24
24
|
get totalBudgeted(): number;
|
|
25
|
-
|
|
25
|
+
/** Resolves `true` when the budget was created, `false` when the API call failed. */
|
|
26
|
+
addBudget: (category: Category, amount: number, parentGuid?: string | null) => Promise<boolean>;
|
|
26
27
|
deleteBudget: (guid: string) => Promise<boolean>;
|
|
27
28
|
loadBudgets: () => Promise<void>;
|
|
28
29
|
setAlert: (alert: {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { CategoryGuids as o } from "../constants/Category.es.js";
|
|
2
2
|
import { BudgetsApi as g } from "../api/BudgetsApi.es.js";
|
|
3
3
|
import { upsertByGuid as n } from "../utils/upsertByGuid.es.js";
|
|
4
|
-
import { augmentBudgets as c, findBudget as
|
|
4
|
+
import { augmentBudgets as c, findBudget as h, findSubBudget as p } from "../utils/BudgetUtil.es.js";
|
|
5
5
|
import { endOfMonth as B } from "date-fns/endOfMonth";
|
|
6
6
|
import { startOfMonth as f } from "date-fns/startOfMonth";
|
|
7
|
-
import { startOfToday as
|
|
7
|
+
import { startOfToday as l } from "date-fns/startOfToday";
|
|
8
8
|
import { makeAutoObservable as S, reaction as b, runInAction as i } from "mobx";
|
|
9
9
|
var A = class {
|
|
10
10
|
api = new g("/", "");
|
|
11
11
|
globalStore;
|
|
12
12
|
alert = null;
|
|
13
13
|
dateRange = {
|
|
14
|
-
start: f(
|
|
15
|
-
end: B(
|
|
14
|
+
start: f(l()),
|
|
15
|
+
end: B(l())
|
|
16
16
|
};
|
|
17
17
|
budgets = [];
|
|
18
18
|
selectedBudget;
|
|
@@ -27,7 +27,7 @@ var A = class {
|
|
|
27
27
|
this.globalStore.recurringTransactionsStore.isDataLoaded || await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData(), await this.loadBudgets(), b(() => this.detailedBudgets, (t) => {
|
|
28
28
|
if (t) {
|
|
29
29
|
const e = this.selectedBudget;
|
|
30
|
-
e && (this.selectedBudget =
|
|
30
|
+
e && (this.selectedBudget = h(t, e.guid));
|
|
31
31
|
const r = this.selectedSubBudget;
|
|
32
32
|
r && r.parent_guid && (this.selectedSubBudget = p(t, r.guid, r.parent_guid));
|
|
33
33
|
}
|
|
@@ -48,11 +48,11 @@ var A = class {
|
|
|
48
48
|
addBudget = async (t, e, r = null) => {
|
|
49
49
|
try {
|
|
50
50
|
const s = await this.api.addBudget(t, e, r);
|
|
51
|
-
i(() => {
|
|
51
|
+
return i(() => {
|
|
52
52
|
this.budgets = n(this.budgets, s);
|
|
53
|
-
});
|
|
53
|
+
}), !0;
|
|
54
54
|
} catch (s) {
|
|
55
|
-
console.error("Error adding budget:", s), this.globalStore.captureException(s, { store: "BudgetsStore" });
|
|
55
|
+
return console.error("Error adding budget:", s), this.globalStore.captureException(s, { store: "BudgetsStore" }), !1;
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
deleteBudget = async (t) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BudgetsStore.es.js","names":[],"sources":["../../../src/core/stores/BudgetsStore.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from 'mobx'\n\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { Theme } from '@mui/system'\n\nimport { BudgetsApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport { CategoryGuids } from '../constants'\nimport { augmentBudgets, findBudget, findSubBudget } from '../utils/BudgetUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Budget,\n Category,\n DateRange,\n DetailedBudget,\n DetailedCategory,\n MerchantBudget,\n} from '../types'\n\nexport class BudgetsStore {\n api: BudgetsApi = new BudgetsApi('/', '')\n\n globalStore: GlobalStore\n\n alert: { msg: string; severity: 'success' | 'error' } | null = null\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n budgets: Budget[] = []\n selectedBudget: DetailedBudget | undefined\n selectedSubBudget: DetailedBudget | undefined\n isDataLoaded = false\n theme = {} as Theme\n merchantBudgets: MerchantBudget[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BudgetsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBudgetData = async () => {\n if (!this.globalStore.recurringTransactionsStore.isDataLoaded) {\n await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData()\n }\n await this.loadBudgets()\n\n /** Reaction to update the selected budget/sub-budget if detailedBudgets is updated **/\n reaction(\n () => this.detailedBudgets,\n (detailedBudgets) => {\n if (detailedBudgets) {\n const budget = this.selectedBudget\n if (budget) {\n this.selectedBudget = findBudget(detailedBudgets, budget.guid)\n }\n\n const subBudget = this.selectedSubBudget\n if (subBudget && subBudget.parent_guid) {\n this.selectedSubBudget = findSubBudget(\n detailedBudgets,\n subBudget.guid,\n subBudget.parent_guid,\n )\n }\n }\n },\n )\n }\n\n get detailedBudgets(): DetailedBudget[] {\n return augmentBudgets(\n this.budgets.filter(\n (budget: Budget) =>\n budget.category_guid !== CategoryGuids.INCOME &&\n budget.category_guid !== CategoryGuids.TRANSFER &&\n budget.category_guid !== CategoryGuids.INVESTMENTS,\n ),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n ).sort((a, b) => {\n if (a.percentage > b.percentage) return -1\n if (a.percentage < b.percentage) return 1\n return 0\n })\n }\n\n // TODO: Replace this with income from recurring transactions. Income budgets are deprecated.\n get incomeBudget(): number | undefined {\n const filteredBudgets = augmentBudgets(\n this.budgets.filter((budget: Budget) => !budget.parent_guid),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n )\n\n const incomeBudget = filteredBudgets.reduce(\n (acc, curr) => {\n if (curr.category_guid !== CategoryGuids.INCOME) return acc\n if (!acc || curr.percentage > acc.percentage) return curr\n return acc\n },\n undefined as DetailedBudget | undefined,\n )\n\n return incomeBudget?.amount\n }\n\n get unbudgetedCategories(): DetailedCategory[] {\n return this.globalStore.categoryStore.spendCategories.filter(\n (category) => !this.detailedBudgets.find((budget) => budget.category_guid === category.guid),\n )\n }\n\n get totalBudgeted(): number {\n return this.detailedBudgets.reduce((total, budget) => total + budget.amount, 0)\n }\n\n addBudget = async (category: Category, amount: number, parentGuid: string | null = null) => {\n try {\n const budget = await this.api.addBudget(category, amount, parentGuid)\n runInAction(() => {\n this.budgets = upsertByGuid(this.budgets, budget)\n })\n } catch (error) {\n console.error('Error adding budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n }\n }\n\n deleteBudget = async (guid: string): Promise<boolean> => {\n const guids = [guid, ...this.budgets.filter((b) => b.parent_guid === guid).map((b) => b.guid)]\n const results = await Promise.allSettled(guids.map((g) => this.api.deleteBudget(g)))\n const deleted = new Set(guids.filter((_, i) => results[i].status === 'fulfilled'))\n runInAction(() => {\n this.budgets = this.budgets.filter((b) => !deleted.has(b.guid))\n })\n let failed = false\n for (const [i, r] of results.entries()) {\n if (r.status === 'rejected') {\n failed = true\n console.error('Error deleting budget:', r.reason)\n this.globalStore.captureException(r.reason, { store: 'BudgetsStore', guid: guids[i] })\n }\n }\n return !failed\n }\n\n loadBudgets = async () => {\n try {\n const budgets = await this.api.getBudgets()\n this.setBudgets(budgets)\n } catch (error) {\n console.error('Error occurred while loading budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n throw error\n }\n }\n\n setAlert = (alert: { msg: string; severity: 'success' | 'error' } | null) => (this.alert = alert)\n\n setBudgets = (budgets: Budget[]) => {\n this.budgets = budgets\n this.isDataLoaded = true\n }\n\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n setSelectedBudget = (budget: DetailedBudget | undefined) => (this.selectedBudget = budget)\n\n setSelectedSubBudget = (budget: DetailedBudget | undefined) => (this.selectedSubBudget = budget)\n\n setTheme = (theme: Theme) => (this.theme = theme)\n\n /**\n * Recalculate budget by using the average amount from top-level categories\n * @param categories Detailed categories\n */\n recalculateBudgets = async (categories: DetailedCategory[]) => {\n try {\n for (const category of categories) {\n const budget = this.budgets.find((budget) => budget.category_guid === category.guid)\n if (budget) {\n await this.api.updateBudget({\n ...budget,\n amount: category.totalAverageAmount,\n })\n } else {\n await this.api.addBudget(category, category.totalAverageAmount)\n }\n }\n const budgetsToDelete = this.budgets.filter(\n (budget) => !categories.find((c) => c.guid === budget.category_guid),\n )\n\n for (const budgetToDelete of budgetsToDelete) {\n await this.api.deleteBudget(budgetToDelete.guid)\n }\n\n await this.loadBudgets()\n\n return { data: this.budgets, isSuccess: true }\n } catch (error) {\n console.error('Error recalculating budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n // Some budgets may have saved before the failure; reload so a retry updates them.\n await this.loadBudgets().catch(() => undefined)\n return { data: [], isSuccess: false }\n }\n }\n\n updateBudget = async (budget: Budget): Promise<boolean> => {\n try {\n const updatedBudget = await this.api.updateBudget(budget)\n\n runInAction(() => {\n const index = this.budgets.findIndex((b) => b.guid === budget.guid)\n if (index >= 0) {\n this.budgets[index] = updatedBudget\n }\n })\n return true\n } catch (error) {\n console.error('Error updating budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return false\n }\n }\n\n getMerchantBudgetByMerchantGuid = (merchantGuid: string): MerchantBudget | undefined => {\n return this.merchantBudgets.find(\n (eachMerchantBudget) => eachMerchantBudget?.merchant_guid === merchantGuid,\n )\n }\n\n setMerchantBudgets = (merchantBudgets: MerchantBudget[]) => {\n this.merchantBudgets = merchantBudgets\n }\n\n addMerchantBudget = async (merchantGuid: string, amount: number) => {\n try {\n const newMerchantBudget = await this.api.addMerchantBudget(merchantGuid, amount)\n\n runInAction(() => {\n this.merchantBudgets = upsertByGuid(this.merchantBudgets, newMerchantBudget)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error adding merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n updateMerchantBudget = async (merchantBudget: MerchantBudget) => {\n try {\n const { guid: merchantBudgetGuid, amount } = merchantBudget\n const updatedMerchantBudget = await this.api.updateMerchantBudget(merchantBudgetGuid, amount)\n\n runInAction(() => {\n const index = this.merchantBudgets.findIndex((b) => b.guid === merchantBudget.guid)\n if (index >= 0) {\n this.merchantBudgets[index] = updatedMerchantBudget\n }\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error updating merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n deleteMerchantBudget = async (merchantBudgetGuid: string) => {\n try {\n await this.api.deleteMerchantBudget(merchantBudgetGuid)\n\n runInAction(() => {\n this.merchantBudgets = this.merchantBudgets.filter((b) => b.guid !== merchantBudgetGuid)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error deleting merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BudgetsStore.es.js","names":[],"sources":["../../../src/core/stores/BudgetsStore.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from 'mobx'\n\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { Theme } from '@mui/system'\n\nimport { BudgetsApi } from '../api'\nimport { upsertByGuid } from '../utils/upsertByGuid'\nimport { CategoryGuids } from '../constants'\nimport { augmentBudgets, findBudget, findSubBudget } from '../utils/BudgetUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\nimport type {\n Budget,\n Category,\n DateRange,\n DetailedBudget,\n DetailedCategory,\n MerchantBudget,\n} from '../types'\n\nexport class BudgetsStore {\n api: BudgetsApi = new BudgetsApi('/', '')\n\n globalStore: GlobalStore\n\n alert: { msg: string; severity: 'success' | 'error' } | null = null\n dateRange: DateRange = { start: startOfMonth(startOfToday()), end: endOfMonth(startOfToday()) }\n budgets: Budget[] = []\n selectedBudget: DetailedBudget | undefined\n selectedSubBudget: DetailedBudget | undefined\n isDataLoaded = false\n theme = {} as Theme\n merchantBudgets: MerchantBudget[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new BudgetsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n loadBudgetData = async () => {\n if (!this.globalStore.recurringTransactionsStore.isDataLoaded) {\n await this.globalStore.recurringTransactionsStore.loadRepeatingTransactionData()\n }\n await this.loadBudgets()\n\n /** Reaction to update the selected budget/sub-budget if detailedBudgets is updated **/\n reaction(\n () => this.detailedBudgets,\n (detailedBudgets) => {\n if (detailedBudgets) {\n const budget = this.selectedBudget\n if (budget) {\n this.selectedBudget = findBudget(detailedBudgets, budget.guid)\n }\n\n const subBudget = this.selectedSubBudget\n if (subBudget && subBudget.parent_guid) {\n this.selectedSubBudget = findSubBudget(\n detailedBudgets,\n subBudget.guid,\n subBudget.parent_guid,\n )\n }\n }\n },\n )\n }\n\n get detailedBudgets(): DetailedBudget[] {\n return augmentBudgets(\n this.budgets.filter(\n (budget: Budget) =>\n budget.category_guid !== CategoryGuids.INCOME &&\n budget.category_guid !== CategoryGuids.TRANSFER &&\n budget.category_guid !== CategoryGuids.INVESTMENTS,\n ),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n ).sort((a, b) => {\n if (a.percentage > b.percentage) return -1\n if (a.percentage < b.percentage) return 1\n return 0\n })\n }\n\n // TODO: Replace this with income from recurring transactions. Income budgets are deprecated.\n get incomeBudget(): number | undefined {\n const filteredBudgets = augmentBudgets(\n this.budgets.filter((budget: Budget) => !budget.parent_guid),\n this.globalStore.categoryStore.detailedCategories,\n this.globalStore.copyStore.copy.budgets,\n this.theme,\n )\n\n const incomeBudget = filteredBudgets.reduce(\n (acc, curr) => {\n if (curr.category_guid !== CategoryGuids.INCOME) return acc\n if (!acc || curr.percentage > acc.percentage) return curr\n return acc\n },\n undefined as DetailedBudget | undefined,\n )\n\n return incomeBudget?.amount\n }\n\n get unbudgetedCategories(): DetailedCategory[] {\n return this.globalStore.categoryStore.spendCategories.filter(\n (category) => !this.detailedBudgets.find((budget) => budget.category_guid === category.guid),\n )\n }\n\n get totalBudgeted(): number {\n return this.detailedBudgets.reduce((total, budget) => total + budget.amount, 0)\n }\n\n /** Resolves `true` when the budget was created, `false` when the API call failed. */\n addBudget = async (\n category: Category,\n amount: number,\n parentGuid: string | null = null,\n ): Promise<boolean> => {\n try {\n const budget = await this.api.addBudget(category, amount, parentGuid)\n runInAction(() => {\n this.budgets = upsertByGuid(this.budgets, budget)\n })\n return true\n } catch (error) {\n console.error('Error adding budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return false\n }\n }\n\n deleteBudget = async (guid: string): Promise<boolean> => {\n const guids = [guid, ...this.budgets.filter((b) => b.parent_guid === guid).map((b) => b.guid)]\n const results = await Promise.allSettled(guids.map((g) => this.api.deleteBudget(g)))\n const deleted = new Set(guids.filter((_, i) => results[i].status === 'fulfilled'))\n runInAction(() => {\n this.budgets = this.budgets.filter((b) => !deleted.has(b.guid))\n })\n let failed = false\n for (const [i, r] of results.entries()) {\n if (r.status === 'rejected') {\n failed = true\n console.error('Error deleting budget:', r.reason)\n this.globalStore.captureException(r.reason, { store: 'BudgetsStore', guid: guids[i] })\n }\n }\n return !failed\n }\n\n loadBudgets = async () => {\n try {\n const budgets = await this.api.getBudgets()\n this.setBudgets(budgets)\n } catch (error) {\n console.error('Error occurred while loading budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n throw error\n }\n }\n\n setAlert = (alert: { msg: string; severity: 'success' | 'error' } | null) => (this.alert = alert)\n\n setBudgets = (budgets: Budget[]) => {\n this.budgets = budgets\n this.isDataLoaded = true\n }\n\n setDateRange = (dateRange: DateRange) => (this.dateRange = dateRange)\n\n setSelectedBudget = (budget: DetailedBudget | undefined) => (this.selectedBudget = budget)\n\n setSelectedSubBudget = (budget: DetailedBudget | undefined) => (this.selectedSubBudget = budget)\n\n setTheme = (theme: Theme) => (this.theme = theme)\n\n /**\n * Recalculate budget by using the average amount from top-level categories\n * @param categories Detailed categories\n */\n recalculateBudgets = async (categories: DetailedCategory[]) => {\n try {\n for (const category of categories) {\n const budget = this.budgets.find((budget) => budget.category_guid === category.guid)\n if (budget) {\n await this.api.updateBudget({\n ...budget,\n amount: category.totalAverageAmount,\n })\n } else {\n await this.api.addBudget(category, category.totalAverageAmount)\n }\n }\n const budgetsToDelete = this.budgets.filter(\n (budget) => !categories.find((c) => c.guid === budget.category_guid),\n )\n\n for (const budgetToDelete of budgetsToDelete) {\n await this.api.deleteBudget(budgetToDelete.guid)\n }\n\n await this.loadBudgets()\n\n return { data: this.budgets, isSuccess: true }\n } catch (error) {\n console.error('Error recalculating budgets:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n // Some budgets may have saved before the failure; reload so a retry updates them.\n await this.loadBudgets().catch(() => undefined)\n return { data: [], isSuccess: false }\n }\n }\n\n updateBudget = async (budget: Budget): Promise<boolean> => {\n try {\n const updatedBudget = await this.api.updateBudget(budget)\n\n runInAction(() => {\n const index = this.budgets.findIndex((b) => b.guid === budget.guid)\n if (index >= 0) {\n this.budgets[index] = updatedBudget\n }\n })\n return true\n } catch (error) {\n console.error('Error updating budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return false\n }\n }\n\n getMerchantBudgetByMerchantGuid = (merchantGuid: string): MerchantBudget | undefined => {\n return this.merchantBudgets.find(\n (eachMerchantBudget) => eachMerchantBudget?.merchant_guid === merchantGuid,\n )\n }\n\n setMerchantBudgets = (merchantBudgets: MerchantBudget[]) => {\n this.merchantBudgets = merchantBudgets\n }\n\n addMerchantBudget = async (merchantGuid: string, amount: number) => {\n try {\n const newMerchantBudget = await this.api.addMerchantBudget(merchantGuid, amount)\n\n runInAction(() => {\n this.merchantBudgets = upsertByGuid(this.merchantBudgets, newMerchantBudget)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error adding merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n updateMerchantBudget = async (merchantBudget: MerchantBudget) => {\n try {\n const { guid: merchantBudgetGuid, amount } = merchantBudget\n const updatedMerchantBudget = await this.api.updateMerchantBudget(merchantBudgetGuid, amount)\n\n runInAction(() => {\n const index = this.merchantBudgets.findIndex((b) => b.guid === merchantBudget.guid)\n if (index >= 0) {\n this.merchantBudgets[index] = updatedMerchantBudget\n }\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error updating merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n\n deleteMerchantBudget = async (merchantBudgetGuid: string) => {\n try {\n await this.api.deleteMerchantBudget(merchantBudgetGuid)\n\n runInAction(() => {\n this.merchantBudgets = this.merchantBudgets.filter((b) => b.guid !== merchantBudgetGuid)\n })\n return { isSuccess: true }\n } catch (error) {\n console.error('Error deleting merchant budget:', error)\n this.globalStore.captureException(error, { store: 'BudgetsStore' })\n return { isSuccess: false }\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InsightsV2Store.es.js","names":[],"sources":["../../../src/core/stores/InsightsV2Store.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\n\nimport type { GlobalStore } from './GlobalStore'\n\nexport type ActionDrawerTrigger = 'primaryCta' | 'secondaryCta' | 'chartBar'\n\nexport interface ActionDrawerState {\n isDrawerOpen: boolean\n trigger: ActionDrawerTrigger\n guid: string\n /**\n * Block-specific drilldown data for the current drawer SESSION, opaque to the\n * store. Each action block defines and reads its own shape (via\n * useActionContext<T>()). Chart drilldowns put `{ chartBarIndex, tabIndex }`\n * here; CTAs carry none.\n *\n * This is an accumulating bag, not a single owner's value: a nested drawer\n * (e.g. TransactionDetailsBlock opened from a row inside TransactionHistory\n * Block) adds its own key via `setActionContext` ON TOP of whatever the outer\n * drawer already put here, so the outer block's own context survives while the\n * nested block is open. It resets to a clean slate only when a NEW drawer\n * session starts (`openActionDrawer`/`openCtaDrawer`, which fully replace the\n * envelope) — not on every `setActionContext` call.\n */\n context: unknown\n}\n\nexport const CLOSED_ACTION_DRAWER: ActionDrawerState = {\n isDrawerOpen: false,\n trigger: 'primaryCta',\n guid: '',\n context: undefined,\n}\n\ninterface OpenActionDrawerArgs {\n guid: string\n trigger: ActionDrawerTrigger\n context?: unknown\n}\n\n/**\n * UI state shared across the insights-v2 widget tree. Owns the action drawer so\n * cards, charts, and action blocks coordinate through the store instead of prop\n * drilling. The drawer state is a fixed envelope (isDrawerOpen/guid/trigger) plus\n * an opaque `context` bag, so per-block drilldown data never leaks into this shape.\n */\nexport class InsightsV2Store {\n globalStore: GlobalStore\n\n actionDrawer: ActionDrawerState = CLOSED_ACTION_DRAWER\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n\n makeAutoObservable(this)\n }\n\n /**\n * Merges keys into the current drawer session's context bag — it does NOT\n * replace it. A nested drawer (e.g. a row click inside TransactionHistoryBlock\n * opening TransactionDetailsBlock) calls this to layer its own key (e.g.\n * `transaction_guid`) on top of whatever context the outer drawer already set\n * (e.g. `chartBarIndex`), so the outer block keeps reading its own keys via\n * useActionContext while the nested block is open. The bag only returns to a\n * clean slate when a new drawer session starts via `openActionDrawer`/\n * `openCtaDrawer`, which fully replace the envelope.\n */\n setActionContext = (context: Record<string, unknown>) => {\n this.actionDrawer = {\n ...this.actionDrawer,\n context: {
|
|
1
|
+
{"version":3,"file":"InsightsV2Store.es.js","names":[],"sources":["../../../src/core/stores/InsightsV2Store.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\n\nimport type { GlobalStore } from './GlobalStore'\n\nexport type ActionDrawerTrigger = 'primaryCta' | 'secondaryCta' | 'chartBar'\n\nexport interface ActionDrawerState {\n isDrawerOpen: boolean\n trigger: ActionDrawerTrigger\n guid: string\n /**\n * Block-specific drilldown data for the current drawer SESSION, opaque to the\n * store. Each action block defines and reads its own shape (via\n * useActionContext<T>()). Chart drilldowns put `{ chartBarIndex, tabIndex }`\n * here; CTAs carry none.\n *\n * This is an accumulating bag, not a single owner's value: a nested drawer\n * (e.g. TransactionDetailsBlock opened from a row inside TransactionHistory\n * Block) adds its own key via `setActionContext` ON TOP of whatever the outer\n * drawer already put here, so the outer block's own context survives while the\n * nested block is open. It resets to a clean slate only when a NEW drawer\n * session starts (`openActionDrawer`/`openCtaDrawer`, which fully replace the\n * envelope) — not on every `setActionContext` call.\n */\n context: unknown\n}\n\nexport const CLOSED_ACTION_DRAWER: ActionDrawerState = {\n isDrawerOpen: false,\n trigger: 'primaryCta',\n guid: '',\n context: undefined,\n}\n\ninterface OpenActionDrawerArgs {\n guid: string\n trigger: ActionDrawerTrigger\n context?: unknown\n}\n\n/**\n * UI state shared across the insights-v2 widget tree. Owns the action drawer so\n * cards, charts, and action blocks coordinate through the store instead of prop\n * drilling. The drawer state is a fixed envelope (isDrawerOpen/guid/trigger) plus\n * an opaque `context` bag, so per-block drilldown data never leaks into this shape.\n */\nexport class InsightsV2Store {\n globalStore: GlobalStore\n\n actionDrawer: ActionDrawerState = CLOSED_ACTION_DRAWER\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n\n makeAutoObservable(this)\n }\n\n /**\n * Merges keys into the current drawer session's context bag — it does NOT\n * replace it. A nested drawer (e.g. a row click inside TransactionHistoryBlock\n * opening TransactionDetailsBlock) calls this to layer its own key (e.g.\n * `transaction_guid`) on top of whatever context the outer drawer already set\n * (e.g. `chartBarIndex`), so the outer block keeps reading its own keys via\n * useActionContext while the nested block is open. The bag only returns to a\n * clean slate when a new drawer session starts via `openActionDrawer`/\n * `openCtaDrawer`, which fully replace the envelope.\n */\n setActionContext = (context: Record<string, unknown>) => {\n this.actionDrawer = {\n ...this.actionDrawer,\n context: {\n ...(this.actionDrawer.context as Record<string, unknown> | undefined),\n ...context,\n },\n }\n }\n\n /**\n * Generic drawer opener — the only opener a new action block needs. Pass the\n * beat guid, the CTA/source that triggered it, and (optionally) a block-specific\n * context object the block reads back via useActionContext.\n */\n openActionDrawer = ({ guid, trigger, context }: OpenActionDrawerArgs) => {\n this.actionDrawer = { isDrawerOpen: true, trigger, guid, context }\n }\n\n /** Convenience opener for CTA drawers (no drilldown context). */\n openCtaDrawer = (guid: string, trigger: 'primaryCta' | 'secondaryCta') => {\n this.openActionDrawer({ guid, trigger })\n }\n\n closeActionDrawer = () => {\n // Preserve `trigger` + `context` so the drawer keeps its variant-specific\n // title/content through the slide-out animation (ActionBlockLayer stays\n // mounted while closing). Only flip isDrawerOpen off and clear the beat guid.\n this.actionDrawer = { ...this.actionDrawer, isDrawerOpen: false, guid: '' }\n }\n}\n"],"mappings":";AA2BA,IAAa,IAA0C;AAAA,EACrD,cAAc;AAAA,EACd,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX,GAca,IAAb,MAA6B;AAAA,EAC3B;AAAA,EAEA,eAAkC;AAAA,EAElC,YAAY,GAA0B;AACpC,SAAK,cAAc,GAEnB,EAAmB,IAAI;AAAA,EACzB;AAAA,EAYA,mBAAA,CAAoB,MAAqC;AACvD,SAAK,eAAe;AAAA,MAClB,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,QACP,GAAI,KAAK,aAAa;AAAA,QACtB,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAOA,mBAAA,CAAoB,EAAE,MAAA,GAAM,SAAA,GAAS,SAAA,EAAA,MAAoC;AACvE,SAAK,eAAe;AAAA,MAAE,cAAc;AAAA,MAAM,SAAA;AAAA,MAAS,MAAA;AAAA,MAAM,SAAA;AAAA,IAAQ;AAAA,EACnE;AAAA,EAGA,gBAAA,CAAiB,GAAc,MAA2C;AACxE,SAAK,iBAAiB;AAAA,MAAE,MAAA;AAAA,MAAM,SAAA;AAAA,IAAQ,CAAC;AAAA,EACzC;AAAA,EAEA,oBAAA,MAA0B;AAIxB,SAAK,eAAe;AAAA,MAAE,GAAG,KAAK;AAAA,MAAc,cAAc;AAAA,MAAO,MAAM;AAAA,IAAG;AAAA,EAC5E;AACF"}
|
|
@@ -45,7 +45,8 @@ export declare class SettingsStore {
|
|
|
45
45
|
updateDevice: (device: Device) => Promise<{
|
|
46
46
|
success: boolean;
|
|
47
47
|
}>;
|
|
48
|
-
|
|
48
|
+
/** Resolves `true` when the profile was saved, `false` when the API call failed. */
|
|
49
|
+
updateNotificationProfile: (profile: NotificationProfile) => Promise<boolean>;
|
|
49
50
|
updateRuleCategory: (rule: TransactionRule) => Promise<void>;
|
|
50
51
|
updateRulePayee: (rule: TransactionRule) => Promise<void>;
|
|
51
52
|
updateUser: (user: User) => Promise<void>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SettingsApi as a } from "../api/SettingsApi.es.js";
|
|
2
2
|
import { TransactionApi as n } from "../api/TransactionApi.es.js";
|
|
3
|
-
import { AccountNotificationTypes as
|
|
3
|
+
import { AccountNotificationTypes as r, BudgetNotificationTypes as c, InsightNotificationTypes as l } from "../types/Notification.es.js";
|
|
4
4
|
import { augmentNotificationProfiles as u } from "../utils/SettingsUtil.es.js";
|
|
5
|
-
import { makeAutoObservable as p, runInAction as
|
|
5
|
+
import { makeAutoObservable as p, runInAction as o } from "mobx";
|
|
6
6
|
var _ = class {
|
|
7
7
|
globalStore;
|
|
8
8
|
api = new a("/", "");
|
|
@@ -20,7 +20,7 @@ var _ = class {
|
|
|
20
20
|
}
|
|
21
21
|
get accountProfiles() {
|
|
22
22
|
const t = this.globalStore.appDataStore.clientCommunicationProfile;
|
|
23
|
-
return this.detailedNotificationProfiles.filter((e) => e.notification_type ===
|
|
23
|
+
return this.detailedNotificationProfiles.filter((e) => e.notification_type === r.DebtPaymentReminder && t.debt_payment_reminder_notifications_enabled || e.notification_type === r.AccountBalanceLow && t.low_balance_notifications_enabled || e.notification_type === r.AccountDepositLarge && t.large_deposit_notifications_enabled || e.notification_type === r.TransactionExpenseLarge && t.large_expense_notifications_enabled || e.notification_type === r.TransactionFeeCharge && t.transaction_fee_notifications_enabled || e.notification_type === r.InternationalTransaction && t.transaction_is_international_notifications_enabled || e.notification_type === r.AccountDepositLargePosted && t.large_deposit_posted_notifications_enabled);
|
|
24
24
|
}
|
|
25
25
|
get budgetProfiles() {
|
|
26
26
|
const t = this.globalStore.appDataStore.clientCommunicationProfile;
|
|
@@ -45,7 +45,7 @@ var _ = class {
|
|
|
45
45
|
try {
|
|
46
46
|
await this.api.deleteDevice(t);
|
|
47
47
|
const e = this.devices.findIndex((i) => i.guid === t);
|
|
48
|
-
return e >= 0 &&
|
|
48
|
+
return e >= 0 && o(() => {
|
|
49
49
|
this.devices.splice(e, 1);
|
|
50
50
|
}), { success: !0 };
|
|
51
51
|
} catch (e) {
|
|
@@ -70,7 +70,7 @@ var _ = class {
|
|
|
70
70
|
loadDevices = async () => {
|
|
71
71
|
try {
|
|
72
72
|
const t = await this.api.getDevices();
|
|
73
|
-
|
|
73
|
+
o(() => {
|
|
74
74
|
this.devices = t;
|
|
75
75
|
});
|
|
76
76
|
} catch (t) {
|
|
@@ -80,7 +80,7 @@ var _ = class {
|
|
|
80
80
|
loadNotificationProfiles = async () => {
|
|
81
81
|
try {
|
|
82
82
|
const t = await this.api.getNotificationProfiles();
|
|
83
|
-
|
|
83
|
+
o(() => {
|
|
84
84
|
this.notificationProfiles = t;
|
|
85
85
|
});
|
|
86
86
|
} catch (t) {
|
|
@@ -90,7 +90,7 @@ var _ = class {
|
|
|
90
90
|
loadTransactionRules = async () => {
|
|
91
91
|
try {
|
|
92
92
|
const t = await this.transactionApi.getTransactionRules();
|
|
93
|
-
|
|
93
|
+
o(() => {
|
|
94
94
|
this.transactionRules = t;
|
|
95
95
|
});
|
|
96
96
|
} catch (t) {
|
|
@@ -128,7 +128,7 @@ var _ = class {
|
|
|
128
128
|
updateDevice = async (t) => {
|
|
129
129
|
try {
|
|
130
130
|
const e = await this.api.updateDevice(t), i = this.devices.findIndex((s) => s.guid === t.guid);
|
|
131
|
-
return i >= 0 &&
|
|
131
|
+
return i >= 0 && o(() => {
|
|
132
132
|
this.devices[i] = e;
|
|
133
133
|
}), { success: !0 };
|
|
134
134
|
} catch (e) {
|
|
@@ -138,11 +138,11 @@ var _ = class {
|
|
|
138
138
|
updateNotificationProfile = async (t) => {
|
|
139
139
|
try {
|
|
140
140
|
const e = await this.api.updateNotificationProfile(t), i = this.notificationProfiles.findIndex((s) => s.guid === t.guid);
|
|
141
|
-
i >= 0 &&
|
|
141
|
+
return i >= 0 && o(() => {
|
|
142
142
|
this.notificationProfiles[i] = e;
|
|
143
|
-
});
|
|
143
|
+
}), !0;
|
|
144
144
|
} catch (e) {
|
|
145
|
-
console.error("Error updating notification profile:", e), this.globalStore.captureException(e, { store: "SettingsStore" });
|
|
145
|
+
return console.error("Error updating notification profile:", e), this.globalStore.captureException(e, { store: "SettingsStore" }), !1;
|
|
146
146
|
}
|
|
147
147
|
};
|
|
148
148
|
updateRuleCategory = async (t) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsStore.es.js","names":[],"sources":["../../../src/core/stores/SettingsStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { AlertProps } from '@mui/material'\n\nimport {\n AccountNotificationTypes,\n BudgetNotificationTypes,\n InsightNotificationTypes,\n} from '../types'\n\nimport type {\n DetailedNotificationProfile,\n Device,\n NotificationProfile,\n SettingsCopy,\n TransactionRule,\n User,\n UserCommunicationProfile,\n} from '../types'\n\nimport { SettingsApi, TransactionApi } from '../api'\nimport { augmentNotificationProfiles } from '../utils/SettingsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\ninterface SettingsAlertProps {\n message: string\n severity: AlertProps['severity']\n}\n\nexport class SettingsStore {\n globalStore: GlobalStore\n api: SettingsApi = new SettingsApi('/', '')\n transactionApi: TransactionApi = new TransactionApi('/', '')\n\n alert: SettingsAlertProps = { message: '', severity: undefined }\n devices: Device[] = []\n notificationProfiles: NotificationProfile[] = []\n selectedRule: TransactionRule | undefined = undefined\n transactionRules: TransactionRule[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new SettingsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n this.transactionApi = new TransactionApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n makeAutoObservable(this)\n }\n\n get accountProfiles() {\n const ccp = this.globalStore.appDataStore.clientCommunicationProfile\n\n // TODO: There has to be a better way to do this, but for now, it works\n return this.detailedNotificationProfiles.filter(\n (np) =>\n (np.notification_type === AccountNotificationTypes.DebtPaymentReminder &&\n ccp.debt_payment_reminder_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountBalanceLow &&\n ccp.low_balance_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountDepositLarge &&\n ccp.large_deposit_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.TransactionExpenseLarge &&\n ccp.large_expense_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.TransactionFeeCharge &&\n ccp.transaction_fee_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.InternationalTransaction &&\n ccp.transaction_is_international_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountDepositLargePosted &&\n ccp.large_deposit_posted_notifications_enabled),\n )\n }\n\n get budgetProfiles() {\n const ccp = this.globalStore.appDataStore.clientCommunicationProfile\n\n // TODO: There has to be a better way to do this, but for now, it works\n return this.detailedNotificationProfiles.filter(\n (np) =>\n (np.notification_type === BudgetNotificationTypes.BudgetExceeded &&\n ccp.budget_exceeded_notifications_enabled) ||\n (np.notification_type === BudgetNotificationTypes.BudgetOffTarget &&\n ccp.budget_off_target_notifications_enabled),\n )\n }\n\n get insightsProfiles() {\n return this.detailedNotificationProfiles.filter((np) =>\n Object.values(InsightNotificationTypes).includes(np.notification_type),\n )\n }\n\n get clientCommunicationProfile() {\n return this.globalStore.appDataStore.clientCommunicationProfile\n }\n\n get copy(): SettingsCopy {\n return this.globalStore.copyStore.copy.settings\n }\n\n get detailedNotificationProfiles(): DetailedNotificationProfile[] {\n // Don't attempt to augment profile if global store is not initialized\n if (!this.globalStore.isInitialized) return []\n\n return augmentNotificationProfiles(\n this.globalStore.accountStore.accounts,\n this.clientCommunicationProfile,\n this.copy,\n this.notificationProfiles,\n this.userCommunicationsProfile,\n this.globalStore.userStore.user,\n )\n }\n\n get userCommunicationsProfile() {\n return this.globalStore.appDataStore.userCommunicationProfile\n }\n\n deleteDevice = async (guid: string) => {\n try {\n await this.api.deleteDevice(guid)\n\n const index = this.devices.findIndex((d) => d.guid === guid)\n if (index >= 0) {\n runInAction(() => {\n this.devices.splice(index, 1)\n })\n }\n\n return { success: true }\n } catch (error) {\n console.error('Error deleting device:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n return { success: false }\n }\n }\n\n deleteTransactionRule = async () => {\n if (!this.selectedRule) {\n return\n }\n try {\n await this.transactionApi.removeTransactionRule(this.selectedRule?.guid)\n this.setAlert(this.copy.delete_rule_success, 'success')\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error deleting transaction rule:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.delete_rule_error, 'error')\n }\n }\n\n generateDeviceToken = async () => {\n try {\n return await this.api.generateDeviceToken()\n } catch (error) {\n console.error('Error generating device token:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n return undefined\n }\n\n loadDevices = async () => {\n try {\n const devices = await this.api.getDevices()\n\n runInAction(() => {\n this.devices = devices\n })\n } catch (error) {\n console.error('Error loading devices:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n loadNotificationProfiles = async () => {\n try {\n const profiles = await this.api.getNotificationProfiles()\n\n runInAction(() => {\n this.notificationProfiles = profiles\n })\n } catch (error) {\n console.error('Error loading notification profiles:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n loadTransactionRules = async () => {\n try {\n const rules = await this.transactionApi.getTransactionRules()\n\n runInAction(() => {\n this.transactionRules = rules\n })\n } catch (error) {\n console.error('Error loading transaction rules:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n sendEmailVerification = async () => {\n try {\n await this.api.sendEmailVerification()\n this.setAlert(this.copy.verification_sent_success, 'success')\n } catch (error) {\n console.error('Error sending email verification:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verification_sent_error, 'error')\n }\n }\n\n sendPhoneVerification = async () => {\n try {\n await this.api.sendPhoneVerification()\n this.setAlert(this.copy.verification_sent_success, 'success')\n } catch (error) {\n console.error('Error sending phone verification:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verification_sent_error, 'error')\n }\n }\n\n setAlert = (message: string, severity: SettingsAlertProps['severity'] = undefined) =>\n (this.alert = { message, severity })\n\n setSelectedRule = (rule?: TransactionRule) => {\n this.selectedRule = rule\n }\n\n updatePassword = async (params: { new_password: string; new_password_again: string }) => {\n try {\n await this.api.updatePassword(params)\n this.setAlert(this.copy.password_updated_success, 'success')\n } catch (error) {\n console.error('Error updating password:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.password_updated_error, 'error')\n }\n }\n\n updateDevice = async (device: Device) => {\n try {\n const updatedDevice = await this.api.updateDevice(device)\n\n const index = this.devices.findIndex((d) => d.guid === device.guid)\n if (index >= 0) {\n runInAction(() => {\n this.devices[index] = updatedDevice\n })\n }\n return { success: true }\n } catch (error) {\n console.error('Error updating device:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n return { success: false }\n }\n }\n\n updateNotificationProfile = async (profile: NotificationProfile) => {\n try {\n const updatedProfile = await this.api.updateNotificationProfile(profile)\n\n const index = this.notificationProfiles.findIndex((p) => p.guid === profile.guid)\n if (index >= 0) {\n runInAction(() => {\n this.notificationProfiles[index] = updatedProfile\n })\n }\n } catch (error) {\n console.error('Error updating notification profile:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n updateRuleCategory = async (rule: TransactionRule) => {\n try {\n await this.transactionApi.updateTransactionRule(rule)\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error updating rule category:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n updateRulePayee = async (rule: TransactionRule) => {\n try {\n await this.transactionApi.updateTransactionRule(rule)\n this.setAlert(this.copy.edit_payee_success, 'success')\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error updating rule payee:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.edit_payee_error, 'error')\n }\n }\n\n updateUser = async (user: User) => {\n try {\n await this.globalStore.userStore.updateUser(user)\n this.setAlert(this.copy.information_updated_success, 'success')\n } catch {\n // Error is already logged and captured in UserStore.updateUser\n this.setAlert(this.copy.information_updated_error, 'error')\n }\n }\n\n updateUserCommunicationProfile = async (profile: UserCommunicationProfile) => {\n try {\n const updatedProfile = await this.api.updateUserCommunicationProfile(profile)\n\n this.globalStore.appDataStore.setUserCommunicationProfile(updatedProfile)\n } catch (error) {\n console.error('Error occurred while updating user communication profile:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n verifyPhoneToken = async (sms_verification_token: string) => {\n try {\n const { verified } = await this.api.verifyPhoneToken(sms_verification_token)\n if (!verified) {\n throw new Error()\n }\n this.setAlert(this.copy.verified_phone_success, 'success')\n } catch (error) {\n console.error('Error verifying phone token:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verified_phone_error, 'error')\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SettingsStore.es.js","names":[],"sources":["../../../src/core/stores/SettingsStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { AlertProps } from '@mui/material'\n\nimport {\n AccountNotificationTypes,\n BudgetNotificationTypes,\n InsightNotificationTypes,\n} from '../types'\n\nimport type {\n DetailedNotificationProfile,\n Device,\n NotificationProfile,\n SettingsCopy,\n TransactionRule,\n User,\n UserCommunicationProfile,\n} from '../types'\n\nimport { SettingsApi, TransactionApi } from '../api'\nimport { augmentNotificationProfiles } from '../utils/SettingsUtil'\n\nimport { GlobalStore } from './GlobalStore'\n\ninterface SettingsAlertProps {\n message: string\n severity: AlertProps['severity']\n}\n\nexport class SettingsStore {\n globalStore: GlobalStore\n api: SettingsApi = new SettingsApi('/', '')\n transactionApi: TransactionApi = new TransactionApi('/', '')\n\n alert: SettingsAlertProps = { message: '', severity: undefined }\n devices: Device[] = []\n notificationProfiles: NotificationProfile[] = []\n selectedRule: TransactionRule | undefined = undefined\n transactionRules: TransactionRule[] = []\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new SettingsApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n this.transactionApi = new TransactionApi(\n globalStore.endpoint,\n globalStore.sessionToken,\n globalStore.onError,\n )\n\n makeAutoObservable(this)\n }\n\n get accountProfiles() {\n const ccp = this.globalStore.appDataStore.clientCommunicationProfile\n\n // TODO: There has to be a better way to do this, but for now, it works\n return this.detailedNotificationProfiles.filter(\n (np) =>\n (np.notification_type === AccountNotificationTypes.DebtPaymentReminder &&\n ccp.debt_payment_reminder_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountBalanceLow &&\n ccp.low_balance_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountDepositLarge &&\n ccp.large_deposit_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.TransactionExpenseLarge &&\n ccp.large_expense_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.TransactionFeeCharge &&\n ccp.transaction_fee_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.InternationalTransaction &&\n ccp.transaction_is_international_notifications_enabled) ||\n (np.notification_type === AccountNotificationTypes.AccountDepositLargePosted &&\n ccp.large_deposit_posted_notifications_enabled),\n )\n }\n\n get budgetProfiles() {\n const ccp = this.globalStore.appDataStore.clientCommunicationProfile\n\n // TODO: There has to be a better way to do this, but for now, it works\n return this.detailedNotificationProfiles.filter(\n (np) =>\n (np.notification_type === BudgetNotificationTypes.BudgetExceeded &&\n ccp.budget_exceeded_notifications_enabled) ||\n (np.notification_type === BudgetNotificationTypes.BudgetOffTarget &&\n ccp.budget_off_target_notifications_enabled),\n )\n }\n\n get insightsProfiles() {\n return this.detailedNotificationProfiles.filter((np) =>\n Object.values(InsightNotificationTypes).includes(np.notification_type),\n )\n }\n\n get clientCommunicationProfile() {\n return this.globalStore.appDataStore.clientCommunicationProfile\n }\n\n get copy(): SettingsCopy {\n return this.globalStore.copyStore.copy.settings\n }\n\n get detailedNotificationProfiles(): DetailedNotificationProfile[] {\n // Don't attempt to augment profile if global store is not initialized\n if (!this.globalStore.isInitialized) return []\n\n return augmentNotificationProfiles(\n this.globalStore.accountStore.accounts,\n this.clientCommunicationProfile,\n this.copy,\n this.notificationProfiles,\n this.userCommunicationsProfile,\n this.globalStore.userStore.user,\n )\n }\n\n get userCommunicationsProfile() {\n return this.globalStore.appDataStore.userCommunicationProfile\n }\n\n deleteDevice = async (guid: string) => {\n try {\n await this.api.deleteDevice(guid)\n\n const index = this.devices.findIndex((d) => d.guid === guid)\n if (index >= 0) {\n runInAction(() => {\n this.devices.splice(index, 1)\n })\n }\n\n return { success: true }\n } catch (error) {\n console.error('Error deleting device:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n return { success: false }\n }\n }\n\n deleteTransactionRule = async () => {\n if (!this.selectedRule) {\n return\n }\n try {\n await this.transactionApi.removeTransactionRule(this.selectedRule?.guid)\n this.setAlert(this.copy.delete_rule_success, 'success')\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error deleting transaction rule:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.delete_rule_error, 'error')\n }\n }\n\n generateDeviceToken = async () => {\n try {\n return await this.api.generateDeviceToken()\n } catch (error) {\n console.error('Error generating device token:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n return undefined\n }\n\n loadDevices = async () => {\n try {\n const devices = await this.api.getDevices()\n\n runInAction(() => {\n this.devices = devices\n })\n } catch (error) {\n console.error('Error loading devices:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n loadNotificationProfiles = async () => {\n try {\n const profiles = await this.api.getNotificationProfiles()\n\n runInAction(() => {\n this.notificationProfiles = profiles\n })\n } catch (error) {\n console.error('Error loading notification profiles:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n loadTransactionRules = async () => {\n try {\n const rules = await this.transactionApi.getTransactionRules()\n\n runInAction(() => {\n this.transactionRules = rules\n })\n } catch (error) {\n console.error('Error loading transaction rules:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n sendEmailVerification = async () => {\n try {\n await this.api.sendEmailVerification()\n this.setAlert(this.copy.verification_sent_success, 'success')\n } catch (error) {\n console.error('Error sending email verification:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verification_sent_error, 'error')\n }\n }\n\n sendPhoneVerification = async () => {\n try {\n await this.api.sendPhoneVerification()\n this.setAlert(this.copy.verification_sent_success, 'success')\n } catch (error) {\n console.error('Error sending phone verification:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verification_sent_error, 'error')\n }\n }\n\n setAlert = (message: string, severity: SettingsAlertProps['severity'] = undefined) =>\n (this.alert = { message, severity })\n\n setSelectedRule = (rule?: TransactionRule) => {\n this.selectedRule = rule\n }\n\n updatePassword = async (params: { new_password: string; new_password_again: string }) => {\n try {\n await this.api.updatePassword(params)\n this.setAlert(this.copy.password_updated_success, 'success')\n } catch (error) {\n console.error('Error updating password:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.password_updated_error, 'error')\n }\n }\n\n updateDevice = async (device: Device) => {\n try {\n const updatedDevice = await this.api.updateDevice(device)\n\n const index = this.devices.findIndex((d) => d.guid === device.guid)\n if (index >= 0) {\n runInAction(() => {\n this.devices[index] = updatedDevice\n })\n }\n return { success: true }\n } catch (error) {\n console.error('Error updating device:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n return { success: false }\n }\n }\n\n /** Resolves `true` when the profile was saved, `false` when the API call failed. */\n updateNotificationProfile = async (profile: NotificationProfile): Promise<boolean> => {\n try {\n const updatedProfile = await this.api.updateNotificationProfile(profile)\n\n const index = this.notificationProfiles.findIndex((p) => p.guid === profile.guid)\n if (index >= 0) {\n runInAction(() => {\n this.notificationProfiles[index] = updatedProfile\n })\n }\n return true\n } catch (error) {\n console.error('Error updating notification profile:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n return false\n }\n }\n\n updateRuleCategory = async (rule: TransactionRule) => {\n try {\n await this.transactionApi.updateTransactionRule(rule)\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error updating rule category:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n updateRulePayee = async (rule: TransactionRule) => {\n try {\n await this.transactionApi.updateTransactionRule(rule)\n this.setAlert(this.copy.edit_payee_success, 'success')\n await this.loadTransactionRules()\n } catch (error) {\n console.error('Error updating rule payee:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.edit_payee_error, 'error')\n }\n }\n\n updateUser = async (user: User) => {\n try {\n await this.globalStore.userStore.updateUser(user)\n this.setAlert(this.copy.information_updated_success, 'success')\n } catch {\n // Error is already logged and captured in UserStore.updateUser\n this.setAlert(this.copy.information_updated_error, 'error')\n }\n }\n\n updateUserCommunicationProfile = async (profile: UserCommunicationProfile) => {\n try {\n const updatedProfile = await this.api.updateUserCommunicationProfile(profile)\n\n this.globalStore.appDataStore.setUserCommunicationProfile(updatedProfile)\n } catch (error) {\n console.error('Error occurred while updating user communication profile:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n }\n }\n\n verifyPhoneToken = async (sms_verification_token: string) => {\n try {\n const { verified } = await this.api.verifyPhoneToken(sms_verification_token)\n if (!verified) {\n throw new Error()\n }\n this.setAlert(this.copy.verified_phone_success, 'success')\n } catch (error) {\n console.error('Error verifying phone token:', error)\n this.globalStore.captureException(error, { store: 'SettingsStore' })\n this.setAlert(this.copy.verified_phone_error, 'error')\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -52,7 +52,8 @@ export declare class TransactionStore {
|
|
|
52
52
|
setAlert: (alert: string) => void;
|
|
53
53
|
addTag: (name: string) => Promise<void>;
|
|
54
54
|
addTagging: (tagGuid: string, transactionGuid: string) => Promise<void>;
|
|
55
|
-
|
|
55
|
+
/** Resolves `true` when the rule was saved, `false` when an API call failed. */
|
|
56
|
+
addOrUpdateTransactionRule: (categoryGuid: string, transaction: Transaction) => Promise<boolean>;
|
|
56
57
|
addTransaction: (transaction: Transaction) => Promise<void>;
|
|
57
58
|
loadAssociatedBeats: (fromDate?: Date) => Promise<void>;
|
|
58
59
|
loadTags: () => Promise<void>;
|
|
@@ -69,7 +70,8 @@ export declare class TransactionStore {
|
|
|
69
70
|
unSplitTransaction: (guid: string) => Promise<void>;
|
|
70
71
|
updateTaggings: (tagGuids: string[], transactionGuid: string) => Promise<void>;
|
|
71
72
|
updateTag: (tag: Tag) => Promise<void>;
|
|
72
|
-
|
|
73
|
+
/** Resolves `true` when the transaction was saved, `false` when the API call failed. */
|
|
74
|
+
updateTransaction: (transaction: Transaction) => Promise<boolean>;
|
|
73
75
|
loadEmbeddedInstanceTransactions: (fromDate: Date) => Promise<void>;
|
|
74
76
|
}
|
|
75
77
|
export declare class UiStore {
|
|
@@ -102,7 +102,7 @@ var P = class {
|
|
|
102
102
|
addOrUpdateTransactionRule = async (t, a) => {
|
|
103
103
|
try {
|
|
104
104
|
const s = this.transactionRules.find((e) => e.guid === a.user_transaction_rule_guid);
|
|
105
|
-
s ? await this.api.updateTransactionRule({
|
|
105
|
+
return s ? await this.api.updateTransactionRule({
|
|
106
106
|
...s,
|
|
107
107
|
category_guid: t,
|
|
108
108
|
description: a.description
|
|
@@ -110,9 +110,9 @@ var P = class {
|
|
|
110
110
|
category_guid: t,
|
|
111
111
|
description: a.description,
|
|
112
112
|
match_description: a.description
|
|
113
|
-
}), await this.loadTransactionRules();
|
|
113
|
+
}), await this.loadTransactionRules(), !0;
|
|
114
114
|
} catch (s) {
|
|
115
|
-
console.error("Error occurred while adding/updating transaction rule:", s), this.globalStore.captureException(s, { store: "TransactionStore" });
|
|
115
|
+
return console.error("Error occurred while adding/updating transaction rule:", s), this.globalStore.captureException(s, { store: "TransactionStore" }), !1;
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
addTransaction = async (t) => {
|
|
@@ -308,13 +308,13 @@ var P = class {
|
|
|
308
308
|
updateTransaction = async (t) => {
|
|
309
309
|
try {
|
|
310
310
|
const a = await this.api.updateTransaction(t), s = this.transactions.findIndex((e) => e.guid === t.guid);
|
|
311
|
-
s >= 0 && this.setTransactions([
|
|
311
|
+
return s >= 0 && this.setTransactions([
|
|
312
312
|
...this.transactions.slice(0, s),
|
|
313
313
|
a,
|
|
314
314
|
...this.transactions.slice(s + 1)
|
|
315
|
-
]);
|
|
315
|
+
]), !0;
|
|
316
316
|
} catch (a) {
|
|
317
|
-
console.error("Error occurred while updating transaction:", a), this.globalStore.captureException(a, { store: "TransactionStore" });
|
|
317
|
+
return console.error("Error occurred while updating transaction:", a), this.globalStore.captureException(a, { store: "TransactionStore" }), !1;
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
320
|
loadEmbeddedInstanceTransactions = async (t) => {
|
|
@@ -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 { formatISO } from 'date-fns/formatISO'\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 { endOfUtcDay, startOfUtcDay } from '../utils/DateUtil'\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 startOfUtcDay(startDate),\n endOfUtcDay(startOfToday()),\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 startOfUtcDay(fromDate),\n endOfUtcDay(startOfToday()),\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 { formatISO } from 'date-fns/formatISO'\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 { endOfUtcDay, startOfUtcDay } from '../utils/DateUtil'\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 /** Resolves `true` when the rule was saved, `false` when an API call failed. */\n addOrUpdateTransactionRule = async (\n categoryGuid: string,\n transaction: Transaction,\n ): Promise<boolean> => {\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 return true\n } catch (error) {\n console.error('Error occurred while adding/updating transaction rule:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n return false\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 startOfUtcDay(startDate),\n endOfUtcDay(startOfToday()),\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 /** Resolves `true` when the transaction was saved, `false` when the API call failed. */\n updateTransaction = async (transaction: Transaction): Promise<boolean> => {\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 return true\n } catch (error) {\n console.error('Error occurred while updating transaction:', error)\n this.globalStore.captureException(error, { store: 'TransactionStore' })\n return false\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 startOfUtcDay(fromDate),\n endOfUtcDay(startOfToday()),\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,11 +1,12 @@
|
|
|
1
1
|
import { UserApi } from '../api';
|
|
2
|
-
import { User, UserFeature, UserProfile } from '../types';
|
|
2
|
+
import { User, UserFeature, UserInsightProfile, UserProfile } from '../types';
|
|
3
3
|
import { GlobalStore } from './GlobalStore';
|
|
4
4
|
export declare class UserStore {
|
|
5
5
|
globalStore: GlobalStore;
|
|
6
6
|
api: UserApi;
|
|
7
7
|
userFeatures: UserFeature[];
|
|
8
8
|
userFeaturesLoaded: boolean;
|
|
9
|
+
userInsightProfile: UserInsightProfile | null;
|
|
9
10
|
constructor(globalStore: GlobalStore);
|
|
10
11
|
get userProfile(): UserProfile;
|
|
11
12
|
get user(): User;
|
|
@@ -13,4 +14,17 @@ export declare class UserStore {
|
|
|
13
14
|
loadUserFeatures: () => Promise<void>;
|
|
14
15
|
updateUser: (user: User) => Promise<void>;
|
|
15
16
|
updateUserProfile: (userProfile: UserProfile) => Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Seeds the profile. The host (pulse) loads `user_insight_profile` and pushes it in here;
|
|
19
|
+
* experiences itself never fetches it.
|
|
20
|
+
*/
|
|
21
|
+
setUserInsightProfile: (profile: UserInsightProfile | null) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Merges `fields` into the seeded profile and PUTs the whole profile. The endpoint is an
|
|
24
|
+
* upsert that writes every profile field from the request, so a partial body would null
|
|
25
|
+
* the fields it omits; the merge is what keeps them. Throws if the host has not seeded the
|
|
26
|
+
* profile yet, and rethrows API failures, so a caller driving UI state (e.g. an insight
|
|
27
|
+
* CTA) reports the error instead of silently treating the save as done.
|
|
28
|
+
*/
|
|
29
|
+
updateUserInsightProfile: (fields: Partial<UserInsightProfile>) => Promise<UserInsightProfile>;
|
|
16
30
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { UserApi as t } from "../api/UserApi.es.js";
|
|
2
|
-
import { makeAutoObservable as s } from "mobx";
|
|
3
|
-
var
|
|
2
|
+
import { makeAutoObservable as s, runInAction as o } from "mobx";
|
|
3
|
+
var u = class {
|
|
4
4
|
globalStore;
|
|
5
5
|
api = new t("/", "");
|
|
6
6
|
userFeatures = [];
|
|
7
7
|
userFeaturesLoaded = !1;
|
|
8
|
+
userInsightProfile = null;
|
|
8
9
|
constructor(e) {
|
|
9
10
|
this.globalStore = e, this.api = new t(e.endpoint, e.sessionToken, e.onError), s(this);
|
|
10
11
|
}
|
|
@@ -41,9 +42,26 @@ var i = class {
|
|
|
41
42
|
console.error("Error occurred while updating user profile:", r), this.globalStore.captureException(r, { store: "UserStore" });
|
|
42
43
|
}
|
|
43
44
|
};
|
|
45
|
+
setUserInsightProfile = (e) => {
|
|
46
|
+
this.userInsightProfile = e;
|
|
47
|
+
};
|
|
48
|
+
updateUserInsightProfile = async (e) => {
|
|
49
|
+
if (!this.userInsightProfile) throw new Error("User insight profile has not been loaded; refusing a partial PUT");
|
|
50
|
+
try {
|
|
51
|
+
const r = await this.api.updateUserInsightProfile({
|
|
52
|
+
...this.userInsightProfile,
|
|
53
|
+
...e
|
|
54
|
+
});
|
|
55
|
+
return o(() => {
|
|
56
|
+
this.userInsightProfile = r;
|
|
57
|
+
}), r;
|
|
58
|
+
} catch (r) {
|
|
59
|
+
throw console.error("Error occurred while updating user insight profile:", r), this.globalStore.captureException(r, { store: "UserStore" }), r;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
44
62
|
};
|
|
45
63
|
export {
|
|
46
|
-
|
|
64
|
+
u as UserStore
|
|
47
65
|
};
|
|
48
66
|
|
|
49
67
|
//# sourceMappingURL=UserStore.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserStore.es.js","names":[],"sources":["../../../src/core/stores/UserStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\n\nimport { UserApi } from '../api'\nimport type { User, UserFeature, UserProfile } from '../types'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class UserStore {\n globalStore: GlobalStore\n api: UserApi = new UserApi('/', '')\n\n userFeatures: UserFeature[] = []\n userFeaturesLoaded: boolean = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new UserApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n get userProfile() {\n return this.globalStore.appDataStore.userProfile\n }\n\n get user() {\n return this.globalStore.appDataStore.user\n }\n\n setUserFeatures = (features: UserFeature[]) => {\n this.userFeatures = features\n this.userFeaturesLoaded = true\n }\n\n loadUserFeatures = async () => {\n try {\n const features = await this.api.getUserFeatures()\n this.setUserFeatures(features)\n } catch (e) {\n console.error('Error occurred while loading user features:', e)\n this.globalStore.captureException(e, { store: 'UserStore' })\n this.setUserFeatures([])\n }\n }\n\n updateUser = async (user: User) => {\n try {\n const updatedUser = await this.api.updateUser(user)\n\n this.globalStore.appDataStore.setUser(updatedUser)\n } catch (error) {\n console.error('Error updating User:', error)\n this.globalStore.captureException(error, { store: 'UserStore' })\n throw error\n }\n }\n\n updateUserProfile = async (userProfile: UserProfile) => {\n try {\n const updatedProfile = await this.api.updateUserProfile(userProfile)\n\n this.globalStore.appDataStore.setUserProfile(updatedProfile)\n } catch (error) {\n console.error('Error occurred while updating user profile:', error)\n this.globalStore.captureException(error, { store: 'UserStore' })\n }\n }\n}\n"],"mappings":";;AAOA,IAAa,IAAb,MAAuB;AAAA,EACrB;AAAA,EACA,MAAe,IAAI,EAAQ,KAAK,EAAE;AAAA,EAElC,eAA8B,CAAC;AAAA,EAC/B,qBAA8B;AAAA,
|
|
1
|
+
{"version":3,"file":"UserStore.es.js","names":[],"sources":["../../../src/core/stores/UserStore.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from 'mobx'\n\nimport { UserApi } from '../api'\nimport type { User, UserFeature, UserInsightProfile, UserProfile } from '../types'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class UserStore {\n globalStore: GlobalStore\n api: UserApi = new UserApi('/', '')\n\n userFeatures: UserFeature[] = []\n userFeaturesLoaded: boolean = false\n userInsightProfile: UserInsightProfile | null = null\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.api = new UserApi(globalStore.endpoint, globalStore.sessionToken, globalStore.onError)\n\n makeAutoObservable(this)\n }\n\n get userProfile() {\n return this.globalStore.appDataStore.userProfile\n }\n\n get user() {\n return this.globalStore.appDataStore.user\n }\n\n setUserFeatures = (features: UserFeature[]) => {\n this.userFeatures = features\n this.userFeaturesLoaded = true\n }\n\n loadUserFeatures = async () => {\n try {\n const features = await this.api.getUserFeatures()\n this.setUserFeatures(features)\n } catch (e) {\n console.error('Error occurred while loading user features:', e)\n this.globalStore.captureException(e, { store: 'UserStore' })\n this.setUserFeatures([])\n }\n }\n\n updateUser = async (user: User) => {\n try {\n const updatedUser = await this.api.updateUser(user)\n\n this.globalStore.appDataStore.setUser(updatedUser)\n } catch (error) {\n console.error('Error updating User:', error)\n this.globalStore.captureException(error, { store: 'UserStore' })\n throw error\n }\n }\n\n updateUserProfile = async (userProfile: UserProfile) => {\n try {\n const updatedProfile = await this.api.updateUserProfile(userProfile)\n\n this.globalStore.appDataStore.setUserProfile(updatedProfile)\n } catch (error) {\n console.error('Error occurred while updating user profile:', error)\n this.globalStore.captureException(error, { store: 'UserStore' })\n }\n }\n\n /**\n * Seeds the profile. The host (pulse) loads `user_insight_profile` and pushes it in here;\n * experiences itself never fetches it.\n */\n setUserInsightProfile = (profile: UserInsightProfile | null) => {\n this.userInsightProfile = profile\n }\n\n /**\n * Merges `fields` into the seeded profile and PUTs the whole profile. The endpoint is an\n * upsert that writes every profile field from the request, so a partial body would null\n * the fields it omits; the merge is what keeps them. Throws if the host has not seeded the\n * profile yet, and rethrows API failures, so a caller driving UI state (e.g. an insight\n * CTA) reports the error instead of silently treating the save as done.\n */\n updateUserInsightProfile = async (fields: Partial<UserInsightProfile>) => {\n if (!this.userInsightProfile) {\n throw new Error('User insight profile has not been loaded; refusing a partial PUT')\n }\n\n try {\n const updated = await this.api.updateUserInsightProfile({\n ...this.userInsightProfile,\n ...fields,\n })\n\n runInAction(() => {\n this.userInsightProfile = updated\n })\n\n return updated\n } catch (error) {\n console.error('Error occurred while updating user insight profile:', error)\n this.globalStore.captureException(error, { store: 'UserStore' })\n throw error\n }\n }\n}\n"],"mappings":";;AAOA,IAAa,IAAb,MAAuB;AAAA,EACrB;AAAA,EACA,MAAe,IAAI,EAAQ,KAAK,EAAE;AAAA,EAElC,eAA8B,CAAC;AAAA,EAC/B,qBAA8B;AAAA,EAC9B,qBAAgD;AAAA,EAEhD,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,MAAM,IAAI,EAAQ,EAAY,UAAU,EAAY,cAAc,EAAY,OAAO,GAE1F,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,KAAK,YAAY,aAAa;AAAA,EACvC;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK,YAAY,aAAa;AAAA,EACvC;AAAA,EAEA,kBAAA,CAAmB,MAA4B;AAC7C,SAAK,eAAe,GACpB,KAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,mBAAmB,YAAY;AAC7B,QAAI;AACF,YAAM,IAAW,MAAM,KAAK,IAAI,gBAAgB;AAChD,WAAK,gBAAgB,CAAQ;AAAA,IAC/B,SAAS,GAAG;AACV,cAAQ,MAAM,+CAA+C,CAAC,GAC9D,KAAK,YAAY,iBAAiB,GAAG,EAAE,OAAO,YAAY,CAAC,GAC3D,KAAK,gBAAgB,CAAC,CAAC;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,aAAa,OAAO,MAAe;AACjC,QAAI;AACF,YAAM,IAAc,MAAM,KAAK,IAAI,WAAW,CAAI;AAElD,WAAK,YAAY,aAAa,QAAQ,CAAW;AAAA,IACnD,SAAS,GAAO;AACd,oBAAQ,MAAM,wBAAwB,CAAK,GAC3C,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC,GACzD;AAAA,IACR;AAAA,EACF;AAAA,EAEA,oBAAoB,OAAO,MAA6B;AACtD,QAAI;AACF,YAAM,IAAiB,MAAM,KAAK,IAAI,kBAAkB,CAAW;AAEnE,WAAK,YAAY,aAAa,eAAe,CAAc;AAAA,IAC7D,SAAS,GAAO;AACd,cAAQ,MAAM,+CAA+C,CAAK,GAClE,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EAMA,wBAAA,CAAyB,MAAuC;AAC9D,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EASA,2BAA2B,OAAO,MAAwC;AACxE,QAAI,CAAC,KAAK,mBACR,OAAM,IAAI,MAAM,kEAAkE;AAGpF,QAAI;AACF,YAAM,IAAU,MAAM,KAAK,IAAI,yBAAyB;AAAA,QACtD,GAAG,KAAK;AAAA,QACR,GAAG;AAAA,MACL,CAAC;AAED,aAAA,EAAA,MAAkB;AAChB,aAAK,qBAAqB;AAAA,MAC5B,CAAC,GAEM;AAAA,IACT,SAAS,GAAO;AACd,oBAAQ,MAAM,uDAAuD,CAAK,GAC1E,KAAK,YAAY,iBAAiB,GAAO,EAAE,OAAO,YAAY,CAAC,GACzD;AAAA,IACR;AAAA,EACF;AACF"}
|
|
@@ -44,6 +44,8 @@ export interface RepeatingTransaction {
|
|
|
44
44
|
recurrence_day: number;
|
|
45
45
|
repeating_transaction_type: RepeatingType;
|
|
46
46
|
second_recurrence_day?: number;
|
|
47
|
+
/** User confirmation state written by subscription insights (e.g. CONFIRMED, CANCELLED). */
|
|
48
|
+
user_response?: string | null;
|
|
47
49
|
account?: Account;
|
|
48
50
|
transactions: Transaction[];
|
|
49
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepeatingTransaction.es.js","names":[],"sources":["../../../src/core/types/RepeatingTransaction.ts"],"sourcesContent":["import { Account } from './Account'\nimport { Transaction, TransactionType } from './Transaction'\n\nexport enum Frequency {\n Unknown = 0,\n EveryWeek = 1,\n EveryOtherWeek = 2,\n EveryMonth = 3,\n EveryOtherMonth = 4,\n EveryQuarter = 5,\n EveryOtherQuarter = 6,\n EveryYear = 7,\n TwiceAMonth = 8,\n}\n\nexport enum RecurrenceStatus {\n Paid = 0,\n Missed = 1,\n Upcoming = 2,\n}\n\nexport enum RecurrenceType {\n Expense = 0,\n Income = 1,\n}\n\nexport enum RepeatingType {\n Unknown = 0,\n Subscription = 1,\n Bill = 2,\n Income = 3,\n Transfer = 4,\n}\n\nexport interface RepeatingTransaction {\n // API fields\n guid: string\n account_guid: string\n category_guid?: string | null\n created_by: number\n main_class_guid?: string | null\n member_guid: string\n merchant_guid?: string | null\n user_guid: string\n description: string\n amount: number\n predicted_occurs_on: string\n transaction_type: TransactionType\n recurrence_type: Frequency\n recurrence_day: number\n repeating_transaction_type: RepeatingType\n second_recurrence_day?: number\n\n // UI fields\n account?: Account\n transactions: Transaction[]\n}\n\nexport interface Recurrence {\n accountGuid: string\n amount: number\n categoryGuid: string\n expectedDate: Date\n frequency: Frequency\n institutionGuid: string\n institutionName: string\n merchantGuid?: string | null\n name: string\n occurredOnDate?: Date\n recurrenceDay: number\n repeatingTransactionGuid: string\n secondRecurrenceDay?: number\n status: RecurrenceStatus\n type: RecurrenceType\n transaction?: Transaction\n}\n"],"mappings":"AAGA,IAAY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,YAAA,CAAA,IAAA,aACA,EAAA,EAAA,iBAAA,CAAA,IAAA,kBACA,EAAA,EAAA,aAAA,CAAA,IAAA,cACA,EAAA,EAAA,kBAAA,CAAA,IAAA,mBACA,EAAA,EAAA,eAAA,CAAA,IAAA,gBACA,EAAA,EAAA,oBAAA,CAAA,IAAA,qBACA,EAAA,EAAA,YAAA,CAAA,IAAA,aACA,EAAA,EAAA,cAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,OAAA,CAAA,IAAA,QACA,EAAA,EAAA,SAAA,CAAA,IAAA,UACA,EAAA,EAAA,WAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,SAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,eAAA,CAAA,IAAA,gBACA,EAAA,EAAA,OAAA,CAAA,IAAA,QACA,EAAA,EAAA,SAAA,CAAA,IAAA,UACA,EAAA,EAAA,WAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"RepeatingTransaction.es.js","names":[],"sources":["../../../src/core/types/RepeatingTransaction.ts"],"sourcesContent":["import { Account } from './Account'\nimport { Transaction, TransactionType } from './Transaction'\n\nexport enum Frequency {\n Unknown = 0,\n EveryWeek = 1,\n EveryOtherWeek = 2,\n EveryMonth = 3,\n EveryOtherMonth = 4,\n EveryQuarter = 5,\n EveryOtherQuarter = 6,\n EveryYear = 7,\n TwiceAMonth = 8,\n}\n\nexport enum RecurrenceStatus {\n Paid = 0,\n Missed = 1,\n Upcoming = 2,\n}\n\nexport enum RecurrenceType {\n Expense = 0,\n Income = 1,\n}\n\nexport enum RepeatingType {\n Unknown = 0,\n Subscription = 1,\n Bill = 2,\n Income = 3,\n Transfer = 4,\n}\n\nexport interface RepeatingTransaction {\n // API fields\n guid: string\n account_guid: string\n category_guid?: string | null\n created_by: number\n main_class_guid?: string | null\n member_guid: string\n merchant_guid?: string | null\n user_guid: string\n description: string\n amount: number\n predicted_occurs_on: string\n transaction_type: TransactionType\n recurrence_type: Frequency\n recurrence_day: number\n repeating_transaction_type: RepeatingType\n second_recurrence_day?: number\n /** User confirmation state written by subscription insights (e.g. CONFIRMED, CANCELLED). */\n user_response?: string | null\n\n // UI fields\n account?: Account\n transactions: Transaction[]\n}\n\nexport interface Recurrence {\n accountGuid: string\n amount: number\n categoryGuid: string\n expectedDate: Date\n frequency: Frequency\n institutionGuid: string\n institutionName: string\n merchantGuid?: string | null\n name: string\n occurredOnDate?: Date\n recurrenceDay: number\n repeatingTransactionGuid: string\n secondRecurrenceDay?: number\n status: RecurrenceStatus\n type: RecurrenceType\n transaction?: Transaction\n}\n"],"mappings":"AAGA,IAAY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,YAAA,CAAA,IAAA,aACA,EAAA,EAAA,iBAAA,CAAA,IAAA,kBACA,EAAA,EAAA,aAAA,CAAA,IAAA,cACA,EAAA,EAAA,kBAAA,CAAA,IAAA,mBACA,EAAA,EAAA,eAAA,CAAA,IAAA,gBACA,EAAA,EAAA,oBAAA,CAAA,IAAA,qBACA,EAAA,EAAA,YAAA,CAAA,IAAA,aACA,EAAA,EAAA,cAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,OAAA,CAAA,IAAA,QACA,EAAA,EAAA,SAAA,CAAA,IAAA,UACA,EAAA,EAAA,WAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,SAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA,GAEY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,EAAA,UAAA,CAAA,IAAA,WACA,EAAA,EAAA,eAAA,CAAA,IAAA,gBACA,EAAA,EAAA,OAAA,CAAA,IAAA,QACA,EAAA,EAAA,SAAA,CAAA,IAAA,UACA,EAAA,EAAA,WAAA,CAAA,IAAA;AACF,GAAA,CAAA,CAAA"}
|
|
@@ -32,6 +32,17 @@ export interface UserProfile {
|
|
|
32
32
|
uses_detailed_notifications: boolean;
|
|
33
33
|
user_guid: string;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Per-user insight settings (pulse `user_insight_profile`). Written by insight CTAs such as
|
|
37
|
+
* designating an emergency savings account or saving a low-balance safety net.
|
|
38
|
+
*/
|
|
39
|
+
export interface UserInsightProfile {
|
|
40
|
+
guid?: string;
|
|
41
|
+
user_guid?: string;
|
|
42
|
+
credit_card_close_to_limit_percentage?: number | null;
|
|
43
|
+
emergency_savings_account_guid?: string | null;
|
|
44
|
+
savings_opportunity_minimum_checking_account_balance?: number | null;
|
|
45
|
+
}
|
|
35
46
|
export type EditableUser = Pick<User, 'birthday' | 'credit_score' | 'email' | 'first_name' | 'last_name' | 'phone' | 'postal_code'>;
|
|
36
47
|
export interface UserFeature {
|
|
37
48
|
feature_guid: string;
|
|
@@ -30,7 +30,7 @@ export type { Offer } from './Offer';
|
|
|
30
30
|
export type { ScheduledPayment } from './ScheduledPayment';
|
|
31
31
|
export type { Tag, Tagging, Transaction, TransactionRule } from './Transaction';
|
|
32
32
|
export { TransactionStatus, TransactionType } from './Transaction';
|
|
33
|
-
export type { Device, EditableUser, User, UserCommunicationProfile, UserFeature, UserProfile, } from './User';
|
|
33
|
+
export type { Device, EditableUser, User, UserCommunicationProfile, UserFeature, UserInsightProfile, UserProfile, } from './User';
|
|
34
34
|
export { ScreenSize } from './ScreenSize';
|
|
35
35
|
export type { MiniWidgetProps, WidgetProps } from './Widgets';
|
|
36
36
|
export type { Holding } from './Holding';
|