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

Fix warning "Function components cannot be given refs" #49377

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
25 changes: 8 additions & 17 deletions src/components/AttachmentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Str} from 'expensify-common';
import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {Animated, Keyboard, View} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import {useSharedValue} from 'react-native-reanimated';
import type {ValueOf} from 'type-fest';
Expand Down Expand Up @@ -49,11 +49,6 @@ import SafeAreaConsumer from './SafeAreaConsumer';
* to display a full size image or PDF modally with optional confirmation button.
*/

type AttachmentModalOnyxProps = {
/** The transaction associated with the receipt attachment, if any */
transaction: OnyxEntry<OnyxTypes.Transaction>;
};

type ImagePickerResponse = {
height?: number;
name: string;
Expand All @@ -70,7 +65,7 @@ type ChildrenProps = {
show: () => void;
};

type AttachmentModalProps = AttachmentModalOnyxProps & {
type AttachmentModalProps = {
/** Optional source (URL, SVG function) for the image shown. If not passed in via props must be specified when modal is opened. */
source?: AvatarSource;

Expand Down Expand Up @@ -154,7 +149,6 @@ function AttachmentModal({
isReceiptAttachment = false,
isWorkspaceAvatar = false,
maybeIcon = false,
transaction,
headerTitle,
children,
fallbackSource,
Expand All @@ -167,6 +161,11 @@ function AttachmentModal({
}: AttachmentModalProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const transactionID = useMemo(() => {
const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
return ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1';
}, [report?.parentReportID, report?.parentReportActionID]);
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`);
const [isModalOpen, setIsModalOpen] = useState(defaultOpen);
const [shouldLoadAttachment, setShouldLoadAttachment] = useState(false);
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
Expand Down Expand Up @@ -634,14 +633,6 @@ function AttachmentModal({

AttachmentModal.displayName = 'AttachmentModal';

export default withOnyx<AttachmentModalProps, AttachmentModalOnyxProps>({
transaction: {
key: ({report}) => {
const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1';
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
})(memo(AttachmentModal));
export default memo(AttachmentModal);

export type {Attachment, FileObject, ImagePickerResponse};
68 changes: 24 additions & 44 deletions src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 're
import type {MeasureInWindowOnSuccessCallback, NativeSyntheticEvent, TextInputFocusEventData, TextInputSelectionChangeEventData} from 'react-native';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import {runOnUI, useSharedValue} from 'react-native-reanimated';
import type {Emoji} from '@assets/emojis/types';
import type {FileObject} from '@components/AttachmentModal';
Expand All @@ -19,8 +19,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {usePersonalDetails} from '@components/OnyxProvider';
import Text from '@components/Text';
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useDebounce from '@hooks/useDebounce';
import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -63,41 +62,31 @@ type SuggestionsRef = {
getIsSuggestionsMenuVisible: () => boolean;
};

type ReportActionComposeOnyxProps = {
/** The NVP describing a user's block status */
blockedFromConcierge: OnyxEntry<OnyxTypes.BlockedFromConcierge>;
type ReportActionComposeProps = Pick<ComposerWithSuggestionsProps, 'reportID' | 'isEmptyChat' | 'isComposerFullSize' | 'lastReportAction'> & {
/** A method to call when the form is submitted */
onSubmit: (newComment: string) => void;

/** Whether the composer input should be shown */
shouldShowComposeInput: OnyxEntry<boolean>;
};

type ReportActionComposeProps = ReportActionComposeOnyxProps &
WithCurrentUserPersonalDetailsProps &
Pick<ComposerWithSuggestionsProps, 'reportID' | 'isEmptyChat' | 'isComposerFullSize' | 'lastReportAction'> & {
/** A method to call when the form is submitted */
onSubmit: (newComment: string) => void;
/** The report currently being looked at */
report: OnyxEntry<OnyxTypes.Report>;

/** The report currently being looked at */
report: OnyxEntry<OnyxTypes.Report>;
/** The type of action that's pending */
pendingAction?: OnyxCommon.PendingAction;

/** The type of action that's pending */
pendingAction?: OnyxCommon.PendingAction;
/** Whether the report is ready for display */
isReportReadyForDisplay?: boolean;

/** Whether the report is ready for display */
isReportReadyForDisplay?: boolean;
/** A method to call when the input is focus */
onComposerFocus?: () => void;

/** A method to call when the input is focus */
onComposerFocus?: () => void;
/** A method to call when the input is blur */
onComposerBlur?: () => void;

/** A method to call when the input is blur */
onComposerBlur?: () => void;
/** Should the input be disabled */
disabled?: boolean;

/** Should the input be disabled */
disabled?: boolean;

/** Should show educational tooltip */
shouldShowEducationalTooltip?: boolean;
};
/** Should show educational tooltip */
shouldShowEducationalTooltip?: boolean;
};

// We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will
// prevent auto focus on existing chat for mobile device
Expand All @@ -109,15 +98,12 @@ const willBlurTextInputOnTapOutside = willBlurTextInputOnTapOutsideFunc();
let onSubmitAction = noop;

function ReportActionCompose({
blockedFromConcierge,
currentUserPersonalDetails,
disabled = false,
isComposerFullSize = false,
onSubmit,
pendingAction,
report,
reportID,
shouldShowComposeInput = true,
isReportReadyForDisplay = true,
isEmptyChat,
lastReportAction,
Expand All @@ -131,6 +117,9 @@ function ReportActionCompose({
const {isSmallScreenWidth, isMediumScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
const {isOffline} = useNetwork();
const actionButtonRef = useRef<View | HTMLDivElement | null>(null);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const [blockedFromConcierge] = useOnyx(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE);
const [shouldShowComposeInput = true] = useOnyx(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT);
const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT;
const navigation = useNavigation();

Expand Down Expand Up @@ -571,15 +560,6 @@ function ReportActionCompose({

ReportActionCompose.displayName = 'ReportActionCompose';

export default withCurrentUserPersonalDetails(
withOnyx<ReportActionComposeProps, ReportActionComposeOnyxProps>({
blockedFromConcierge: {
key: ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE,
},
shouldShowComposeInput: {
key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT,
},
})(memo(ReportActionCompose)),
);
export default memo(ReportActionCompose);
export {onSubmitAction};
export type {SuggestionsRef, ComposerRef};
120 changes: 42 additions & 78 deletions src/pages/home/report/ReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, {memo, useCallback, useContext, useEffect, useMemo, useRef, useSta
import type {GestureResponderEvent, TextInput} from 'react-native';
import {InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import type {Emoji} from '@assets/emojis/types';
import {AttachmentContext} from '@components/AttachmentContext';
import Button from '@components/Button';
Expand Down Expand Up @@ -64,7 +64,6 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import type {JoinWorkspaceResolution} from '@src/types/onyx/OriginalMessage';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions';
Expand All @@ -82,19 +81,6 @@ import ReportActionItemSingle from './ReportActionItemSingle';
import ReportActionItemThread from './ReportActionItemThread';
import ReportAttachmentsContext from './ReportAttachmentsContext';

type ReportActionItemOnyxProps = {
/** IOU report for this action, if any */
iouReport: OnyxEntry<OnyxTypes.Report>;

emojiReactions: OnyxEntry<OnyxTypes.ReportActionReactions>;

/** The user's wallet account */
userWallet: OnyxEntry<OnyxTypes.UserWallet>;

/** The transaction (linked with the report action) route error */
linkedTransactionRouteError: NonNullable<OnyxEntry<Errors>> | null;
};

type ReportActionItemProps = {
/** Report for this action */
report: OnyxTypes.Report;
Expand Down Expand Up @@ -150,31 +136,34 @@ type ReportActionItemProps = {

/** Whether context menu should be displayed */
shouldDisplayContextMenu?: boolean;
} & ReportActionItemOnyxProps;
};

function ReportActionItem({
action,
report,
transactionThreadReport,
linkedReportActionID,
displayAsGroup,
emojiReactions,
index,
iouReport,
isMostRecentIOUReportAction,
parentReportAction,
shouldDisplayNewMarker,
userWallet,
shouldHideThreadDividerLine = false,
shouldShowSubscriptAvatar = false,
onPress = undefined,
isFirstVisibleReportAction = false,
shouldUseThreadDividerLine = false,
linkedTransactionRouteError,
hideThreadReplies = false,
shouldDisplayContextMenu = true,
parentReportActionForTransactionThread,
}: ReportActionItemProps) {
const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${ReportActionsUtils.getIOUReportIDFromReportActionPreview(action) ?? -1}`, {initialValue: {} as OnyxTypes.Report});
const [emojiReactions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${action.reportActionID}`, {initialValue: {}});
const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET);
const [linkedTransactionRouteError] = useOnyx(
`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? -1 : -1}`,
{selector: (transaction) => transaction?.errorFields?.route ?? null},
);
const {translate} = useLocalize();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const blockedFromConcierge = useBlockedFromConcierge();
Expand Down Expand Up @@ -997,61 +986,36 @@ function ReportActionItem({
);
}

export default withOnyx<ReportActionItemProps, ReportActionItemOnyxProps>({
iouReport: {
key: ({action}) => {
const iouReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action);
return `${ONYXKEYS.COLLECTION.REPORT}${iouReportID ?? -1}`;
},
initialValue: {} as OnyxTypes.Report,
},
emojiReactions: {
key: ({action}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${action.reportActionID}`,
initialValue: {},
},
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
linkedTransactionRouteError: {
key: ({action}) =>
`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? -1 : -1}`,
selector: (transaction: OnyxEntry<OnyxTypes.Transaction>) => transaction?.errorFields?.route ?? null,
},
})(
memo(ReportActionItem, (prevProps, nextProps) => {
const prevParentReportAction = prevProps.parentReportAction;
const nextParentReportAction = nextProps.parentReportAction;
return (
prevProps.displayAsGroup === nextProps.displayAsGroup &&
prevProps.isMostRecentIOUReportAction === nextProps.isMostRecentIOUReportAction &&
prevProps.shouldDisplayNewMarker === nextProps.shouldDisplayNewMarker &&
lodashIsEqual(prevProps.emojiReactions, nextProps.emojiReactions) &&
lodashIsEqual(prevProps.action, nextProps.action) &&
lodashIsEqual(prevProps.iouReport, nextProps.iouReport) &&
lodashIsEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) &&
lodashIsEqual(prevProps.report.isDeletedParentAction, nextProps.report.isDeletedParentAction) &&
lodashIsEqual(prevProps.report.errorFields, nextProps.report.errorFields) &&
prevProps.report?.statusNum === nextProps.report?.statusNum &&
prevProps.report?.stateNum === nextProps.report?.stateNum &&
prevProps.report?.parentReportID === nextProps.report?.parentReportID &&
prevProps.report?.parentReportActionID === nextProps.report?.parentReportActionID &&
// TaskReport's created actions render the TaskView, which updates depending on certain fields in the TaskReport
ReportUtils.isTaskReport(prevProps.report) === ReportUtils.isTaskReport(nextProps.report) &&
prevProps.action.actionName === nextProps.action.actionName &&
prevProps.report.reportName === nextProps.report.reportName &&
prevProps.report.description === nextProps.report.description &&
ReportUtils.isCompletedTaskReport(prevProps.report) === ReportUtils.isCompletedTaskReport(nextProps.report) &&
prevProps.report.managerID === nextProps.report.managerID &&
prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine &&
prevProps.report?.total === nextProps.report?.total &&
prevProps.report?.nonReimbursableTotal === nextProps.report?.nonReimbursableTotal &&
prevProps.report?.policyAvatar === nextProps.report?.policyAvatar &&
prevProps.linkedReportActionID === nextProps.linkedReportActionID &&
lodashIsEqual(prevProps.report.fieldList, nextProps.report.fieldList) &&
lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) &&
lodashIsEqual(prevProps.reportActions, nextProps.reportActions) &&
lodashIsEqual(prevProps.linkedTransactionRouteError, nextProps.linkedTransactionRouteError) &&
lodashIsEqual(prevParentReportAction, nextParentReportAction)
);
}),
);
export default memo(ReportActionItem, (prevProps, nextProps) => {
const prevParentReportAction = prevProps.parentReportAction;
const nextParentReportAction = nextProps.parentReportAction;
return (
prevProps.displayAsGroup === nextProps.displayAsGroup &&
prevProps.isMostRecentIOUReportAction === nextProps.isMostRecentIOUReportAction &&
prevProps.shouldDisplayNewMarker === nextProps.shouldDisplayNewMarker &&
lodashIsEqual(prevProps.action, nextProps.action) &&
lodashIsEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) &&
lodashIsEqual(prevProps.report.isDeletedParentAction, nextProps.report.isDeletedParentAction) &&
lodashIsEqual(prevProps.report.errorFields, nextProps.report.errorFields) &&
prevProps.report?.statusNum === nextProps.report?.statusNum &&
prevProps.report?.stateNum === nextProps.report?.stateNum &&
prevProps.report?.parentReportID === nextProps.report?.parentReportID &&
prevProps.report?.parentReportActionID === nextProps.report?.parentReportActionID &&
// TaskReport's created actions render the TaskView, which updates depending on certain fields in the TaskReport
ReportUtils.isTaskReport(prevProps.report) === ReportUtils.isTaskReport(nextProps.report) &&
prevProps.action.actionName === nextProps.action.actionName &&
prevProps.report.reportName === nextProps.report.reportName &&
prevProps.report.description === nextProps.report.description &&
ReportUtils.isCompletedTaskReport(prevProps.report) === ReportUtils.isCompletedTaskReport(nextProps.report) &&
prevProps.report.managerID === nextProps.report.managerID &&
prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine &&
prevProps.report?.total === nextProps.report?.total &&
prevProps.report?.nonReimbursableTotal === nextProps.report?.nonReimbursableTotal &&
prevProps.report?.policyAvatar === nextProps.report?.policyAvatar &&
prevProps.linkedReportActionID === nextProps.linkedReportActionID &&
lodashIsEqual(prevProps.report.fieldList, nextProps.report.fieldList) &&
lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) &&
lodashIsEqual(prevProps.reportActions, nextProps.reportActions) &&
lodashIsEqual(prevParentReportAction, nextParentReportAction)
);
});
Loading
Loading