From f9da22c5a1c989bf09484da9b86549b407ed5446 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 14 Feb 2021 09:50:26 +0100 Subject: [PATCH] Added support for margin param in buildQrCodeUrl function --- src/short-urls/helpers/QrCodeModal.tsx | 4 +- src/utils/helpers/qrCodes.ts | 30 +++++++----- test/utils/helpers/qrCodes.test.ts | 65 ++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/short-urls/helpers/QrCodeModal.tsx b/src/short-urls/helpers/QrCodeModal.tsx index 8f968c87..dc601d84 100644 --- a/src/short-urls/helpers/QrCodeModal.tsx +++ b/src/short-urls/helpers/QrCodeModal.tsx @@ -15,13 +15,15 @@ interface QrCodeModalConnectProps extends ShortUrlModalProps { const QrCodeModal = ({ shortUrl: { shortUrl }, toggle, isOpen, selectedServer }: QrCodeModalConnectProps) => { const [ size, setSize ] = useState(300); + const [ margin ] = useState(0); const [ format, setFormat ] = useState('png'); const capabilities: QrCodeCapabilities = useMemo(() => ({ useSizeInPath: !versionMatch(selectedServer.version, { minVersion: '2.5.0' }), svgIsSupported: versionMatch(selectedServer.version, { minVersion: '2.4.0' }), + marginIsSupported: versionMatch(selectedServer.version, { minVersion: '2.6.0' }), }), [ selectedServer ]); const qrCodeUrl = useMemo( - () => buildQrCodeUrl(shortUrl, size, format, capabilities), + () => buildQrCodeUrl(shortUrl, { size, format, margin }, capabilities), [ shortUrl, size, format, capabilities ], ); const modalSize = useMemo(() => { diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index 13b298ca..707eeb2f 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -1,25 +1,31 @@ -import { always, cond } from 'ramda'; +import { isEmpty } from 'ramda'; +import { stringifyQuery } from './query'; export interface QrCodeCapabilities { useSizeInPath: boolean; svgIsSupported: boolean; + marginIsSupported: boolean; } export type QrCodeFormat = 'svg' | 'png'; +export interface QrCodeOptions { + size: number; + format: QrCodeFormat; + margin: number; +} + export const buildQrCodeUrl = ( shortUrl: string, - size: number, - format: QrCodeFormat, - { useSizeInPath, svgIsSupported }: QrCodeCapabilities, + { size, format, margin }: QrCodeOptions, + { useSizeInPath, svgIsSupported, marginIsSupported }: QrCodeCapabilities, ): string => { - const sizeFragment = useSizeInPath ? `/${size}` : `?size=${size}`; - const formatFragment = !svgIsSupported ? '' : `format=${format}`; - const joinSymbolResolver = cond([ - [ () => useSizeInPath && svgIsSupported, always('?') ], - [ () => !useSizeInPath && svgIsSupported, always('&') ], - ]); - const joinSymbol = joinSymbolResolver() ?? ''; + const baseUrl = `${shortUrl}/qr-code${useSizeInPath ? `/${size}` : ''}`; + const query = stringifyQuery({ + size: useSizeInPath ? undefined : size, + format: svgIsSupported ? format : undefined, + margin: marginIsSupported ? margin : undefined, + }); - return `${shortUrl}/qr-code${sizeFragment}${joinSymbol}${formatFragment}`; + return `${baseUrl}${isEmpty(query) ? '' : `?${query}`}`; }; diff --git a/test/utils/helpers/qrCodes.test.ts b/test/utils/helpers/qrCodes.test.ts index fe0a0f76..e432f855 100644 --- a/test/utils/helpers/qrCodes.test.ts +++ b/test/utils/helpers/qrCodes.test.ts @@ -3,15 +3,62 @@ import { buildQrCodeUrl, QrCodeFormat } from '../../../src/utils/helpers/qrCodes describe('qrCodes', () => { describe('buildQrCodeUrl', () => { test.each([ - [ 'foo.com', 530, 'svg', { useSizeInPath: true, svgIsSupported: true }, 'foo.com/qr-code/530?format=svg' ], - [ 'foo.com', 530, 'png', { useSizeInPath: true, svgIsSupported: true }, 'foo.com/qr-code/530?format=png' ], - [ 'bar.io', 870, 'svg', { useSizeInPath: false, svgIsSupported: false }, 'bar.io/qr-code?size=870' ], - [ 'bar.io', 200, 'png', { useSizeInPath: false, svgIsSupported: true }, 'bar.io/qr-code?size=200&format=png' ], - [ 'bar.io', 200, 'svg', { useSizeInPath: false, svgIsSupported: true }, 'bar.io/qr-code?size=200&format=svg' ], - [ 'foo.net', 480, 'png', { useSizeInPath: true, svgIsSupported: false }, 'foo.net/qr-code/480' ], - [ 'foo.net', 480, 'svg', { useSizeInPath: true, svgIsSupported: false }, 'foo.net/qr-code/480' ], - ])('builds expected URL based in params', (shortUrl, size, format, capabilities, expectedUrl) => { - expect(buildQrCodeUrl(shortUrl, size, format as QrCodeFormat, capabilities)).toEqual(expectedUrl); + [ + 'foo.com', + { size: 530, format: 'svg' as QrCodeFormat, margin: 0 }, + { useSizeInPath: true, svgIsSupported: true, marginIsSupported: false }, + 'foo.com/qr-code/530?format=svg', + ], + [ + 'foo.com', + { size: 530, format: 'png' as QrCodeFormat, margin: 0 }, + { useSizeInPath: true, svgIsSupported: true, marginIsSupported: false }, + 'foo.com/qr-code/530?format=png', + ], + [ + 'bar.io', + { size: 870, format: 'svg' as QrCodeFormat, margin: 0 }, + { useSizeInPath: false, svgIsSupported: false, marginIsSupported: false }, + 'bar.io/qr-code?size=870', + ], + [ + 'bar.io', + { size: 200, format: 'png' as QrCodeFormat, margin: 0 }, + { useSizeInPath: false, svgIsSupported: true, marginIsSupported: false }, + 'bar.io/qr-code?size=200&format=png', + ], + [ + 'bar.io', + { size: 200, format: 'svg' as QrCodeFormat, margin: 0 }, + { useSizeInPath: false, svgIsSupported: true, marginIsSupported: false }, + 'bar.io/qr-code?size=200&format=svg', + ], + [ + 'foo.net', + { size: 480, format: 'png' as QrCodeFormat, margin: 0 }, + { useSizeInPath: true, svgIsSupported: false, marginIsSupported: false }, + 'foo.net/qr-code/480', + ], + [ + 'foo.net', + { size: 480, format: 'svg' as QrCodeFormat, margin: 0 }, + { useSizeInPath: true, svgIsSupported: false, marginIsSupported: false }, + 'foo.net/qr-code/480', + ], + [ + 'shlink.io', + { size: 123, format: 'svg' as QrCodeFormat, margin: 10 }, + { useSizeInPath: true, svgIsSupported: false, marginIsSupported: false }, + 'shlink.io/qr-code/123', + ], + [ + 'shlink.io', + { size: 456, format: 'png' as QrCodeFormat, margin: 10 }, + { useSizeInPath: true, svgIsSupported: true, marginIsSupported: true }, + 'shlink.io/qr-code/456?format=png&margin=10', + ], + ])('builds expected URL based in params', (shortUrl, options, capabilities, expectedUrl) => { + expect(buildQrCodeUrl(shortUrl, options, capabilities)).toEqual(expectedUrl); }); }); });