Skip to content

Commit 177b08c

Browse files
committed
Merge branch 'main' of https://github.com/Expensify/App into feat/#Expensify#23229-linking
2 parents 07b40b0 + 846a4b7 commit 177b08c

File tree

15 files changed

+82
-82
lines changed

15 files changed

+82
-82
lines changed

docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ Every expense has an Attendees field and will list the expense creator’s name
1111
## How to Add Additional Attendees to an Expense
1212
* Go to the attendees field
1313
* Search for the names of the attendees
14-
* The default list will be of internal attendees belonging to your workspace and domain.
14+
* The default list will be of internal attendees belonging to your workspace and domain
1515
* External attendees are not part of your workspace or domain, so you will need to enter their name or email
1616
* Select the attendees you would like to add
1717
* Save the expense
18-
* Once added, the list of attendees for each expense will be visible on the expense line.
19-
* An amount per employee expense will also be displayed on the report for easy viewing
18+
* Once added, the list of attendees for each expense will be visible on the expense line
19+
* An amount per employee expense will also be displayed on the report for easy viewing
20+
21+
![image of an expense with attendee tracking]({{site.url}}/assets/images/attendee-tracking.png){:width="100%"}
2022

2123
# FAQ
2224

docs/articles/expensify-classic/getting-started/Best-Practices.md

-5
This file was deleted.

docs/articles/expensify-classic/integrations/HR-integrations/Workday.md

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ Before completing the steps below, you will need Workday Report Writer access to
6464
- Note: _if there is field data you want to import that is not listed above, or you have any special requests, let your Expensify Account Manager know and we will work with you to accommodate the request._
6565
4. Rename the columns so they match Expensify's API key names (The full list of names are found here):
6666
- employeeID
67+
- customField1
68+
- customField2
6769
- firstName
6870
- lastName
6971
- employeeEmail
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Coming Soon
2+
title: Add Members to your Workspace
33
description: Coming Soon
44
---
55
## Resource Coming Soon!
563 KB
Loading

src/components/FlatList/MVCPFlatList.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable es/no-optional-chaining, es/no-nullish-coalescing-operators, react/prop-types */
2+
import PropTypes from 'prop-types';
23
import React from 'react';
34
import {FlatList} from 'react-native';
4-
import PropTypes from 'prop-types';
55

66
function mergeRefs(...args) {
77
return function forwardRef(node) {

src/components/withToggleVisibilityView.js

-52
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, {ComponentType, ForwardedRef, ReactElement, RefAttributes} from 'react';
2+
import {View} from 'react-native';
3+
import {SetOptional} from 'type-fest';
4+
import getComponentDisplayName from '@libs/getComponentDisplayName';
5+
import styles from '@styles/styles';
6+
7+
type ToggleVisibilityViewProps = {
8+
/** Whether the content is visible. */
9+
isVisible: boolean;
10+
};
11+
12+
export default function withToggleVisibilityView<TProps extends ToggleVisibilityViewProps, TRef>(
13+
WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>,
14+
): (props: TProps & RefAttributes<TRef>) => ReactElement | null {
15+
function WithToggleVisibilityView({isVisible = false, ...rest}: SetOptional<TProps, 'isVisible'>, ref: ForwardedRef<TRef>) {
16+
return (
17+
<View style={!isVisible && styles.visuallyHidden}>
18+
<WrappedComponent
19+
// eslint-disable-next-line react/jsx-props-no-spreading
20+
{...(rest as TProps)}
21+
ref={ref}
22+
isVisible={isVisible}
23+
/>
24+
</View>
25+
);
26+
}
27+
28+
WithToggleVisibilityView.displayName = `WithToggleVisibilityViewWithRef(${getComponentDisplayName(WrappedComponent)})`;
29+
return React.forwardRef(WithToggleVisibilityView);
30+
}

src/libs/SidebarUtils.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Onyx.connect({
3838
const reportActionsForDisplay = actionsArray.filter(
3939
(reportAction, actionKey) =>
4040
ReportActionsUtils.shouldReportActionBeVisible(reportAction, actionKey) &&
41+
!ReportActionsUtils.isWhisperAction(reportAction) &&
4142
reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED &&
4243
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
4344
);
@@ -452,7 +453,7 @@ function getOptionData(
452453
} else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) {
453454
result.alternateText = `${lastActorDisplayName}: ${lastMessageText}`;
454455
} else {
455-
result.alternateText = lastAction && lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
456+
result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
456457
}
457458
} else {
458459
if (!lastMessageText) {

src/pages/ReimbursementAccount/AddressForm.js

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ function AddressForm(props) {
107107
hint={props.translate('common.noPO')}
108108
renamedInputKeys={props.inputKeys}
109109
maxInputLength={CONST.FORM_CHARACTER_LIMIT}
110+
isLimitedToUSA
110111
/>
111112
</View>
112113
<TextInput

src/pages/home/report/ReportActionItemMessageEdit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ function ReportActionItemMessageEdit(props) {
316316
// When user tries to save the empty message, it will delete it. Prompt the user to confirm deleting.
317317
if (!trimmedNewDraft) {
318318
textInputRef.current.blur();
319-
ReportActionContextMenu.showDeleteModal(props.reportID, props.action, false, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus()));
319+
ReportActionContextMenu.showDeleteModal(props.reportID, props.action, true, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus()));
320320
return;
321321
}
322322
Report.editReportComment(props.reportID, props.action, trimmedNewDraft);

src/pages/home/report/ReportActionItemSingle.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ function ReportActionItemSingle(props) {
108108

109109
// If this is a report preview, display names and avatars of both people involved
110110
let secondaryAvatar = {};
111-
const primaryDisplayName = ReportUtils.getDisplayNameForParticipant(actorAccountID);
111+
const primaryDisplayName = displayName;
112112
if (displayAllActors) {
113113
// The ownerAccountID and actorAccountID can be the same if the a user requests money back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice
114114
const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID;

src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js

+33-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import lodashGet from 'lodash/get';
2+
import lodashSize from 'lodash/size';
23
import PropTypes from 'prop-types';
34
import React, {useCallback, useEffect, useRef, useState} from 'react';
45
import {View} from 'react-native';
56
import {withOnyx} from 'react-native-onyx';
67
import HeaderWithBackButton from '@components/HeaderWithBackButton';
78
import ScreenWrapper from '@components/ScreenWrapper';
9+
import transactionPropTypes from '@components/transactionPropTypes';
810
import useInitialValue from '@hooks/useInitialValue';
911
import useLocalize from '@hooks/useLocalize';
12+
import compose from '@libs/compose';
1013
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
1114
import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
1215
import Navigation from '@libs/Navigation/Navigation';
16+
import * as TransactionUtils from '@libs/TransactionUtils';
1317
import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
1418
import styles from '@styles/styles';
1519
import * as IOU from '@userActions/IOU';
@@ -36,14 +40,18 @@ const propTypes = {
3640

3741
/** The current tab we have navigated to in the request modal. String that corresponds to the request type. */
3842
selectedTab: PropTypes.oneOf([CONST.TAB.DISTANCE, CONST.TAB.MANUAL, CONST.TAB.SCAN]),
43+
44+
/** Transaction that stores the distance request data */
45+
transaction: transactionPropTypes,
3946
};
4047

4148
const defaultProps = {
4249
iou: iouDefaultProps,
50+
transaction: {},
4351
selectedTab: undefined,
4452
};
4553

46-
function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
54+
function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) {
4755
const {translate} = useLocalize();
4856
const prevMoneyRequestId = useRef(iou.id);
4957
const optionsSelectorRef = useRef();
@@ -54,7 +62,9 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
5462
const isScanRequest = MoneyRequestUtils.isScanRequest(selectedTab);
5563
const isSplitRequest = iou.id === CONST.IOU.TYPE.SPLIT;
5664
const [headerTitle, setHeaderTitle] = useState();
57-
65+
const waypoints = lodashGet(transaction, 'comment.waypoints', {});
66+
const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints);
67+
const isInvalidWaypoint = lodashSize(validatedWaypoints) < 2;
5868
useEffect(() => {
5969
if (isDistanceRequest) {
6070
setHeaderTitle(translate('common.distance'));
@@ -85,10 +95,12 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
8595
}, []);
8696

8797
useEffect(() => {
98+
const isInvalidDistanceRequest = !isDistanceRequest || isInvalidWaypoint;
99+
88100
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
89101
if (prevMoneyRequestId.current !== iou.id) {
90102
// The ID is cleared on completing a request. In that case, we will do nothing
91-
if (iou.id && !isDistanceRequest && !isSplitRequest) {
103+
if (iou.id && isInvalidDistanceRequest && !isSplitRequest) {
92104
navigateBack(true);
93105
}
94106
return;
@@ -100,14 +112,14 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
100112
if (shouldReset) {
101113
IOU.resetMoneyRequestInfo(moneyRequestId);
102114
}
103-
if (!isDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) {
115+
if (isInvalidDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) {
104116
navigateBack(true);
105117
}
106118

107119
return () => {
108120
prevMoneyRequestId.current = iou.id;
109121
};
110-
}, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, iouType, reportID, navigateBack]);
122+
}, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, iouType, reportID, navigateBack, isInvalidWaypoint]);
111123

112124
return (
113125
<ScreenWrapper
@@ -143,11 +155,19 @@ MoneyRequestParticipantsPage.displayName = 'MoneyRequestParticipantsPage';
143155
MoneyRequestParticipantsPage.propTypes = propTypes;
144156
MoneyRequestParticipantsPage.defaultProps = defaultProps;
145157

146-
export default withOnyx({
147-
iou: {
148-
key: ONYXKEYS.IOU,
149-
},
150-
selectedTab: {
151-
key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`,
152-
},
153-
})(MoneyRequestParticipantsPage);
158+
export default compose(
159+
withOnyx({
160+
iou: {
161+
key: ONYXKEYS.IOU,
162+
},
163+
selectedTab: {
164+
key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`,
165+
},
166+
}),
167+
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
168+
withOnyx({
169+
transaction: {
170+
key: ({iou}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${iou.transactionID}`,
171+
},
172+
}),
173+
)(MoneyRequestParticipantsPage);

src/pages/signin/LoginForm/BaseLoginForm.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Text from '@components/Text';
1515
import TextInput from '@components/TextInput';
1616
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
1717
import withNavigationFocus from '@components/withNavigationFocus';
18-
import withToggleVisibilityView, {toggleVisibilityViewPropTypes} from '@components/withToggleVisibilityView';
18+
import withToggleVisibilityView from '@components/withToggleVisibilityView';
1919
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
2020
import usePrevious from '@hooks/usePrevious';
2121
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
@@ -72,14 +72,14 @@ const propTypes = {
7272
/** Whether or not the sign in page is being rendered in the RHP modal */
7373
isInModal: PropTypes.bool,
7474

75+
isVisible: PropTypes.bool.isRequired,
76+
7577
/** Whether navigation is focused */
7678
isFocused: PropTypes.bool.isRequired,
7779

7880
...windowDimensionsPropTypes,
7981

8082
...withLocalizePropTypes,
81-
82-
...toggleVisibilityViewPropTypes,
8383
};
8484

8585
const defaultProps = {

src/styles/styles.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3573,7 +3573,8 @@ const styles = (theme: ThemeDefault) =>
35733573
googlePillButtonContainer: {
35743574
colorScheme: 'light',
35753575
height: 40,
3576-
width: 219,
3576+
width: 300,
3577+
overflow: 'hidden',
35773578
},
35783579

35793580
thirdPartyLoadingContainer: {

0 commit comments

Comments
 (0)