@@ -22,14 +22,8 @@ import { logger } from 'matrix-js-sdk/src/logger';
2222import { MatrixClient } from 'matrix-js-sdk/src/client' ;
2323
2424import { _t } from "../../../languageHandler" ;
25- import AccessibleButton from '../elements/AccessibleButton' ;
26- import QRCode from '../elements/QRCode' ;
27- import Spinner from '../elements/Spinner' ;
28- import { Icon as BackButtonIcon } from "../../../../res/img/element-icons/back.svg" ;
29- import { Icon as DevicesIcon } from "../../../../res/img/element-icons/devices.svg" ;
30- import { Icon as WarningBadge } from "../../../../res/img/element-icons/warning-badge.svg" ;
31- import { Icon as InfoIcon } from "../../../../res/img/element-icons/i.svg" ;
3225import { wrapRequestWithDialog } from '../../../utils/UserInteractiveAuth' ;
26+ import LoginWithQRFlow from './LoginWithQRFlow' ;
3327
3428/**
3529 * The intention of this enum is to have a mode that scans a QR code instead of generating one.
@@ -41,7 +35,7 @@ export enum Mode {
4135 Show = "show" ,
4236}
4337
44- enum Phase {
38+ export enum Phase {
4539 Loading ,
4640 ShowingQR ,
4741 Connecting ,
@@ -51,6 +45,14 @@ enum Phase {
5145 Error ,
5246}
5347
48+ export enum Click {
49+ Cancel ,
50+ Decline ,
51+ Approve ,
52+ TryAgain ,
53+ Back ,
54+ }
55+
5456interface IProps {
5557 client : MatrixClient ;
5658 mode : Mode ;
@@ -68,7 +70,7 @@ interface IState {
6870/**
6971 * A component that allows sign in and E2EE set up with a QR code.
7072 *
71- * It implements both `login.start` and `login- reciprocate` capabilities as well as both scanning and showing QR codes.
73+ * It implements `login.reciprocate` capabilities and showing QR codes.
7274 *
7375 * This uses the unstable feature of MSC3906: https://github.com/matrix-org/matrix-spec-proposals/pull/3906
7476 */
@@ -138,6 +140,7 @@ export default class LoginWithQR extends React.Component<IProps, IState> {
138140 this . props . onFinished ( true ) ;
139141 return ;
140142 }
143+ this . setState ( { phase : Phase . Verifying } ) ;
141144 await this . state . rendezvous . verifyNewDeviceOnExistingDevice ( ) ;
142145 this . props . onFinished ( true ) ;
143146 } catch ( e ) {
@@ -197,200 +200,41 @@ export default class LoginWithQR extends React.Component<IProps, IState> {
197200 } ) ;
198201 }
199202
200- private cancelClicked = async ( e : React . FormEvent ) => {
201- e . preventDefault ( ) ;
202- await this . state . rendezvous ?. cancel ( RendezvousFailureReason . UserCancelled ) ;
203- this . reset ( ) ;
204- this . props . onFinished ( false ) ;
205- } ;
206-
207- private declineClicked = async ( e : React . FormEvent ) => {
208- e . preventDefault ( ) ;
209- await this . state . rendezvous ?. declineLoginOnExistingDevice ( ) ;
210- this . reset ( ) ;
211- this . props . onFinished ( false ) ;
212- } ;
213-
214- private tryAgainClicked = async ( e : React . FormEvent ) => {
215- e . preventDefault ( ) ;
216- this . reset ( ) ;
217- await this . updateMode ( this . props . mode ) ;
218- } ;
219-
220- private onBackClick = async ( ) => {
221- await this . state . rendezvous ?. cancel ( RendezvousFailureReason . UserCancelled ) ;
222-
223- this . props . onFinished ( false ) ;
224- } ;
225-
226- private cancelButton = ( ) => < AccessibleButton
227- kind = "primary_outline"
228- onClick = { this . cancelClicked }
229- >
230- { _t ( "Cancel" ) }
231- </ AccessibleButton > ;
232-
233- private simpleSpinner = ( description ?: string ) : JSX . Element => {
234- return < div className = "mx_LoginWithQR_spinner" >
235- < div >
236- < Spinner />
237- { description && < p > { description } </ p > }
238- </ div >
239- </ div > ;
240- } ;
241-
242- public render ( ) {
243- let title : string ;
244- let titleIcon : JSX . Element | undefined ;
245- let main : JSX . Element | undefined ;
246- let buttons : JSX . Element | undefined ;
247- let backButton = true ;
248- let cancellationMessage : string | undefined ;
249- let centreTitle = false ;
250-
251- switch ( this . state . phase ) {
252- case Phase . Error :
253- switch ( this . state . failureReason ) {
254- case RendezvousFailureReason . Expired :
255- cancellationMessage = _t ( "The linking wasn't completed in the required time." ) ;
256- break ;
257- case RendezvousFailureReason . InvalidCode :
258- cancellationMessage = _t ( "The scanned code is invalid." ) ;
259- break ;
260- case RendezvousFailureReason . UnsupportedAlgorithm :
261- cancellationMessage = _t ( "Linking with this device is not supported." ) ;
262- break ;
263- case RendezvousFailureReason . UserDeclined :
264- cancellationMessage = _t ( "The request was declined on the other device." ) ;
265- break ;
266- case RendezvousFailureReason . OtherDeviceAlreadySignedIn :
267- cancellationMessage = _t ( "The other device is already signed in." ) ;
268- break ;
269- case RendezvousFailureReason . OtherDeviceNotSignedIn :
270- cancellationMessage = _t ( "The other device isn't signed in." ) ;
271- break ;
272- case RendezvousFailureReason . UserCancelled :
273- cancellationMessage = _t ( "The request was cancelled." ) ;
274- break ;
275- case RendezvousFailureReason . Unknown :
276- cancellationMessage = _t ( "An unexpected error occurred." ) ;
277- break ;
278- case RendezvousFailureReason . HomeserverLacksSupport :
279- cancellationMessage = _t ( "The homeserver doesn't support signing in another device." ) ;
280- break ;
281- default :
282- cancellationMessage = _t ( "The request was cancelled." ) ;
283- break ;
284- }
285- title = _t ( "Connection failed" ) ;
286- centreTitle = true ;
287- titleIcon = < WarningBadge className = "error" /> ;
288- backButton = false ;
289- main = < p data-testid = "cancellation-message" > { cancellationMessage } </ p > ;
290- buttons = < >
291- < AccessibleButton
292- kind = "primary"
293- onClick = { this . tryAgainClicked }
294- >
295- { _t ( "Try again" ) }
296- </ AccessibleButton >
297- { this . cancelButton ( ) }
298- </ > ;
203+ private onClick = async ( type : Click ) => {
204+ switch ( type ) {
205+ case Click . Cancel :
206+ await this . state . rendezvous ?. cancel ( RendezvousFailureReason . UserCancelled ) ;
207+ this . reset ( ) ;
208+ this . props . onFinished ( false ) ;
299209 break ;
300- case Phase . Connected :
301- title = _t ( "Devices connected" ) ;
302- titleIcon = < DevicesIcon className = "normal" /> ;
303- backButton = false ;
304- main = < >
305- < p > { _t ( "Check that the code below matches with your other device:" ) } </ p >
306- < div className = "mx_LoginWithQR_confirmationDigits" >
307- { this . state . confirmationDigits }
308- </ div >
309- < div className = "mx_LoginWithQR_confirmationAlert" >
310- < div >
311- < InfoIcon />
312- </ div >
313- < div > { _t ( "By approving access for this device, it will have full access to your account." ) } </ div >
314- </ div >
315- </ > ;
316-
317- buttons = < >
318- < AccessibleButton
319- data-testid = "decline-login-button"
320- kind = "primary_outline"
321- onClick = { this . declineClicked }
322- >
323- { _t ( "Cancel" ) }
324- </ AccessibleButton >
325- < AccessibleButton
326- data-testid = "approve-login-button"
327- kind = "primary"
328- onClick = { this . approveLogin }
329- >
330- { _t ( "Approve" ) }
331- </ AccessibleButton >
332- </ > ;
333- break ;
334- case Phase . ShowingQR :
335- title = _t ( "Sign in with QR code" ) ;
336- if ( this . state . rendezvous ) {
337- const code = < div className = "mx_LoginWithQR_qrWrapper" >
338- < QRCode data = { [ { data : Buffer . from ( this . state . rendezvous . code ) , mode : 'byte' } ] } className = "mx_QRCode" />
339- </ div > ;
340- main = < >
341- < p > { _t ( "Scan the QR code below with your device that's signed out." ) } </ p >
342- < ol >
343- < li > { _t ( "Start at the sign in screen" ) } </ li >
344- < li > { _t ( "Select 'Scan QR code'" ) } </ li >
345- < li > { _t ( "Review and approve the sign in" ) } </ li >
346- </ ol >
347- { code }
348- </ > ;
349- } else {
350- main = this . simpleSpinner ( ) ;
351- buttons = this . cancelButton ( ) ;
352- }
353- break ;
354- case Phase . Loading :
355- main = this . simpleSpinner ( ) ;
210+ case Click . Approve :
211+ await this . approveLogin ( ) ;
356212 break ;
357- case Phase . Connecting :
358- main = this . simpleSpinner ( _t ( "Connecting..." ) ) ;
359- buttons = this . cancelButton ( ) ;
213+ case Click . Decline :
214+ await this . state . rendezvous ?. declineLoginOnExistingDevice ( ) ;
215+ this . reset ( ) ;
216+ this . props . onFinished ( false ) ;
360217 break ;
361- case Phase . WaitingForDevice :
362- main = this . simpleSpinner ( _t ( "Waiting for device to sign in" ) ) ;
363- buttons = this . cancelButton ( ) ;
218+ case Click . TryAgain :
219+ this . reset ( ) ;
220+ await this . updateMode ( this . props . mode ) ;
364221 break ;
365- case Phase . Verifying :
366- title = _t ( "Success" ) ;
367- centreTitle = true ;
368- main = this . simpleSpinner ( _t ( "Completing set up of your new device" ) ) ;
222+ case Click . Back :
223+ await this . state . rendezvous ?. cancel ( RendezvousFailureReason . UserCancelled ) ;
224+ this . props . onFinished ( false ) ;
369225 break ;
370226 }
227+ } ;
371228
229+ public render ( ) {
372230 return (
373- < div data-testid = "login-with-qr" className = "mx_LoginWithQR" >
374- < div className = { centreTitle ? "mx_LoginWithQR_centreTitle" : "" } >
375- { backButton ?
376- < AccessibleButton
377- data-testid = "back-button"
378- className = "mx_LoginWithQR_BackButton"
379- onClick = { this . onBackClick }
380- title = "Back"
381- >
382- < BackButtonIcon />
383- </ AccessibleButton >
384- : null }
385- < h1 > { titleIcon } { title } </ h1 >
386- </ div >
387- < div className = "mx_LoginWithQR_main" >
388- { main }
389- </ div >
390- < div className = "mx_LoginWithQR_buttons" >
391- { buttons }
392- </ div >
393- </ div >
231+ < LoginWithQRFlow
232+ onClick = { this . onClick }
233+ phase = { this . state . phase }
234+ code = { this . state . phase === Phase . ShowingQR ? this . state . rendezvous ?. code : undefined }
235+ confirmationDigits = { this . state . phase === Phase . Connected ? this . state . confirmationDigits : undefined }
236+ failureReason = { this . state . phase === Phase . Error ? this . state . failureReason : undefined }
237+ />
394238 ) ;
395239 }
396240}
0 commit comments