diff --git a/web/cashtab/src/hooks/useWallet.js b/web/cashtab/src/hooks/useWallet.js --- a/web/cashtab/src/hooks/useWallet.js +++ b/web/cashtab/src/hooks/useWallet.js @@ -18,7 +18,11 @@ checkWalletForTokenInfo, isActiveWebsocket, } from 'utils/cashMethods'; -import { isValidCashtabSettings, isValidContactList } from 'utils/validation'; +import { + isValidCashtabSettings, + isValidContactList, + parseInvalidSettingsForMigration, +} from 'utils/validation'; import localforage from 'localforage'; import { currency } from 'components/Common/Ticker'; import isEmpty from 'lodash.isempty'; @@ -1149,9 +1153,21 @@ setCashtabSettings(localSettings); return localSettings; } - // if not valid, also set cashtabSettings to default - setCashtabSettings(currency.defaultSettings); - return currency.defaultSettings; + // If a settings object is present but invalid, parse to find and add missing keys + let modifiedLocalSettings = + parseInvalidSettingsForMigration(localSettings); + if (isValidCashtabSettings(modifiedLocalSettings)) { + // modifiedLocalSettings placed in local storage + localforage.setItem('settings', modifiedLocalSettings); + setCashtabSettings(modifiedLocalSettings); + // update missing key in local storage without overwriting existing valid settings + return modifiedLocalSettings; + } else { + // if not valid, also set cashtabSettings to default + setCashtabSettings(currency.defaultSettings); + // localforage not needed as function will continue until localSettings are valid + return currency.defaultSettings; + } }; const loadContactList = async () => { diff --git a/web/cashtab/src/utils/__tests__/validation.test.js b/web/cashtab/src/utils/__tests__/validation.test.js --- a/web/cashtab/src/utils/__tests__/validation.test.js +++ b/web/cashtab/src/utils/__tests__/validation.test.js @@ -20,6 +20,7 @@ isValidAirdropOutputsArray, isValidAirdropExclusionArray, isValidContactList, + parseInvalidSettingsForMigration, } from '../validation'; import { currency } from 'components/Common/Ticker.js'; import { fromSmallestDenomination } from 'utils/cashMethods'; @@ -662,4 +663,28 @@ }, ]), ).toBe(false)); + it('updates an invalid settings object and keeps existing valid settings intact', () => + expect( + parseInvalidSettingsForMigration({ + fiatCurrency: 'gbp', + }), + ).toStrictEqual({ + fiatCurrency: 'gbp', + sendModal: false, + })); + it('sets settings object with no exsting valid settings to default values', () => + expect(parseInvalidSettingsForMigration({})).toStrictEqual({ + fiatCurrency: 'usd', + sendModal: false, + })); + it('does nothing if valid settings object is present in localStorage', () => + expect( + parseInvalidSettingsForMigration({ + fiatCurrency: 'brl', + sendModal: true, + }), + ).toStrictEqual({ + fiatCurrency: 'brl', + sendModal: true, + })); }); diff --git a/web/cashtab/src/utils/validation.js b/web/cashtab/src/utils/validation.js --- a/web/cashtab/src/utils/validation.js +++ b/web/cashtab/src/utils/validation.js @@ -140,6 +140,21 @@ } }; +export const parseInvalidSettingsForMigration = invalidCashtabSettings => { + // create a copy of the invalidCashtabSettings + let migratedCashtabSettings = invalidCashtabSettings; + // determine if settings are invalid because it is missing a parameter + for (let param in currency.defaultSettings) { + if ( + !Object.prototype.hasOwnProperty.call(invalidCashtabSettings, param) + ) { + // adds the default setting for only that parameter + migratedCashtabSettings[param] = currency.defaultSettings[param]; + } + } + return migratedCashtabSettings; +}; + export const isValidContactList = contactList => { /* A valid contact list is an array of objects