diff --git a/src/components/AnchorForCommentsOnly/AnchorWithAuthToken.js b/src/components/AnchorForCommentsOnly/AnchorWithAuthToken.js
new file mode 100644
index 000000000000..14440fc60dee
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/AnchorWithAuthToken.js
@@ -0,0 +1,50 @@
+import _ from 'underscore';
+import React from 'react';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
+import ONYXKEYS from '../../ONYXKEYS';
+import {
+ propTypes as anchorForCommentsOnlyPropTypes,
+ defaultProps as anchorForCommentsOnlyDefaultProps,
+} from './anchorForCommentsOnlyPropTypes';
+import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
+import addAuthTokenToURL from '../../libs/addAuthTokenToURL';
+
+const propTypes = {
+ /** Session info for the currently logged in user. */
+ session: PropTypes.shape({
+ /** Currently logged in user authToken */
+ authToken: PropTypes.string,
+ }),
+
+ ...anchorForCommentsOnlyPropTypes,
+};
+
+const defaultProps = {
+ session: {
+ authToken: null,
+ },
+ ...anchorForCommentsOnlyDefaultProps,
+};
+
+const AnchorWithAuthToken = (props) => {
+ const urlWithAuthToken = addAuthTokenToURL({
+ url: props.href,
+ authToken: props.session.authToken,
+ });
+ const propsToPass = _.omit(props, 'session');
+ propsToPass.href = urlWithAuthToken;
+ propsToPass.shouldDownloadFile = true;
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ return ;
+};
+
+AnchorWithAuthToken.propTypes = propTypes;
+AnchorWithAuthToken.defaultProps = defaultProps;
+AnchorWithAuthToken.displayName = 'AnchorWithAuthToken';
+
+export default withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+})(AnchorWithAuthToken);
diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js
new file mode 100644
index 000000000000..37faebd2ee02
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import {StyleSheet, Text} from 'react-native';
+import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
+
+/*
+ * This is a default anchor component for regular links.
+ */
+const BaseAnchorForCommentsOnly = ({
+ href,
+ rel,
+ target,
+ children,
+ style,
+ ...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 000000000000..9a63b54b1804
--- /dev/null
+++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly/index.native.js
@@ -0,0 +1,30 @@
+import React from 'react';
+import {Linking, StyleSheet, Text} from 'react-native';
+import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
+import fileDownload from '../../../libs/fileDownload';
+
+/*
+ * This is a default anchor component for regular links.
+ */
+const BaseAnchorForCommentsOnly = ({
+ href,
+ children,
+ style,
+ shouldDownloadFile,
+ ...props
+}) => (
+ (shouldDownloadFile ? fileDownload(href) : Linking.openURL(href))}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...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
index eb61cdc7d3a1..04fddf8e02bf 100644
--- a/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
+++ b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
@@ -3,25 +3,36 @@ import PropTypes from 'prop-types';
/**
* Text based component that is passed a URL to open onPress
*/
-const anchorForCommentsOnlyPropTypes = {
- // The URL to open
+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
+ /** 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
+ /** 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,
+ /** Should the link be treated as a file download or a regular hyperlink? (relevant to native platforms only) */
+ shouldDownloadFile: PropTypes.bool,
- // Any children to display
+ /** Any children to display */
children: PropTypes.node,
- // Any additional styles to apply
+ /** Any additional styles to apply */
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.any,
};
-export default anchorForCommentsOnlyPropTypes;
+const defaultProps = {
+ href: '',
+ rel: '',
+ target: '',
+ shouldDownloadFile: false,
+ children: null,
+ style: {},
+};
+
+export {propTypes, defaultProps};
diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js
index 3edda2184b8c..6a5daf6a672b 100644
--- a/src/components/AnchorForCommentsOnly/index.js
+++ b/src/components/AnchorForCommentsOnly/index.js
@@ -1,37 +1,40 @@
+import _ from 'underscore';
import React from 'react';
-import {StyleSheet, Text} from 'react-native';
-import anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes';
+import PropTypes from 'prop-types';
+import {
+ propTypes as anchorForCommentsOnlyPropTypes,
+ defaultProps as anchorForCommentsOnlyDefaultProps,
+} from './anchorForCommentsOnlyPropTypes';
+import AnchorWithAuthToken from './AnchorWithAuthToken';
+import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
+
+const propTypes = {
+ /** Do we need an auth token to view this link or download the remote resource? */
+ isAuthTokenRequired: PropTypes.bool,
+
+ ...anchorForCommentsOnlyPropTypes,
+};
const defaultProps = {
- href: '',
- rel: '',
- target: '',
- children: null,
- style: {},
+ isAuthTokenRequired: false,
+ ...anchorForCommentsOnlyDefaultProps,
};
-const AnchorForCommentsOnly = ({
- href,
- rel,
- target,
- children,
- style,
- ...props
-}) => (
- {
+ const propsToPass = _.omit(props, 'isAuthTokenRequired');
+ return props.isAuthTokenRequired
// eslint-disable-next-line react/jsx-props-no-spreading
- {...props}
- >
- {children}
-
-);
+ ?
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ : ;
+};
-AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes;
+AnchorForCommentsOnly.propTypes = propTypes;
AnchorForCommentsOnly.defaultProps = defaultProps;
AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly';
diff --git a/src/components/AnchorForCommentsOnly/index.native.js b/src/components/AnchorForCommentsOnly/index.native.js
deleted file mode 100644
index a5b184a8a6b3..000000000000
--- a/src/components/AnchorForCommentsOnly/index.native.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import {Linking, StyleSheet, Text} from 'react-native';
-import anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes';
-
-const defaultProps = {
- href: '',
- rel: null,
- target: null,
- children: null,
- style: {},
-};
-
-const AnchorForCommentsOnly = ({
- href,
- children,
- style,
- ...props
-}) => (
- // eslint-disable-next-line react/jsx-props-no-spreading
- Linking.openURL(href)} {...props}>{children}
-);
-
-AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes;
-AnchorForCommentsOnly.defaultProps = defaultProps;
-AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly';
-
-export default AnchorForCommentsOnly;
diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js
index 38214a6582d7..13df9ea60f68 100755
--- a/src/components/RenderHTML.js
+++ b/src/components/RenderHTML.js
@@ -43,9 +43,13 @@ function computeImagesMaxWidth(contentWidth) {
function AnchorRenderer({tnode, key, style}) {
const htmlAttribs = tnode.attributes;
+
+ // An auth token is needed to download Expensify chat attachments
+ const isAttachment = Boolean(htmlAttribs['data-expensify-source']);
return (