diff --git a/packages/desktop-client/src/components/Modals.js b/packages/desktop-client/src/components/Modals.js index f824e30c7874ca7788c3fa40506ae88b44df41b1..894c340778749711016a1340497f561fa8fc1b76 100644 --- a/packages/desktop-client/src/components/Modals.js +++ b/packages/desktop-client/src/components/Modals.js @@ -19,6 +19,7 @@ import NordigenExternalMsg from 'loot-design/src/components/modals/NordigenExter import PlaidExternalMsg from 'loot-design/src/components/modals/PlaidExternalMsg'; import SelectLinkedAccounts from 'loot-design/src/components/modals/SelectLinkedAccounts'; +import useFeatureFlag from '../hooks/useFeatureFlag'; import useSyncServerStatus from '../hooks/useSyncServerStatus'; import ConfirmCategoryDelete from './modals/ConfirmCategoryDelete'; @@ -40,6 +41,9 @@ function Modals({ budgetId, actions, }) { + const isNewAutocompleteEnabled = useFeatureFlag('newAutocomplete'); + const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); + const syncServerStatus = useSyncServerStatus(); return modalStack.map(({ name, options = {} }, idx) => { @@ -272,6 +276,7 @@ function Modals({ actions={actions} name={options.name} onSubmit={options.onSubmit} + isNewAutocompleteEnabled={isNewAutocompleteEnabled} /> ); }} @@ -283,6 +288,7 @@ function Modals({ modalProps={modalProps} month={options.month} actions={actions} + isGoalTemplatesEnabled={isGoalTemplatesEnabled} /> </Route> </Switch> diff --git a/packages/desktop-client/src/components/SidebarWithData.js b/packages/desktop-client/src/components/SidebarWithData.js index b63092b183c44e31faf7b4e2baaeb70f1bd31a6b..0dffcfadea96208202061bc31112d2661f0bbe73 100644 --- a/packages/desktop-client/src/components/SidebarWithData.js +++ b/packages/desktop-client/src/components/SidebarWithData.js @@ -22,6 +22,8 @@ import { Sidebar } from 'loot-design/src/components/sidebar'; import { styles, colors } from 'loot-design/src/style'; import ExpandArrow from 'loot-design/src/svg/v0/ExpandArrow'; +import useFeatureFlag from '../hooks/useFeatureFlag'; + function EditableBudgetName({ prefs, savePrefs }) { let dispatch = useDispatch(); let history = useHistory(); @@ -123,6 +125,8 @@ function SidebarWithData({ saveGlobalPrefs, getAccounts, }) { + const syncAccount = useFeatureFlag('syncAccount'); + useEffect(() => void getAccounts(), [getAccounts]); async function onReorder(id, dropPos, targetId) { @@ -149,9 +153,7 @@ function SidebarWithData({ onFloat={() => saveGlobalPrefs({ floatingSidebar: !floatingSidebar })} onReorder={onReorder} onAddAccount={() => - replaceModal( - prefs['flags.syncAccount'] ? 'add-account' : 'add-local-account', - ) + replaceModal(syncAccount ? 'add-account' : 'add-local-account') } showClosedAccounts={prefs['ui.showClosedAccounts']} onToggleClosedAccounts={() => diff --git a/packages/desktop-client/src/components/Titlebar.js b/packages/desktop-client/src/components/Titlebar.js index 5233286ea3839d98257c30cabf794d737a3cbf1c..e6fb8c910cc27f093ef17b45118cae1aba9dfd36 100644 --- a/packages/desktop-client/src/components/Titlebar.js +++ b/packages/desktop-client/src/components/Titlebar.js @@ -25,6 +25,8 @@ import ArrowButtonRight1 from 'loot-design/src/svg/v2/ArrowButtonRight1'; import NavigationMenu from 'loot-design/src/svg/v2/NavigationMenu'; import tokens from 'loot-design/src/tokens'; +import useFeatureFlag from '../hooks/useFeatureFlag'; + import AccountSyncCheck from './accounts/AccountSyncCheck'; import AnimatedRefresh from './AnimatedRefresh'; import { MonthCountSelector } from './budget/MonthCountSelector'; @@ -163,7 +165,7 @@ function BudgetTitlebar({ globalPrefs, saveGlobalPrefs, localPrefs }) { let [loading, setLoading] = useState(false); let [showTooltip, setShowTooltip] = useState(false); - let reportBudgetEnabled = localPrefs['flags.reportBudget']; + const reportBudgetEnabled = useFeatureFlag('reportBudget'); function onSwitchType() { setLoading(true); diff --git a/packages/desktop-client/src/components/accounts/Account.js b/packages/desktop-client/src/components/accounts/Account.js index 32bccd20c4a8908a04c40c697aed42f3cc9606d9..54de03461746e7ba6657ae1b91180646d6a46a5c 100644 --- a/packages/desktop-client/src/components/accounts/Account.js +++ b/packages/desktop-client/src/components/accounts/Account.js @@ -60,6 +60,7 @@ import Pencil1 from 'loot-design/src/svg/v2/Pencil1'; import SvgRemove from 'loot-design/src/svg/v2/Remove'; import SearchAlternate from 'loot-design/src/svg/v2/SearchAlternate'; +import useFeatureFlag from '../../hooks/useFeatureFlag'; import useSyncServerStatus from '../../hooks/useSyncServerStatus'; import { authorizeBank } from '../../nordigen'; import { useActiveLocation } from '../ActiveLocation'; @@ -1914,13 +1915,13 @@ function AccountHack(props) { } export default function Account(props) { + const syncEnabled = useFeatureFlag('syncAccount'); let state = useSelector(state => ({ newTransactions: state.queries.newTransactions, matchedTransactions: state.queries.matchedTransactions, accounts: state.queries.accounts, failedAccounts: state.account.failedAccounts, categoryGroups: state.queries.categories.grouped, - syncEnabled: state.prefs.local['flags.syncAccount'], dateFormat: state.prefs.local.dateFormat || 'MM/dd/yyyy', hideFraction: state.prefs.local.hideFraction || false, expandSplits: props.match && state.prefs.local['expand-splits'], @@ -1975,6 +1976,7 @@ export default function Account(props) { <AccountHack {...state} {...actionCreators} + syncEnabled={syncEnabled} modalShowing={ state.modalShowing || !!(activeLocation.state && activeLocation.state.locationPtr) diff --git a/packages/desktop-client/src/components/settings/Experimental.js b/packages/desktop-client/src/components/settings/Experimental.js index e51a325d0f24777885400fe4c73e77b308bcedb8..2dcf251e3634fba9f89b30997e8273f5c228cec5 100644 --- a/packages/desktop-client/src/components/settings/Experimental.js +++ b/packages/desktop-client/src/components/settings/Experimental.js @@ -4,15 +4,13 @@ import { Link, Text, View } from 'loot-design/src/components/common'; import { Checkbox } from 'loot-design/src/components/forms'; import { colors } from 'loot-design/src/style'; +import { useAllFeatureFlags } from '../../hooks/useFeatureFlag'; + import { Setting } from './UI'; export default function ExperimentalFeatures({ prefs, savePrefs }) { let [expanded, setExpanded] = React.useState(false); - let flags = Object.fromEntries( - Object.entries(prefs) - .filter(([key]) => key.startsWith('flags.')) - .map(([key, value]) => [key.replace('flags.', ''), value]), - ); + const flags = useAllFeatureFlags(); let disabled = prefs.budgetType === 'report' && flags.reportBudget; return ( diff --git a/packages/desktop-client/src/hooks/useFeatureFlag.js b/packages/desktop-client/src/hooks/useFeatureFlag.js index 4ea6dc4fd5ceea447c56288cc4864afa91ca1e96..6cda94e421b10c562c00f574d3086c8b939f702e 100644 --- a/packages/desktop-client/src/hooks/useFeatureFlag.js +++ b/packages/desktop-client/src/hooks/useFeatureFlag.js @@ -1,5 +1,30 @@ import { useSelector } from 'react-redux'; +const DEFAULT_FEATURE_FLAG_STATE = { + newAutocomplete: false, + syncAccount: false, + goalTemplatesEnabled: false, +}; + export default function useFeatureFlag(name) { - return useSelector(state => state.prefs.local[`flags.${name}`]); + return useSelector(state => { + const value = state.prefs.local[`flags.${name}`]; + + return value === undefined + ? DEFAULT_FEATURE_FLAG_STATE[name] || false + : value; + }); +} + +export function useAllFeatureFlags() { + return useSelector(state => { + return { + ...DEFAULT_FEATURE_FLAG_STATE, + ...Object.fromEntries( + Object.entries(state.prefs.local) + .filter(([key]) => key.startsWith('flags.')) + .map(([key, value]) => [key.replace('flags.', ''), value]), + ), + }; + }); } diff --git a/packages/loot-design/src/components/budget/rollover/BudgetSummary.js b/packages/loot-design/src/components/budget/rollover/BudgetSummary.js index 1d23c300ff77be9dddef2075b38094930e36379a..2aa757e67d705a2bbcfc10774091f379b4018c0c 100644 --- a/packages/loot-design/src/components/budget/rollover/BudgetSummary.js +++ b/packages/loot-design/src/components/budget/rollover/BudgetSummary.js @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import { connect } from 'react-redux'; import Component from '@reactions/component'; import { css } from 'glamor'; @@ -7,7 +6,6 @@ import { css } from 'glamor'; import { rolloverBudget } from 'loot-core/src/client/queries'; import * as monthUtils from 'loot-core/src/shared/months'; -import * as actions from '../../../../../loot-core/src/client/actions'; import { colors, styles } from '../../../style'; import DotsHorizontalTriple from '../../../svg/v1/DotsHorizontalTriple'; import ArrowButtonDown1 from '../../../svg/v2/ArrowButtonDown1'; @@ -245,7 +243,7 @@ function ToBudget({ month, prevMonthName, collapsed, onBudgetAction }) { ); } -function BudgetSummaryComponent({ month, localPrefs }) { +export function BudgetSummary({ month, isGoalTemplatesEnabled }) { let { currentMonth, summaryCollapsed: collapsed, @@ -266,8 +264,6 @@ function BudgetSummaryComponent({ month, localPrefs }) { let ExpandOrCollapseIcon = collapsed ? ArrowButtonDown1 : ArrowButtonUp1; - let goalTemplatesEnabled = localPrefs['flags.goalTemplatesEnabled']; - return ( <View style={{ @@ -378,11 +374,11 @@ function BudgetSummaryComponent({ month, localPrefs }) { name: 'set-3-avg', text: 'Set budgets to 3 month avg', }, - goalTemplatesEnabled && { + isGoalTemplatesEnabled && { name: 'apply-goal-template', text: 'Apply budget template', }, - goalTemplatesEnabled && { + isGoalTemplatesEnabled && { name: 'overwrite-goal-template', text: 'Overwrite with budget template', }, @@ -423,8 +419,3 @@ function BudgetSummaryComponent({ month, localPrefs }) { </View> ); } - -export const BudgetSummary = connect( - state => ({ localPrefs: state.prefs.local }), - actions, -)(BudgetSummaryComponent); diff --git a/packages/loot-design/src/components/modals/EditField.js b/packages/loot-design/src/components/modals/EditField.js index ce88888a9b951cc34680d06de0d49a086af5a0b9..44d1ff40b81ca01e545ea98020baa3ce147d0256 100644 --- a/packages/loot-design/src/components/modals/EditField.js +++ b/packages/loot-design/src/components/modals/EditField.js @@ -200,7 +200,6 @@ export default connect( categoryGroups: state.queries.categories.grouped, accounts: state.queries.accounts, payees: state.queries.payees, - isNewAutocompleteEnabled: state.prefs.local['flags.newAutocomplete'], }), actions, )(EditField); diff --git a/upcoming-release-notes/786.md b/upcoming-release-notes/786.md new file mode 100644 index 0000000000000000000000000000000000000000..049342f8d32bd8896d86af17e13e5203824b907a --- /dev/null +++ b/upcoming-release-notes/786.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Refactored all feature flgas to use the new `useFeatureFlag` hook