Skip to content

Commit

Permalink
[TS migration] Migrate MoneyTemporaryForRefactorRequestParticipantsSe…
Browse files Browse the repository at this point in the history
…lector.js to MoneyRequestParticipantsSelector.tsx
  • Loading branch information
pasyukevich committed Apr 29, 2024
1 parent d8e6990 commit 31c2be1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 64 deletions.
3 changes: 2 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4648,7 +4648,8 @@ type Country = keyof typeof CONST.ALL_COUNTRIES;

type IOUType = ValueOf<typeof CONST.IOU.TYPE>;
type IOUAction = ValueOf<typeof CONST.IOU.ACTION>;
type IOURequestType = ValueOf<typeof CONST.IOU.REQUEST_TYPE>;

export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType};
export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType};

export default CONST;
4 changes: 2 additions & 2 deletions src/components/ReferralProgramCTA.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useEffect} from 'react';
import type {ViewStyle} from 'react-native';
import type {StyleProp, ViewStyle} from 'react-native';
import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
Expand All @@ -19,7 +19,7 @@ type ReferralProgramCTAProps = {
| typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT
| typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE
| typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND;
style?: ViewStyle;
style?: StyleProp<ViewStyle>;
onDismiss?: () => void;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import lodashEvery from 'lodash/every';
import lodashGet from 'lodash/get';
import lodashIsEqual from 'lodash/isEqual';
import lodashMap from 'lodash/map';
import lodashPick from 'lodash/pick';
import lodashReject from 'lodash/reject';
import lodashSome from 'lodash/some';
import lodashValues from 'lodash/values';
import PropTypes from 'prop-types';
import React, {memo, useCallback, useEffect, useMemo} from 'react';
import type {GestureResponderEvent} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import BlockingView from '@components/BlockingViews/BlockingView';
import Button from '@components/Button';
Expand All @@ -28,48 +23,45 @@ import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionSt
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import type {MaybePhraseKey} from '@libs/Localize';
import Navigation from '@libs/Navigation/Navigation';
import type {Options} from '@libs/OptionsListUtils';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import variables from '@styles/variables';
import * as Report from '@userActions/Report';
import type {IOUAction, IOURequestType, IOUType} from '@src/CONST';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Participant} from '@src/types/onyx/IOU';

const propTypes = {
type MoneyRequestParticipantsSelectorProps = {
/** Callback to request parent modal to go to next step, which should be split */
onFinish: PropTypes.func.isRequired,
onFinish: (value?: string) => void;

/** Callback to add participants in MoneyRequestModal */
onParticipantsAdded: PropTypes.func.isRequired,

onParticipantsAdded: (value: Participant[]) => void;
/** Selected participants from MoneyRequestModal with login */
participants: PropTypes.arrayOf(
PropTypes.shape({
accountID: PropTypes.number,
login: PropTypes.string,
isPolicyExpenseChat: PropTypes.bool,
isOwnPolicyExpenseChat: PropTypes.bool,
selected: PropTypes.bool,
}),
),
participants?: Participant[];

/** The type of IOU report, i.e. split, request, send, track */
iouType: PropTypes.oneOf(lodashValues(CONST.IOU.TYPE)).isRequired,
iouType: IOUType;

/** The expense type, ie. manual, scan, distance */
iouRequestType: PropTypes.oneOf(lodashValues(CONST.IOU.REQUEST_TYPE)).isRequired,
iouRequestType: IOURequestType;

/** The action of the IOU, i.e. create, split, move */
action: PropTypes.oneOf(lodashValues(CONST.IOU.ACTION)),
};

const defaultProps = {
participants: [],
action: CONST.IOU.ACTION.CREATE,
action?: IOUAction;
};

function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onFinish, onParticipantsAdded, iouType, iouRequestType, action}) {
function MoneyRequestParticipantsSelector({
participants = [],
onFinish,
onParticipantsAdded,
iouType,
iouRequestType,
action = CONST.IOU.ACTION.CREATE,
}: MoneyRequestParticipantsSelectorProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
Expand All @@ -84,13 +76,13 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
shouldInitialize: didScreenTransitionEnd,
});

const offlineMessage = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : '';
const offlineMessage: MaybePhraseKey = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : '';

const maxParticipantsReached = participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS;
const {isSmallScreenWidth} = useWindowDimensions();

const isIOUSplit = iouType === CONST.IOU.TYPE.SPLIT;
const isCategorizeOrShareAction = [CONST.IOU.ACTION.CATEGORIZE, CONST.IOU.ACTION.SHARE].includes(action);
const isCategorizeOrShareAction = ([CONST.IOU.ACTION.CATEGORIZE, CONST.IOU.ACTION.SHARE] as string[]).includes(action);

useEffect(() => {
Report.searchInServer(debouncedSearchTerm.trim());
Expand All @@ -102,7 +94,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
* @returns {Array}
*/
const [sections, newChatOptions] = useMemo(() => {
const newSections = [];
const newSections: OptionsListUtils.CategorySection[] = [];
if (!areOptionsInitialized || !didScreenTransitionEnd) {
return [newSections, {}];
}
Expand All @@ -118,14 +110,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
// sees the option to submit an expense from their admin on their own Workspace Chat.
(iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.SPLIT) && action !== CONST.IOU.ACTION.SUBMIT,

(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
(canUseP2PDistanceRequests ?? iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
false,
{},
[],
false,
{},
[],
(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
(canUseP2PDistanceRequests ?? iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
false,
undefined,
undefined,
Expand All @@ -138,7 +130,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF

const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(
debouncedSearchTerm,
participants,
participants.map((participant) => ({...participant, reportID: participant.reportID ?? ''})),
chatOptions.recentReports,
chatOptions.personalDetails,
maxParticipantsReached,
Expand All @@ -164,11 +156,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
shouldShow: chatOptions.personalDetails.length > 0,
});

if (chatOptions.userToInvite && !OptionsListUtils.isCurrentUser(chatOptions.userToInvite)) {
if (
chatOptions.userToInvite &&
!OptionsListUtils.isCurrentUser({...chatOptions.userToInvite, accountID: chatOptions.userToInvite?.accountID ?? -1, status: chatOptions.userToInvite?.status ?? undefined})
) {
newSections.push({
title: undefined,
data: lodashMap([chatOptions.userToInvite], (participant) => {
const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false);
data: [chatOptions.userToInvite].map((participant) => {
const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false;
return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails);
}),
shouldShow: true,
Expand Down Expand Up @@ -200,7 +195,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
* @param {Object} option
*/
const addSingleParticipant = useCallback(
(option) => {
(option: Participant) => {
onParticipantsAdded([
{
...lodashPick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText', 'policyID'),
Expand All @@ -219,20 +214,20 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
* @param {Object} option
*/
const addParticipantToSelection = useCallback(
(option) => {
const isOptionSelected = (selectedOption) => {
if (selectedOption.accountID && selectedOption.accountID === option.accountID) {
(option: Participant) => {
const isOptionSelected = (selectedOption: Participant) => {
if (selectedOption.accountID && selectedOption.accountID === option?.accountID) {
return true;
}

if (selectedOption.reportID && selectedOption.reportID === option.reportID) {
if (selectedOption.reportID && selectedOption.reportID === option?.reportID) {
return true;
}

return false;
};
const isOptionInList = lodashSome(participants, isOptionSelected);
let newSelectedOptions;
const isOptionInList = participants.some(isOptionSelected);
let newSelectedOptions: Participant[];

if (isOptionInList) {
newSelectedOptions = lodashReject(participants, isOptionSelected);
Expand Down Expand Up @@ -260,30 +255,30 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
const headerMessage = useMemo(
() =>
OptionsListUtils.getHeaderMessage(
lodashGet(newChatOptions, 'personalDetails', []).length + lodashGet(newChatOptions, 'recentReports', []).length !== 0,
Boolean(newChatOptions.userToInvite),
((newChatOptions as Options)?.personalDetails ?? []).length + ((newChatOptions as Options)?.recentReports ?? []).length !== 0,
Boolean((newChatOptions as Options)?.userToInvite),
debouncedSearchTerm.trim(),
maxParticipantsReached,
lodashSome(participants, (participant) => participant.searchText.toLowerCase().includes(debouncedSearchTerm.trim().toLowerCase())),
participants.some((participant) => participant?.searchText?.toLowerCase().includes(debouncedSearchTerm.trim().toLowerCase())),
),
[maxParticipantsReached, newChatOptions, participants, debouncedSearchTerm],
);

// Right now you can't split an expense with a workspace and other additional participants
// This is getting properly fixed in https://github.com/Expensify/App/issues/27508, but as a stop-gap to prevent
// the app from crashing on native when you try to do this, we'll going to hide the button if you have a workspace and other participants
const hasPolicyExpenseChatParticipant = lodashSome(participants, (participant) => participant.isPolicyExpenseChat);
const hasPolicyExpenseChatParticipant = participants.some((participant) => participant.isPolicyExpenseChat);
const shouldShowSplitBillErrorMessage = participants.length > 1 && hasPolicyExpenseChatParticipant;

// canUseP2PDistanceRequests is true if the iouType is track expense, but we don't want to allow splitting distance with track expense yet
const isAllowedToSplit =
(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) &&
(canUseP2PDistanceRequests ?? iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) &&
iouType !== CONST.IOU.TYPE.PAY &&
iouType !== CONST.IOU.TYPE.TRACK &&
![CONST.IOU.ACTION.SHARE, CONST.IOU.ACTION.SUBMIT, CONST.IOU.ACTION.CATEGORIZE].includes(action);
!([CONST.IOU.ACTION.SHARE, CONST.IOU.ACTION.SUBMIT, CONST.IOU.ACTION.CATEGORIZE] as string[]).includes(action);

const handleConfirmSelection = useCallback(
(keyEvent, option) => {
(keyEvent?: GestureResponderEvent | KeyboardEvent, option?: Participant) => {
const shouldAddSingleParticipant = option && !participants.length;
if (shouldShowSplitBillErrorMessage || (!participants.length && !option)) {
return;
Expand Down Expand Up @@ -355,7 +350,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
</>
);

const isAllSectionsEmpty = lodashEvery(sections, (section) => section.data.length === 0);
const isAllSectionsEmpty = sections.every((section) => section.data.length === 0);
if (isCategorizeOrShareAction && isAllSectionsEmpty && didScreenTransitionEnd && debouncedSearchTerm.trim() === '' && areOptionsInitialized) {
return renderEmptyWorkspaceView();
}
Expand All @@ -379,15 +374,10 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
);
}

MoneyTemporaryForRefactorRequestParticipantsSelector.propTypes = propTypes;
MoneyTemporaryForRefactorRequestParticipantsSelector.defaultProps = defaultProps;
MoneyTemporaryForRefactorRequestParticipantsSelector.displayName = 'MoneyTemporaryForRefactorRequestParticipantsSelector';
MoneyRequestParticipantsSelector.displayName = 'MoneyTemporaryForRefactorRequestParticipantsSelector';

export default memo(
MoneyTemporaryForRefactorRequestParticipantsSelector,
MoneyRequestParticipantsSelector,
(prevProps, nextProps) =>
lodashIsEqual(prevProps.participants, nextProps.participants) &&
prevProps.iouRequestType === nextProps.iouRequestType &&
prevProps.iouType === nextProps.iouType &&
lodashIsEqual(prevProps.betas, nextProps.betas),
lodashIsEqual(prevProps.participants, nextProps.participants) && prevProps.iouRequestType === nextProps.iouRequestType && prevProps.iouType === nextProps.iouType,
);
2 changes: 1 addition & 1 deletion src/pages/iou/request/step/IOURequestStepParticipants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import MoneyRequestParticipantsSelector from '@pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector';
import MoneyRequestParticipantsSelector from '@pages/iou/request/MoneyRequestParticipantsSelector';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
Expand Down
1 change: 1 addition & 0 deletions src/types/onyx/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Participant = {
text?: string;
isSelected?: boolean;
isSelfDM?: boolean;
iouType?: string;
};

type Split = {
Expand Down

0 comments on commit 31c2be1

Please sign in to comment.