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

Download E.cash attachments immediately #3066

Merged
merged 2 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
50 changes: 50 additions & 0 deletions src/components/AnchorForCommentsOnly/AnchorWithAuthToken.js
Original file line number Diff line number Diff line change
@@ -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 <BaseAnchorForCommentsOnly {...propsToPass} />;
};

AnchorWithAuthToken.propTypes = propTypes;
AnchorWithAuthToken.defaultProps = defaultProps;
AnchorWithAuthToken.displayName = 'AnchorWithAuthToken';

export default withOnyx({
session: {
key: ONYXKEYS.SESSION,
},
})(AnchorWithAuthToken);
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this include the shouldDownloadFile prop since it is being passed from AnchorWithAuthToken.js . If it is not necessary to have shouldDownloadFile here because it is passed in ...props, then is it redundant when we have shouldDownloadFile in the props for BaseAnchorForCommentsOnly/index.native.js ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question.

Should this include the shouldDownloadFile prop since it is being passed from AnchorWithAuthToken.js

It's not necessary because it's not being used in this file. It is passed to the nested Text in ...props, but because the Text doesn't take a shouldDownloadFile prop it just has no effect.

is it redundant when we have shouldDownloadFile in the props for BaseAnchorForCommentsOnly/index.native.js

It's not redundant, because the shouldDownloadFile prop is used to determine onPress prop of the Text component in BaseAnchorForCommentsOnly/index.native.js. Then it's also passed to the Text component as part of ...props, but like the web implementation just has no effect.

...props
}) => (
<Text
style={StyleSheet.flatten(style)}
accessibilityRole="link"
href={href}
rel={rel}
target={target}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{children}
</Text>
);

BaseAnchorForCommentsOnly.propTypes = propTypes;
BaseAnchorForCommentsOnly.defaultProps = defaultProps;
BaseAnchorForCommentsOnly.displayName = 'BaseAnchorForCommentsOnly';

export default BaseAnchorForCommentsOnly;
joelbettner marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -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
}) => (
<Text
style={StyleSheet.flatten(style)}
onPress={() => (shouldDownloadFile ? fileDownload(href) : Linking.openURL(href))}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{children}
</Text>
);

BaseAnchorForCommentsOnly.propTypes = propTypes;
BaseAnchorForCommentsOnly.defaultProps = defaultProps;
BaseAnchorForCommentsOnly.displayName = 'BaseAnchorForCommentsOnly';

export default BaseAnchorForCommentsOnly;
Original file line number Diff line number Diff line change
Expand Up @@ -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};
57 changes: 30 additions & 27 deletions src/components/AnchorForCommentsOnly/index.js
Original file line number Diff line number Diff line change
@@ -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
}) => (
<Text
style={StyleSheet.flatten(style)}
accessibilityRole="link"
href={href}
rel={rel}
target={target}
/*
* 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');
return props.isAuthTokenRequired
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{children}
</Text>
);
? <AnchorWithAuthToken {...propsToPass} />
// eslint-disable-next-line react/jsx-props-no-spreading
: <BaseAnchorForCommentsOnly {...propsToPass} />;
};

AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes;
AnchorForCommentsOnly.propTypes = propTypes;
AnchorForCommentsOnly.defaultProps = defaultProps;
AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly';

Expand Down
27 changes: 0 additions & 27 deletions src/components/AnchorForCommentsOnly/index.native.js

This file was deleted.

4 changes: 4 additions & 0 deletions src/components/RenderHTML.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<AnchorForCommentsOnly
href={htmlAttribs.href}
isAuthTokenRequired={isAttachment}

// Unless otherwise specified open all links in
// a new window. On Desktop this means that we will
Expand Down