Skip to content

Commit

Permalink
Merge pull request #2566 from Expensify/main
Browse files Browse the repository at this point in the history
  • Loading branch information
OSBotify committed Apr 26, 2021
2 parents 10c47e0 + 03e2127 commit 0e66043
Show file tree
Hide file tree
Showing 23 changed files with 524 additions and 159 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001002903
versionName "1.0.29-3"
versionCode 1001003001
versionName "1.0.30-1"
}
splits {
abi {
Expand Down
4 changes: 2 additions & 2 deletions ios/ExpensifyCash/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.29</string>
<string>1.0.30</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.0.29.3</string>
<string>1.0.30.1</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
4 changes: 2 additions & 2 deletions ios/ExpensifyCashTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.29</string>
<string>1.0.30</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0.29.3</string>
<string>1.0.30.1</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion 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": "expensify.cash",
"version": "1.0.29-3",
"version": "1.0.30-1",
"author": "Expensify, Inc.",
"homepage": "https://expensify.cash",
"description": "Expensify.cash is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
4 changes: 4 additions & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const CONST = {
IOU: 'IOU',
},
},
TYPE: {
CHAT: 'chat',
IOU: 'iou',
},
},
MODAL: {
MODAL_TYPE: {
Expand Down
5 changes: 3 additions & 2 deletions src/ROUTES.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import lodashGet from 'lodash/get';
import {wrapWithForwardSlash} from './libs/Url';
import {addTrailingForwardSlash} from './libs/Url';

/**
* This is a file containing constants for all of the routes we want to be able to go to
Expand Down Expand Up @@ -43,13 +43,14 @@ export default {
* @returns {Object}
*/
parseReportRouteParams: (route) => {
if (!route.startsWith(wrapWithForwardSlash(REPORT))) {
if (!route.startsWith(addTrailingForwardSlash(REPORT))) {
return {};
}

const pathSegments = route.split('/');
return {
reportID: lodashGet(pathSegments, 1),
isParticipantsRoute: Boolean(lodashGet(pathSegments, 2)),
};
},
};
140 changes: 140 additions & 0 deletions src/components/ReportActionItemIOUPreview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import {View, TouchableOpacity} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
import ONYXKEYS from '../ONYXKEYS';
import ReportActionItemIOUQuote from './ReportActionItemIOUQuote';
import ReportActionPropTypes from '../pages/home/report/ReportActionPropTypes';
import Text from './Text';
import MultipleAvatars from './MultipleAvatars';
import styles from '../styles/styles';

const propTypes = {
// All the data of the action
action: PropTypes.shape(ReportActionPropTypes).isRequired,

// Is this the most recent IOU Action?
isMostRecentIOUReportAction: PropTypes.bool.isRequired,

// Whether there is an outstanding amount in IOU
hasOutstandingIOU: PropTypes.bool.isRequired,

/* --- Onyx Props --- */
// Active IOU Report for current report
iou: PropTypes.shape({
// Email address of the manager in this iou report
managerEmail: PropTypes.string,

// Email address of the creator of this iou report
ownerEmail: PropTypes.string,

// Outstanding amount of this transaction
cachedTotal: PropTypes.string,
}),

// All of the personal details for everyone
personalDetails: PropTypes.objectOf(PropTypes.shape({

// This is either the user's full name, or their login if full name is an empty string
displayName: PropTypes.string.isRequired,
})).isRequired,

// Session info for the currently logged in user.
session: PropTypes.shape({
// Currently logged in user email
email: PropTypes.string,
}).isRequired,
};

const defaultProps = {
iou: {},
};

const ReportActionItemIOUPreview = ({
action,
isMostRecentIOUReportAction,
hasOutstandingIOU,
iou,
personalDetails,
session,
}) => {
const managerName = lodashGet(
personalDetails,
[iou.managerEmail, 'displayName'],
iou.managerEmail ? Str.removeSMSDomain(iou.managerEmail) : '',
);
const ownerName = lodashGet(
personalDetails,
[iou.ownerEmail, 'displayName'],
iou.ownerEmail ? Str.removeSMSDomain(iou.ownerEmail) : '',
);
const managerAvatar = lodashGet(personalDetails, [iou.managerEmail, 'avatar'], '');
const ownerAvatar = lodashGet(personalDetails, [iou.ownerEmail, 'avatar'], '');
const sessionEmail = lodashGet(session, 'email', null);
const cachedTotal = iou.cachedTotal ? iou.cachedTotal.replace(/[()]/g, '') : '';

// Pay button should be visible to manager person in the report
// Check if the currently logged in user is the manager.
const isCurrentUserManager = iou.managerEmail === sessionEmail;

return (
<View>
<ReportActionItemIOUQuote action={action} />
{isMostRecentIOUReportAction
&& hasOutstandingIOU
&& !_.isEmpty(iou) && (
<View style={styles.iouPreviewBox}>
<View style={styles.flexRow}>
<View style={styles.flex1}>
<Text style={styles.h1}>{cachedTotal}</Text>
<Text style={styles.mt2}>
{managerName}
{' owes '}
{ownerName}
</Text>
</View>
<View style={styles.iouPreviewBoxAvatar}>
<MultipleAvatars
avatarImageURLs={[managerAvatar, ownerAvatar]}
secondAvatarStyle={[styles.secondAvatarInline]}
/>
</View>
</View>
{isCurrentUserManager && (
<TouchableOpacity
style={[styles.buttonSmall, styles.buttonSuccess, styles.mt4]}
>
<Text
style={[
styles.buttonSmallText,
styles.buttonSuccessText,
]}
>
Pay
</Text>
</TouchableOpacity>
)}
</View>
)}
</View>
);
};

ReportActionItemIOUPreview.propTypes = propTypes;
ReportActionItemIOUPreview.defaultProps = defaultProps;
ReportActionItemIOUPreview.displayName = 'ReportActionItemIOUPreview';

export default withOnyx({
iou: {
key: ({iouReportID}) => `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReportID}`,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
session: {
key: ONYXKEYS.SESSION,
},
})(ReportActionItemIOUPreview);
29 changes: 29 additions & 0 deletions src/components/ReportActionItemIOUQuote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import styles from '../styles/styles';
import ReportActionPropTypes from '../pages/home/report/ReportActionPropTypes';
import RenderHTML from './RenderHTML';

const propTypes = {
// All the data of the action
action: PropTypes.shape(ReportActionPropTypes).isRequired,
};

const ReportActionItemIOUQuote = ({action}) => (
<View style={[styles.chatItemMessage]}>
{_.map(action.message, (fragment, index) => {
const viewDetails = '<br /><a href="#">View Details</a>';
const html = `<blockquote>${fragment.text}${viewDetails}</blockquote>`;
return (
<RenderHTML key={`iouQuote-${action.sequenceNumber}-${index}`} html={html} />
);
})}
</View>
);

ReportActionItemIOUQuote.propTypes = propTypes;
ReportActionItemIOUQuote.displayName = 'ReportActionItemIOUQuote';

export default ReportActionItemIOUQuote;
4 changes: 2 additions & 2 deletions src/libs/Navigation/AppNavigator/AuthScreens.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import CONST from '../../../CONST';
import compose from '../../compose';
import {
subscribeToReportCommentEvents,
fetchAll as fetchAllReports,
fetchAllReports,
} from '../../actions/Report';
import * as PersonalDetails from '../../actions/PersonalDetails';
import * as Pusher from '../../Pusher/pusher';
Expand Down Expand Up @@ -119,7 +119,7 @@ class AuthScreens extends React.Component {
PersonalDetails.fetch();
User.getUserDetails();
User.getBetas();
fetchAllReports(true, true);
fetchAllReports(true, true, true);
fetchCountryCodeByRequestIP();
UnreadIndicatorUpdater.listenForReportChanges();

Expand Down
9 changes: 8 additions & 1 deletion src/libs/Navigation/CustomActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ import {CommonActions} from '@react-navigation/native';
*/
function pushDrawerRoute(screenName, params) {
return (state) => {
// Non Drawer navigators have routes and not history so we'll fallback to navigate() in the case where we are
// unable to push a new screen onto the history stack e.g. navigating to a ReportScreen via a modal screen.
// Note: One downside of this is that the history will be reset.
if (state.type !== 'drawer') {
return CommonActions.navigate(screenName, params);
}

const screenRoute = {type: 'route', name: screenName};
const history = [...state.history].map(() => screenRoute);
const history = [...(state.history || [])].map(() => screenRoute);
history.push(screenRoute);
return CommonActions.reset({
...state,
Expand Down
6 changes: 4 additions & 2 deletions src/libs/Navigation/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ function navigate(route = ROUTES.HOME) {
return;
}

const {reportID} = ROUTES.parseReportRouteParams(route);
if (reportID) {
// Navigate to the ReportScreen with a custom action so that we can preserve the history. We're looking to see if we
// have a participants route since those should go through linkTo() as they open a different screen.
const {reportID, isParticipantsRoute} = ROUTES.parseReportRouteParams(route);
if (reportID && !isParticipantsRoute) {
navigationRef.current.dispatch(CustomActions.pushDrawerRoute(SCREENS.REPORT, {reportID}));
return;
}
Expand Down
16 changes: 0 additions & 16 deletions src/libs/Url.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,7 @@ function addTrailingForwardSlash(url) {
return url;
}

/**
* Add / to the beginning and end of any URL if not present
* @param {String} url
* @returns {String}
*/
function wrapWithForwardSlash(url) {
const newUrl = addTrailingForwardSlash(url);
if (newUrl.startsWith('/')) {
return newUrl;
}

return `/${newUrl}`;
}


export {
// eslint-disable-next-line import/prefer-default-export
addTrailingForwardSlash,
wrapWithForwardSlash,
};
Loading

0 comments on commit 0e66043

Please sign in to comment.