diff --git a/src/pages/settings/Profile/PronounsPage.tsx b/src/pages/settings/Profile/PronounsPage.tsx index 705a83e3ac46..d56291dbc139 100644 --- a/src/pages/settings/Profile/PronounsPage.tsx +++ b/src/pages/settings/Profile/PronounsPage.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import CollapsibleHeaderOnKeyboard from '@components/CollapsibleHeaderOnKeyboard'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -31,7 +31,7 @@ function PronounsPage({currentUserPersonalDetails}: PronounsPageProps) { const currentPronouns = currentUserPersonalDetails?.pronouns ?? ''; const currentPronounsKey = currentPronouns.substring(CONST.PRONOUNS.PREFIX.length); const [searchValue, setSearchValue] = useState(''); - const isOptionSelected = useRef(false); + const [selectedPronouns, setSelectedPronouns] = useState(currentPronouns); const currentUserAccountID = currentUserPersonalDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID; useEffect(() => { @@ -41,6 +41,7 @@ function PronounsPage({currentUserPersonalDetails}: PronounsPageProps) { const currentPronounsText = CONST.PRONOUNS_LIST.find((value) => value === currentPronounsKey); setSearchValue(currentPronounsText ? translate(`pronouns.${currentPronounsText}`) : ''); + setSelectedPronouns(currentPronouns); // Only need to update search value when the first time the data is loaded // eslint-disable-next-line react-hooks/exhaustive-deps @@ -49,13 +50,12 @@ function PronounsPage({currentUserPersonalDetails}: PronounsPageProps) { const filteredPronounsList = useMemo((): PronounEntry[] => { const pronouns = CONST.PRONOUNS_LIST.map((value) => { const fullPronounKey = `${CONST.PRONOUNS.PREFIX}${value}`; - const isCurrentPronouns = fullPronounKey === currentPronouns; return { text: translate(`pronouns.${value}`), value: fullPronounKey, keyForList: value, - isSelected: isCurrentPronouns, + isSelected: fullPronounKey === selectedPronouns, }; }).sort((a, b) => localeCompare(a.text.toLowerCase(), b.text.toLowerCase())); @@ -65,17 +65,26 @@ function PronounsPage({currentUserPersonalDetails}: PronounsPageProps) { return []; } return pronouns.filter((pronoun) => pronoun.text.toLowerCase().indexOf(trimmedSearch.toLowerCase()) >= 0); - }, [searchValue, currentPronouns, translate, localeCompare]); + }, [searchValue, selectedPronouns, translate, localeCompare]); - const updatePronouns = (selectedPronouns: PronounEntry) => { - if (isOptionSelected.current) { - return; - } - isOptionSelected.current = true; - updatePronounsPersonalDetails(selectedPronouns.keyForList === currentPronounsKey ? '' : (selectedPronouns?.value ?? ''), currentUserAccountID); - Navigation.goBack(); + const selectPronoun = (selectedPronoun: PronounEntry) => { + setSelectedPronouns(selectedPronoun.value === selectedPronouns ? '' : (selectedPronoun?.value ?? '')); }; + const savePronouns = useCallback(() => { + updatePronounsPersonalDetails(selectedPronouns, currentUserAccountID); + Navigation.goBack(); + }, [selectedPronouns, currentUserAccountID]); + + const confirmButtonOptions = useMemo( + () => ({ + showButton: true, + text: translate('common.save'), + onConfirm: savePronouns, + }), + [savePronouns, translate], + ); + const textInputOptions = useMemo( () => ({ label: translate('pronounsPage.pronouns'), @@ -107,9 +116,10 @@ function PronounsPage({currentUserPersonalDetails}: PronounsPageProps) { diff --git a/src/pages/workspace/rules/RulesReimbursableDefaultPage.tsx b/src/pages/workspace/rules/RulesReimbursableDefaultPage.tsx index 065a4dcc0a56..0cd55451553a 100644 --- a/src/pages/workspace/rules/RulesReimbursableDefaultPage.tsx +++ b/src/pages/workspace/rules/RulesReimbursableDefaultPage.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; @@ -28,14 +28,36 @@ function RulesReimbursableDefaultPage({ const reimbursableMode = getCashExpenseReimbursableMode(policy); + // The draft holds the user's in-page selection. Until they pick a row it stays undefined and we fall back to the + // persisted reimbursableMode, which also covers the page rendering before the policy is in Onyx. + const [draftMode, setDraftMode] = useState(); + const selectedMode = draftMode ?? reimbursableMode; + const reimbursableModes = Object.values(CONST.POLICY.CASH_EXPENSE_REIMBURSEMENT_CHOICES).map((mode) => ({ text: translate(`workspace.rules.individualExpenseRules.${mode}`), alternateText: translate(`workspace.rules.individualExpenseRules.${mode}Description`), value: mode, - isSelected: reimbursableMode === mode, + isSelected: selectedMode === mode, keyForList: mode, })); + const saveAndGoBack = useCallback(() => { + if (!selectedMode) { + return; + } + setPolicyReimbursableMode(policyID, selectedMode, policy?.defaultReimbursable, policy?.disabledFields?.reimbursable); + Navigation.goBack(); + }, [policyID, selectedMode, policy?.defaultReimbursable, policy?.disabledFields?.reimbursable]); + + const confirmButtonOptions = useMemo( + () => ({ + showButton: true, + text: translate('common.save'), + onConfirm: saveAndGoBack, + }), + [saveAndGoBack, translate], + ); + return ( { - setPolicyReimbursableMode(policyID, item.value, policy?.defaultReimbursable, policy?.disabledFields?.reimbursable); - Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); + setDraftMode(item.value); }} + confirmButtonOptions={confirmButtonOptions} shouldSingleExecuteRowSelect style={{containerStyle: styles.pt3}} initiallyFocusedItemKey={reimbursableMode}