...
  View open merge request
Commits (18)
......@@ -141,10 +141,13 @@ Basically a file like something.tns.ts will replace the web version of that file
Run `tns run android --bundle` or `tns run android --hmr` for hot reloading.
If using an editor which supports Typescript, make sure to set the tsconfig to tsconfig.tns.ts. You will need to switch it back and forth depending on whether you want the tsconfig for the web app or native app.
** Troubleshooting **
- Delete node modules and generated resources `rm -rf hooks platforms node_modules` then `npm i`
- Force a new apk build `tns build android`
- `java.lang.ClassNotFoundException: com.tns.passit.AutofillService` Force a new apk build `tns build android`.
- `JavaScript heap out of memory` error run `export NODE_OPTIONS=--max-old-space-size=4096`. As mentioned [here](https://docs.nativescript.org/performance-optimizations/bundling-with-webpack#javascript-heap-out-of-memory).
### Technologies used
......
This diff is collapsed.
......@@ -189,3 +189,9 @@ ActionBar,
background-color: #0092a8;
color: #0092a8;
}
.text-link {
font-weight: bold;
color: #0092a8;
text-decoration: underline;
}
......@@ -6,7 +6,6 @@ import { routes } from "./account.common";
import { LoggedInGuard } from "../guards";
import { AccountComponent } from "./account.component";
import { ManageBackupCodeContainer } from "./manage-backup-code/manage-backup-code.container";
import { DeleteContainer } from "./delete/delete.container";
import { ResetPasswordVerifyContainer } from "./reset-password/reset-password-verify/reset-password-verify.container";
import { SetPasswordContainer } from "./reset-password/set-password/set-password.container";
......@@ -21,14 +20,6 @@ export const appRoutes: Routes = [
title: "Account Management"
}
},
{
path: "change-backup-code",
component: ManageBackupCodeContainer,
canActivate: [LoggedInGuard],
data: {
title: "Change Backup Code"
}
},
{
path: "delete",
component: DeleteContainer,
......
......@@ -8,6 +8,7 @@ import { RegisterContainer } from "./register/register.container";
import { ConfirmEmailContainer } from "./confirm-email";
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
import { ResetPasswordContainer } from "./reset-password/reset-password.container";
import { ManageBackupCodeContainer } from "./manage-backup-code/manage-backup-code.container";
export const routes: Routes = [
{
......@@ -18,6 +19,14 @@ export const routes: Routes = [
title: "Change Account Password"
}
},
{
path: "change-backup-code",
component: ManageBackupCodeContainer,
canActivate: [LoggedInGuard],
data: {
title: "Change Backup Code"
}
},
{
path: "forgot-password",
component: ForgotLearnMoreContainer,
......@@ -66,5 +75,5 @@ export const routes: Routes = [
title: "Reset Password",
showNavBar: false
}
},
}
];
......@@ -28,6 +28,7 @@ import { BackupCodePdfService } from "./backup-code-pdf.service";
import { ConfirmEmailComponent, ConfirmEmailContainer } from "./confirm-email";
import { ErrorReportingComponent } from "./error-reporting/error-reporting.component";
import { ErrorReportingContainer } from "./error-reporting/error-reporting.container";
import { ManageBackupCodeContainer } from "./manage-backup-code/manage-backup-code.container";
import {
ChangePasswordComponent,
ChangePasswordContainer
......@@ -63,7 +64,8 @@ export const COMPONENTS = [
ResetPasswordVerifyComponent,
SetPasswordComponent,
ManageBackupCodeComponent,
PasswordInputComponent
PasswordInputComponent,
ManageBackupCodeContainer
];
export const SERVICES = [BackupCodePdfService, UserService, ConfirmEmailGuard];
......
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root"
})
export class BackupCodePdfService {
constructor() {}
/**
* Downloads PDF containing backup code string and matching QR Code
* @param code: 32 character backupcode string
*/
download(code: string) {}
}
<Button text="new-backup-code works!" class="btn btn-primary"></Button>
\ No newline at end of file
<StackLayout #printArea>
<Label class="p-10 m-b-10" text="Backup Code: "></Label>
<Label class="p-10 m-b-10" [text]="code"></Label>
<Button
(tap)="generateBarcode()"
id="barcode"
text="Step 3: Generate Backup Code Page"
></Button>
<Image
#barcodeImg
id="barcode-img"
height="500"
stretch="aspectFill"
class="text-center"
></Image>
<app-button text="Step 4: Print" type="text" (tap)="print()"></app-button>
</StackLayout>
import { Component, Input, ViewChild, ElementRef } from "@angular/core";
import { Printer } from "nativescript-printer";
import { Image } from "tns-core-modules/ui/image";
const ZXing = require("nativescript-zxing");
const ImageSource = require("image-source");
@Component({
selector: "app-download-backup-code",
templateUrl: "./download-backup-code.component.html",
styleUrls: [
"./download-backup-code.component.scss",
"../manage-backup-code.component.scss"
]
})
export class DownloadBackupCodeComponent {
@Input() code: string;
@ViewChild("printArea") printArea: ElementRef;
@ViewChild("barcodeImg") barcodeImg: ElementRef;
generateBarcode() {
if (this.code) {
const barcodeImage = <Image>this.barcodeImg.nativeElement;
const zx = new ZXing();
const newImg = zx.createBarcode({
encode: this.code,
format: ZXing.QR_CODE
});
barcodeImage.imageSource = ImageSource.fromNativeSource(newImg);
} else {
alert("invalid code");
}
}
print() {
const printer = new Printer();
printer.isSupported().then((supported: boolean) => {
printer.printScreen({ view: this.printArea.nativeElement });
});
}
}
<ns-action-bar-container></ns-action-bar-container>
<account-frame
title="Change Backup Code"
submitText="Next"
(onSubmit)="onSubmit()"
>
<Label class="text-label m-b-20" textWrap="true" (tap)="learnMore()">
<FormattedString>
<Span
text="Replace your old backup code with a new one. Not sure what this is? "
></Span>
<Span text="Learn More &#8250;" class="text-link"></Span>
</FormattedString>
</Label>
<app-non-field-errors
*ngIf="nonFieldErrors"
[nonFieldErrors]="nonFieldErrors"
></app-non-field-errors>
<app-text-field
#password
autocorrect="false"
autocapitalizationType="none"
type="password"
label="Verify Password"
returnKeyType="next"
[isFormSubmitted]="form.isSubmitted"
[ngrxFormControl]="form.controls.oldPassword"
></app-text-field>
<progress-indicator
[inProgress]="hasStarted"
inProgressText="Verifying"
></progress-indicator>
<app-download-backup-code
*ngIf="hasFinished"
[code]="backupCode"
></app-download-backup-code>
</account-frame>
import {
Component,
Input,
Output,
ChangeDetectionStrategy,
EventEmitter,
OnDestroy,
ViewChild,
ElementRef
} from "@angular/core";
import { FormGroupState } from "ngrx-forms";
import { IForm } from "./manage-backup-code.reducer";
@Component({
selector: "app-manage-backup-code",
templateUrl: "./manage-backup-code.component.html",
styleUrls: [
"./manage-backup-code.component.scss",
"../account.component.scss",
"../../../styles/_utility.scss"
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ManageBackupCodeComponent implements OnDestroy {
@Input() form: FormGroupState<IForm>;
@Input() errorMessage: string;
@Input() hasStarted: boolean;
@Input() hasFinished: boolean;
@Input() nonFieldErrors: string[];
@Input() backupCode: string;
@Output() newBackupCode = new EventEmitter();
@Output() getBackupPDF = new EventEmitter();
@Output() reset = new EventEmitter();
@Output() toggleShowConfirm = new EventEmitter();
@ViewChild("passwordInput") passwordInput: ElementRef;
onSubmit() {
if (this.form.isValid) {
this.newBackupCode.emit();
}
}
ngOnDestroy() {
this.reset.emit();
}
learnMore() {
alert("TODO: create learn more page and navigate to it");
}
}
......@@ -50,7 +50,7 @@ export class ManageBackupCodeContainer {
}
getBackupPDF() {
this.backupCodeToPdf.download(this.backupCode);
this.backupCodeToPdf.download("this is fine");
}
newBackupCode() {
this.store.dispatch(new SubmitForm());
......
......@@ -140,6 +140,7 @@ export class ResetPasswordVerifyComponent implements OnInit, OnDestroy {
const code = jsQR(imageData.data, imageData.width, imageData.height);
this.showQuitButton = true;
if (code) {
console.log(code.data);
this.handleQrFound(code.data);
}
}
......
......@@ -11,13 +11,13 @@ import { StoreModule } from "@ngrx/store";
import { SharedModule } from "../shared/shared.module";
import { NgrxFormsModule } from "ngrx-forms";
import { ProgressIndicatorModule } from "../progress-indicator/progress-indicator.module";
import { VerifyMfaComponent } from './verify-mfa/verify-mfa.component';
import { VerifyMfaComponent } from "./verify-mfa/verify-mfa.component";
@NgModule({
declarations: [LoginComponent, LoginContainer, VerifyMfaComponent],
imports: [
NativeScriptCommonModule,
StoreModule.forFeature("login", fromLogin.reducer),
StoreModule.forFeature("login", fromLogin.reducers),
EffectsModule.forFeature([LoginEffects, TNSLoginEffects]),
SharedModule,
NgrxFormsModule,
......
......@@ -47,7 +47,8 @@ export class SideDrawer {
templates: [
{ title: "Passwords" },
// {title: "Groups"},
{ title: "Change Account Password" },
{ title: "Change Account Password & Backup Code" },
{ title: "Change Backup Code" },
{ title: "Import" },
{ title: "Export" },
{ title: "Error Reporting" },
......@@ -76,20 +77,23 @@ export class SideDrawer {
);
return;
case 2:
this.zone.run(() => this.router.navigate(["/import"]));
this.zone.run(() => this.router.navigate(["/account/change-backup-code"]));
return;
case 3:
this.zone.run(() => this.router.navigate(["/export"]));
this.zone.run(() => this.router.navigate(["/import"]));
return;
case 4:
this.zone.run(() => this.router.navigate(["/export"]));
return;
case 5:
this.zone.run(() =>
this.router.navigate(["/account/error-reporting"])
);
return;
case 5:
case 6:
this.store.dispatch(new LogoutAction());
return;
case 6:
case 7:
this.zone.run(() =>
this.router.navigate(["/account/forgot-password"])
);
......
......@@ -37,13 +37,11 @@
</FlexboxLayout>
<StackLayout orientation="vertical">
<Label
class="p-10 m-b-10"
<app-non-field-errors
*ngIf="nonFieldErrors"
[text]="nonFieldErrors"
backgroundColor="#f0f0f0"
flexGrow="1"
></Label>
[nonFieldErrors]="nonFieldErrors"
></app-non-field-errors>
<ng-content></ng-content>
</StackLayout>
</StackLayout>
......
import { Component, Input } from "@angular/core";
@Component({
selector: "app-non-field-errors",
template: `
<Label
class="p-10 m-b-10"
[text]="nonFieldErrors"
backgroundColor="#f0f0f0"
flexGrow="1"
></Label>
`
})
export class NonFieldErrorsComponent {
@Input() nonFieldErrors?: string[];
}
......@@ -16,6 +16,7 @@ import { NsCheckboxComponent } from "./ns-checkbox/ns-checkbox.component";
import { ServerSelectComponent } from "./server-select/server-select.component";
import { AccountFrameComponent } from "./account-frame/account-frame.component";
import { BulletListComponent } from "./bullet-list/bullet-list.component.tns";
import { NonFieldErrorsComponent } from "./non-field-errors/non-field-errors.component";
export const COMPONENTS = [
ButtonComponent,
......@@ -29,7 +30,8 @@ export const COMPONENTS = [
TextLinkComponent,
ServerSelectComponent,
AccountFrameComponent,
BulletListComponent
BulletListComponent,
NonFieldErrorsComponent
];
@NgModule({
......
......@@ -4,3 +4,4 @@ declare module "@braintree/sanitize-url" {
declare module "canvg";
declare module "instascan";
declare module "nativescript-zxing";