2021-08-16 14:12:07 +03:00
|
|
|
import { FC, useMemo, useState } from 'react';
|
|
|
|
import { Modal, DropdownItem, FormGroup, ModalBody, ModalHeader, Row, Button } from 'reactstrap';
|
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
|
import { faFileDownload as downloadIcon } from '@fortawesome/free-solid-svg-icons';
|
2020-01-15 20:16:12 +03:00
|
|
|
import { ExternalLink } from 'react-external-link';
|
2021-02-14 12:16:30 +03:00
|
|
|
import classNames from 'classnames';
|
2020-08-30 10:59:14 +03:00
|
|
|
import { ShortUrlModalProps } from '../data';
|
2021-03-06 11:58:29 +03:00
|
|
|
import { SelectedServer } from '../../servers/data';
|
2021-01-21 18:51:54 +03:00
|
|
|
import { DropdownBtn } from '../../utils/DropdownBtn';
|
2021-01-24 19:37:31 +03:00
|
|
|
import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';
|
2021-08-16 18:13:31 +03:00
|
|
|
import { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes';
|
|
|
|
import {
|
|
|
|
supportsQrCodeSizeInQuery,
|
|
|
|
supportsQrCodeSvgFormat,
|
|
|
|
supportsQrCodeMargin,
|
|
|
|
supportsQrErrorCorrection,
|
|
|
|
} from '../../utils/helpers/features';
|
2021-08-16 14:12:07 +03:00
|
|
|
import { ImageDownloader } from '../../common/services/ImageDownloader';
|
|
|
|
import { Versions } from '../../utils/helpers/version';
|
2018-07-27 19:05:09 +03:00
|
|
|
import './QrCodeModal.scss';
|
|
|
|
|
2021-01-21 18:51:54 +03:00
|
|
|
interface QrCodeModalConnectProps extends ShortUrlModalProps {
|
2021-03-06 11:58:29 +03:00
|
|
|
selectedServer: SelectedServer;
|
2021-01-21 18:51:54 +03:00
|
|
|
}
|
|
|
|
|
2021-08-16 18:13:31 +03:00
|
|
|
const QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC<Versions>) => ( // eslint-disable-line
|
2021-08-16 14:12:07 +03:00
|
|
|
{ shortUrl: { shortUrl, shortCode }, toggle, isOpen, selectedServer }: QrCodeModalConnectProps,
|
|
|
|
) => {
|
2021-01-21 18:51:54 +03:00
|
|
|
const [ size, setSize ] = useState(300);
|
2021-02-14 12:16:30 +03:00
|
|
|
const [ margin, setMargin ] = useState(0);
|
2021-01-21 18:51:54 +03:00
|
|
|
const [ format, setFormat ] = useState<QrCodeFormat>('png');
|
2021-08-16 18:13:31 +03:00
|
|
|
const [ errorCorrection, setErrorCorrection ] = useState<QrErrorCorrection>('L');
|
2021-01-24 19:37:31 +03:00
|
|
|
const capabilities: QrCodeCapabilities = useMemo(() => ({
|
2021-03-06 11:58:29 +03:00
|
|
|
useSizeInPath: !supportsQrCodeSizeInQuery(selectedServer),
|
|
|
|
svgIsSupported: supportsQrCodeSvgFormat(selectedServer),
|
|
|
|
marginIsSupported: supportsQrCodeMargin(selectedServer),
|
2021-08-16 18:13:31 +03:00
|
|
|
errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer),
|
|
|
|
}) as QrCodeCapabilities, [ selectedServer ]);
|
2021-01-21 18:51:54 +03:00
|
|
|
const qrCodeUrl = useMemo(
|
2021-08-16 18:13:31 +03:00
|
|
|
() => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities),
|
|
|
|
[ shortUrl, size, format, margin, errorCorrection, capabilities ],
|
2021-01-21 18:51:54 +03:00
|
|
|
);
|
2021-02-14 12:16:30 +03:00
|
|
|
const totalSize = useMemo(() => size + margin, [ size, margin ]);
|
2021-01-21 18:51:54 +03:00
|
|
|
const modalSize = useMemo(() => {
|
2021-02-14 12:16:30 +03:00
|
|
|
if (totalSize < 500) {
|
2021-01-21 18:51:54 +03:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2021-02-14 12:16:30 +03:00
|
|
|
return totalSize < 800 ? 'lg' : 'xl';
|
|
|
|
}, [ totalSize ]);
|
2021-01-21 18:51:54 +03:00
|
|
|
|
|
|
|
return (
|
2021-02-27 10:52:10 +03:00
|
|
|
<Modal isOpen={isOpen} toggle={toggle} centered size={modalSize}>
|
2021-01-21 18:51:54 +03:00
|
|
|
<ModalHeader toggle={toggle}>
|
|
|
|
QR code for <ExternalLink href={shortUrl}>{shortUrl}</ExternalLink>
|
|
|
|
</ModalHeader>
|
|
|
|
<ModalBody>
|
2021-08-16 18:13:31 +03:00
|
|
|
<Row>
|
|
|
|
<FormGroup
|
2021-02-14 12:16:30 +03:00
|
|
|
className={classNames({
|
2021-08-16 18:13:31 +03:00
|
|
|
'col-md-4': capabilities.marginIsSupported && capabilities.svgIsSupported && !capabilities.errorCorrectionIsSupported,
|
|
|
|
'col-md-6': capabilities.errorCorrectionIsSupported || (!capabilities.marginIsSupported && capabilities.svgIsSupported) || (capabilities.marginIsSupported && !capabilities.svgIsSupported),
|
|
|
|
'col-12': !capabilities.marginIsSupported && !capabilities.svgIsSupported && !capabilities.errorCorrectionIsSupported,
|
2021-02-14 12:16:30 +03:00
|
|
|
})}
|
|
|
|
>
|
2021-08-16 18:13:31 +03:00
|
|
|
<label className="mb-0">Size: {size}px</label>
|
|
|
|
<input
|
|
|
|
type="range"
|
|
|
|
className="form-control-range"
|
|
|
|
value={size}
|
|
|
|
step={10}
|
|
|
|
min={50}
|
|
|
|
max={1000}
|
|
|
|
onChange={(e) => setSize(Number(e.target.value))}
|
|
|
|
/>
|
|
|
|
</FormGroup>
|
|
|
|
{capabilities.marginIsSupported && (
|
|
|
|
<FormGroup className={capabilities.svgIsSupported && !capabilities.errorCorrectionIsSupported ? 'col-md-4' : 'col-md-6'}>
|
|
|
|
<label className="mb-0">Margin: {margin}px</label>
|
2021-01-21 18:51:54 +03:00
|
|
|
<input
|
|
|
|
type="range"
|
|
|
|
className="form-control-range"
|
2021-08-16 18:13:31 +03:00
|
|
|
value={margin}
|
|
|
|
step={1}
|
|
|
|
min={0}
|
|
|
|
max={100}
|
|
|
|
onChange={(e) => setMargin(Number(e.target.value))}
|
2021-01-21 18:51:54 +03:00
|
|
|
/>
|
|
|
|
</FormGroup>
|
2021-02-14 12:16:30 +03:00
|
|
|
)}
|
2021-01-24 19:37:31 +03:00
|
|
|
{capabilities.svgIsSupported && (
|
2021-08-16 18:13:31 +03:00
|
|
|
<FormGroup className={capabilities.marginIsSupported && !capabilities.errorCorrectionIsSupported ? 'col-md-4' : 'col-md-6'}>
|
2021-01-24 19:37:31 +03:00
|
|
|
<DropdownBtn text={`Format (${format})`}>
|
|
|
|
<DropdownItem active={format === 'png'} onClick={() => setFormat('png')}>PNG</DropdownItem>
|
|
|
|
<DropdownItem active={format === 'svg'} onClick={() => setFormat('svg')}>SVG</DropdownItem>
|
|
|
|
</DropdownBtn>
|
2021-08-16 18:13:31 +03:00
|
|
|
</FormGroup>
|
|
|
|
)}
|
|
|
|
{capabilities.errorCorrectionIsSupported && (
|
|
|
|
<FormGroup className="col-md-6">
|
|
|
|
<DropdownBtn text={`Error correction (${errorCorrection})`}>
|
|
|
|
<DropdownItem active={errorCorrection === 'L'} onClick={() => setErrorCorrection('L')}>
|
|
|
|
<b>L</b>ow
|
|
|
|
</DropdownItem>
|
|
|
|
<DropdownItem active={errorCorrection === 'M'} onClick={() => setErrorCorrection('M')}>
|
|
|
|
<b>M</b>edium
|
|
|
|
</DropdownItem>
|
|
|
|
<DropdownItem active={errorCorrection === 'Q'} onClick={() => setErrorCorrection('Q')}>
|
|
|
|
<b>Q</b>uartile
|
|
|
|
</DropdownItem>
|
|
|
|
<DropdownItem active={errorCorrection === 'H'} onClick={() => setErrorCorrection('H')}>
|
|
|
|
<b>H</b>igh
|
|
|
|
</DropdownItem>
|
|
|
|
</DropdownBtn>
|
|
|
|
</FormGroup>
|
2021-01-24 19:37:31 +03:00
|
|
|
)}
|
2021-01-21 18:51:54 +03:00
|
|
|
</Row>
|
|
|
|
<div className="text-center">
|
|
|
|
<div className="mb-3">
|
2021-05-07 02:56:53 +03:00
|
|
|
<ExternalLink href={qrCodeUrl} />
|
2021-01-24 19:37:31 +03:00
|
|
|
<CopyToClipboardIcon text={qrCodeUrl} />
|
2021-01-21 18:51:54 +03:00
|
|
|
</div>
|
|
|
|
<img src={qrCodeUrl} className="qr-code-modal__img" alt="QR code" />
|
2021-08-16 14:12:07 +03:00
|
|
|
<ForServerVersion minVersion="2.9.0">
|
|
|
|
<div className="mt-3">
|
|
|
|
<Button
|
|
|
|
block
|
|
|
|
color="primary"
|
|
|
|
onClick={async () => imageDownloader.saveImage(qrCodeUrl, `${shortCode}-qr-code.${format}`)}
|
|
|
|
>
|
|
|
|
Download <FontAwesomeIcon icon={downloadIcon} className="ml-1" />
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
</ForServerVersion>
|
2021-01-21 18:51:54 +03:00
|
|
|
</div>
|
|
|
|
</ModalBody>
|
2021-02-27 10:52:10 +03:00
|
|
|
</Modal>
|
2021-01-21 18:51:54 +03:00
|
|
|
);
|
|
|
|
};
|
2018-08-26 00:39:27 +03:00
|
|
|
|
2018-11-01 14:35:51 +03:00
|
|
|
export default QrCodeModal;
|