From 9ad2cc2d50d8fc1d3d85de5e7fe384001d3294c0 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Sun, 12 Apr 2020 17:55:42 -0500 Subject: [PATCH] Challenge modal TS --- .../directives/views/challengeModal.js | 132 -------------- .../directives/views/challengeModal.ts | 168 ++++++++++++++++++ 2 files changed, 168 insertions(+), 132 deletions(-) delete mode 100644 app/assets/javascripts/directives/views/challengeModal.js create mode 100644 app/assets/javascripts/directives/views/challengeModal.ts diff --git a/app/assets/javascripts/directives/views/challengeModal.js b/app/assets/javascripts/directives/views/challengeModal.js deleted file mode 100644 index 490a32060..000000000 --- a/app/assets/javascripts/directives/views/challengeModal.js +++ /dev/null @@ -1,132 +0,0 @@ -import template from '%/directives/challenge-modal.pug'; -import { ChallengeType, ChallengeValue, removeFromArray } from 'snjs'; -import { PureCtrl } from '@Controllers/abstract/pure_ctrl'; - -class ChallengeModalCtrl extends PureCtrl { - /* @ngInject */ - constructor( - $element, - $timeout - ) { - super($timeout); - this.$element = $element; - this.processingTypes = []; - } - - $onInit() { - super.$onInit(); - const values = {}; - const types = this.challenge.types; - for (const type of types) { - values[type] = { - value: '', - invalid: false - }; - } - this.setState({ - types: types, - values: values, - processing: false - }); - this.orchestrator.setCallbacks({ - onComplete: () => { - this.dismiss(); - }, - onValidValue: (value) => { - this.state.values[value.type].invalid = false; - removeFromArray(this.processingTypes, value.type); - this.reloadProcessingStatus(); - }, - onInvalidValue: (value) => { - this.state.values[value.type].invalid = true; - removeFromArray(this.processingTypes, value.type); - this.reloadProcessingStatus(); - } - }); - } - - deinit() { - this.application = null; - this.orchestrator = null; - this.challenge = null; - super.deinit(); - } - - reloadProcessingStatus() { - this.setState({ - processing: this.processingTypes.length > 0 - }); - } - - promptForChallenge(challenge) { - if (challenge === ChallengeType.LocalPasscode) { - return 'Enter your application passcode'; - } else { - return 'Enter your account password'; - } - } - - cancel() { - if (!this.cancelable) { - return; - } - this.dismiss(); - } - - onTextValueChange(challenge) { - const values = this.state.values; - values[challenge].invalid = false; - this.setState({ values }); - } - - validate() { - const failed = []; - for (const type of this.state.types) { - const value = this.state.values[type]; - if (!value || value.length === 0) { - this.state.values[type].invalid = true; - } - } - return failed.length === 0; - } - - async submit() { - if (!this.validate()) { - return; - } - this.setState({ processing: true }); - const values = []; - for (const key of Object.keys(this.state.values)) { - const type = Number(key); - if(this.state.values[key].valid) { - continue; - } - const rawValue = this.state.values[key].value; - const value = new ChallengeValue(type, rawValue); - values.push(value); - } - this.processingTypes = values.map((v) => v.type); - this.orchestrator.submitValues(values); - } - - dismiss() { - const elem = this.$element; - const scope = elem.scope(); - scope.$destroy(); - elem.remove(); - } -} - -export class ChallengeModal { - constructor() { - this.restrict = 'E'; - this.template = template; - this.controller = ChallengeModalCtrl; - this.controllerAs = 'ctrl'; - this.bindToController = { - challenge: '=', - orchestrator: '=', - application: '=' - }; - } -} diff --git a/app/assets/javascripts/directives/views/challengeModal.ts b/app/assets/javascripts/directives/views/challengeModal.ts new file mode 100644 index 000000000..a3c8ff15b --- /dev/null +++ b/app/assets/javascripts/directives/views/challengeModal.ts @@ -0,0 +1,168 @@ +import { WebDirective } from './../../types'; +import { WebApplication } from './../../application'; +import template from '%/directives/challenge-modal.pug'; +import { + ChallengeType, + ChallengeValue, + removeFromArray, + Challenge, + ChallengeOrchestrator +} from 'snjs'; +import { PureCtrl } from '@Controllers/abstract/pure_ctrl'; + +type InputValue = { + value: string + invalid: boolean +} +type ChallengeModalScope = { + application: WebApplication + challenge: Challenge + orchestrator: ChallengeOrchestrator +} + +type Values = Record + +type ChallengeModalState = { + types: ChallengeType[] + values: Partial + processing: boolean +} + +class ChallengeModalCtrl extends PureCtrl implements ChallengeModalScope { + private $element: JQLite + private processingTypes: ChallengeType[] = [] + application!: WebApplication + challenge!: Challenge + orchestrator!: ChallengeOrchestrator + + /* @ngInject */ + constructor( + $element: JQLite, + $timeout: ng.ITimeoutService + ) { + super($timeout); + this.$element = $element; + } + + getState() { + return this.state as ChallengeModalState; + } + + $onInit() { + super.$onInit(); + const values = {} as Values; + const types = this.challenge.types; + for (const type of types) { + values[type] = { + value: '', + invalid: false + }; + } + this.setState({ + types: types, + values: values, + processing: false + }); + this.orchestrator.setCallbacks( + (value) => { + this.getState().values[value.type]!.invalid = false; + removeFromArray(this.processingTypes, value.type); + this.reloadProcessingStatus(); + }, + (value) => { + this.getState().values[value.type]!.invalid = true; + removeFromArray(this.processingTypes, value.type); + this.reloadProcessingStatus(); + }, + () => { + this.dismiss(); + }, + ); + } + + deinit() { + (this.application as any) = undefined; + (this.orchestrator as any) = undefined; + (this.challenge as any) = undefined; + super.deinit(); + } + + reloadProcessingStatus() { + this.setState({ + processing: this.processingTypes.length > 0 + }); + } + + promptForChallenge(challenge: ChallengeType) { + if (challenge === ChallengeType.LocalPasscode) { + return 'Enter your application passcode'; + } else { + return 'Enter your account password'; + } + } + + cancel() { + // if (!this.cancelable) { + // return; + // } + this.dismiss(); + } + + onTextValueChange(challenge: ChallengeType) { + const values = this.getState().values; + values[challenge]!.invalid = false; + this.setState({ values }); + } + + validate() { + const failed = []; + for (const type of this.getState().types) { + const value = this.getState().values[type]; + if (!value || value.value.length === 0) { + this.getState().values[type]!.invalid = true; + } + } + return failed.length === 0; + } + + async submit() { + if (!this.validate()) { + return; + } + this.setState({ processing: true }); + const values = []; + for (const key of Object.keys(this.getState().values)) { + const type = Number(key) as ChallengeType; + if (!this.getState().values[type]!.invalid) { + continue; + } + const rawValue = this.getState().values[type]!.value; + const value = new ChallengeValue(type, rawValue); + values.push(value); + } + this.processingTypes = values.map((v) => v.type); + this.orchestrator.submitValues(values); + } + + dismiss() { + const elem = this.$element; + const scope = elem.scope(); + scope.$destroy(); + elem.remove(); + } +} + +export class ChallengeModal extends WebDirective { + constructor() { + super(); + this.restrict = 'E'; + this.template = template; + this.controller = ChallengeModalCtrl; + this.controllerAs = 'ctrl'; + this.bindToController = { + challenge: '=', + orchestrator: '=', + application: '=' + }; + } +}