diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js index 268351699567..172743fa19bc 100644 --- a/src/components/MenuItem.js +++ b/src/components/MenuItem.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; +import PressableWithFeedback from './Pressable/PressableWithFeedback'; import Text from './Text'; import styles from '../styles/styles'; import themeColors from '../styles/themes/default'; @@ -49,6 +50,8 @@ const defaultProps = { iconHeight: undefined, description: undefined, iconRight: Expensicons.ArrowRight, + onIconRightPress: undefined, + iconRightAccessibilityLabel: undefined, iconStyles: [], iconFill: undefined, secondaryIconFill: undefined, @@ -77,6 +80,8 @@ const defaultProps = { numberOfLinesTitle: 1, shouldGreyOutWhenDisabled: true, shouldRenderAsHTML: false, + rightComponent: undefined, + shouldShowRightComponent: false, }; const MenuItem = React.forwardRef((props, ref) => { @@ -131,6 +136,8 @@ const MenuItem = React.forwardRef((props, ref) => { return ''; }, [props.title, props.shouldRenderAsHTML, props.shouldParseTitle, html]); + const hasPressableRightComponent = props.onIconRightPress || props.iconRight || (props.rightComponent && props.shouldShowRightComponent); + return ( {(isHovered) => ( @@ -295,7 +302,7 @@ const MenuItem = React.forwardRef((props, ref) => { - + {Boolean(props.badgeText) && ( { )} {Boolean(props.shouldShowRightIcon) && ( - + - + )} + {props.shouldShowRightComponent && props.rightComponent} {props.shouldShowSelectedState && } diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js index 6272a7a2ef7d..3ba8bed19575 100644 --- a/src/components/menuItemPropTypes.js +++ b/src/components/menuItemPropTypes.js @@ -67,6 +67,12 @@ const propTypes = { /** Overrides the icon for shouldShowRightIcon */ iconRight: PropTypes.elementType, + /** Function to fire when the right icon has been pressed */ + onIconRightPress: PropTypes.func, + + /** accessibilityLabel for the right icon when it's pressable */ + iconRightAccessibilityLabel: PropTypes.string, + /** A description text to show under the title */ description: PropTypes.string, @@ -147,6 +153,12 @@ const propTypes = { /** Should render the content in HTML format */ shouldRenderAsHTML: PropTypes.bool, + + /** Component to be displayed on the right */ + rightComponent: PropTypes.node, + + /** Should render component on the right */ + shouldShowRightComponent: PropTypes.bool, }; export default propTypes; diff --git a/src/languages/en.ts b/src/languages/en.ts index 403931d542f3..13b2fd597ff2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -814,6 +814,14 @@ export default { availableSpend: 'Remaining spending power', virtualCardNumber: 'Virtual card number', physicalCardNumber: 'Physical card number', + cardDetails: { + cardNumber: 'Virtual card number', + expiration: 'Expiration', + cvv: 'CVV', + address: 'Address', + revealDetails: 'Reveal details', + copyCardNumber: 'Copy card number', + }, }, transferAmountPage: { transfer: ({amount}: TransferParams) => `Transfer${amount ? ` ${amount}` : ''}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index ffe334f4a807..2cc5d817907d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -809,6 +809,14 @@ export default { availableSpend: 'Capacidad de gasto restante', virtualCardNumber: 'Número de la tarjeta virtual', physicalCardNumber: 'Número de la tarjeta física', + cardDetails: { + cardNumber: 'Número de tarjeta virtual', + expiration: 'Expiración', + cvv: 'CVV', + address: 'Dirección', + revealDetails: 'Revelar detalles', + copyCardNumber: 'Copiar número de la tarjeta', + }, }, transferAmountPage: { transfer: ({amount}: TransferParams) => `Transferir${amount ? ` ${amount}` : ''}`, diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index a401dea4b911..6b9335ab263d 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -152,4 +152,29 @@ function getNewPersonalDetailsOnyxData(logins, accountIDs) { }; } -export {getDisplayNameOrDefault, getPersonalDetailsByIDs, getAccountIDsByLogins, getLoginsByAccountIDs, getNewPersonalDetailsOnyxData}; +/** + * Applies common formatting to each piece of an address + * + * @param {String} piece - address piece to format + * @returns {String} - formatted piece + */ +function formatPiece(piece) { + return piece ? `${piece}, ` : ''; +} + +/** + * Formats an address object into an easily readable string + * + * @param {OnyxTypes.PrivatePersonalDetails} privatePersonalDetails - details object + * @returns {String} - formatted address + */ +function getFormattedAddress(privatePersonalDetails) { + const {address} = privatePersonalDetails; + const [street1, street2] = (address.street || '').split('\n'); + const formattedAddress = formatPiece(street1) + formatPiece(street2) + formatPiece(address.city) + formatPiece(address.state) + formatPiece(address.zip) + formatPiece(address.country); + + // Remove the last comma of the address + return formattedAddress.trim().replace(/,$/, ''); +} + +export {getDisplayNameOrDefault, getPersonalDetailsByIDs, getAccountIDsByLogins, getLoginsByAccountIDs, getNewPersonalDetailsOnyxData, getFormattedAddress}; diff --git a/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js b/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js index faac43e52656..f639a7eebc15 100644 --- a/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js +++ b/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js @@ -16,6 +16,7 @@ import ONYXKEYS from '../../../../ONYXKEYS'; import {withNetwork} from '../../../../components/OnyxProvider'; import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails'; import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator'; +import * as PersonalDetailsUtils from '../../../../libs/PersonalDetailsUtils'; const propTypes = { /* Onyx Props */ @@ -58,32 +59,9 @@ const defaultProps = { function PersonalDetailsInitialPage(props) { usePrivatePersonalDetails(); const privateDetails = props.privatePersonalDetails || {}; - const address = privateDetails.address || {}; const legalName = `${privateDetails.legalFirstName || ''} ${privateDetails.legalLastName || ''}`.trim(); const isLoadingPersonalDetails = lodashGet(props.privatePersonalDetails, 'isLoading', true); - /** - * Applies common formatting to each piece of an address - * - * @param {String} piece - * @returns {String} - */ - const formatPiece = (piece) => (piece ? `${piece}, ` : ''); - - /** - * Formats an address object into an easily readable string - * - * @returns {String} - */ - const getFormattedAddress = () => { - const [street1, street2] = (address.street || '').split('\n'); - const formattedAddress = - formatPiece(street1) + formatPiece(street2) + formatPiece(address.city) + formatPiece(address.state) + formatPiece(address.zip) + formatPiece(address.country); - - // Remove the last comma of the address - return formattedAddress.trim().replace(/,$/, ''); - }; - return ( Navigation.navigate(ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS)} diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.js b/src/pages/settings/Wallet/ExpensifyCardPage.js index bc49301e8d80..026e8147d79f 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.js +++ b/src/pages/settings/Wallet/ExpensifyCardPage.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React from 'react'; +import React, {useState} from 'react'; import {ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -16,6 +16,8 @@ import * as CurrencyUtils from '../../../libs/CurrencyUtils'; import Navigation from '../../../libs/Navigation/Navigation'; import styles from '../../../styles/styles'; import * as CardUtils from '../../../libs/CardUtils'; +import Button from '../../../components/Button'; +import CardDetails from './WalletPage/CardDetails'; const propTypes = { /* Onyx Props */ @@ -45,12 +47,18 @@ function ExpensifyCardPage({ const virtualCard = _.find(domainCards, (card) => card.isVirtual) || {}; const physicalCard = _.find(domainCards, (card) => !card.isVirtual) || {}; + const [shouldShowCardDetails, setShouldShowCardDetails] = useState(false); + if (_.isEmpty(virtualCard) && _.isEmpty(physicalCard)) { return ; } const formattedAvailableSpendAmount = CurrencyUtils.convertToDisplayString(physicalCard.availableSpend || virtualCard.availableSpend || 0); + const handleRevealDetails = () => { + setShouldShowCardDetails(true); + }; + return ( - {!_.isEmpty(physicalCard) && ( - + {!_.isEmpty(virtualCard) && ( + <> + {shouldShowCardDetails ? ( + + ) : ( + + } + /> + )} + )} {!_.isEmpty(physicalCard) && ( { + Clipboard.setString(pan); + }; + + return ( + <> + + + + } + interactive={false} + /> + + + + + ); +} + +CardDetails.displayName = 'CardDetails'; +CardDetails.propTypes = propTypes; +CardDetails.defaultProps = defaultProps; + +export default withOnyx({ + privatePersonalDetails: { + key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, + }, +})(CardDetails);