Skip to content
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
78 changes: 44 additions & 34 deletions src/components/QRShare/QRShareWithDownload/index.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
import React, {Component} from 'react';
import {withNetwork} from '@components/OnyxProvider';
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
import useNetwork from '@hooks/useNetwork';
import fileDownload from '@libs/fileDownload';
import QRShare from '..';

class QRShareWithDownload extends Component {
qrShareRef = React.createRef();

constructor(props) {
super(props);

this.download = this.download.bind(this);
}

download() {
return new Promise((resolve, reject) => {
// eslint-disable-next-line es/no-optional-chaining
const svg = this.qrShareRef.current?.getSvg();
if (svg == null) {
return reject();
}

svg.toDataURL((dataURL) => resolve(fileDownload(dataURL, getQrCodeFileName(this.props.title))));
});
}

render() {
return (
<QRShare
ref={this.qrShareRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...this.props}
logo={this.props.network.isOffline ? null : this.props.logo}
/>
);
}
function QRShareWithDownload({innerRef, ...props}) {
Comment thread
fabioh8010 marked this conversation as resolved.
const {isOffline} = useNetwork();
const qrShareRef = useRef(null);

useImperativeHandle(
innerRef,
() => ({
download: () =>
new Promise((resolve, reject) => {
// eslint-disable-next-line es/no-optional-chaining
const svg = qrShareRef.current?.getSvg();
if (svg == null) {
return reject();
}

svg.toDataURL((dataURL) => resolve(fileDownload(dataURL, getQrCodeFileName(props.title))));
}),
}),
[props.title],
);

return (
<QRShare
ref={qrShareRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
logo={isOffline ? null : props.logo}
/>
);
}

QRShareWithDownload.propTypes = qrSharePropTypes;
QRShareWithDownload.defaultProps = qrShareDefaultProps;
QRShareWithDownload.displayName = 'QRShareWithDownload';

const QRShareWithDownloadWithRef = forwardRef((props, ref) => (
<QRShareWithDownload
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));

QRShareWithDownloadWithRef.displayName = 'QRShareWithDownloadWithRef';
Comment thread
fabioh8010 marked this conversation as resolved.

export default withNetwork()(QRShareWithDownload);
export default QRShareWithDownloadWithRef;
59 changes: 34 additions & 25 deletions src/components/QRShare/QRShareWithDownload/index.native.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
import React, {Component} from 'react';
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import ViewShot from 'react-native-view-shot';
import {withNetwork} from '@components/OnyxProvider';
import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
import useNetwork from '@hooks/useNetwork';
import fileDownload from '@libs/fileDownload';
import QRShare from '..';

class QRShareWithDownload extends Component {
qrCodeScreenshotRef = React.createRef();
function QRShareWithDownload({innerRef, ...props}) {
Comment thread
fabioh8010 marked this conversation as resolved.
const {isOffline} = useNetwork();
const qrCodeScreenshotRef = useRef(null);

constructor(props) {
super(props);
useImperativeHandle(
innerRef,
() => ({
download: () => qrCodeScreenshotRef.current.capture().then((uri) => fileDownload(uri, getQrCodeFileName(props.title))),
}),
[props.title],
);

this.download = this.download.bind(this);
}

download() {
return this.qrCodeScreenshotRef.current.capture().then((uri) => fileDownload(uri, getQrCodeFileName(this.props.title)));
}

render() {
return (
<ViewShot ref={this.qrCodeScreenshotRef}>
<QRShare
// eslint-disable-next-line react/jsx-props-no-spreading
{...this.props}
logo={this.props.network.isOffline ? null : this.props.logo}
/>
</ViewShot>
);
}
return (
<ViewShot ref={qrCodeScreenshotRef}>
<QRShare
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
logo={isOffline ? null : props.logo}
/>
</ViewShot>
);
}

QRShareWithDownload.propTypes = qrSharePropTypes;
QRShareWithDownload.defaultProps = qrShareDefaultProps;
QRShareWithDownload.displayName = 'QRShareWithDownload';

const QRShareWithDownloadWithRef = forwardRef((props, ref) => (
<QRShareWithDownload
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));
Comment thread
fabioh8010 marked this conversation as resolved.

QRShareWithDownloadWithRef.displayName = 'QRShareWithDownloadWithRef';

export default withNetwork()(QRShareWithDownload);
export default QRShareWithDownloadWithRef;
139 changes: 67 additions & 72 deletions src/components/QRShare/index.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,91 @@
import React, {Component} from 'react';
import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
import QRCode from '@components/QRCode';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withTheme, {withThemePropTypes} from '@components/withTheme';
import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles';
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
import compose from '@libs/compose';
import useTheme from '@styles/themes/useTheme';
import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import {qrShareDefaultProps, qrSharePropTypes} from './propTypes';

const propTypes = {
...qrSharePropTypes,
...windowDimensionsPropTypes,
...withLocalizePropTypes,
...withThemeStylesPropTypes,
...withThemePropTypes,
};
function QRShare({innerRef, url, title, subtitle, logo, logoRatio, logoMarginRatio}) {
Comment thread
fabioh8010 marked this conversation as resolved.
const styles = useThemeStyles();
const theme = useTheme();

class QRShare extends Component {
constructor(props) {
super(props);
const [qrCodeSize, setQrCodeSize] = useState(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Having small initial size for QR code made it change its size while page is opening. Ref: #44436

const svgRef = useRef(null);

this.state = {
qrCodeSize: 1,
};
useImperativeHandle(
innerRef,
() => ({
getSvg: () => svgRef.current,
}),
[],
);

this.onLayout = this.onLayout.bind(this);
this.getSvg = this.getSvg.bind(this);
}

onLayout(event) {
const onLayout = (event) => {
const containerWidth = event.nativeEvent.layout.width - variables.qrShareHorizontalPadding * 2 || 0;
setQrCodeSize(Math.max(1, containerWidth));
};

this.setState({
qrCodeSize: Math.max(1, containerWidth),
});
}
return (
<View
style={styles.shareCodeContainer}
onLayout={onLayout}
>
<View style={styles.expensifyQrLogo}>
<ExpensifyWordmark
fill={theme.QRLogo}
width="100%"
height="100%"
/>
</View>

getSvg() {
return this.svg;
}
<QRCode
getRef={(svg) => (svgRef.current = svg)}
url={url}
logo={logo}
size={qrCodeSize}
logoRatio={logoRatio}
logoMarginRatio={logoMarginRatio}
/>

render() {
return (
<View
style={this.props.themeStyles.shareCodeContainer}
onLayout={this.onLayout}
<Text
family="EXP_NEW_KANSAS_MEDIUM"
fontSize={variables.fontSizeXLarge}
numberOfLines={2}
style={styles.qrShareTitle}
>
<View style={this.props.themeStyles.expensifyQrLogo}>
<ExpensifyWordmark
fill={this.props.theme.QRLogo}
width="100%"
height="100%"
/>
</View>

<QRCode
getRef={(svg) => (this.svg = svg)}
url={this.props.url}
logo={this.props.logo}
size={this.state.qrCodeSize}
logoRatio={this.props.logoRatio}
logoMarginRatio={this.props.logoMarginRatio}
/>
{title}
</Text>

{!_.isEmpty(subtitle) && (
<Text
family="EXP_NEW_KANSAS_MEDIUM"
fontSize={variables.fontSizeXLarge}
fontSize={variables.fontSizeLabel}
numberOfLines={2}
style={this.props.themeStyles.qrShareTitle}
style={[styles.mt1, styles.textAlignCenter]}
color={theme.textSupporting}
>
{this.props.title}
{subtitle}
</Text>

{!_.isEmpty(this.props.subtitle) && (
<Text
fontSize={variables.fontSizeLabel}
numberOfLines={2}
style={[this.props.themeStyles.mt1, this.props.themeStyles.textAlignCenter]}
color={this.props.theme.textSupporting}
>
{this.props.subtitle}
</Text>
)}
</View>
);
}
)}
</View>
);
}
QRShare.propTypes = propTypes;

QRShare.propTypes = qrSharePropTypes;
QRShare.defaultProps = qrShareDefaultProps;
QRShare.displayName = 'QRShare';

const QRShareWithRef = forwardRef((props, ref) => (
<QRShare
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));

QRShareWithRef.displayName = 'QRShareWithRef';

export default compose(withLocalize, withWindowDimensions, withThemeStyles, withTheme)(QRShare);
export default QRShareWithRef;
14 changes: 12 additions & 2 deletions src/components/QRShare/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,41 @@ const qrSharePropTypes = {
* The QR code URL
*/
url: PropTypes.string.isRequired,

/**
* The title that is displayed below the QR Code (usually the user or report name)
*/
title: PropTypes.string.isRequired,

/**
* The subtitle which will be shown below the title (usually user email or workspace name)
* */
subtitle: PropTypes.string,

/**
* The logo which will be display in the middle of the QR code
*/
logo: PropTypes.oneOfType([PropTypes.shape({uri: PropTypes.string}), PropTypes.number, PropTypes.string]),

/**
* The size ratio of logo to QR code
*/
logoRatio: PropTypes.number,

/**
* The size ratio of margin around logo to QR code
*/
logoMarginRatio: PropTypes.number,

/**
* Forwarded ref
*/
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
};

const defaultProps = {
const qrShareDefaultProps = {
subtitle: undefined,
logo: undefined,
};

export {qrSharePropTypes, defaultProps as qrShareDefaultProps};
export {qrSharePropTypes, qrShareDefaultProps};