You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			TypeScript
		
	
		
		
			
		
	
	
			192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			TypeScript
		
	
| 
											6 years ago
										 | import React from 'react'; | ||
|  | import classNames from 'classnames'; | ||
|  | 
 | ||
| 
											4 years ago
										 | import { SessionIcon } from './icon'; | ||
| 
											4 years ago
										 | import { withTheme } from 'styled-components'; | ||
| 
											4 years ago
										 | import autoBind from 'auto-bind'; | ||
| 
											4 years ago
										 | import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton'; | ||
|  | import { Constants } from '../session'; | ||
| 
											6 years ago
										 | 
 | ||
|  | interface State { | ||
|  |   error: string; | ||
|  |   errorCount: number; | ||
|  |   clearDataView: boolean; | ||
|  | } | ||
|  | 
 | ||
| 
											5 years ago
										 | export const MAX_LOGIN_TRIES = 3; | ||
|  | 
 | ||
| 
											4 years ago
										 | class SessionPasswordPromptInner extends React.PureComponent<{}, State> { | ||
| 
											4 years ago
										 |   private inputRef?: any; | ||
| 
											6 years ago
										 | 
 | ||
| 
											6 years ago
										 |   constructor(props: any) { | ||
|  |     super(props); | ||
|  | 
 | ||
|  |     this.state = { | ||
|  |       error: '', | ||
|  |       errorCount: 0, | ||
|  |       clearDataView: false, | ||
|  |     }; | ||
|  | 
 | ||
| 
											4 years ago
										 |     autoBind(this); | ||
| 
											6 years ago
										 |   } | ||
|  | 
 | ||
| 
											6 years ago
										 |   public componentDidMount() { | ||
| 
											4 years ago
										 |     setTimeout(() => { | ||
|  |       this.inputRef?.focus(); | ||
|  |     }, 100); | ||
| 
											6 years ago
										 |   } | ||
|  | 
 | ||
| 
											6 years ago
										 |   public render() { | ||
| 
											5 years ago
										 |     const showResetElements = this.state.errorCount >= MAX_LOGIN_TRIES; | ||
| 
											6 years ago
										 | 
 | ||
|  |     const wrapperClass = this.state.clearDataView | ||
|  |       ? 'clear-data-wrapper' | ||
|  |       : 'password-prompt-wrapper'; | ||
|  |     const containerClass = this.state.clearDataView | ||
|  |       ? 'clear-data-container' | ||
|  |       : 'password-prompt-container'; | ||
| 
											5 years ago
										 |     const infoAreaClass = this.state.clearDataView ? 'warning-info-area' : 'password-info-area'; | ||
| 
											6 years ago
										 |     const infoTitle = this.state.clearDataView | ||
| 
											5 years ago
										 |       ? window.i18n('clearAllData') | ||
| 
											6 years ago
										 |       : window.i18n('passwordViewTitle'); | ||
|  |     const buttonGroup = this.state.clearDataView | ||
|  |       ? this.renderClearDataViewButtons() | ||
|  |       : this.renderPasswordViewButtons(); | ||
|  |     const featureElement = this.state.clearDataView ? ( | ||
| 
											5 years ago
										 |       <p className="text-center">{window.i18n('deleteAccountWarning')}</p> | ||
| 
											6 years ago
										 |     ) : ( | ||
|  |       <input | ||
|  |         id="password-prompt-input" | ||
|  |         type="password" | ||
|  |         defaultValue="" | ||
| 
											6 years ago
										 |         placeholder={' '} | ||
| 
											6 years ago
										 |         onKeyUp={this.onKeyUp} | ||
| 
											4 years ago
										 |         ref={input => { | ||
|  |           this.inputRef = input; | ||
|  |         }} | ||
| 
											6 years ago
										 |       /> | ||
|  |     ); | ||
|  |     const infoIcon = this.state.clearDataView ? ( | ||
| 
											4 years ago
										 |       <SessionIcon iconType="warning" iconSize={35} iconColor="#ce0000" /> | ||
| 
											6 years ago
										 |     ) : ( | ||
| 
											4 years ago
										 |       <SessionIcon iconType="lock" iconSize={35} iconColor={Constants.UI.COLORS.GREEN} /> | ||
| 
											6 years ago
										 |     ); | ||
|  |     const errorSection = !this.state.clearDataView && ( | ||
|  |       <div className="password-prompt-error-section"> | ||
|  |         {this.state.error && ( | ||
|  |           <> | ||
|  |             {showResetElements ? ( | ||
| 
											5 years ago
										 |               <div className="session-label warning">{window.i18n('maxPasswordAttempts')}</div> | ||
| 
											6 years ago
										 |             ) : ( | ||
|  |               <div className="session-label primary">{this.state.error}</div> | ||
|  |             )} | ||
|  |           </> | ||
|  |         )} | ||
|  |       </div> | ||
|  |     ); | ||
|  | 
 | ||
|  |     return ( | ||
|  |       <div className={wrapperClass}> | ||
|  |         <div className={containerClass}> | ||
|  |           <div className={infoAreaClass}> | ||
|  |             {infoIcon} | ||
|  | 
 | ||
|  |             <h1>{infoTitle}</h1> | ||
|  |           </div> | ||
|  | 
 | ||
|  |           {featureElement} | ||
|  |           {errorSection} | ||
|  |           {buttonGroup} | ||
|  |         </div> | ||
|  |       </div> | ||
|  |     ); | ||
|  |   } | ||
|  | 
 | ||
|  |   public async onKeyUp(event: any) { | ||
|  |     switch (event.key) { | ||
|  |       case 'Enter': | ||
|  |         await this.initLogin(); | ||
|  |         break; | ||
|  |       default: | ||
|  |     } | ||
|  |     event.preventDefault(); | ||
|  |   } | ||
|  | 
 | ||
|  |   public async onLogin(passPhrase: string) { | ||
| 
											6 years ago
										 |     const passPhraseTrimmed = passPhrase.trim(); | ||
| 
											6 years ago
										 | 
 | ||
|  |     try { | ||
| 
											6 years ago
										 |       await window.onLogin(passPhraseTrimmed); | ||
| 
											6 years ago
										 |     } catch (error) { | ||
| 
											6 years ago
										 |       // Increment the error counter and show the button if necessary
 | ||
|  |       this.setState({ | ||
|  |         errorCount: this.state.errorCount + 1, | ||
|  |       }); | ||
|  | 
 | ||
| 
											6 years ago
										 |       this.setState({ error }); | ||
| 
											6 years ago
										 |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   private async initLogin() { | ||
| 
											4 years ago
										 |     const passPhrase = String((this.inputRef as HTMLInputElement).value); | ||
| 
											6 years ago
										 |     await this.onLogin(passPhrase); | ||
|  |   } | ||
|  | 
 | ||
|  |   private initClearDataView() { | ||
|  |     this.setState({ | ||
|  |       error: '', | ||
|  |       errorCount: 0, | ||
|  |       clearDataView: true, | ||
|  |     }); | ||
|  |   } | ||
|  | 
 | ||
|  |   private renderPasswordViewButtons(): JSX.Element { | ||
| 
											5 years ago
										 |     const showResetElements = this.state.errorCount >= MAX_LOGIN_TRIES; | ||
| 
											6 years ago
										 | 
 | ||
|  |     return ( | ||
|  |       <div className={classNames(showResetElements && 'button-group')}> | ||
|  |         {showResetElements && ( | ||
|  |           <> | ||
|  |             <SessionButton | ||
|  |               text="Reset Database" | ||
|  |               buttonType={SessionButtonType.BrandOutline} | ||
|  |               buttonColor={SessionButtonColor.Danger} | ||
|  |               onClick={this.initClearDataView} | ||
|  |             /> | ||
|  |           </> | ||
|  |         )} | ||
|  |         <SessionButton | ||
|  |           text={window.i18n('unlock')} | ||
|  |           buttonType={SessionButtonType.BrandOutline} | ||
|  |           buttonColor={SessionButtonColor.Green} | ||
|  |           onClick={this.initLogin} | ||
|  |         /> | ||
|  |       </div> | ||
|  |     ); | ||
|  |   } | ||
|  | 
 | ||
|  |   private renderClearDataViewButtons(): JSX.Element { | ||
|  |     return ( | ||
|  |       <div className="button-group"> | ||
|  |         <SessionButton | ||
|  |           text={window.i18n('cancel')} | ||
|  |           buttonType={SessionButtonType.Default} | ||
|  |           buttonColor={SessionButtonColor.Primary} | ||
|  |           onClick={() => { | ||
|  |             this.setState({ clearDataView: false }); | ||
|  |           }} | ||
|  |         /> | ||
|  | 
 | ||
|  |         <SessionButton | ||
| 
											5 years ago
										 |           text={window.i18n('clearAllData')} | ||
| 
											6 years ago
										 |           buttonType={SessionButtonType.Default} | ||
|  |           buttonColor={SessionButtonColor.Danger} | ||
|  |           onClick={window.clearLocalData} | ||
|  |         /> | ||
|  |       </div> | ||
|  |     ); | ||
|  |   } | ||
|  | } | ||
| 
											5 years ago
										 | 
 | ||
|  | export const SessionPasswordPrompt = withTheme(SessionPasswordPromptInner); |