From 05a362cffdd6d9eda06fb15d9b5a77ca18794c6b Mon Sep 17 00:00:00 2001 From: Xiphe Date: Tue, 15 Sep 2020 12:57:56 +0200 Subject: [PATCH] fix: do not require MoneyMoney accounts and categories to have an icon prior to this change the app would not work when no valid icon was received from MM no idea in which cases this happnens but anyhow... fix https://github.com/Xiphe/budgetbudget/issues/61 --- cypress/integration/budgetView.spec.ts | 1 + cypress/integration/createNewBudget.spec.ts | 2 +- main/moneymoney/handlers.ts | 19 ++++- src/moneymoney/Types.ts | 76 +++++++++++-------- src/moneymoney/getAccounts.ts | 4 +- src/views/CategorySidebar/CategorySidebar.tsx | 2 +- 6 files changed, 66 insertions(+), 38 deletions(-) diff --git a/cypress/integration/budgetView.spec.ts b/cypress/integration/budgetView.spec.ts index 17c6745..fe5b6de 100644 --- a/cypress/integration/budgetView.spec.ts +++ b/cypress/integration/budgetView.spec.ts @@ -14,6 +14,7 @@ describe('Budget View', () => { it('displays correct overview values', () => { const incomeCategory = category({ name: 'Income this month' }); const spendingCategory = category(); + delete spendingCategory.icon; const myBudget = budget({ settings: settings({ startBalance: 100, diff --git a/cypress/integration/createNewBudget.spec.ts b/cypress/integration/createNewBudget.spec.ts index 5179c32..5919e87 100644 --- a/cypress/integration/createNewBudget.spec.ts +++ b/cypress/integration/createNewBudget.spec.ts @@ -6,7 +6,7 @@ describe('Create New Budget', () => { }); it('creates a new budget files with options', () => { - const accounts = [account(), account()]; + const accounts = [account({ icon: undefined }), account()]; const categories = [category(), category(), category()]; cy.open({ diff --git a/main/moneymoney/handlers.ts b/main/moneymoney/handlers.ts index 4db1768..f85ae18 100644 --- a/main/moneymoney/handlers.ts +++ b/main/moneymoney/handlers.ts @@ -13,20 +13,35 @@ function delay(t: number) { return new Promise((r) => setTimeout(r, t)); } +function identify(thing: any) { + switch (true) { + case thing.budget !== undefined: + return `Category "${thing.name}"`; + case thing.accountNumber !== undefined: + return `Account "${thing.name}"`; + default: + return thing.name || thing; + } +} + function base64Icons(data: unknown) { if (!Array.isArray(data)) { throw new Error('Unexpectedly got non-array as data'); } return data.map((entry: unknown) => { - if (entry === null || typeof entry !== 'object') { + if (typeof entry !== 'object' || entry === null) { throw new Error('Unexpectedly got non-object in data array'); } const icon: unknown = (entry as any).icon; if (!(icon instanceof Buffer)) { - throw new Error(`Unexpectedly got ${typeof icon} as icon`); + console.warn( + `Unexpectedly got ${typeof icon} as icon in `, + identify(entry), + ); + return entry; } return { diff --git a/src/moneymoney/Types.ts b/src/moneymoney/Types.ts index 25972a0..b9aeb7a 100644 --- a/src/moneymoney/Types.ts +++ b/src/moneymoney/Types.ts @@ -66,42 +66,54 @@ const transactionsByAccountShape = t.array( ), 'transactions', ); -const interopAccountShape = t.type( - { - accountNumber: t.string, +const interopAccountShape = t.intersection([ + t.type( + { + accountNumber: t.string, + name: t.string, + balance: t.array(t.tuple([t.number, t.string])), + currency: t.string, + group: t.boolean, + indentation: t.number, + portfolio: t.boolean, + uuid: t.string, + }, + 'account', + ), + t.partial( + { + icon: t.string, + }, + 'accountOptional', + ), +]); +const categoryShape = t.intersection([ + t.type({ + budget: t.union([ + t.type({}), + t.type({ + amount: t.number, + available: t.number, + period: t.union([ + t.literal('monthly'), + t.literal('quarterly'), + t.literal('yearly'), + t.literal('total'), + ]), + }), + ]), name: t.string, - balance: t.array(t.tuple([t.number, t.string])), currency: t.string, + default: t.boolean, group: t.boolean, + indentation: t.number, - icon: t.string, - portfolio: t.boolean, uuid: t.string, - }, - 'account', -); -const categoryShape = t.type({ - budget: t.union([ - t.type({}), - t.type({ - amount: t.number, - available: t.number, - period: t.union([ - t.literal('monthly'), - t.literal('quarterly'), - t.literal('yearly'), - t.literal('total'), - ]), - }), - ]), - name: t.string, - currency: t.string, - default: t.boolean, - group: t.boolean, - icon: t.string, - indentation: t.number, - uuid: t.string, -}); + }), + t.partial({ + icon: t.string, + }), +]); export type Category = t.TypeOf; export type Transaction = t.TypeOf; @@ -113,7 +125,7 @@ export type Account = { group: boolean; indentation: number; portfolio: boolean; - icon: string; + icon?: string; uuid: string; number: string; }; diff --git a/src/moneymoney/getAccounts.ts b/src/moneymoney/getAccounts.ts index 40308ee..3db724d 100644 --- a/src/moneymoney/getAccounts.ts +++ b/src/moneymoney/getAccounts.ts @@ -6,7 +6,7 @@ import memoizeOne from 'memoize-one'; const filterAccounts = memoizeOne( (currency: string, interopAccounts: InteropAccount[]): Account[] => { return interopAccounts - .map( + .map( ({ accountNumber, balance, @@ -35,7 +35,7 @@ const filterAccounts = memoizeOne( }; }, ) - .filter((data: Account | false): data is Account => Boolean(data)); + .filter((data): data is Account => Boolean(data)); }, ); diff --git a/src/views/CategorySidebar/CategorySidebar.tsx b/src/views/CategorySidebar/CategorySidebar.tsx index 11858ca..67870e7 100644 --- a/src/views/CategorySidebar/CategorySidebar.tsx +++ b/src/views/CategorySidebar/CategorySidebar.tsx @@ -79,7 +79,7 @@ export default function CategorySidebar({ > {!group && ( )}