diff --git a/app/assets/javascripts/views/challenge_modal/challenge-modal.pug b/app/assets/javascripts/views/challenge_modal/challenge-modal.pug index 159dd38e9..9e1fcef49 100644 --- a/app/assets/javascripts/views/challenge_modal/challenge-modal.pug +++ b/app/assets/javascripts/views/challenge_modal/challenge-modal.pug @@ -11,26 +11,44 @@ .sk-panel-content .sk-panel-section div(ng-repeat="type in ctrl.state.types") - .sk-p.sk-bold.sk-panel-row + .sk-p.sk-bold.sk-panel-row.centered strong {{ctrl.promptForChallenge(type)}} .sk-panel-row input.sk-input.contrast( - ng-model="ctrl.state.values[type].value" - should-focus="$index == 0" - sn-autofocus="true" + ng-model="ctrl.state.values[type].value" + should-focus="$index == 0" + sn-autofocus="true" sn-enter="ctrl.submit()" , ng-change="ctrl.onTextValueChange(type)" type="password" ) - .sk-panel-row + .sk-panel-row.centered label.sk-label.danger( ng-if="ctrl.state.values[type].invalid" ) Invalid authentication. Please try again. - .sk-panel-row .sk-panel-footer.extra-padding .sk-button.info.big.block.bold( ng-click="ctrl.submit()", ng-class="{'info' : !ctrl.state.processing, 'neutral': ctrl.state.processing}" ng-disabled="ctrl.state.processing" ) - .sk-label {{ctrl.state.processing ? 'Generating Keys...' : 'Submit'}} + .sk-label {{ctrl.state.processing ? 'Generating Keys...' : 'Submit'}} + + .sk-panel-footer(ng-if="ctrl.state.showForgotPasscodeLink") + a.sk-panel-row.sk-a.info.centered( + ng-if="!ctrl.state.forgotPasscode" + ng-click="ctrl.onForgotPasscodeClick()" + ) Forgot your passcode? + p.sk-panel-row.sk-p(ng-if="ctrl.state.forgotPasscode"). + {{ + ctrl.state.hasAccount + ? "If you forgot your local passcode, your only option is to clear + your local data from this device and sign back in to your account." + : "If you forgot your local passcode, your only option is + to delete your data." + }} + a.sk-panel-row.sk-a.danger.centered( + ng-if="ctrl.state.forgotPasscode" + ng-click="ctrl.destroyLocalData()" + ) Delete Local Data + .sk-panel-row diff --git a/app/assets/javascripts/views/challenge_modal/challenge_modal.ts b/app/assets/javascripts/views/challenge_modal/challenge_modal.ts index 608f07030..2c372776c 100644 --- a/app/assets/javascripts/views/challenge_modal/challenge_modal.ts +++ b/app/assets/javascripts/views/challenge_modal/challenge_modal.ts @@ -5,9 +5,12 @@ import { ChallengeValue, removeFromArray, Challenge, + ChallengeReason, } from 'snjs'; import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl'; import { WebDirective } from '@/types'; +import { confirmDialog } from '@/services/alertService'; +import { STRING_SIGN_OUT_CONFIRMATION } from '@/strings'; type InputValue = { value: string @@ -19,7 +22,9 @@ type Values = Record type ChallengeModalState = { types: ChallengeType[] values: Partial - processing: boolean + processing: boolean, + forgotPasscode: boolean, + showForgotPasscodeLink: boolean, } class ChallengeModalCtrl extends PureViewCtrl { @@ -27,6 +32,7 @@ class ChallengeModalCtrl extends PureViewCtrl { private processingTypes: ChallengeType[] = [] application!: WebApplication challenge!: Challenge + private cancelable = false /* @ngInject */ constructor( @@ -51,10 +57,15 @@ class ChallengeModalCtrl extends PureViewCtrl { invalid: false }; } + const showForgotPasscodeLink = this.challenge.reason === ChallengeReason.ApplicationUnlock + this.cancelable = !showForgotPasscodeLink this.setState({ - types: types, - values: values, - processing: false + types, + values, + processing: false, + forgotPasscode: false, + showForgotPasscodeLink, + hasAccount: this.application.hasAccount(), }); this.application.setChallengeCallbacks({ challenge: this.challenge, @@ -94,13 +105,29 @@ class ChallengeModalCtrl extends PureViewCtrl { } } + async destroyLocalData() { + if (await confirmDialog({ + text: STRING_SIGN_OUT_CONFIRMATION, + confirmButtonStyle: "danger" + })) { + await this.application.signOut(); + this.dismiss(); + }; + } + cancel() { - // if (!this.cancelable) { - // return; - // } + if (!this.cancelable) { + return; + } this.dismiss(); } + onForgotPasscodeClick() { + this.setState({ + forgotPasscode: true + }); + } + onTextValueChange(challenge: ChallengeType) { const values = this.getState().values; values[challenge]!.invalid = false; diff --git a/app/assets/stylesheets/_modals.scss b/app/assets/stylesheets/_modals.scss index cb29d8caf..faf3e89dd 100644 --- a/app/assets/stylesheets/_modals.scss +++ b/app/assets/stylesheets/_modals.scss @@ -12,7 +12,15 @@ } #privileges-modal { - width: 700px; + width: 400px; + + input { + text-align: center; + } + + .sk-panel-header { + justify-content: center; + } table { margin-bottom: 12px;