11import React , { useEffect , useRef , useCallback , useState } from 'react'
22import { useTranslation } from 'react-i18next'
3+ import { askForCameraAccess } from 'services/remote'
34import Dialog from 'widgets/Dialog'
5+ import AlertDialog from 'widgets/AlertDialog'
6+ import { isSuccessResponse } from 'utils'
47import jsQR from 'jsqr'
58
69import styles from './cameraScanDialog.module.scss'
@@ -17,7 +20,7 @@ const CameraScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm:
1720 const videoRef = useRef < HTMLVideoElement > ( )
1821 const canvasRef = useRef < HTMLCanvasElement > ( null )
1922 const canvas2dRef = useRef < CanvasRenderingContext2D > ( )
20- const [ loading , setLoading ] = useState ( true )
23+ const [ dialogType , setDialogType ] = useState < '' | 'no-camera' | 'access-fail' | 'scan' > ( '' )
2124
2225 const drawLine = ( begin : Point , end : Point ) => {
2326 if ( ! canvas2dRef . current ) return
@@ -31,7 +34,7 @@ const CameraScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm:
3134
3235 const scan = useCallback ( ( ) => {
3336 if ( videoRef . current ?. readyState === HTMLMediaElement . HAVE_ENOUGH_DATA ) {
34- setLoading ( false )
37+ setDialogType ( 'scan' )
3538 const canvas2d = canvasRef . current ?. getContext ( '2d' )
3639 if ( canvas2d ) {
3740 canvas2d . drawImage ( videoRef . current , 0 , 0 , IMAGE_SIZE , IMAGE_SIZE )
@@ -50,24 +53,31 @@ const CameraScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm:
5053 }
5154 }
5255 requestAnimationFrame ( scan )
53- } , [ ] )
56+ } , [ setDialogType ] )
5457
5558 useEffect ( ( ) => {
5659 let mediaStream : MediaStream
57- navigator . mediaDevices
58- . getUserMedia ( {
59- audio : false ,
60- video : { width : IMAGE_SIZE , height : IMAGE_SIZE } ,
61- } )
62- . then ( res => {
63- if ( res ) {
64- videoRef . current = document . createElement ( 'video' )
65- videoRef . current . srcObject = res
66- videoRef . current . play ( )
67- mediaStream = res
68- requestAnimationFrame ( scan )
69- }
70- } )
60+
61+ askForCameraAccess ( ) . then ( accessRes => {
62+ if ( isSuccessResponse ( accessRes ) ) {
63+ navigator . mediaDevices
64+ . getUserMedia ( {
65+ audio : false ,
66+ video : { width : IMAGE_SIZE , height : IMAGE_SIZE } ,
67+ } )
68+ . then ( res => {
69+ if ( res ) {
70+ videoRef . current = document . createElement ( 'video' )
71+ videoRef . current . srcObject = res
72+ videoRef . current . play ( )
73+ mediaStream = res
74+ requestAnimationFrame ( scan )
75+ }
76+ } )
77+ } else {
78+ setDialogType ( 'access-fail' )
79+ }
80+ } )
7181
7282 return ( ) => {
7383 if ( mediaStream ) {
@@ -79,24 +89,32 @@ const CameraScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm:
7989 } , [ ] )
8090
8191 return (
82- < Dialog
83- show
84- title = { t ( 'wallet-connect.scan-with-camera' ) }
85- onCancel = { close }
86- showCancel = { false }
87- showConfirm = { false }
88- showFooter = { false }
89- >
90- < div className = { styles . container } >
91- < div className = { styles . scanBox } >
92- { loading ? (
93- < div > { t ( 'wallet-connect.waiting-camera' ) } </ div >
94- ) : (
92+ < >
93+ < Dialog
94+ show = { dialogType === 'scan' }
95+ title = { t ( 'wallet-connect.scan-with-camera' ) }
96+ onCancel = { close }
97+ showCancel = { false }
98+ showConfirm = { false }
99+ showFooter = { false }
100+ >
101+ < div className = { styles . container } >
102+ < div className = { styles . scanBox } >
95103 < canvas ref = { canvasRef } width = "400px" height = "400px" />
96- ) }
104+ </ div >
97105 </ div >
98- </ div >
99- </ Dialog >
106+ </ Dialog >
107+
108+ < AlertDialog
109+ show = { dialogType === 'access-fail' }
110+ title = { t ( 'wallet-connect.camera-fail' ) }
111+ message = { t ( 'wallet-connect.camera-msg' ) }
112+ type = "failed"
113+ onCancel = { ( ) => {
114+ close ( )
115+ } }
116+ />
117+ </ >
100118 )
101119}
102120
0 commit comments