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
  • Loading branch information
perunt committed Nov 5, 2023
2 parents 07b40b0 + 846a4b7 commit 177b08c
Show file tree
Hide file tree
Showing 15 changed files with 82 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Every expense has an Attendees field and will list the expense creator’s name
## How to Add Additional Attendees to an Expense
* Go to the attendees field
* Search for the names of the attendees
* The default list will be of internal attendees belonging to your workspace and domain.
* The default list will be of internal attendees belonging to your workspace and domain
* External attendees are not part of your workspace or domain, so you will need to enter their name or email
* Select the attendees you would like to add
* Save the expense
* Once added, the list of attendees for each expense will be visible on the expense line.
* An amount per employee expense will also be displayed on the report for easy viewing
* Once added, the list of attendees for each expense will be visible on the expense line
* An amount per employee expense will also be displayed on the report for easy viewing

![image of an expense with attendee tracking]({{site.url}}/assets/images/attendee-tracking.png){:width="100%"}

# FAQ

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Before completing the steps below, you will need Workday Report Writer access to
- 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._
4. Rename the columns so they match Expensify's API key names (The full list of names are found here):
- employeeID
- customField1
- customField2
- firstName
- lastName
- employeeEmail
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Coming Soon
title: Add Members to your Workspace
description: Coming Soon
---
## Resource Coming Soon!
Binary file added docs/assets/images/attendee-tracking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/FlatList/MVCPFlatList.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable es/no-optional-chaining, es/no-nullish-coalescing-operators, react/prop-types */
import PropTypes from 'prop-types';
import React from 'react';
import {FlatList} from 'react-native';
import PropTypes from 'prop-types';

function mergeRefs(...args) {
return function forwardRef(node) {
Expand Down
52 changes: 0 additions & 52 deletions src/components/withToggleVisibilityView.js

This file was deleted.

30 changes: 30 additions & 0 deletions src/components/withToggleVisibilityView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, {ComponentType, ForwardedRef, ReactElement, RefAttributes} from 'react';
import {View} from 'react-native';
import {SetOptional} from 'type-fest';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import styles from '@styles/styles';

type ToggleVisibilityViewProps = {
/** Whether the content is visible. */
isVisible: boolean;
};

export default function withToggleVisibilityView<TProps extends ToggleVisibilityViewProps, TRef>(
WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>,
): (props: TProps & RefAttributes<TRef>) => ReactElement | null {
function WithToggleVisibilityView({isVisible = false, ...rest}: SetOptional<TProps, 'isVisible'>, ref: ForwardedRef<TRef>) {
return (
<View style={!isVisible && styles.visuallyHidden}>
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...(rest as TProps)}
ref={ref}
isVisible={isVisible}
/>
</View>
);
}

WithToggleVisibilityView.displayName = `WithToggleVisibilityViewWithRef(${getComponentDisplayName(WrappedComponent)})`;
return React.forwardRef(WithToggleVisibilityView);
}
3 changes: 2 additions & 1 deletion src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Onyx.connect({
const reportActionsForDisplay = actionsArray.filter(
(reportAction, actionKey) =>
ReportActionsUtils.shouldReportActionBeVisible(reportAction, actionKey) &&
!ReportActionsUtils.isWhisperAction(reportAction) &&
reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED &&
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
Expand Down Expand Up @@ -452,7 +453,7 @@ function getOptionData(
} else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) {
result.alternateText = `${lastActorDisplayName}: ${lastMessageText}`;
} else {
result.alternateText = lastAction && lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
}
} else {
if (!lastMessageText) {
Expand Down
1 change: 1 addition & 0 deletions src/pages/ReimbursementAccount/AddressForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ function AddressForm(props) {
hint={props.translate('common.noPO')}
renamedInputKeys={props.inputKeys}
maxInputLength={CONST.FORM_CHARACTER_LIMIT}
isLimitedToUSA
/>
</View>
<TextInput
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/report/ReportActionItemMessageEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ function ReportActionItemMessageEdit(props) {
// When user tries to save the empty message, it will delete it. Prompt the user to confirm deleting.
if (!trimmedNewDraft) {
textInputRef.current.blur();
ReportActionContextMenu.showDeleteModal(props.reportID, props.action, false, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus()));
ReportActionContextMenu.showDeleteModal(props.reportID, props.action, true, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus()));
return;
}
Report.editReportComment(props.reportID, props.action, trimmedNewDraft);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/report/ReportActionItemSingle.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function ReportActionItemSingle(props) {

// If this is a report preview, display names and avatars of both people involved
let secondaryAvatar = {};
const primaryDisplayName = ReportUtils.getDisplayNameForParticipant(actorAccountID);
const primaryDisplayName = displayName;
if (displayAllActors) {
// 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
const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import lodashGet from 'lodash/get';
import lodashSize from 'lodash/size';
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import transactionPropTypes from '@components/transactionPropTypes';
import useInitialValue from '@hooks/useInitialValue';
import useLocalize from '@hooks/useLocalize';
import compose from '@libs/compose';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
import styles from '@styles/styles';
import * as IOU from '@userActions/IOU';
Expand All @@ -36,14 +40,18 @@ const propTypes = {

/** The current tab we have navigated to in the request modal. String that corresponds to the request type. */
selectedTab: PropTypes.oneOf([CONST.TAB.DISTANCE, CONST.TAB.MANUAL, CONST.TAB.SCAN]),

/** Transaction that stores the distance request data */
transaction: transactionPropTypes,
};

const defaultProps = {
iou: iouDefaultProps,
transaction: {},
selectedTab: undefined,
};

function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) {
const {translate} = useLocalize();
const prevMoneyRequestId = useRef(iou.id);
const optionsSelectorRef = useRef();
Expand All @@ -54,7 +62,9 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
const isScanRequest = MoneyRequestUtils.isScanRequest(selectedTab);
const isSplitRequest = iou.id === CONST.IOU.TYPE.SPLIT;
const [headerTitle, setHeaderTitle] = useState();

const waypoints = lodashGet(transaction, 'comment.waypoints', {});
const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints);
const isInvalidWaypoint = lodashSize(validatedWaypoints) < 2;
useEffect(() => {
if (isDistanceRequest) {
setHeaderTitle(translate('common.distance'));
Expand Down Expand Up @@ -85,10 +95,12 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
}, []);

useEffect(() => {
const isInvalidDistanceRequest = !isDistanceRequest || isInvalidWaypoint;

// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
if (prevMoneyRequestId.current !== iou.id) {
// The ID is cleared on completing a request. In that case, we will do nothing
if (iou.id && !isDistanceRequest && !isSplitRequest) {
if (iou.id && isInvalidDistanceRequest && !isSplitRequest) {
navigateBack(true);
}
return;
Expand All @@ -100,14 +112,14 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
if (shouldReset) {
IOU.resetMoneyRequestInfo(moneyRequestId);
}
if (!isDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) {
if (isInvalidDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) {
navigateBack(true);
}

return () => {
prevMoneyRequestId.current = iou.id;
};
}, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, iouType, reportID, navigateBack]);
}, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, iouType, reportID, navigateBack, isInvalidWaypoint]);

return (
<ScreenWrapper
Expand Down Expand Up @@ -143,11 +155,19 @@ MoneyRequestParticipantsPage.displayName = 'MoneyRequestParticipantsPage';
MoneyRequestParticipantsPage.propTypes = propTypes;
MoneyRequestParticipantsPage.defaultProps = defaultProps;

export default withOnyx({
iou: {
key: ONYXKEYS.IOU,
},
selectedTab: {
key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`,
},
})(MoneyRequestParticipantsPage);
export default compose(
withOnyx({
iou: {
key: ONYXKEYS.IOU,
},
selectedTab: {
key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
transaction: {
key: ({iou}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${iou.transactionID}`,
},
}),
)(MoneyRequestParticipantsPage);
6 changes: 3 additions & 3 deletions src/pages/signin/LoginForm/BaseLoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Text from '@components/Text';
import TextInput from '@components/TextInput';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withNavigationFocus from '@components/withNavigationFocus';
import withToggleVisibilityView, {toggleVisibilityViewPropTypes} from '@components/withToggleVisibilityView';
import withToggleVisibilityView from '@components/withToggleVisibilityView';
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
import usePrevious from '@hooks/usePrevious';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
Expand Down Expand Up @@ -72,14 +72,14 @@ const propTypes = {
/** Whether or not the sign in page is being rendered in the RHP modal */
isInModal: PropTypes.bool,

isVisible: PropTypes.bool.isRequired,

/** Whether navigation is focused */
isFocused: PropTypes.bool.isRequired,

...windowDimensionsPropTypes,

...withLocalizePropTypes,

...toggleVisibilityViewPropTypes,
};

const defaultProps = {
Expand Down
3 changes: 2 additions & 1 deletion src/styles/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3573,7 +3573,8 @@ const styles = (theme: ThemeDefault) =>
googlePillButtonContainer: {
colorScheme: 'light',
height: 40,
width: 219,
width: 300,
overflow: 'hidden',
},

thirdPartyLoadingContainer: {
Expand Down

0 comments on commit 177b08c

Please sign in to comment.