From 2312acfafe0b90d80c7b6fb6088df0471578bb03 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Wed, 5 Jun 2024 13:25:30 +0530 Subject: [PATCH 1/5] fix: Web - Split - Enter and CMD+Enter open user profile instead of splitting expense. Signed-off-by: Krishna Gupta --- .../ButtonWithDropdownMenu/index.tsx | 14 ++++ .../ButtonWithDropdownMenu/types.ts | 2 + .../MoneyRequestConfirmationList.tsx | 3 + src/components/SettlementButton.tsx | 67 +++++++++++++------ 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 094c26a2b387..cfe27f43b214 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -4,6 +4,7 @@ import Button from '@components/Button'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -33,6 +34,7 @@ function ButtonWithDropdownMenu({ onOptionSelected, enterKeyEventListenerPriority = 0, wrapperStyle, + useKeyboardShortcuts = false, }: ButtonWithDropdownMenuProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -65,6 +67,18 @@ function ButtonWithDropdownMenu({ }); } }, [windowWidth, windowHeight, isMenuVisible, anchorAlignment.vertical]); + + useKeyboardShortcut( + CONST.KEYBOARD_SHORTCUTS.CTRL_ENTER, + (e) => { + onPress(e, selectedItem.value); + }, + { + captureOnInputs: true, + shouldBubble: false, + isActive: useKeyboardShortcuts, + }, + ); return ( {shouldAlwaysShowDropdownMenu || options.length > 1 ? ( diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 1ad2ccb0d717..f4b5b5e7dae6 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -77,6 +77,8 @@ type ButtonWithDropdownMenuProps = { /** Whether the button should use split style or not */ isSplitButton?: boolean; + + useKeyboardShortcuts?: boolean; }; export type {PaymentType, WorkspaceMemberBulkActionType, WorkspaceDistanceRatesBulkActionType, DropdownOption, ButtonWithDropdownMenuProps, WorkspaceTaxRatesBulkActionType}; diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index a82cbbe61668..ec46c77724f0 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -788,6 +788,7 @@ function MoneyRequestConfirmationList({ vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }} enterKeyEventListenerPriority={1} + useKeyboardShortcuts /> ) : ( ); @@ -1241,6 +1243,7 @@ function MoneyRequestConfirmationList({ footerContent={footerContent} listFooterContent={listFooterContent} containerStyle={[styles.flexBasisAuto]} + disableKeyboardShortcuts /> ); diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index b6e2a753c829..3ac6a4057dd1 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,7 +1,8 @@ -import React, {useEffect, useMemo} from 'react'; +import React, {useEffect, useMemo, useRef, useState} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import * as ReportUtils from '@libs/ReportUtils'; @@ -105,6 +106,8 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to open confirmation modal if any of the transactions is on HOLD */ confirmApproval?: () => void; + + useKeyboardShortcuts?: boolean; }; function SettlementButton({ @@ -140,6 +143,7 @@ function SettlementButton({ enterKeyEventListenerPriority = 0, confirmApproval, policy, + useKeyboardShortcuts = false, }: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -255,6 +259,21 @@ function SettlementButton({ IOU.savePreferredPaymentMethod(id, value); }; + const [selectedPaymentType, setSelectedPaymentType] = useState(paymentButtonOptions[0].value); + const triggerKYCFlowRef = useRef<(event: GestureResponderEvent | KeyboardEvent | undefined, method?: PaymentMethodType | undefined) => void>(() => {}); + + useKeyboardShortcut( + CONST.KEYBOARD_SHORTCUTS.CTRL_ENTER, + (e) => { + selectPaymentType(e, selectedPaymentType, triggerKYCFlowRef.current); + }, + { + captureOnInputs: true, + shouldBubble: false, + isActive: useKeyboardShortcuts, + }, + ); + return ( - {(triggerKYCFlow, buttonRef) => ( - - success - buttonRef={buttonRef} - shouldAlwaysShowDropdownMenu={isInvoiceReport} - customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} - menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} - isSplitButton={!isInvoiceReport} - isDisabled={isDisabled} - isLoading={isLoading} - onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} - pressOnEnter={pressOnEnter} - options={paymentButtonOptions} - onOptionSelected={(option) => savePreferredPaymentMethod(policyID, option.value)} - style={style} - buttonSize={buttonSize} - anchorAlignment={paymentMethodDropdownAnchorAlignment} - enterKeyEventListenerPriority={enterKeyEventListenerPriority} - /> - )} + {(triggerKYCFlow, buttonRef) => { + triggerKYCFlowRef.current = triggerKYCFlow; + return ( + + success + buttonRef={buttonRef} + shouldAlwaysShowDropdownMenu={isInvoiceReport} + customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} + menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} + isSplitButton={!isInvoiceReport} + isDisabled={isDisabled} + isLoading={isLoading} + onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + pressOnEnter={pressOnEnter} + options={paymentButtonOptions} + onOptionSelected={(option) => { + setSelectedPaymentType(option.value); + savePreferredPaymentMethod(policyID, option.value); + }} + style={style} + buttonSize={buttonSize} + anchorAlignment={paymentMethodDropdownAnchorAlignment} + enterKeyEventListenerPriority={enterKeyEventListenerPriority} + /> + ); + }} ); } From 990ccb2da957118d70fc47c9e2930448c5f24800 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 15 Jun 2024 08:22:10 +0530 Subject: [PATCH 2/5] clean up repearted code. Signed-off-by: Krishna Gupta --- src/components/SettlementButton.tsx | 67 +++++++++++------------------ 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index bf18c10caa5f..a49c275dcc25 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,8 +1,7 @@ -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import * as ReportUtils from '@libs/ReportUtils'; @@ -254,21 +253,6 @@ function SettlementButton({ IOU.savePreferredPaymentMethod(id, value); }; - const [selectedPaymentType, setSelectedPaymentType] = useState(paymentButtonOptions[0].value); - const triggerKYCFlowRef = useRef<(event: GestureResponderEvent | KeyboardEvent | undefined, method?: PaymentMethodType | undefined) => void>(() => {}); - - useKeyboardShortcut( - CONST.KEYBOARD_SHORTCUTS.CTRL_ENTER, - (e) => { - selectPaymentType(e, selectedPaymentType, triggerKYCFlowRef.current); - }, - { - captureOnInputs: true, - shouldBubble: false, - isActive: useKeyboardShortcuts, - }, - ); - return ( - {(triggerKYCFlow, buttonRef) => { - triggerKYCFlowRef.current = triggerKYCFlow; - return ( - - success - buttonRef={buttonRef} - shouldAlwaysShowDropdownMenu={isInvoiceReport} - customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} - menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} - isSplitButton={!isInvoiceReport} - isDisabled={isDisabled} - isLoading={isLoading} - onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} - pressOnEnter={pressOnEnter} - options={paymentButtonOptions} - onOptionSelected={(option) => { - setSelectedPaymentType(option.value); - savePreferredPaymentMethod(policyID, option.value); - }} - style={style} - buttonSize={buttonSize} - anchorAlignment={paymentMethodDropdownAnchorAlignment} - enterKeyEventListenerPriority={enterKeyEventListenerPriority} - /> - ); - }} + {(triggerKYCFlow, buttonRef) => ( + + success + buttonRef={buttonRef} + shouldAlwaysShowDropdownMenu={isInvoiceReport} + customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} + menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} + isSplitButton={!isInvoiceReport} + isDisabled={isDisabled} + isLoading={isLoading} + onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} + pressOnEnter={pressOnEnter} + options={paymentButtonOptions} + onOptionSelected={(option) => { + savePreferredPaymentMethod(policyID, option.value); + }} + style={style} + buttonSize={buttonSize} + anchorAlignment={paymentMethodDropdownAnchorAlignment} + enterKeyEventListenerPriority={enterKeyEventListenerPriority} + useKeyboardShortcuts={useKeyboardShortcuts} + /> + )} ); } From 7c4f38e304c3f658bf7709574fcdc8f6ca081e92 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 21 Jun 2024 14:15:36 +0530 Subject: [PATCH 3/5] fix buttonRef in ButtonWithDropdownMenu. Signed-off-by: Krishna Gupta --- src/components/ButtonWithDropdownMenu/index.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index cfe27f43b214..6d3b63eb4eab 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -79,6 +79,15 @@ function ButtonWithDropdownMenu({ isActive: useKeyboardShortcuts, }, ); + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (caretButton.current || !buttonRef?.current || !(shouldAlwaysShowDropdownMenu || options.length > 1)) { + return; + } + caretButton.current = buttonRef.current; + }, [buttonRef, options.length, shouldAlwaysShowDropdownMenu]); + return ( {shouldAlwaysShowDropdownMenu || options.length > 1 ? ( @@ -86,9 +95,7 @@ function ButtonWithDropdownMenu({