ParityQrSigner.tsx
1 import React from 'react'; 2 import classnames from 'classnames'; 3 import QrSigner from '@parity/qr-signer'; 4 5 import translate from 'translations'; 6 import { Spinner } from 'components/ui'; 7 import './ParityQrSigner.scss'; 8 9 interface State { 10 webcamError: null | React.ReactElement<any>; 11 isLoading: boolean; 12 } 13 14 interface ScanProps { 15 scan: true; 16 onScan(data: string): void; 17 } 18 19 interface ShowProps { 20 scan: false; 21 account: string; 22 data?: string; 23 rlp?: string; 24 } 25 26 interface SharedProps { 27 size?: number; 28 } 29 30 type Props = (ScanProps | ShowProps) & SharedProps; 31 32 export default class ParityQrSigner extends React.PureComponent<Props, State> { 33 public state: State = { 34 webcamError: null, 35 isLoading: true 36 }; 37 38 public componentDidMount() { 39 this.checkForWebcam(); 40 if (navigator.mediaDevices) { 41 navigator.mediaDevices.addEventListener('devicechange', this.checkForWebcam); 42 } 43 } 44 45 public componentWillUnmount() { 46 if (navigator.mediaDevices && navigator.mediaDevices.ondevicechange) { 47 navigator.mediaDevices.removeEventListener('devicechange', this.checkForWebcam); 48 } 49 } 50 51 public checkForWebcam = async () => { 52 if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { 53 try { 54 await navigator.mediaDevices.getUserMedia({ video: true }); 55 this.setState({ 56 webcamError: null, 57 isLoading: false 58 }); 59 } catch (e) { 60 const err = e as DOMException; 61 let errorMessage; 62 switch (err.name) { 63 case 'NotAllowedError': 64 case 'SecurityError': 65 errorMessage = translate('ADD_PARITY_ERROR_DISABLED'); 66 break; 67 case 'NotFoundError': 68 case 'OverconstrainedError': 69 errorMessage = translate('ADD_PARITY_ERROR_NO_CAM'); 70 break; 71 default: 72 errorMessage = translate('ADD_PARITY_ERROR_UNKNOWN'); 73 } 74 this.setState({ 75 webcamError: errorMessage, 76 isLoading: false 77 }); 78 } 79 } 80 }; 81 82 public render() { 83 const { webcamError, isLoading } = this.state; 84 const size = this.props.size || 300; 85 86 return ( 87 <div 88 className={classnames({ 89 ParityQrSigner: true, 90 'is-disabled': !!webcamError || isLoading 91 })} 92 style={{ 93 width: size, 94 height: size 95 }} 96 > 97 {isLoading ? ( 98 <div className="ParityQrSigner-loader"> 99 <Spinner size="x3" light={true} /> 100 </div> 101 ) : webcamError ? ( 102 <div className="ParityQrSigner-error"> 103 <i className="ParityQrSigner-error-icon fa fa-exclamation-circle" /> 104 {webcamError} 105 </div> 106 ) : ( 107 <QrSigner {...this.props} size={size} /> 108 )} 109 </div> 110 ); 111 } 112 }