Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/Expensify/App into feat/#Ex…
Browse files Browse the repository at this point in the history
…pensify#23132-display-status-lhn
  • Loading branch information
perunt committed Aug 17, 2023
2 parents 924bf6e + 63d87ba commit 0cbe2b3
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 146 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001035500
versionName "1.3.55-0"
versionCode 1001035501
versionName "1.3.55-1"
}

flavorDimensions "default"
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.55.0</string>
<string>1.3.55.1</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.55.0</string>
<string>1.3.55.1</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.3.55-0",
"version": "1.3.55-1",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
2 changes: 2 additions & 0 deletions src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export default {
REPORT_WITH_ID: 'r/:reportID?',
EDIT_REQUEST: 'r/:threadReportID/edit/:field',
getEditRequestRoute: (threadReportID, field) => `r/${threadReportID}/edit/${field}`,
EDIT_CURRENCY_REQUEST: 'r/:threadReportID/edit/currency',
getEditRequestCurrencyRoute: (threadReportID, currency, backTo) => `r/${threadReportID}/edit/currency?currency=${currency}&backTo=${backTo}`,
getReportRoute: (reportID) => `r/${reportID}`,
REPORT_WITH_ID_DETAILS_SHARE_CODE: 'r/:reportID/details/shareCode',
getReportShareCodeRoute: (reportID) => `r/${reportID}/details/shareCode`,
Expand Down
15 changes: 3 additions & 12 deletions src/components/CurrencySymbolButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,16 @@ const propTypes = {

/** Function to call when currency button is pressed */
onCurrencyButtonPress: PropTypes.func.isRequired,

/** Flag to indicate if the button should be disabled */
disabled: PropTypes.bool,
};

const defaultProps = {
disabled: false,
};

function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol, disabled}) {
function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}) {
const {translate} = useLocalize();
return (
<Tooltip text={!disabled && translate('iOUCurrencySelection.selectCurrency')}>
<Tooltip text={translate('iOUCurrencySelection.selectCurrency')}>
<PressableWithoutFeedback
onPress={onCurrencyButtonPress}
accessibilityLabel={!disabled && translate('iOUCurrencySelection.selectCurrency')}
accessibilityLabel={translate('iOUCurrencySelection.selectCurrency')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
disabled={disabled}
>
<Text style={styles.iouAmountText}>{currencySymbol}</Text>
</PressableWithoutFeedback>
Expand All @@ -40,6 +32,5 @@ function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol, disabled})

CurrencySymbolButton.propTypes = propTypes;
CurrencySymbolButton.displayName = 'CurrencySymbolButton';
CurrencySymbolButton.defaultProps = defaultProps;

export default CurrencySymbolButton;
79 changes: 79 additions & 0 deletions src/components/DisplayNames/DisplayNamesTooltipItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import styles from '../../styles/styles';
import Text from '../Text';
import UserDetailsTooltip from '../UserDetailsTooltip';

const propTypes = {
index: PropTypes.number,

/** The full title of the DisplayNames component (not split up) */
getTooltipShiftX: PropTypes.func,

/** The Account ID for the tooltip */
accountID: PropTypes.number,

/** The name to display in bold */
displayName: PropTypes.string,

/** The login for the tooltip fallback */
login: PropTypes.string,

/** The avatar for the tooltip fallback */
avatar: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

/** Arbitrary styles of the displayName text */
// eslint-disable-next-line react/forbid-prop-types
textStyles: PropTypes.arrayOf(PropTypes.object),

/** Refs to all the names which will be used to correct the horizontal position of the tooltip */
childRefs: PropTypes.shape({
// eslint-disable-next-line react/forbid-prop-types
current: PropTypes.arrayOf(PropTypes.object),
}),
};

const defaultProps = {
index: 0,
getTooltipShiftX: () => {},
accountID: 0,
displayName: '',
login: '',
avatar: '',
textStyles: [],
childRefs: {current: []},
};

function DisplayNamesTooltipItem({index, getTooltipShiftX, accountID, avatar, login, displayName, textStyles, childRefs}) {
const tooltipIndexBridge = useCallback(() => getTooltipShiftX(index), [getTooltipShiftX, index]);

return (
<UserDetailsTooltip
key={index}
accountID={accountID}
fallbackUserDetails={{
avatar,
login,
displayName,
}}
shiftHorizontal={tooltipIndexBridge}
>
{/* We need to get the refs to all the names which will be used to correct the horizontal position of the tooltip */}
<Text
eslint-disable-next-line
no-param-reassign
// eslint-disable-next-line no-param-reassign
ref={(el) => (childRefs.current[index] = el)}
style={[...textStyles, styles.pre]}
>
{displayName}
</Text>
</UserDetailsTooltip>
);
}

DisplayNamesTooltipItem.propTypes = propTypes;
DisplayNamesTooltipItem.defaultProps = defaultProps;
DisplayNamesTooltipItem.displayName = 'DisplayNamesTooltipItem';

export default DisplayNamesTooltipItem;
92 changes: 92 additions & 0 deletions src/components/DisplayNames/DisplayNamesWithTooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, {Fragment, useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import styles from '../../styles/styles';
import Text from '../Text';
import Tooltip from '../Tooltip';
import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
import {defaultProps, propTypes} from './displayNamesPropTypes';

function DisplayNamesWithToolTip(props) {
const containerRef = useRef(null);
const childRefs = useRef([]);
const [isEllipsisActive, setIsEllipsisActive] = useState(false);

useEffect(() => {
setIsEllipsisActive(
containerRef.current && containerRef.current.offsetWidth && containerRef.current.scrollWidth && containerRef.current.offsetWidth < containerRef.current.scrollWidth,
);
}, []);

/**
* We may need to shift the Tooltip horizontally as some of the inline text wraps well with ellipsis,
* but their container node overflows the parent view which causes the tooltip to be misplaced.
*
* So we shift it by calculating it as follows:
* 1. We get the container layout and take the Child inline text node.
* 2. Now we get the tooltip original position.
* 3. If inline node's right edge is overflowing the container's right edge, we set the tooltip to the center
* of the distance between the left edge of the inline node and right edge of the container.
* @param {Number} index Used to get the Ref to the node at the current index
* @returns {Number} Distance to shift the tooltip horizontally
*/
const getTooltipShiftX = useCallback((index) => {
// Only shift the tooltip in case the containerLayout or Refs to the text node are available
if (!containerRef || !childRefs.current[index]) {
return;
}
const {width: containerWidth, left: containerLeft} = containerRef.current.getBoundingClientRect();

// We have to return the value as Number so we can't use `measureWindow` which takes a callback
const {width: textNodeWidth, left: textNodeLeft} = childRefs.current[index].getBoundingClientRect();
const tooltipX = textNodeWidth / 2 + textNodeLeft;
const containerRight = containerWidth + containerLeft;
const textNodeRight = textNodeWidth + textNodeLeft;
const newToolX = textNodeLeft + (containerRight - textNodeLeft) / 2;

// When text right end is beyond the Container right end
return textNodeRight > containerRight ? -(tooltipX - newToolX) : 0;
}, []);

return (
// Tokenization of string only support prop numberOfLines on Web
<Text
style={[...props.textStyles, styles.pRelative]}
numberOfLines={props.numberOfLines || undefined}
ref={(el) => (containerRef.current = el)}
>
{props.shouldUseFullTitle
? props.fullTitle
: _.map(props.displayNamesWithTooltips, ({displayName, accountID, avatar, login}, index) => (
<Fragment key={index}>
<DisplayNamesTooltipItem
index={index}
getTooltipShiftX={getTooltipShiftX}
accountID={accountID}
displayName={displayName}
login={login}
avatar={avatar}
textStyles={props.textStyles}
childRefs={childRefs}
addComma={index < props.displayNamesWithTooltips.length - 1}
/>
{index < props.displayNamesWithTooltips.length - 1 && <Text style={props.textStyles}>,&nbsp;</Text>}
</Fragment>
))}
{Boolean(isEllipsisActive) && (
<View style={styles.displayNameTooltipEllipsis}>
<Tooltip text={props.fullTitle}>
{/* There is some Gap for real ellipsis so we are adding 4 `.` to cover */}
<Text>....</Text>
</Tooltip>
</View>
)}
</Text>
);
}

DisplayNamesWithToolTip.propTypes = propTypes;
DisplayNamesWithToolTip.defaultProps = defaultProps;
DisplayNamesWithToolTip.displayName = 'DisplayNamesWithTooltip';

export default DisplayNamesWithToolTip;
39 changes: 39 additions & 0 deletions src/components/DisplayNames/DisplayNamesWithoutTooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
import React from 'react';
import styles from '../../styles/styles';
import Text from '../Text';

const propTypes = {
/** The full title of the DisplayNames component (not split up) */
fullTitle: PropTypes.string,

/** Arbitrary styles of the displayName text */
// eslint-disable-next-line react/forbid-prop-types
textStyles: PropTypes.arrayOf(PropTypes.object),

/** Number of lines before wrapping */
numberOfLines: PropTypes.number,
};

const defaultProps = {
fullTitle: '',
textStyles: [],
numberOfLines: 1,
};

function DisplayNamesWithoutTooltip({textStyles, numberOfLines, fullTitle}) {
return (
<Text
style={[...textStyles, numberOfLines === 1 ? styles.pre : styles.preWrap]}
numberOfLines={numberOfLines}
>
{fullTitle}
</Text>
);
}

DisplayNamesWithoutTooltip.propTypes = propTypes;
DisplayNamesWithoutTooltip.defaultProps = defaultProps;
DisplayNamesWithoutTooltip.displayName = 'DisplayNamesWithoutTooltip';

export default DisplayNamesWithoutTooltip;
Loading

0 comments on commit 0cbe2b3

Please sign in to comment.