Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS migration] Migrate MoneyTemporaryForRefactorRequestParticipantsSe… #41216

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4722,7 +4722,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
2 changes: 1 addition & 1 deletion src/libs/actions/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ function getPolicy(policyID: string | undefined): Policy | EmptyObject {
/**
* Returns a primary policy for the user
*/
function getPrimaryPolicy(activePolicyID?: string): Policy | undefined {
function getPrimaryPolicy(activePolicyID?: OnyxEntry<string>): Policy | undefined {
const activeAdminWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies);
const primaryPolicy: Policy | null | undefined = allPolicies?.[activePolicyID ?? ''];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
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 Button from '@components/Button';
import FormHelpMessage from '@components/FormHelpMessage';
Expand All @@ -23,46 +19,36 @@ import usePermissions from '@hooks/usePermissions';
import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus';
import useThemeStyles from '@hooks/useThemeStyles';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import type {MaybePhraseKey} from '@libs/Localize';
import type {Options} from '@libs/OptionsListUtils';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as Policy from '@userActions/Policy';
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 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}: MoneyRequestParticipantsSelectorProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
Expand All @@ -79,10 +65,10 @@ 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 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].some((option) => option === action);

const shouldShowReferralBanner = !isDismissed && iouType !== CONST.IOU.TYPE.INVOICE;

Expand All @@ -96,7 +82,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
* @returns {Array}
*/
const [sections, newChatOptions] = useMemo(() => {
const newSections = [];
const newSections: OptionsListUtils.CategorySection[] = [];
if (!areOptionsInitialized || !didScreenTransitionEnd) {
return [newSections, {}];
}
Expand All @@ -112,13 +98,15 @@ 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,

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
false,
{},
[],
false,
{},
[],
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) && !isCategorizeOrShareAction,
false,
undefined,
Expand All @@ -131,7 +119,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
isCategorizeOrShareAction ? 0 : undefined,
);

const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(debouncedSearchTerm, participants, chatOptions.recentReports, chatOptions.personalDetails, personalDetails, true);
const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(
debouncedSearchTerm,
participants.map((participant) => ({...participant, reportID: participant.reportID ?? ''})),
chatOptions.recentReports,
chatOptions.personalDetails,
personalDetails,
true,
);

newSections.push(formatResults.section);

Expand All @@ -147,11 +142,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 @@ -182,8 +180,8 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
* @param {Object} option
*/
const addSingleParticipant = useCallback(
(option) => {
const newParticipants = [
(option: Participant) => {
const newParticipants: Participant[] = [
{
...lodashPick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText', 'policyID'),
selected: true,
Expand All @@ -195,7 +193,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
const primaryPolicy = Policy.getPrimaryPolicy(activePolicyID);

newParticipants.push({
policyID: primaryPolicy.id,
policyID: primaryPolicy?.id,
isSender: true,
selected: false,
iouType,
Expand All @@ -214,20 +212,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 @@ -255,28 +253,29 @@ 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(),
pasyukevich marked this conversation as resolved.
Show resolved Hide resolved
lodashSome(participants, (participant) => participant.searchText.toLowerCase().includes(debouncedSearchTerm.trim().toLowerCase())),
participants.some((participant) => participant?.searchText?.toLowerCase().includes(debouncedSearchTerm.trim().toLowerCase())),
),
[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 =
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
(canUseP2PDistanceRequests || iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE) &&
![CONST.IOU.TYPE.PAY, CONST.IOU.TYPE.TRACK, CONST.IOU.TYPE.INVOICE].includes(iouType) &&
![CONST.IOU.ACTION.SHARE, CONST.IOU.ACTION.SUBMIT, CONST.IOU.ACTION.CATEGORIZE].includes(action);
![CONST.IOU.TYPE.PAY, CONST.IOU.TYPE.TRACK, CONST.IOU.TYPE.INVOICE].some((option) => option === iouType) &&
![CONST.IOU.ACTION.SHARE, CONST.IOU.ACTION.SUBMIT, CONST.IOU.ACTION.CATEGORIZE].some((option) => option === 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 @@ -348,15 +347,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,
);
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 @@ -23,6 +23,7 @@ type Participant = {
isSelected?: boolean;
isSelfDM?: boolean;
isSender?: boolean;
iouType?: string;
};

type Split = {
Expand Down
Loading