Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
63 changes: 63 additions & 0 deletions src/components/Badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import {Pressable, View} from 'react-native';
import PropTypes from 'prop-types';
import styles, {getBadgeColorStyle} from '../styles/styles';
import Text from './Text';

const propTypes = {
/** Is Success type */
success: PropTypes.bool,

/** Is Error type */
error: PropTypes.bool,

/** Whether badge is clickable */
pressable: PropTypes.bool,

/** Text to display in the Badge */
text: PropTypes.string.isRequired,

/** Styles for Badge */
badgeStyles: PropTypes.arrayOf(PropTypes.object),

/** Callback to be called on onPress */
onPress: PropTypes.func,
};

const defaultProps = {
success: false,
error: false,
pressable: false,
badgeStyles: [],
onPress: undefined,
};

const Badge = (props) => {
const textStyles = props.success || props.error ? styles.textWhite : undefined;
const Wrapper = props.pressable ? Pressable : View;
const wrapperStyles = ({pressed}) => ([
styles.badge,
styles.ml2,
getBadgeColorStyle(props.success, props.error, pressed),
...props.badgeStyles,
]);

return (
<Wrapper
style={props.pressable ? wrapperStyles : wrapperStyles(false)}
onPress={props.onPress}
>
<Text
style={[styles.badgeText, textStyles]}
numberOfLines={1}
>
{props.text}
</Text>
</Wrapper>
);
};

Badge.displayName = 'Badge';
Badge.propTypes = propTypes;
Badge.defaultProps = defaultProps;
export default Badge;
18 changes: 6 additions & 12 deletions src/components/EnvironmentBadge.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import React from 'react';
import {View} from 'react-native';
import styles from '../styles/styles';
import CONST from '../CONST';
import Text from './Text';
import withEnvironment, {environmentPropTypes} from './withEnvironment';
import Badge from './Badge';

const EnvironmentBadge = (props) => {
// If we are on production, don't show any badge
if (props.environment === CONST.ENVIRONMENT.PRODUCTION) {
return null;
}

const backgroundColorStyle = props.environment === CONST.ENVIRONMENT.STAGING
? styles.badgeSuccess
: styles.badgeDanger;

return (
<View style={[styles.badge, backgroundColorStyle, styles.ml2]}>
<Text style={styles.badgeText}>
{props.environment}
</Text>
</View>
<Badge
success={props.environment === CONST.ENVIRONMENT.STAGING}
error={props.environment !== CONST.ENVIRONMENT.STAGING}
text={props.environment}
/>
);
};

Expand Down
32 changes: 11 additions & 21 deletions src/components/IOUBadge.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import {Pressable} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import ONYXKEYS from '../ONYXKEYS';
import styles, {getBadgeColorStyle} from '../styles/styles';
import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import CONST from '../CONST';
import Text from './Text';
import Badge from './Badge';

const propTypes = {
/** IOU Report data object */
Expand Down Expand Up @@ -53,24 +51,16 @@ const IOUBadge = (props) => {
Navigation.navigate(ROUTES.getIouDetailsRoute(props.iouReport.chatReportID, props.iouReport.reportID));
};
return (
<Pressable
style={({pressed}) => ([
styles.badge,
styles.ml2,
getBadgeColorStyle(props.session.email === props.iouReport.ownerEmail, pressed),
])}
>
<Text
style={styles.badgeText}
numberOfLines={1}
onPress={launchIOUDetailsModal}
>
{props.numberFormat(
props.iouReport.total / 100,
{style: 'currency', currency: props.iouReport.currency},
)}
</Text>
</Pressable>
<Badge
pressable
onPress={launchIOUDetailsModal}
success={props.session.email === props.iouReport.ownerEmail}
error={props.session.email !== props.iouReport.ownerEmail}
text={props.numberFormat(
props.iouReport.total / 100,
{style: 'currency', currency: props.iouReport.currency},
)}
/>
);
};

Expand Down
7 changes: 7 additions & 0 deletions src/components/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ import styles, {getButtonBackgroundColorStyle, getIconFillColor} from '../styles
import Icon from './Icon';
import {ArrowRight} from './Icon/Expensicons';
import getButtonState from '../libs/getButtonState';
import Badge from './Badge';

const propTypes = {
/** Text to be shown as badge near the right end. */
badgeText: PropTypes.string,

/** Any additional styles to apply */
// eslint-disable-next-line react/forbid-prop-types
wrapperStyle: PropTypes.object,
Expand Down Expand Up @@ -58,6 +62,7 @@ const propTypes = {
};

const defaultProps = {
badgeText: undefined,
shouldShowRightIcon: false,
wrapperStyle: {},
success: false,
Expand All @@ -74,6 +79,7 @@ const defaultProps = {
};

const MenuItem = ({
badgeText,
onPress,
icon,
iconRight,
Expand Down Expand Up @@ -141,6 +147,7 @@ const MenuItem = ({
</View>
</View>
<View style={[styles.flexRow, styles.menuItemTextContainer]}>
{badgeText && <Badge text={badgeText} badgeStyles={[styles.alignSelfCenter]} />}
{subtitle && (
<View style={[styles.justifyContentCenter, styles.mr1]}>
<Text
Expand Down
21 changes: 21 additions & 0 deletions src/pages/settings/InitialPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ const propTypes = {
role: PropTypes.string,
})),

/** The user's wallet account */
userWallet: PropTypes.shape({
/** The user's current wallet balance */
availableBalance: PropTypes.number,
}),

...withLocalizePropTypes,
};

Expand All @@ -75,6 +81,9 @@ const defaultProps = {
network: {},
session: {},
policies: {},
userWallet: {
availableBalance: 0,
},
};

const defaultMenuItems = [
Expand Down Expand Up @@ -113,10 +122,17 @@ const defaultMenuItems = [
const InitialSettingsPage = ({
myPersonalDetails,
network,
numberFormat,
session,
policies,
translate,
userWallet,
}) => {
const walletBalance = numberFormat(
userWallet.availableBalance,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks like if the user has no availableBalance, this can be $NaN, so I think we want a fallback of 0 here.

{style: 'currency', currency: 'USD'},
);

// On the very first sign in or after clearing storage these
// details will not be present on the first render so we'll just
// return nothing for now.
Expand Down Expand Up @@ -169,6 +185,7 @@ const InitialSettingsPage = ({
</View>
{_.map(menuItems, (item, index) => {
const keyTitle = item.translationKey ? translate(item.translationKey) : item.title;
const isPaymentItem = item.translationKey === 'common.payments';
return (
<MenuItem
key={`${keyTitle}_${index}`}
Expand All @@ -178,6 +195,7 @@ const InitialSettingsPage = ({
iconStyles={item.iconStyles}
iconFill={item.iconFill}
shouldShowRightIcon
badgeText={isPaymentItem ? walletBalance : undefined}
/>
);
})}
Expand Down Expand Up @@ -206,5 +224,8 @@ export default compose(
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
}),
)(InitialSettingsPage);
20 changes: 12 additions & 8 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ const styles = {
},

badgeText: {
color: themeColors.textReversed,
color: themeColors.text,
fontSize: variables.fontSizeSmall,
lineHeight: 16,
...whiteSpace.noWrap,
Expand Down Expand Up @@ -2012,17 +2012,21 @@ function getBackgroundColorStyle(backgroundColor) {
}

/**
* Generate a style for the background color of the IOU badge
* Generate a style for the background color of the Badge
*
* @param {Boolean} isOwner
* @param {Boolean} [isPressed]
* @returns {Object}
* @param {Boolean} success
* @param {Boolean} error
* @param {boolean} [isPressed=false]
* @return {Object}
*/
function getBadgeColorStyle(isOwner, isPressed = false) {
if (isOwner) {
function getBadgeColorStyle(success, error, isPressed = false) {
if (success) {
return isPressed ? styles.badgeSuccessPressed : styles.badgeSuccess;
}
return isPressed ? styles.badgeDangerPressed : styles.badgeDanger;
if (error) {
return isPressed ? styles.badgeDangerPressed : styles.badgeDanger;
}
return {};
}

/**
Expand Down