From c95cb144a84505ca2027c07e76737dc74561ff5f Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 14 Feb 2021 10:16:30 +0100 Subject: [PATCH] Added margin option to QR code component --- src/short-urls/helpers/QrCodeModal.tsx | 38 +++++++++++++++---- src/utils/helpers/qrCodes.ts | 2 +- test/short-urls/helpers/QrCodeModal.test.tsx | 39 ++++++++++++++------ test/utils/helpers/qrCodes.test.ts | 6 +++ 4 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/short-urls/helpers/QrCodeModal.tsx b/src/short-urls/helpers/QrCodeModal.tsx index dc601d84..e26d289a 100644 --- a/src/short-urls/helpers/QrCodeModal.tsx +++ b/src/short-urls/helpers/QrCodeModal.tsx @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react'; import { DropdownItem, FormGroup, Modal, ModalBody, ModalHeader, Row } from 'reactstrap'; import { ExternalLink } from 'react-external-link'; +import classNames from 'classnames'; import { ShortUrlModalProps } from '../data'; import { ReachableServer } from '../../servers/data'; import { versionMatch } from '../../utils/helpers/version'; @@ -15,7 +16,7 @@ interface QrCodeModalConnectProps extends ShortUrlModalProps { const QrCodeModal = ({ shortUrl: { shortUrl }, toggle, isOpen, selectedServer }: QrCodeModalConnectProps) => { const [ size, setSize ] = useState(300); - const [ margin ] = useState(0); + const [ margin, setMargin ] = useState(0); const [ format, setFormat ] = useState('png'); const capabilities: QrCodeCapabilities = useMemo(() => ({ useSizeInPath: !versionMatch(selectedServer.version, { minVersion: '2.5.0' }), @@ -24,15 +25,16 @@ const QrCodeModal = ({ shortUrl: { shortUrl }, toggle, isOpen, selectedServer }: }), [ selectedServer ]); const qrCodeUrl = useMemo( () => buildQrCodeUrl(shortUrl, { size, format, margin }, capabilities), - [ shortUrl, size, format, capabilities ], + [ shortUrl, size, format, margin, capabilities ], ); + const totalSize = useMemo(() => size + margin, [ size, margin ]); const modalSize = useMemo(() => { - if (size < 500) { + if (totalSize < 500) { return undefined; } - return size < 800 ? 'lg' : 'xl'; - }, [ size ]); + return totalSize < 800 ? 'lg' : 'xl'; + }, [ totalSize ]); return ( @@ -41,7 +43,13 @@ const QrCodeModal = ({ shortUrl: { shortUrl }, toggle, isOpen, selectedServer }: -
+
+ {capabilities.marginIsSupported && ( +
+ + + setMargin(Number(e.target.value))} + /> + +
+ )} {capabilities.svgIsSupported && ( -
+
setFormat('png')}>PNG setFormat('svg')}>SVG diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index 707eeb2f..60342bd4 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -24,7 +24,7 @@ export const buildQrCodeUrl = ( const query = stringifyQuery({ size: useSizeInPath ? undefined : size, format: svgIsSupported ? format : undefined, - margin: marginIsSupported ? margin : undefined, + margin: marginIsSupported && margin > 0 ? margin : undefined, }); return `${baseUrl}${isEmpty(query) ? '' : `?${query}`}`; diff --git a/test/short-urls/helpers/QrCodeModal.test.tsx b/test/short-urls/helpers/QrCodeModal.test.tsx index 924c8cb3..d84b5572 100644 --- a/test/short-urls/helpers/QrCodeModal.test.tsx +++ b/test/short-urls/helpers/QrCodeModal.test.tsx @@ -11,7 +11,7 @@ import { DropdownBtn } from '../../../src/utils/DropdownBtn'; describe('', () => { let wrapper: ShallowWrapper; const shortUrl = 'https://doma.in/abc123'; - const createWrapper = (version = '2.5.0') => { + const createWrapper = (version = '2.6.0') => { const selectedServer = Mock.of({ version }); wrapper = shallow( @@ -37,11 +37,20 @@ describe('', () => { }); it.each([ - [ '2.3.0', '/qr-code/300' ], - [ '2.4.0', '/qr-code/300?format=png' ], - [ '2.5.0', '/qr-code?size=300&format=png' ], - ])('displays an image with the QR code of the URL', (version, expectedUrl) => { + [ '2.3.0', 0, '/qr-code/300' ], + [ '2.4.0', 0, '/qr-code/300?format=png' ], + [ '2.4.0', 10, '/qr-code/300?format=png' ], + [ '2.5.0', 0, '/qr-code?size=300&format=png' ], + [ '2.6.0', 0, '/qr-code?size=300&format=png' ], + [ '2.6.0', 10, '/qr-code?size=300&format=png&margin=10' ], + ])('displays an image with the QR code of the URL', (version, margin, expectedUrl) => { const wrapper = createWrapper(version); + const formControls = wrapper.find('.form-control-range'); + + if (formControls.length > 1) { + formControls.at(1).simulate('change', { target: { value: `${margin}` } }); + } + const modalBody = wrapper.find(ModalBody); const img = modalBody.find('img'); const linkInBody = modalBody.find(ExternalLink); @@ -53,23 +62,31 @@ describe('', () => { }); it.each([ - [ 530, 'lg' ], - [ 200, undefined ], - [ 830, 'xl' ], - ])('renders expected size', (size, modalSize) => { + [ 530, 0, 'lg' ], + [ 200, 0, undefined ], + [ 830, 0, 'xl' ], + [ 430, 80, 'lg' ], + [ 200, 50, undefined ], + [ 720, 100, 'xl' ], + ])('renders expected size', (size, margin, modalSize) => { const wrapper = createWrapper(); - const sizeInput = wrapper.find('.form-control-range'); + const formControls = wrapper.find('.form-control-range'); + const sizeInput = formControls.at(0); + const marginInput = formControls.at(1); sizeInput.simulate('change', { target: { value: `${size}` } }); + marginInput.simulate('change', { target: { value: `${margin}` } }); expect(wrapper.find('.mt-2').text()).toEqual(`${size}x${size}`); - expect(wrapper.find('label').text()).toEqual(`Size: ${size}px`); + expect(wrapper.find('label').at(0).text()).toEqual(`Size: ${size}px`); + expect(wrapper.find('label').at(1).text()).toEqual(`Margin: ${margin}px`); expect(wrapper.find(Modal).prop('size')).toEqual(modalSize); }); it.each([ [ '2.3.0', 0, 'col-12' ], [ '2.4.0', 1, 'col-md-6' ], + [ '2.6.0', 1, 'col-md-4' ], ])('shows expected components based on server version', (version, expectedAmountOfDropdowns, expectedRangeClass) => { const wrapper = createWrapper(version); const dropdown = wrapper.find(DropdownBtn); diff --git a/test/utils/helpers/qrCodes.test.ts b/test/utils/helpers/qrCodes.test.ts index e432f855..12f1afdd 100644 --- a/test/utils/helpers/qrCodes.test.ts +++ b/test/utils/helpers/qrCodes.test.ts @@ -57,6 +57,12 @@ describe('qrCodes', () => { { useSizeInPath: true, svgIsSupported: true, marginIsSupported: true }, 'shlink.io/qr-code/456?format=png&margin=10', ], + [ + 'shlink.io', + { size: 456, format: 'png' as QrCodeFormat, margin: 0 }, + { useSizeInPath: true, svgIsSupported: true, marginIsSupported: true }, + 'shlink.io/qr-code/456?format=png', + ], ])('builds expected URL based in params', (shortUrl, options, capabilities, expectedUrl) => { expect(buildQrCodeUrl(shortUrl, options, capabilities)).toEqual(expectedUrl); });