Skip to content

Commit

Permalink
Merge pull request #32690 from fabioh8010/feature/migrate-qrshare-to-…
Browse files Browse the repository at this point in the history
…function-component

Migrate QRShare to function component
  • Loading branch information
marcaaron authored Dec 12, 2023
2 parents d3724c8 + d78c28f commit ca8b9b0
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 133 deletions.
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}) {
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';

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}) {
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}
/>
));

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}) {
const styles = useThemeStyles();
const theme = useTheme();

class QRShare extends Component {
constructor(props) {
super(props);
const [qrCodeSize, setQrCodeSize] = useState(1);
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};

0 comments on commit ca8b9b0

Please sign in to comment.