diff --git a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js b/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
deleted file mode 100644
index dec809e1266be..0000000000000
--- a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import {Pressable} from 'react-native';
-import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
-import AttachmentView from '../AttachmentView';
-import fileDownload from '../../libs/fileDownload';
-import addEncryptedAuthTokenToURL from '../../libs/addEncryptedAuthTokenToURL';
-
-class BaseAnchorForAttachmentsOnly extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- isDownloading: false,
- };
- this.processDownload = this.processDownload.bind(this);
- }
-
- /**
- * Initiate file downloading and update downloading flags
- *
- * @param {String} href
- * @param {String} fileName
- */
- processDownload(href, fileName) {
- this.setState({isDownloading: true});
- fileDownload(href, fileName).then(() => this.setState({isDownloading: false}));
- }
-
- render() {
- const source = addEncryptedAuthTokenToURL(this.props.source);
-
- return (
- {
- if (this.state.isDownloading) {
- return;
- }
- this.processDownload(source, this.props.displayName);
- }}
- >
-
-
- );
- }
-}
-
-BaseAnchorForAttachmentsOnly.propTypes = anchorForAttachmentsOnlyPropTypes.propTypes;
-BaseAnchorForAttachmentsOnly.defaultProps = anchorForAttachmentsOnlyPropTypes.defaultProps;
-
-export default BaseAnchorForAttachmentsOnly;
diff --git a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js b/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
deleted file mode 100644
index a17f0a27ce4d6..0000000000000
--- a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
-
-const propTypes = {
- /** The URL of the attachment */
- source: PropTypes.string,
-
- /** Filename for attachments. */
- displayName: PropTypes.string,
-
- /** Any additional styles to apply */
- style: stylePropTypes,
-};
-
-const defaultProps = {
- source: '',
- style: {},
- displayName: '',
-};
-
-export {propTypes, defaultProps};
diff --git a/src/components/AnchorForAttachmentsOnly/index.js b/src/components/AnchorForAttachmentsOnly/index.js
deleted file mode 100644
index a71d65e969cd7..0000000000000
--- a/src/components/AnchorForAttachmentsOnly/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
-import BaseAnchorForAttachmentsOnly from './BaseAnchorForAttachmentsOnly';
-
-// eslint-disable-next-line react/jsx-props-no-spreading
-const AnchorForAttachmentsOnly = props => ;
-
-AnchorForAttachmentsOnly.propTypes = anchorForAttachmentsOnlyPropTypes.propTypes;
-AnchorForAttachmentsOnly.defaultProps = anchorForAttachmentsOnlyPropTypes.defaultProps;
-AnchorForAttachmentsOnly.displayName = 'AnchorForAttachmentsOnly';
-
-export default AnchorForAttachmentsOnly;
diff --git a/src/components/AnchorForAttachmentsOnly/index.native.js b/src/components/AnchorForAttachmentsOnly/index.native.js
deleted file mode 100644
index 0a98ee0bb4ec8..0000000000000
--- a/src/components/AnchorForAttachmentsOnly/index.native.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
-import BaseAnchorForAttachmentsOnly from './BaseAnchorForAttachmentsOnly';
-import styles from '../../styles/styles';
-
-// eslint-disable-next-line react/jsx-props-no-spreading
-const AnchorForAttachmentsOnly = props => ;
-
-AnchorForAttachmentsOnly.propTypes = anchorForAttachmentsOnlyPropTypes.propTypes;
-AnchorForAttachmentsOnly.defaultProps = anchorForAttachmentsOnlyPropTypes.defaultProps;
-AnchorForAttachmentsOnly.displayName = 'AnchorForAttachmentsOnly';
-
-export default AnchorForAttachmentsOnly;
diff --git a/src/components/AnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly.js
deleted file mode 100644
index c93ecb416b644..0000000000000
--- a/src/components/AnchorForCommentsOnly.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import _ from 'underscore';
-import React from 'react';
-import {StyleSheet} from 'react-native';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import PropTypes from 'prop-types';
-import Text from './Text';
-import PressableWithSecondaryInteraction from './PressableWithSecondaryInteraction';
-import * as ReportActionContextMenu from '../pages/home/report/ContextMenu/ReportActionContextMenu';
-import * as ContextMenuActions from '../pages/home/report/ContextMenu/ContextMenuActions';
-import Tooltip from './Tooltip';
-import canUseTouchScreen from '../libs/canUseTouchscreen';
-import styles from '../styles/styles';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-
-const propTypes = {
- /** The URL to open */
- href: PropTypes.string,
-
- /** What headers to send to the linked page (usually noopener and noreferrer)
- This is unused in native, but is here for parity with web */
- rel: PropTypes.string,
-
- /** Used to determine where to open a link ("_blank" is passed for a new tab)
- This is unused in native, but is here for parity with web */
- target: PropTypes.string,
-
- /** Any children to display */
- children: PropTypes.node,
-
- /** Anchor text of URLs or emails. */
- displayName: PropTypes.string,
-
- /** Any additional styles to apply */
- // eslint-disable-next-line react/forbid-prop-types
- style: PropTypes.any,
-
- /** Press handler for the link, when not passed, default href is used to create a link like behaviour */
- onPress: PropTypes.func,
-
- ...windowDimensionsPropTypes,
-};
-
-const defaultProps = {
- href: '',
- rel: '',
- target: '',
- children: null,
- style: {},
- displayName: '',
- onPress: undefined,
-};
-
-/*
- * This is a default anchor component for regular links.
- */
-const BaseAnchorForCommentsOnly = (props) => {
- let linkRef;
- const rest = _.omit(props, _.keys(propTypes));
- const linkProps = {};
- if (_.isFunction(props.onPress)) {
- linkProps.onPress = props.onPress;
- } else {
- linkProps.href = props.href;
- }
- const defaultTextStyle = canUseTouchScreen() || props.isSmallScreenWidth ? {} : styles.userSelectText;
-
- return (
- {
- ReportActionContextMenu.showContextMenu(
- Str.isValidEmail(props.displayName) ? ContextMenuActions.CONTEXT_MENU_TYPES.EMAIL : ContextMenuActions.CONTEXT_MENU_TYPES.LINK,
- event,
- props.href,
- lodashGet(linkRef, 'current'),
- );
- }
- }
- >
-
- linkRef = el}
- style={StyleSheet.flatten([props.style, defaultTextStyle])}
- accessibilityRole="link"
- hrefAttrs={{
- rel: props.rel,
- target: props.target,
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...linkProps}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...rest}
- >
- {props.children}
-
-
-
- );
-};
-
-BaseAnchorForCommentsOnly.propTypes = propTypes;
-BaseAnchorForCommentsOnly.defaultProps = defaultProps;
-BaseAnchorForCommentsOnly.displayName = 'BaseAnchorForCommentsOnly';
-
-export default withWindowDimensions(BaseAnchorForCommentsOnly);
diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js
new file mode 100644
index 0000000000000..dab9d2ea718f3
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js
@@ -0,0 +1,104 @@
+import _ from 'underscore';
+import React from 'react';
+import {Pressable, StyleSheet} from 'react-native';
+import lodashGet from 'lodash/get';
+import Str from 'expensify-common/lib/str';
+import Text from '../../Text';
+import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
+import PressableWithSecondaryInteraction from '../../PressableWithSecondaryInteraction';
+import * as ReportActionContextMenu from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
+import * as ContextMenuActions from '../../../pages/home/report/ContextMenu/ContextMenuActions';
+import AttachmentView from '../../AttachmentView';
+import fileDownload from '../../../libs/fileDownload';
+import Tooltip from '../../Tooltip';
+import canUseTouchScreen from '../../../libs/canUseTouchscreen';
+import styles from '../../../styles/styles';
+
+/*
+ * This is a default anchor component for regular links.
+ */
+class BaseAnchorForCommentsOnly extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isDownloading: false,
+ };
+ this.processDownload = this.processDownload.bind(this);
+ }
+
+ /**
+ * Initiate file downloading and update downloading flags
+ *
+ * @param {String} href
+ * @param {String} fileName
+ */
+ processDownload(href, fileName) {
+ this.setState({isDownloading: true});
+ fileDownload(href, fileName).then(() => this.setState({isDownloading: false}));
+ }
+
+ render() {
+ let linkRef;
+ const rest = _.omit(this.props, _.keys(propTypes));
+ const defaultTextStyle = canUseTouchScreen() || this.props.isSmallScreenWidth ? {} : styles.userSelectText;
+
+ return (
+ this.props.isAttachment
+ ? (
+ {
+ if (this.state.isDownloading) {
+ return;
+ }
+ this.processDownload(this.props.href, this.props.displayName);
+ }}
+ >
+
+
+ )
+ : (
+ {
+ ReportActionContextMenu.showContextMenu(
+ Str.isValidEmail(this.props.displayName) ? ContextMenuActions.CONTEXT_MENU_TYPES.EMAIL : ContextMenuActions.CONTEXT_MENU_TYPES.LINK,
+ event,
+ this.props.href,
+ lodashGet(linkRef, 'current'),
+ );
+ }
+ }
+ >
+
+ linkRef = el}
+ style={StyleSheet.flatten([this.props.style, defaultTextStyle])}
+ accessibilityRole="link"
+ href={this.props.href}
+ hrefAttrs={{
+ rel: this.props.rel,
+ target: this.props.target,
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...rest}
+ >
+ {this.props.children}
+
+
+
+ )
+ );
+ }
+}
+
+BaseAnchorForCommentsOnly.propTypes = propTypes;
+BaseAnchorForCommentsOnly.defaultProps = defaultProps;
+BaseAnchorForCommentsOnly.displayName = 'BaseAnchorForCommentsOnly';
+
+export default BaseAnchorForCommentsOnly;
diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.native.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.native.js
new file mode 100644
index 0000000000000..19e1b28774c2a
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.native.js
@@ -0,0 +1,95 @@
+import _ from 'underscore';
+import React from 'react';
+import lodashGet from 'lodash/get';
+import {Linking, StyleSheet, Pressable} from 'react-native';
+import Str from 'expensify-common/lib/str';
+import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
+import fileDownload from '../../../libs/fileDownload';
+import Text from '../../Text';
+import PressableWithSecondaryInteraction from '../../PressableWithSecondaryInteraction';
+import * as ReportActionContextMenu from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
+import * as ContextMenuActions from '../../../pages/home/report/ContextMenu/ContextMenuActions';
+import AttachmentView from '../../AttachmentView';
+import styles from '../../../styles/styles';
+
+/*
+ * This is a default anchor component for regular links.
+ */
+class BaseAnchorForCommentsOnly extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isDownloading: false,
+ };
+ this.processDownload = this.processDownload.bind(this);
+ }
+
+ /**
+ * Initiate file downloading and update downloading flags
+ *
+ * @param {String} href
+ * @param {String} fileName
+ */
+ processDownload(href, fileName) {
+ this.setState({isDownloading: true});
+ fileDownload(href, fileName).then(() => this.setState({isDownloading: false}));
+ }
+
+ render() {
+ let linkRef;
+ const rest = _.omit(this.props, _.keys(propTypes));
+ return (
+ this.props.isAttachment
+ ? (
+ {
+ if (this.state.isDownloading) {
+ return;
+ }
+ this.processDownload(this.props.href, this.props.displayName);
+ }}
+ >
+
+
+ )
+ : (
+ {
+ ReportActionContextMenu.showContextMenu(
+ Str.isValidEmail(this.props.displayName) ? ContextMenuActions.CONTEXT_MENU_TYPES.EMAIL : ContextMenuActions.CONTEXT_MENU_TYPES.LINK,
+ event,
+ this.props.href,
+ lodashGet(linkRef, 'current'),
+ );
+ }
+ }
+ onPress={() => Linking.openURL(this.props.href)}
+ >
+ linkRef = el}
+ style={StyleSheet.flatten(this.props.style)}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...rest}
+ >
+ {this.props.children}
+
+
+ )
+ );
+ }
+}
+
+BaseAnchorForCommentsOnly.propTypes = propTypes;
+BaseAnchorForCommentsOnly.defaultProps = defaultProps;
+BaseAnchorForCommentsOnly.displayName = 'BaseAnchorForCommentsOnly';
+
+export default BaseAnchorForCommentsOnly;
diff --git a/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
new file mode 100644
index 0000000000000..fd8b2148a4af3
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
@@ -0,0 +1,43 @@
+import PropTypes from 'prop-types';
+
+/**
+ * Text based component that is passed a URL to open onPress
+ */
+const propTypes = {
+ /** The URL to open */
+ href: PropTypes.string,
+
+ /** What headers to send to the linked page (usually noopener and noreferrer)
+ This is unused in native, but is here for parity with web */
+ rel: PropTypes.string,
+
+ /** Used to determine where to open a link ("_blank" is passed for a new tab)
+ This is unused in native, but is here for parity with web */
+ target: PropTypes.string,
+
+ /** Flag to differentiate attachments and hyperlink. Base on flag link will be treated as a file download or a regular hyperlink */
+ isAttachment: PropTypes.bool,
+
+ /** Any children to display */
+ children: PropTypes.node,
+
+ /** Filename in case of attachments, anchor text in case of URLs or emails. */
+ displayName: PropTypes.string,
+
+ /** Any additional styles to apply */
+ // eslint-disable-next-line react/forbid-prop-types
+ style: PropTypes.any,
+
+};
+
+const defaultProps = {
+ href: '',
+ rel: '',
+ target: '',
+ isAttachment: false,
+ children: null,
+ style: {},
+ displayName: '',
+};
+
+export {propTypes, defaultProps};
diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js
new file mode 100644
index 0000000000000..55dc0b3154efb
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/index.js
@@ -0,0 +1,40 @@
+import _ from 'underscore';
+import React from 'react';
+import PropTypes from 'prop-types';
+import * as anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes';
+import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
+import addEncryptedAuthTokenToURL from '../../libs/addEncryptedAuthTokenToURL';
+
+const propTypes = {
+ /** Do we need an auth token to view this link or download the remote resource? */
+ isAuthTokenRequired: PropTypes.bool,
+
+ // eslint-disable-next-line react/forbid-foreign-prop-types
+ ...anchorForCommentsOnlyPropTypes.propTypes,
+};
+
+const defaultProps = {
+ isAuthTokenRequired: false,
+ ...anchorForCommentsOnlyPropTypes.defaultProps,
+};
+
+/*
+ * This component acts as a switch between AnchorWithAuthToken and default BaseAnchorForCommentsOnly.
+ * It is an optimization so that we can attach an auth token to a URL when one is required,
+ * without using Onyx.connect on links that don't need an authToken.
+ */
+const AnchorForCommentsOnly = (props) => {
+ const propsToPass = _.omit(props, 'isAuthTokenRequired');
+ if (props.isAuthTokenRequired) {
+ propsToPass.href = addEncryptedAuthTokenToURL(props.href);
+ propsToPass.isAttachment = true;
+ }
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ return ;
+};
+
+AnchorForCommentsOnly.propTypes = propTypes;
+AnchorForCommentsOnly.defaultProps = defaultProps;
+AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly';
+
+export default AnchorForCommentsOnly;
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
index 9d395a8779b99..e93ba851d9964 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
@@ -13,7 +13,6 @@ import CONST from '../../../CONST';
import styles from '../../../styles/styles';
import Navigation from '../../../libs/Navigation/Navigation';
import AnchorForCommentsOnly from '../../AnchorForCommentsOnly';
-import AnchorForAttachmentsOnly from '../../AnchorForAttachmentsOnly';
const AnchorRenderer = (props) => {
const htmlAttribs = props.tnode.attributes;
@@ -29,22 +28,31 @@ const AnchorRenderer = (props) => {
&& !attrHref.startsWith(CONFIG.EXPENSIFY.CONCIERGE_URL)
&& attrHref.replace(CONFIG.EXPENSIFY.EXPENSIFY_URL, '');
- const navigateToLink = () => {
- // If we are handling a New Expensify link then we will assume this should be opened by the app internally. This ensures that the links are opened internally via react-navigation
- // instead of in a new tab or with a page refresh (which is the default behavior of an anchor tag)
- if (internalNewExpensifyPath) {
- Navigation.navigate(internalNewExpensifyPath);
- return;
- }
+ // If we are handling a New Expensify link then we will assume this should be opened by the app internally. This ensures that the links are opened internally via react-navigation
+ // instead of in a new tab or with a page refresh (which is the default behavior of an anchor tag)
+ if (internalNewExpensifyPath) {
+ return (
+ Navigation.navigate(internalNewExpensifyPath)}
+ >
+
+
+ );
+ }
- // If we are handling an old dot Expensify link we need to open it with openOldDotLink() so we can navigate to it with the user already logged in.
- // As attachments also use expensify.com we don't want it working the same as links.
- if (internalExpensifyPath && !isAttachment) {
- Link.openOldDotLink(internalExpensifyPath);
- return;
- }
- Linking.openURL(attrHref);
- };
+ // If we are handling an old dot Expensify link (excluding Concierge) we need to open it with openOldDotLink() so we can navigate to it with the user already logged in.
+ // As attachments also use expensify.com we don't want it working the same as links.
+ if (internalExpensifyPath && !isAttachment) {
+ return (
+ Link.openOldDotLink(internalExpensifyPath)}
+ >
+
+
+ );
+ }
if (!HTMLEngineUtils.isInsideComment(props.tnode)) {
// This is not a comment from a chat, the AnchorForCommentsOnly uses a Pressable to create a context menu on right click.
@@ -53,25 +61,17 @@ const AnchorRenderer = (props) => {
return (
Linking.openURL(attrHref)}
>
);
}
- if (isAttachment) {
- return (
-
- );
- }
-
return (
{
style={{...props.style, ...parentStyle}}
key={props.key}
displayName={displayName}
-
- // Only pass the press handler for internal links, for public links fallback to default link handling
- onPress={internalNewExpensifyPath || internalExpensifyPath ? navigateToLink : undefined}
>
diff --git a/src/stories/Banner.stories.js b/src/stories/Banner.stories.js
index 180d130029dd9..247489d497112 100644
--- a/src/stories/Banner.stories.js
+++ b/src/stories/Banner.stories.js
@@ -27,15 +27,8 @@ HTMLBanner.args = {
shouldRenderHTML: true,
};
-const BannerWithLink = Template.bind({});
-BannerWithLink.args = {
- text: 'This is a informational banner containing internal Link and public link',
- shouldRenderHTML: true,
-};
-
export default story;
export {
InfoBanner,
HTMLBanner,
- BannerWithLink,
};