From b1e271f16d0823e1d1719ea0c1bd5d3ba10717db Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 20 Aug 2024 17:41:27 +0800 Subject: [PATCH 1/3] don't render report mention markdown if it's not a policy report --- .../MentionReportContext.tsx | 11 ++++++ .../index.tsx} | 9 +++-- src/components/MenuItem.tsx | 8 +++- .../MoneyRequestConfirmationListFooter.tsx | 38 ++++++++++--------- .../TextInput/BaseTextInput/index.native.tsx | 3 +- .../TextInput/BaseTextInput/index.tsx | 3 +- .../TextInput/BaseTextInput/types.ts | 4 ++ .../step/IOURequestStepDescription.tsx | 3 ++ 8 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx rename src/components/HTMLEngineProvider/HTMLRenderers/{MentionReportRenderer.tsx => MentionReportRenderer/index.tsx} (93%) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx new file mode 100644 index 000000000000..04654d1fef53 --- /dev/null +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx @@ -0,0 +1,11 @@ +import {createContext} from 'react'; + +type MentionReportContextProps = { + currentReportID: string; +}; + +const MentionReportContext = createContext({ + currentReportID: '', +}); + +export {MentionReportContext}; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx similarity index 93% rename from src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx rename to src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 66e297e50734..6974c6e18c66 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -1,5 +1,5 @@ import isEmpty from 'lodash/isEmpty'; -import React, {useMemo} from 'react'; +import React, {useContext, useMemo} from 'react'; import type {TextStyle} from 'react-native'; import {StyleSheet} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; @@ -16,6 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import {MentionReportContext} from './MentionReportContext'; type MentionReportOnyxProps = { /** All reports shared with the user */ @@ -56,10 +57,12 @@ function MentionReportRenderer({style, tnode, TDefaultRenderer, reports, ...defa const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const htmlAttributeReportID = tnode.attributes.reportid; + const {currentReportID: currentReportIDContext} = useContext(MentionReportContext); const currentReportID = useCurrentReportID(); + const currentReportIDValue = currentReportIDContext ?? currentReportID?.currentReportID; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [currentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${currentReportID?.currentReportID || -1}`); + const [currentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${currentReportIDValue || -1}`); // When we invite someone to a room they don't have the policy object, but we still want them to be able to see and click on report mentions, so we only check if the policyID in the report is from a workspace const isGroupPolicyReport = useMemo(() => currentReport && !isEmptyObject(currentReport) && !!currentReport.policyID && currentReport.policyID !== CONST.POLICY.ID_FAKE, [currentReport]); @@ -71,7 +74,7 @@ function MentionReportRenderer({style, tnode, TDefaultRenderer, reports, ...defa const {reportID, mentionDisplayText} = mentionDetails; const navigationRoute = reportID ? ROUTES.REPORT_WITH_ID.getRoute(reportID) : undefined; - const isCurrentRoomMention = reportID === currentReportID?.currentReportID; + const isCurrentRoomMention = reportID === currentReportIDValue; const flattenStyle = StyleSheet.flatten(style as TextStyle); const {color, ...styleWithoutColor} = flattenStyle; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 6757d0602691..586f4d2dfdf0 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -267,6 +267,9 @@ type MenuItemBaseProps = { /** Whether should render error text as HTML or as Text */ shouldRenderErrorAsHTML?: boolean; + /** List of markdown rules that will be ignored */ + excludedMarkdownRules: string[]; + /** Should check anonymous user in onPress function */ shouldCheckActionAllowedOnPress?: boolean; @@ -402,6 +405,7 @@ function MenuItem( shouldParseHelperText = false, shouldRenderHintAsHTML = false, shouldRenderErrorAsHTML = false, + excludedMarkdownRules = [], shouldCheckActionAllowedOnPress = true, onSecondaryInteraction, titleWithTooltips, @@ -457,8 +461,8 @@ function MenuItem( if (!title || !shouldParseTitle) { return ''; } - return Parser.replace(title, {shouldEscapeText}); - }, [title, shouldParseTitle, shouldEscapeText]); + return Parser.replace(title, {shouldEscapeText, disabledRules: excludedMarkdownRules}); + }, [title, shouldParseTitle, shouldEscapeText, excludedMarkdownRules]); const helperHtml = useMemo(() => { if (!helperText || !shouldParseHelperText) { diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 623348a4c7a4..bc14e1b6203a 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -28,6 +28,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {Unit} from '@src/types/onyx/Policy'; import ConfirmedRoute from './ConfirmedRoute'; +import {MentionReportContext} from './HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext'; import MenuItem from './MenuItem'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import PDFThumbnail from './PDFThumbnail'; @@ -296,23 +297,26 @@ function MoneyRequestConfirmationListFooter({ }, { item: ( - { - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams(), reportActionID), - ); - }} - style={[styles.moneyRequestMenuItem]} - titleStyle={styles.flex1} - disabled={didConfirm} - interactive={!isReadOnly} - numberOfLinesTitle={2} - /> + + { + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams(), reportActionID), + ); + }} + style={[styles.moneyRequestMenuItem]} + titleStyle={styles.flex1} + disabled={didConfirm} + interactive={!isReadOnly} + numberOfLinesTitle={2} + /> + ), shouldShow: true, isSupplementary: false, diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index 59f205da023f..a03e9dbb9aa2 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -61,6 +61,7 @@ function BaseTextInput( prefixCharacter = '', inputID, isMarkdownEnabled = false, + excludedMarkdownStyles = [], shouldShowClearButton = false, prefixContainerStyle = [], prefixStyle = [], @@ -74,7 +75,7 @@ function BaseTextInput( const inputProps = {shouldSaveDraft: false, shouldUseDefaultValue: false, ...props}; const theme = useTheme(); const styles = useThemeStyles(); - const markdownStyle = useMarkdownStyle(); + const markdownStyle = useMarkdownStyle(undefined, excludedMarkdownStyles); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index 685d54d86765..ff1a186d86b8 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -63,6 +63,7 @@ function BaseTextInput( prefixCharacter = '', inputID, isMarkdownEnabled = false, + excludedMarkdownStyles = [], shouldShowClearButton = false, prefixContainerStyle = [], prefixStyle = [], @@ -75,7 +76,7 @@ function BaseTextInput( const theme = useTheme(); const styles = useThemeStyles(); - const markdownStyle = useMarkdownStyle(); + const markdownStyle = useMarkdownStyle(undefined, excludedMarkdownStyles); const {hasError = false} = inputProps; const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); diff --git a/src/components/TextInput/BaseTextInput/types.ts b/src/components/TextInput/BaseTextInput/types.ts index 80325e0a21f3..cb66876d56d0 100644 --- a/src/components/TextInput/BaseTextInput/types.ts +++ b/src/components/TextInput/BaseTextInput/types.ts @@ -1,3 +1,4 @@ +import type {MarkdownStyle} from '@expensify/react-native-live-markdown'; import type {GestureResponderEvent, StyleProp, TextInputProps, TextStyle, ViewStyle} from 'react-native'; import type {AnimatedTextInputRef} from '@components/RNTextInput'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -112,6 +113,9 @@ type CustomBaseTextInputProps = { /** Should live markdown be enabled. Changes RNTextInput component to RNMarkdownTextInput */ isMarkdownEnabled?: boolean; + /** List of markdowns that won't be styled as a markdown */ + excludedMarkdownStyles?: Array; + /** Whether the clear button should be displayed */ shouldShowClearButton?: boolean; diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index 993bf580f038..a4c6ce577798 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -149,6 +149,8 @@ function IOURequestStepDescription({ const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportActionsUtils.isMoneyRequestAction(reportAction) || !ReportUtils.canEditMoneyRequest(reportAction)); + const isReportInGroupPolicy = !!report?.policyID && report.policyID !== CONST.POLICY.ID_FAKE; + return ( From 133ab781a62fe905e3b5eddd5d65fb5eba2aaf7c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 20 Aug 2024 18:00:53 +0800 Subject: [PATCH 2/3] lint --- .../MentionReportRenderer/MentionReportContext.tsx | 2 +- .../HTMLRenderers/MentionReportRenderer/index.tsx | 2 +- src/components/MoneyRequestConfirmationListFooter.tsx | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx index 04654d1fef53..9fe1088c9809 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext.tsx @@ -8,4 +8,4 @@ const MentionReportContext = createContext({ currentReportID: '', }); -export {MentionReportContext}; +export default MentionReportContext; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 6974c6e18c66..e4351ebe961a 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import {MentionReportContext} from './MentionReportContext'; +import MentionReportContext from './MentionReportContext'; type MentionReportOnyxProps = { /** All reports shared with the user */ diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index bc14e1b6203a..ff18b48d5901 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -28,7 +28,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {Unit} from '@src/types/onyx/Policy'; import ConfirmedRoute from './ConfirmedRoute'; -import {MentionReportContext} from './HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext'; +import MentionReportContext from './HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext'; import MenuItem from './MenuItem'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import PDFThumbnail from './PDFThumbnail'; @@ -267,6 +267,8 @@ function MoneyRequestConfirmationListFooter({ const resolvedThumbnail = isLocalFile ? receiptThumbnail : tryResolveUrlFromApiRoot(receiptThumbnail ?? ''); const resolvedReceiptImage = isLocalFile ? receiptImage : tryResolveUrlFromApiRoot(receiptImage ?? ''); + const mentionReportContextValue = useMemo(() => ({currentReportID: reportID}), [reportID]); + // An intermediate structure that helps us classify the fields as "primary" and "supplementary". // The primary fields are always shown to the user, while an extra action is needed to reveal the supplementary ones. const classifiedFields = [ @@ -297,7 +299,7 @@ function MoneyRequestConfirmationListFooter({ }, { item: ( - + Date: Tue, 27 Aug 2024 00:52:47 +0800 Subject: [PATCH 3/3] make it optional --- src/components/MenuItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 586f4d2dfdf0..93c0f0d291b6 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -268,7 +268,7 @@ type MenuItemBaseProps = { shouldRenderErrorAsHTML?: boolean; /** List of markdown rules that will be ignored */ - excludedMarkdownRules: string[]; + excludedMarkdownRules?: string[]; /** Should check anonymous user in onPress function */ shouldCheckActionAllowedOnPress?: boolean;