From e277eefcb27cc6d859b3e3935812dc76b2157a25 Mon Sep 17 00:00:00 2001 From: Drew Ansbacher Date: Tue, 10 Aug 2021 10:35:59 -0600 Subject: [PATCH] complete flow --- setup-wizard/src/app/app-routing.module.ts | 4 ++ .../src/app/pages/embassy/embassy.page.ts | 30 ++++++++++--- .../pages/loading/loading-routing.module.ts | 16 +++++++ .../src/app/pages/loading/loading.module.ts | 19 ++++++++ .../src/app/pages/loading/loading.page.html | 36 +++++++++++++++ .../src/app/pages/loading/loading.page.scss | 43 ++++++++++++++++++ .../src/app/pages/loading/loading.page.ts | 45 +++++++++++++++++++ .../src/app/pages/password/password.page.html | 15 +++---- .../src/app/pages/password/password.page.ts | 29 +++++++++--- .../src/app/pages/recover/recover.page.html | 12 ----- .../src/app/pages/recover/recover.page.ts | 3 +- .../src/app/services/api/api.service.ts | 9 ++-- .../src/app/services/api/mock-api.service.ts | 20 +++------ .../src/app/services/state.service.ts | 21 +++++++-- setup-wizard/src/global.scss | 10 +++++ 15 files changed, 257 insertions(+), 55 deletions(-) create mode 100644 setup-wizard/src/app/pages/loading/loading-routing.module.ts create mode 100644 setup-wizard/src/app/pages/loading/loading.module.ts create mode 100644 setup-wizard/src/app/pages/loading/loading.page.html create mode 100644 setup-wizard/src/app/pages/loading/loading.page.scss create mode 100644 setup-wizard/src/app/pages/loading/loading.page.ts diff --git a/setup-wizard/src/app/app-routing.module.ts b/setup-wizard/src/app/app-routing.module.ts index 7348a7dc9..e478807fc 100644 --- a/setup-wizard/src/app/app-routing.module.ts +++ b/setup-wizard/src/app/app-routing.module.ts @@ -13,6 +13,10 @@ const routes: Routes = [ path: 'embassy', loadChildren: () => import('./pages/embassy/embassy.module').then( m => m.EmbassyPageModule), }, + { + path: 'loading', + loadChildren: () => import('./pages/loading/loading.module').then( m => m.LoadingPageModule), + }, ]; @NgModule({ diff --git a/setup-wizard/src/app/pages/embassy/embassy.page.ts b/setup-wizard/src/app/pages/embassy/embassy.page.ts index e9089929e..1e38156a2 100644 --- a/setup-wizard/src/app/pages/embassy/embassy.page.ts +++ b/setup-wizard/src/app/pages/embassy/embassy.page.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core' -import { ModalController, NavController } from '@ionic/angular' +import { AlertController, ModalController, NavController } from '@ionic/angular' import { ApiService, EmbassyDrive } from 'src/app/services/api/api.service' import { StateService } from 'src/app/services/state.service' import { PasswordPage } from '../password/password.page' @@ -18,7 +18,8 @@ export class EmbassyPage { private readonly apiService: ApiService, private readonly navCtrl: NavController, private modalController: ModalController, - private stateService: StateService + private stateService: StateService, + private readonly alertCtrl: AlertController, ) {} async ngOnInit() { @@ -30,12 +31,31 @@ export class EmbassyPage { const modal = await this.modalController.create({ component: PasswordPage, componentProps: { - embassyDrive: drive, - verify: false + embassyDrive: drive } }) modal.onDidDismiss().then(async ret => { - if (!ret.data) return + if (!ret.data && !ret.data.success) return + + if(!!this.stateService.recoveryDrive) { + await this.navCtrl.navigateForward(`/loading`, { animationDirection: 'forward' }) + } else { + const alert = await this.alertCtrl.create({ + cssClass: 'success-alert', + header: 'Success!', + subHeader: `Your Embassy is set up and ready to go.`, + backdropDismiss: false, + buttons: [ + { + text: 'Go To Embassy', + handler: () => { + window.location.reload() + } + } + ] + }) + await alert.present() + } }) await modal.present(); } diff --git a/setup-wizard/src/app/pages/loading/loading-routing.module.ts b/setup-wizard/src/app/pages/loading/loading-routing.module.ts new file mode 100644 index 000000000..615b57e24 --- /dev/null +++ b/setup-wizard/src/app/pages/loading/loading-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { LoadingPage } from './loading.page'; + +const routes: Routes = [ + { + path: '', + component: LoadingPage, + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LoadingPageRoutingModule {} diff --git a/setup-wizard/src/app/pages/loading/loading.module.ts b/setup-wizard/src/app/pages/loading/loading.module.ts new file mode 100644 index 000000000..886cb4594 --- /dev/null +++ b/setup-wizard/src/app/pages/loading/loading.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { FormsModule } from '@angular/forms'; +import { LoadingPage } from './loading.page'; +import { PasswordPageModule } from '../password/password.module'; +import { LoadingPageRoutingModule } from './loading-routing.module'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + IonicModule, + LoadingPageRoutingModule, + PasswordPageModule, + ], + declarations: [LoadingPage] +}) +export class LoadingPageModule {} diff --git a/setup-wizard/src/app/pages/loading/loading.page.html b/setup-wizard/src/app/pages/loading/loading.page.html new file mode 100644 index 000000000..a63cbd3d3 --- /dev/null +++ b/setup-wizard/src/app/pages/loading/loading.page.html @@ -0,0 +1,36 @@ + + + + + +
+ +
+ + + + Loading Embassy + Progress: {{(stateService.dataProgress * 100).toFixed(0) }}% + + + + + + + +
+
+
+
+ + \ No newline at end of file diff --git a/setup-wizard/src/app/pages/loading/loading.page.scss b/setup-wizard/src/app/pages/loading/loading.page.scss new file mode 100644 index 000000000..506e177dd --- /dev/null +++ b/setup-wizard/src/app/pages/loading/loading.page.scss @@ -0,0 +1,43 @@ +.selected { + border: 4px solid gray; +} +ion-card-title { + margin: 24px 0; + font-family: 'Montserrat'; + font-size: x-large; + --color: var(--ion-color-light); +} + +ion-item { + --border-radius: 4px; + --border-style: solid; + --border-width: 1px; + --border-color: var(--ion-color-light); +} + +.input-label { + text-align: left; + padding-bottom: 2px; + font-size: small; + color: var(--ion-color-light); + font-weight: bold; +} + +.claim-button { + margin-inline-start: 0; + margin-inline-end: 0; + margin-top: 24px; + height: 48px; + --background: linear-gradient(45deg, var(--ion-color-light) 16%, var(--ion-color-medium) 150%); +} + +.card-footer { + text-align: left; + --background: rgb(222, 222, 222); + border-top: solid; + border-width: 1px; + border-color: var(--ion-color-medium); + ion-item { + --border-color: var(--ion-color-medium); + } +} \ No newline at end of file diff --git a/setup-wizard/src/app/pages/loading/loading.page.ts b/setup-wizard/src/app/pages/loading/loading.page.ts new file mode 100644 index 000000000..91184d906 --- /dev/null +++ b/setup-wizard/src/app/pages/loading/loading.page.ts @@ -0,0 +1,45 @@ +import { Component } from '@angular/core' +import { AlertController, NavController } from '@ionic/angular' +import { BehaviorSubject } from 'rxjs' +import { StateService } from 'src/app/services/state.service' + +@Component({ + selector: 'loading', + templateUrl: 'loading.page.html', + styleUrls: ['loading.page.scss'], +}) +export class LoadingPage { + constructor( + private stateService: StateService, + private alertCtrl: AlertController + ) {} + + ngOnInit () { + this.stateService.pollDataTransferProgress() + const progSub = this.stateService.dataProgSubject.subscribe(async progress => { + if(progress === 1) { + await this.successAlert() + progSub.unsubscribe() + } + }) + } + + async successAlert () { + const alert = await this.alertCtrl.create({ + cssClass: 'success-alert', + header: 'Success!', + subHeader: `Your Embassy is set up and ready to go.`, + backdropDismiss: false, + buttons: [ + { + text: 'Go To Embassy', + handler: () => { + window.location.reload() + } + } + ] + }) + await alert.present() + } +} + diff --git a/setup-wizard/src/app/pages/password/password.page.html b/setup-wizard/src/app/pages/password/password.page.html index cac59071c..538bfdc5e 100644 --- a/setup-wizard/src/app/pages/password/password.page.html +++ b/setup-wizard/src/app/pages/password/password.page.html @@ -1,27 +1,26 @@ - Verify Recovery Drive Password - Set Password + Verify Recovery Drive Password + Set Password
- +

Password:

-
+

Warning: After submit, any data currently stored on {{ embassyDrive.labels.length ? embassyDrive.labels.join(' / ') : embassyDrive.logicalname }} will be wiped.

Password:

Verify Password:

Cancel - - {{ verify ? 'Verify Password' : 'Submit' }} + + {{ !recoveryDrive ? 'Verify Password' : 'Submit' }} diff --git a/setup-wizard/src/app/pages/password/password.page.ts b/setup-wizard/src/app/pages/password/password.page.ts index a33266b88..4ef50f274 100644 --- a/setup-wizard/src/app/pages/password/password.page.ts +++ b/setup-wizard/src/app/pages/password/password.page.ts @@ -1,6 +1,7 @@ import { Component, Input } from '@angular/core' import { LoadingController, ModalController } from '@ionic/angular' import { ApiService, EmbassyDrive, RecoveryDrive } from 'src/app/services/api/api.service' +import { StateService } from 'src/app/services/state.service' @Component({ selector: 'password', @@ -10,7 +11,6 @@ import { ApiService, EmbassyDrive, RecoveryDrive } from 'src/app/services/api/ap export class PasswordPage { @Input() recoveryDrive: RecoveryDrive @Input() embassyDrive: EmbassyDrive - @Input() verify: boolean error = '' password = '' @@ -19,7 +19,8 @@ export class PasswordPage { constructor( private modalController: ModalController, private apiService: ApiService, - private loadingCtrl: LoadingController + private loadingCtrl: LoadingController, + private stateService: StateService ) {} ngOnInit() { } @@ -48,16 +49,34 @@ export class PasswordPage { async submitPw () { this.validate() + if (!this.error && this.password !== this.passwordVer) { + this.error="*passwords dont match" + } + if(this.error) return + const loader = await this.loadingCtrl.create({ + message: 'Setting up your Embassy!' + }) + + await loader.present() + this.stateService.embassyDrive = this.embassyDrive + this.stateService.embassyPassword = this.password + + try { + await this.stateService.setupEmbassy() + this.modalController.dismiss({ success: true }) + } catch (e) { + this.error = e.message + } finally { + loader.dismiss() + } } validate () { if (this.password.length < 12) { - this.error="*passwords must be 12 characters or greater" - } else if (this.password !== this.passwordVer) { - this.error="*passwords dont match" + this.error="*password must be 12 characters or greater" } else { this.error = '' } diff --git a/setup-wizard/src/app/pages/recover/recover.page.html b/setup-wizard/src/app/pages/recover/recover.page.html index 4f5f15765..59db3c6d7 100644 --- a/setup-wizard/src/app/pages/recover/recover.page.html +++ b/setup-wizard/src/app/pages/recover/recover.page.html @@ -60,18 +60,6 @@ Next - - diff --git a/setup-wizard/src/app/pages/recover/recover.page.ts b/setup-wizard/src/app/pages/recover/recover.page.ts index f61d62685..63a9f91be 100644 --- a/setup-wizard/src/app/pages/recover/recover.page.ts +++ b/setup-wizard/src/app/pages/recover/recover.page.ts @@ -41,8 +41,7 @@ export class RecoverPage { const modal = await this.modalController.create({ component: PasswordPage, componentProps: { - recoveryDrive: this.selectedDrive, - verify: true + recoveryDrive: this.selectedDrive } }) modal.onDidDismiss().then(async ret => { diff --git a/setup-wizard/src/app/services/api/api.service.ts b/setup-wizard/src/app/services/api/api.service.ts index b9ed35fc7..fa371189f 100644 --- a/setup-wizard/src/app/services/api/api.service.ts +++ b/setup-wizard/src/app/services/api/api.service.ts @@ -4,12 +4,15 @@ export abstract class ApiService { protected error$: Subject = new Subject(); watchError$ = this.error$.asObservable(); abstract getEmbassyDrives (): Promise; - abstract selectEmbassyDrive (logicalName: string): Promise; abstract getRecoveryDrives (): Promise; - abstract selectRecoveryDrive (logicalName: string, password: string): Promise; abstract getDataTransferProgress (): Promise; - abstract submitPassword (password: string): Promise; abstract verifyRecoveryPassword (logicalname: string, password: string): Promise; + abstract setupEmbassy (setupInfo: { + embassyLogicalname: string, + embassyPassword: string + recoveryLogicalname?: string, + recoveryPassword?: string + }): Promise } export interface TransferProgress { diff --git a/setup-wizard/src/app/services/api/mock-api.service.ts b/setup-wizard/src/app/services/api/mock-api.service.ts index e69218543..475bf6f3d 100644 --- a/setup-wizard/src/app/services/api/mock-api.service.ts +++ b/setup-wizard/src/app/services/api/mock-api.service.ts @@ -58,11 +58,6 @@ export class MockApiService extends ApiService { ] } - async selectEmbassyDrive(drive) { - await pauseFor(2000) - return - } - async getRecoveryDrives() { await pauseFor(2000) return [ @@ -79,20 +74,15 @@ export class MockApiService extends ApiService { ] } - async selectRecoveryDrive(logicalName, password) { - await pauseFor(2000) - return - } - - async submitPassword(password) { - await pauseFor(2000) - return - } - async verifyRecoveryPassword(logicalname, password) { await pauseFor(2000) return password.length > 8 } + + async setupEmbassy (setupInfo){ + await pauseFor(2000) + return + } } let tries = 0 diff --git a/setup-wizard/src/app/services/state.service.ts b/setup-wizard/src/app/services/state.service.ts index 1f2957145..87d563c37 100644 --- a/setup-wizard/src/app/services/state.service.ts +++ b/setup-wizard/src/app/services/state.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core' +import { BehaviorSubject } from 'rxjs'; import { ApiService, EmbassyDrive, RecoveryDrive } from './api/api.service' @Injectable({ @@ -8,11 +9,12 @@ export class StateService { polling = false embassyDrive: EmbassyDrive; + embassyPassword: string recoveryDrive: RecoveryDrive; recoveryPassword: string dataTransferProgress: { bytesTransfered: number; totalBytes: number } | null; dataProgress = 0; - + dataProgSubject = new BehaviorSubject(this.dataProgress) constructor( private readonly apiService: ApiService ) {} @@ -21,15 +23,16 @@ export class StateService { this.polling = false this.embassyDrive = null + this.embassyPassword = null this.recoveryDrive = null this.recoveryPassword = null this.dataTransferProgress = null this.dataProgress = 0 } - async pollDataTransferProgress() { + async pollDataTransferProgress(callback?: () => void) { this.polling = true - await pauseFor(7000) + await pauseFor(1000) if ( this.dataTransferProgress?.totalBytes && @@ -43,8 +46,18 @@ export class StateService { } if (this.dataTransferProgress.totalBytes) { this.dataProgress = this.dataTransferProgress.bytesTransfered / this.dataTransferProgress.totalBytes + this.dataProgSubject.next(this.dataProgress) } - this.pollDataTransferProgress() + this.pollDataTransferProgress(callback) + } + + async setupEmbassy () { + await this.apiService.setupEmbassy({ + embassyLogicalname: this.embassyDrive.logicalname, + embassyPassword: this.embassyPassword, + recoveryLogicalname: this.recoveryDrive?.logicalname, + recoveryPassword: this.recoveryPassword + }) } } diff --git a/setup-wizard/src/global.scss b/setup-wizard/src/global.scss index 8597f7fd0..467d346a4 100644 --- a/setup-wizard/src/global.scss +++ b/setup-wizard/src/global.scss @@ -69,4 +69,14 @@ ion-item { font-size: 28px; margin-right: 10px; } +} + +.success-alert .alert-wrapper { + box-shadow: 4px 4px 30px var(--ion-color-light); + border: 1px solid rgba(255,255,255,.3); + background: var(--ion-color-light); +} + +.success-alert .alert-title { + color: var(--ion-color-success); } \ No newline at end of file