Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pay button to money request header #18692

Merged
merged 69 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
0d9213e
Start working on money request header
iwiznia May 9, 2023
bd575fb
Merge branch 'main' into ionatan_payheader
iwiznia May 11, 2023
5e93f1f
Refactor calls to api
iwiznia May 11, 2023
0d9a80d
Pass policyID when needed
iwiznia May 11, 2023
e60ff26
Add missing prop
iwiznia May 11, 2023
7af54a9
Lint, hide button for the person that's owed
iwiznia May 12, 2023
8f41a21
Remove useless componentButtonWithDropdown
iwiznia May 12, 2023
dbe3ad3
Convert to functional and try to use measureInWindow
iwiznia May 12, 2023
17d4d80
Merge main
iwiznia May 12, 2023
6b3f7b2
Fix measureInWindow
roryabraham May 12, 2023
7e189ea
Merge pull request #18868 from Expensify/Rory-FixMeasureInWindowV2
iwiznia May 12, 2023
3f7b823
Tweak logic and positioning
iwiznia May 12, 2023
1f196bc
Trying to positiong the popover correctly
iwiznia May 12, 2023
9de7b5f
Create useArrowKeyFocusManager hook
roryabraham May 12, 2023
c35e14d
Make useArrowKeyFocusManager more powerful and easy to use
roryabraham May 12, 2023
887a89c
Add isActive prop to useKeyboardShortcut
roryabraham May 13, 2023
43b07b2
Create useWindowDimensions hook
roryabraham May 13, 2023
a64b767
Get popover displaying in the correct place
roryabraham May 13, 2023
25d53a7
fix useKeyboardShortcut cleanup
roryabraham May 13, 2023
659d888
Remove unnecessary measureContent prop from PopoverWithMeasuredContent
roryabraham May 13, 2023
630a358
Fix comment indentation
roryabraham May 13, 2023
4c548fb
Add JSdocs in useArrowKeyFocusManager
roryabraham May 13, 2023
83d4d95
Add JSDocs for useKeyboardShortcut
roryabraham May 13, 2023
bbda68b
Fix BasePaymentsPage
roryabraham May 13, 2023
911168b
add TODO
roryabraham May 13, 2023
e082b99
Merge pull request #18883 from Expensify/Rory-PayHeader
iwiznia May 15, 2023
4f050f6
Do not require gold wallet for paying expense reports
iwiznia May 15, 2023
19bd75f
Fix popover menu's clicks
iwiznia May 15, 2023
3c9d4bd
Fix positioning of some popovers
iwiznia May 15, 2023
f92af92
Fix popovers on user and workspace avatar
iwiznia May 15, 2023
ac1a3ef
Fix popover payment methods
iwiznia May 15, 2023
00d63be
Fix position of settlement button
iwiznia May 15, 2023
ae921ba
Undo changes to prettier
iwiznia May 15, 2023
21e48d1
Merge with main
iwiznia May 15, 2023
f4254fa
Change state num to state
iwiznia May 15, 2023
3aedfa7
Add shouldShowPaymentOptions
iwiznia May 15, 2023
fbad575
Remove todos
iwiznia May 15, 2023
dcc53db
Fixes from review
iwiznia May 16, 2023
60e500d
Use ReportUtils methods
iwiznia May 16, 2023
53cecb7
Fix import
iwiznia May 16, 2023
a8cacdf
Use correct state
iwiznia May 16, 2023
9603521
Pass additional styles to settlement button for use in the report pre…
iwiznia May 16, 2023
5e7679d
Merge from main
iwiznia May 16, 2023
8d55041
Prettier
iwiznia May 16, 2023
ba16ae4
Fix popover position
iwiznia May 16, 2023
f400b8d
Add missing routes
iwiznia May 16, 2023
10f9653
Fix tests
iwiznia May 16, 2023
7348e6d
Merge branch 'main' into ionatan_payheader
iwiznia May 16, 2023
548077f
Fix tests?
iwiznia May 17, 2023
19552df
prettier
iwiznia May 17, 2023
e2fffdc
Merge branch 'main' into ionatan_payheader
Julesssss May 17, 2023
75234ba
Merge from main
iwiznia May 17, 2023
b3da93c
Merge from main
iwiznia May 17, 2023
ce79bde
Use correct proptypes
iwiznia May 17, 2023
9902558
fix button style in preview, pay request directly
luacmartins May 17, 2023
3922698
fix payment button style on header
luacmartins May 17, 2023
cf1add9
fix show pay button logic
luacmartins May 17, 2023
8bc42d2
use session email
luacmartins May 17, 2023
24640a1
fix logic in requestmoney
luacmartins May 17, 2023
5c291e2
hide button in preview when settling
luacmartins May 17, 2023
5667dba
Use constant, remove dupe
iwiznia May 17, 2023
a9f0ee3
fix logic with KYC flow
luacmartins May 17, 2023
73b3cb2
call right command
luacmartins May 17, 2023
bee11bb
use ACH method for VBA payments
luacmartins May 17, 2023
e3cbd2f
add paypal option
luacmartins May 17, 2023
c5fb5c4
clean up payMoneyrequest
luacmartins May 17, 2023
ef52c5d
fix style
luacmartins May 17, 2023
6fa4cd5
fix picker anchor, add optimistic lastPaymentMethod
luacmartins May 17, 2023
552f62e
update preview action
luacmartins May 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ const CONST = {
},
STATE: {
SUBMITTED: 'SUBMITTED',
PROCESSING: 'PROCESSING',
},
STATE_NUM: {
OPEN: 0,
Expand Down Expand Up @@ -960,6 +961,7 @@ const CONST = {
ELSEWHERE: 'Elsewhere',
EXPENSIFY: 'Expensify',
PAYPAL_ME: 'PayPal.me',
VBBA: 'ACH',
},
MONEY_REQUEST_TYPE: {
SEND: 'send',
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ export default {
// A unique identifier that each user has that's used to send notifications
NVP_PRIVATE_PUSH_NOTIFICATION_ID: 'private_pushNotificationID',

// The NVP with the last payment method used per policy
NVP_LAST_PAYMENT_METHOD: 'nvp_lastPaymentMethod',

// Does this user have push notifications enabled for this device?
PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled',

Expand Down
1 change: 1 addition & 0 deletions src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const SETTINGS_CONTACT_METHODS = 'settings/profile/contact-methods';

export default {
BANK_ACCOUNT: 'bank-account',
BANK_ACCOUNT_NEW: 'bank-account/new',
BANK_ACCOUNT_WITH_STEP_TO_OPEN: 'bank-account/:stepToOpen?',
BANK_ACCOUNT_PERSONAL: 'bank-account/personal',
getBankAccountRoute: (stepToOpen = '', policyID = '') => `bank-account/${stepToOpen}?policyID=${policyID}`,
Expand Down
11 changes: 8 additions & 3 deletions src/components/AddPaymentMethodMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ import PopoverMenu from './PopoverMenu';
import paypalMeDataPropTypes from './paypalMeDataPropTypes';

const propTypes = {
/** Should the component be visible? */
isVisible: PropTypes.bool.isRequired,

/** Callback to execute when the component closes. */
onClose: PropTypes.func.isRequired,

/** Anchor position for the AddPaymentMenu. */
anchorPosition: PropTypes.shape({
top: PropTypes.number,
left: PropTypes.number,
horizontal: PropTypes.number,
vertical: PropTypes.number,
}),

/** Account details for PayPal.Me */
Expand All @@ -43,7 +48,7 @@ const AddPaymentMethodMenu = (props) => (
isVisible={props.isVisible}
onClose={props.onClose}
anchorPosition={props.anchorPosition}
onItemSelected={() => props.onClose()}
onItemSelected={props.onClose}
menuItems={[
{
text: props.translate('common.bankAccount'),
Expand Down
1 change: 1 addition & 0 deletions src/components/AvatarWithImagePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ class AvatarWithImagePicker extends React.Component {
onItemSelected={() => this.setState({isMenuVisible: false})}
menuItems={this.createMenuItems(openPicker)}
anchorPosition={this.props.anchorPosition}
anchorAlignment={this.props.anchorAlignment}
/>
</>
)}
Expand Down
18 changes: 17 additions & 1 deletion src/components/Button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ const propTypes = {

/** Accessibility label for the component */
accessibilityLabel: PropTypes.string,

/** A ref to forward the button */
forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.oneOfType([PropTypes.instanceOf(React.Component), PropTypes.func])})]),
};

const defaultProps = {
Expand Down Expand Up @@ -141,6 +144,7 @@ const defaultProps = {
shouldEnableHapticFeedback: false,
nativeID: '',
accessibilityLabel: '',
forwardedRef: undefined,
};

class Button extends Component {
Expand Down Expand Up @@ -240,6 +244,7 @@ class Button extends Component {
render() {
return (
<PressableWithFeedback
ref={this.props.forwardedRef}
onPress={(e) => {
if (e && e.type === 'click') {
e.currentTarget.blur();
Expand Down Expand Up @@ -303,4 +308,15 @@ class Button extends Component {
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;

export default compose(withNavigationFallback, withNavigationFocus)(Button);
export default compose(
withNavigationFallback,
withNavigationFocus,
)(
React.forwardRef((props, ref) => (
<Button
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
forwardedRef={ref}
/>
)),
);
65 changes: 0 additions & 65 deletions src/components/ButtonWithDropdown.js

This file was deleted.

139 changes: 139 additions & 0 deletions src/components/ButtonWithDropdownMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React, {useState, useRef, useEffect} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import _ from 'underscore';
import useWindowDimensions from '../hooks/useWindowDimensions';
import styles from '../styles/styles';
import Button from './Button';
import PopoverMenu from './PopoverMenu';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import themeColors from '../styles/themes/default';
import CONST from '../CONST';

const propTypes = {
/** Text to display for the menu header */
menuHeaderText: PropTypes.string,

/** Callback to execute when the main button is pressed */
onPress: PropTypes.func.isRequired,

/** Whether we should show a loading state for the main button */
isLoading: PropTypes.bool,

/** Should the confirmation button be disabled? */
isDisabled: PropTypes.bool,

/** Additional styles to add to the component */
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),

/** Menu options to display */
/** e.g. [{text: 'Pay with Expensify', icon: Wallet}, {text: 'PayPal', icon: PayPal}] */
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
icon: PropTypes.elementType,
iconWidth: PropTypes.number,
iconHeight: PropTypes.number,
iconDescription: PropTypes.string,
}),
).isRequired,
};

const defaultProps = {
isLoading: false,
isDisabled: false,
menuHeaderText: '',
style: [],
};

const ButtonWithDropdownMenu = (props) => {
const [selectedItemIndex, setSelectedItemIndex] = useState(0);
const [isMenuVisible, setIsMenuVisible] = useState(false);
const [popoverAnchorPosition, setPopoverAnchorPosition] = useState(null);
const {width: windowWidth, height: windowHeight} = useWindowDimensions();
const caretButton = useRef(null);
useEffect(() => {
if (!caretButton.current) {
return;
}
caretButton.current.measureInWindow((x, y, w, h) => {
setPopoverAnchorPosition({
horizontal: x + w,
vertical: y + h,
});
});
}, [windowWidth, windowHeight]);

Comment on lines +57 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused a regression #20262. The popover position is calculated too early at the first render where animation is not done yet (position is not stable yet).

const selectedItem = props.options[selectedItemIndex];
return (
<View>
{props.options.length > 1 ? (
<View style={[styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, ...props.style]}>
<Button
success
onPress={(event) => props.onPress(event, selectedItem.value)}
text={selectedItem.text}
isDisabled={props.isDisabled}
isLoading={props.isLoading}
shouldRemoveRightBorderRadius
style={[styles.flex1, styles.pr0]}
pressOnEnter
/>
<View style={styles.buttonDivider} />
<Button
ref={caretButton}
success
isDisabled={props.isDisabled}
style={[styles.pl0]}
onPress={() => {
setIsMenuVisible(true);
}}
shouldRemoveLeftBorderRadius
>
<Icon
src={Expensicons.DownArrow}
fill={themeColors.textLight}
/>
</Button>
</View>
) : (
<Button
success
isDisabled={props.isDisabled}
style={[styles.w100, ...props.style]}
isLoading={props.isLoading}
text={selectedItem.text}
onPress={(event) => props.onPress(event, props.options[0].value)}
pressOnEnter
/>
)}
{props.options.length > 1 && !_.isEmpty(popoverAnchorPosition) && (
<PopoverMenu
isVisible={isMenuVisible}
onClose={() => setIsMenuVisible(false)}
onItemSelected={() => setIsMenuVisible(false)}
anchorPosition={popoverAnchorPosition}
anchorAlignment={{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
}}
headerText={props.menuHeaderText}
menuItems={_.map(props.options, (item, index) => ({
...item,
onSelected: () => {
setSelectedItemIndex(index);
},
}))}
/>
)}
</View>
);
};

ButtonWithDropdownMenu.propTypes = propTypes;
ButtonWithDropdownMenu.defaultProps = defaultProps;
ButtonWithDropdownMenu.displayName = 'ButtonWithDropdownMenu';

export default React.memo(ButtonWithDropdownMenu);
Loading