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

[TS migration] Migrate 'QRShare' component to TypeScript #33345

Merged
merged 10 commits into from
Jan 8, 2024
14 changes: 8 additions & 6 deletions src/components/QRCode.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, {Ref} from 'react';
import React from 'react';
import {ImageSourcePropType} from 'react-native';
import QRCodeLibrary from 'react-native-qrcode-svg';
import {Svg} from 'react-native-svg';
import useTheme from '@hooks/useTheme';
import CONST from '@src/CONST';

type LogoRatio = typeof CONST.QR.DEFAULT_LOGO_SIZE_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_SIZE_RATIO;
type QRCodeLogoRatio = typeof CONST.QR.DEFAULT_LOGO_SIZE_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_SIZE_RATIO;

type LogoMarginRatio = typeof CONST.QR.DEFAULT_LOGO_MARGIN_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_MARGIN_RATIO;
type QRCodeLogoMarginRatio = typeof CONST.QR.DEFAULT_LOGO_MARGIN_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_MARGIN_RATIO;

type QRCodeProps = {
/** The QR code URL */
Expand All @@ -19,10 +20,10 @@ type QRCodeProps = {
logo?: ImageSourcePropType;

/** The size ratio of logo to QR code */
logoRatio?: LogoRatio;
logoRatio?: QRCodeLogoRatio;

/** The size ratio of margin around logo to QR code */
logoMarginRatio?: LogoMarginRatio;
logoMarginRatio?: QRCodeLogoMarginRatio;

/** The QRCode size */
size?: number;
Expand All @@ -37,7 +38,7 @@ type QRCodeProps = {
* Function to retrieve the internal component ref and be able to call it's
* methods
*/
getRef?: (ref: Ref<SVGElement>) => Ref<SVGElement>;
getRef?: (ref: Svg) => Svg;
};

function QRCode({url, logo, getRef, size = 120, color, backgroundColor, logoRatio = CONST.QR.DEFAULT_LOGO_SIZE_RATIO, logoMarginRatio = CONST.QR.DEFAULT_LOGO_MARGIN_RATIO}: QRCodeProps) {
Expand All @@ -61,3 +62,4 @@ function QRCode({url, logo, getRef, size = 120, color, backgroundColor, logoRati
QRCode.displayName = 'QRCode';

export default QRCode;
export type {QRCodeLogoMarginRatio, QRCodeLogoRatio};
46 changes: 0 additions & 46 deletions src/components/QRShare/QRShareWithDownload/index.native.js

This file was deleted.

35 changes: 35 additions & 0 deletions src/components/QRShare/QRShareWithDownload/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, {ForwardedRef, forwardRef, useImperativeHandle, useRef} from 'react';
import ViewShot from 'react-native-view-shot';
import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
import {QRShareProps} from '@components/QRShare/types';
import useNetwork from '@hooks/useNetwork';
import fileDownload from '@libs/fileDownload';
import QRShare from '..';
import QRShareWithDownloadHandle from './types';

function QRShareWithDownload(props: QRShareProps, ref: ForwardedRef<QRShareWithDownloadHandle>) {
const {isOffline} = useNetwork();
const qrCodeScreenshotRef = useRef<ViewShot>(null);

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

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

QRShareWithDownload.displayName = 'QRShareWithDownload';

export default forwardRef(QRShareWithDownload);
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import React, {ForwardedRef, forwardRef, useImperativeHandle, useRef} from 'react';
import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
import {QRShareHandle, QRShareProps} from '@components/QRShare/types';
import useNetwork from '@hooks/useNetwork';
import fileDownload from '@libs/fileDownload';
import QRShare from '..';
import QRShareWithDownloadHandle from './types';

function QRShareWithDownload({innerRef, ...props}) {
function QRShareWithDownload(props: QRShareProps, ref: ForwardedRef<QRShareWithDownloadHandle>) {
const {isOffline} = useNetwork();
const qrShareRef = useRef(null);
const qrShareRef = useRef<QRShareHandle>(null);

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

Expand All @@ -31,23 +32,11 @@ function QRShareWithDownload({innerRef, ...props}) {
ref={qrShareRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
logo={isOffline ? null : props.logo}
logo={isOffline ? undefined : 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 QRShareWithDownloadWithRef;
export default forwardRef(QRShareWithDownload);
5 changes: 5 additions & 0 deletions src/components/QRShare/QRShareWithDownload/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type QRShareWithDownloadHandle = {
download: () => Promise<void> | undefined;
};

export default QRShareWithDownloadHandle;
3 changes: 0 additions & 3 deletions src/components/QRShare/getQrCodeDownloadFileName.js

This file was deleted.

3 changes: 3 additions & 0 deletions src/components/QRShare/getQrCodeDownloadFileName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const getQrCodeDownloadFileName = (title: string): string => `${title}-ShareCode.png`;

export default getQrCodeDownloadFileName;
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import React, {ForwardedRef, forwardRef, useImperativeHandle, useRef, useState} from 'react';
import {LayoutChangeEvent, View} from 'react-native';
import {Svg} from 'react-native-svg';
import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
import QRCode from '@components/QRCode';
import Text from '@components/Text';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import {qrShareDefaultProps, qrSharePropTypes} from './propTypes';
import {QRShareHandle, QRShareProps} from './types';

function QRShare({innerRef, url, title, subtitle, logo, logoRatio, logoMarginRatio}) {
function QRShare({url, title, subtitle, logo, logoRatio, logoMarginRatio}: QRShareProps, ref: ForwardedRef<QRShareHandle>) {
const styles = useThemeStyles();
const theme = useTheme();

const [qrCodeSize, setQrCodeSize] = useState(1);
const svgRef = useRef(null);
const svgRef = useRef<Svg>();

useImperativeHandle(
innerRef,
ref,
() => ({
getSvg: () => svgRef.current,
}),
[],
);

const onLayout = (event) => {
const onLayout = (event: LayoutChangeEvent) => {
const containerWidth = event.nativeEvent.layout.width - variables.qrShareHorizontalPadding * 2 || 0;
setQrCodeSize(Math.max(1, containerWidth));
};
Expand Down Expand Up @@ -60,7 +60,7 @@ function QRShare({innerRef, url, title, subtitle, logo, logoRatio, logoMarginRat
{title}
</Text>

{!_.isEmpty(subtitle) && (
{!!subtitle && (
<Text
fontSize={variables.fontSizeLabel}
numberOfLines={2}
Expand All @@ -74,18 +74,6 @@ function QRShare({innerRef, url, title, subtitle, logo, logoRatio, logoMarginRat
);
}

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 QRShareWithRef;
export default forwardRef(QRShare);
41 changes: 41 additions & 0 deletions src/components/QRShare/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {ImageSourcePropType} from 'react-native';
import {Svg} from 'react-native-svg';
import {QRCodeLogoMarginRatio, QRCodeLogoRatio} from '@components/QRCode';

type QRShareProps = {
/**
* The QR code URL
*/
url: string;

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

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

/**
* The logo which will be display in the middle of the QR code
*/
logo?: ImageSourcePropType;

/**
* The size ratio of logo to QR code
*/
logoRatio?: QRCodeLogoRatio;

/**
* The size ratio of margin around logo to QR code
*/
logoMarginRatio?: QRCodeLogoMarginRatio;
};

type QRShareHandle = {
getSvg: () => Svg | undefined;
};

export type {QRShareHandle, QRShareProps};