diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx index a06e2dbbf421..9551e9d8f7c8 100755 --- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx @@ -58,6 +58,7 @@ function BaseHTMLEngineProvider({textSelectable = false, children, enableExperim contentModel: HTMLContentModel.textual, }), 'mention-user': HTMLElementModel.fromCustomModel({tagName: 'mention-user', contentModel: HTMLContentModel.textual}), + 'mention-report': HTMLElementModel.fromCustomModel({tagName: 'mention-report', contentModel: HTMLContentModel.textual}), 'mention-here': HTMLElementModel.fromCustomModel({tagName: 'mention-here', contentModel: HTMLContentModel.textual}), 'next-step': HTMLElementModel.fromCustomModel({ tagName: 'next-step', diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx new file mode 100644 index 000000000000..52377fa20b4d --- /dev/null +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx @@ -0,0 +1,125 @@ +import isEmpty from 'lodash/isEmpty'; +import React, {useMemo} from 'react'; +import type {TextStyle} from 'react-native'; +import {StyleSheet} from 'react-native'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import type {CustomRendererProps, TPhrasing, TText} from 'react-native-render-html'; +import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; +import Text from '@components/Text'; +import useCurrentReportID from '@hooks/useCurrentReportID'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {getReport} from '@libs/ReportUtils'; +import * as ReportUtils from '@libs/ReportUtils'; +import Navigation from '@navigation/Navigation'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {Report} from '@src/types/onyx'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type MentionReportOnyxProps = { + /** All reports shared with the user */ + reports: OnyxCollection; +}; + +type MentionReportRendererProps = MentionReportOnyxProps & CustomRendererProps; + +const removeLeadingLTRAndHash = (value: string) => value.replace(CONST.UNICODE.LTR, '').replace('#', ''); + +const getMentionDetails = (htmlAttributeReportID: string, currentReport: OnyxEntry | EmptyObject, reports: OnyxCollection, tnode: TText | TPhrasing) => { + let reportID: string | undefined; + let mentionDisplayText: string; + + // Get mention details based on reportID from tag attribute + if (!isEmpty(htmlAttributeReportID)) { + const report = getReport(htmlAttributeReportID); + + reportID = report?.reportID ?? undefined; + mentionDisplayText = removeLeadingLTRAndHash(report?.reportName ?? report?.displayName ?? htmlAttributeReportID); + // Get mention details from name inside tnode + } else if ('data' in tnode && !isEmptyObject(tnode.data)) { + mentionDisplayText = removeLeadingLTRAndHash(tnode.data); + + // eslint-disable-next-line rulesdir/prefer-early-return + Object.values(reports ?? {}).forEach((report) => { + if (report?.policyID === currentReport?.policyID && removeLeadingLTRAndHash(report?.reportName ?? '') === mentionDisplayText) { + reportID = report?.reportID; + } + }); + } else { + return null; + } + + return {reportID, mentionDisplayText}; +}; + +function MentionReportRenderer({style, tnode, TDefaultRenderer, reports, ...defaultRendererProps}: MentionReportRendererProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const htmlAttributeReportID = tnode.attributes.reportid; + + const currentReportID = useCurrentReportID(); + const currentReport = getReport(currentReportID?.currentReportID); + const isGroupPolicyReport = useMemo(() => (currentReport && !isEmptyObject(currentReport) ? ReportUtils.isGroupPolicy(currentReport) : false), [currentReport]); + + const mentionDetails = getMentionDetails(htmlAttributeReportID, currentReport, reports, tnode); + if (!mentionDetails) { + return null; + } + const {reportID, mentionDisplayText} = mentionDetails; + + const navigationRoute = reportID ? ROUTES.REPORT_WITH_ID.getRoute(reportID) : undefined; + const isCurrentRoomMention = reportID === currentReportID?.currentReportID; + + const flattenStyle = StyleSheet.flatten(style as TextStyle); + const {color, ...styleWithoutColor} = flattenStyle; + + return ( + + {() => ( + { + event.preventDefault(); + Navigation.navigate(navigationRoute); + } + : undefined + } + role={isGroupPolicyReport ? CONST.ROLE.LINK : undefined} + accessibilityLabel={isGroupPolicyReport ? `/${navigationRoute}` : undefined} + > + #{mentionDisplayText} + + )} + + ); +} + +MentionReportRenderer.displayName = 'MentionReportRenderer'; + +const chatReportSelector = (report: OnyxEntry): Report => + (report && { + reportID: report.reportID, + reportName: report.reportName, + displayName: report.displayName, + policyID: report.policyID, + }) as Report; + +export default withOnyx({ + reports: { + key: ONYXKEYS.COLLECTION.REPORT, + selector: chatReportSelector, + }, +})(MentionReportRenderer); diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/index.ts b/src/components/HTMLEngineProvider/HTMLRenderers/index.ts index fdd0c89ec5a0..ce24584048b0 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/index.ts +++ b/src/components/HTMLEngineProvider/HTMLRenderers/index.ts @@ -5,6 +5,7 @@ import EditedRenderer from './EditedRenderer'; import EmojiRenderer from './EmojiRenderer'; import ImageRenderer from './ImageRenderer'; import MentionHereRenderer from './MentionHereRenderer'; +import MentionReportRenderer from './MentionReportRenderer'; import MentionUserRenderer from './MentionUserRenderer'; import NextStepEmailRenderer from './NextStepEmailRenderer'; import PreRenderer from './PreRenderer'; @@ -25,6 +26,7 @@ const HTMLEngineProviderComponentList: CustomTagRendererRecord = { pre: PreRenderer, /* eslint-disable @typescript-eslint/naming-convention */ 'mention-user': MentionUserRenderer, + 'mention-report': MentionReportRenderer, 'mention-here': MentionHereRenderer, emoji: EmojiRenderer, 'next-step-email': NextStepEmailRenderer,