Commit e373fff4 authored by David Burke's avatar David Burke

Moved accounts to be a lazy loaded module

parent 60db0508
Pipeline #51153311 (#2285) failed with stage
in 6 minutes and 16 seconds
......@@ -8259,7 +8259,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
......@@ -8277,11 +8278,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
......@@ -8294,15 +8297,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
......@@ -8405,7 +8411,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
......@@ -8415,6 +8422,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
......@@ -8427,17 +8435,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
......@@ -8454,6 +8465,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
......@@ -8526,7 +8538,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
......@@ -8536,6 +8549,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
......@@ -8611,7 +8625,8 @@
},
"safe-buffer": {
"version": "5.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
......@@ -8641,6 +8656,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
......@@ -8658,6 +8674,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
......@@ -8696,11 +8713,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true
"bundled": true,
"optional": true
}
}
},
......@@ -12566,7 +12585,7 @@
},
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
"resolved": "http://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
"integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
"dev": true,
"requires": {
......@@ -12582,13 +12601,13 @@
},
"shelljs": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.0.tgz",
"resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.6.0.tgz",
"integrity": "sha1-zh7YN7Sw5Vtew9q4QlGrnb3Ax+w=",
"dev": true
},
"tapable": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz",
"integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==",
"dev": true
},
......@@ -12803,7 +12822,7 @@
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
"dev": true
},
......@@ -16045,7 +16064,7 @@
"dependencies": {
"convert-source-map": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
"resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
"integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=",
"dev": true
}
......
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { routes } from "./account.common";
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AccountRoutingModule {}
import { Routes } from "@angular/router";
import { AlreadyLoggedInGuard } from "../guards";
import { AccountComponent } from "./account.component";
import { ChangePasswordContainer } from "./change-password";
import { ForgotLearnMoreContainer } from "./change-password/forgot-learn-more/forgot-learn-more.container";
import { ManageBackupCodeContainer } from "./manage-backup-code/manage-backup-code.container";
import { ErrorReportingContainer } from "./error-reporting/error-reporting.container";
import { DeleteContainer } from "./delete/delete.container";
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 { ResetPasswordVerifyContainer } from "./reset-password/reset-password-verify/reset-password-verify.container";
import { SetPasswordContainer } from "./reset-password/set-password/set-password.container";
import { LoginContainer } from "./login/login.container";
export const routes: Routes = [
{
path: "login",
component: LoginContainer,
// canActivate: [AlreadyLoggedInGuard],
data: {
title: "Log In",
showNavBar: false
}
},
{
path: "",
component: AccountComponent,
data: {
title: "Account Management"
}
},
{
path: "change-password",
component: ChangePasswordContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Change Account Password"
}
},
{
path: "forgot-password",
component: ForgotLearnMoreContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Forgot Your Password?"
}
},
{
path: "change-backup-code",
component: ManageBackupCodeContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Change Backup Code"
}
},
{
path: "error-reporting",
component: ErrorReportingContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Error Reporting"
}
},
{
path: "delete",
component: DeleteContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Delete Account"
}
},
{
path: "register",
component: RegisterContainer,
canActivate: [AlreadyLoggedInGuard],
data: {
title: "Register",
showNavBar: false
}
},
{
path: "confirm-email",
component: ConfirmEmailContainer,
canActivate: [ConfirmEmailGuard],
data: {
title: "Confirm Email"
}
},
{
path: "confirm-email/:code",
component: ConfirmEmailContainer,
data: {
title: "Confirm Email"
}
},
{
path: "reset-password",
component: ResetPasswordContainer,
canActivate: [AlreadyLoggedInGuard],
data: {
title: "Reset Password",
showNavBar: false
}
},
{
path: "reset-password-verify",
component: ResetPasswordVerifyContainer,
data: {
title: "Reset Password",
showNavBar: false
}
},
{
path: "reset-password/set-password",
component: SetPasswordContainer,
// canActivate: [LoggedInGuard],
data: {
title: "Set Account Password",
showNavBar: false
}
}
];
......@@ -15,8 +15,7 @@ import {
AccountActionTypes,
LoginAction,
LoginFailureAction,
LoginSuccessAction,
LogoutSuccessAction
LoginSuccessAction
} from "./account.actions";
import * as fromAccount from "./account.reducer";
......@@ -76,41 +75,6 @@ export class LoginEffects {
})
);
@Effect({ dispatch: false })
loginRedirect$ = this.actions$.pipe(
ofType(
AccountActionTypes.LOGIN_REDIRECT,
AccountActionTypes.LOGOUT_SUCCESS
),
tap(() => {
this.router.navigate(["/login"], { replaceUrl: true });
})
);
@Effect()
logout$ = this.actions$.pipe(
ofType(AccountActionTypes.LOGOUT),
exhaustMap(() =>
this.userService
.logout()
.then(() => new LogoutSuccessAction())
.catch(() => new LogoutSuccessAction())
)
);
@Effect({ dispatch: false })
logoutSuccess$ = this.actions$.pipe(
ofType(AccountActionTypes.LOGOUT_SUCCESS),
tap(() => localStorage.clear()),
tap(() => this.router.navigate(["/login"]))
);
@Effect({ dispatch: false })
userMustConfirmEmail$ = this.actions$.pipe(
ofType(AccountActionTypes.USER_MUST_CONFIRM_EMAIL),
tap(() => this.router.navigate(["/confirm-email"]))
);
constructor(
private actions$: Actions,
private userService: UserService,
......
......@@ -54,6 +54,7 @@ import { ForgotLearnMoreComponent } from "./change-password/forgot-learn-more/fo
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
import { UserService } from "./user";
import { DeleteEffects } from "./delete/delete.effects";
import { AccountRoutingModule } from "./account-routing.module";
export const COMPONENTS = [
LoginContainer,
......@@ -112,7 +113,8 @@ export const SERVICES = [BackupCodePdfService, UserService, ConfirmEmailGuard];
ManageBackupCodeEffects,
ChangePasswordEffects,
DeleteEffects
])
]),
AccountRoutingModule
],
declarations: COMPONENTS,
exports: COMPONENTS,
......
......@@ -3,18 +3,8 @@ import {
createSelector,
ActionReducerMap
} from "@ngrx/store";
import { AccountActions, AccountActionTypes } from "./account.actions";
import * as fromConfirmEmail from "./confirm-email/confirm-email.reducer";
import * as fromLogin from "./login/login.reducer";
import {
RegisterActionTypes,
RegisterAction,
RegisterSuccessAction
} from "./register/register.actions";
import {
ErrorReportingTypes,
ErrorReportingActionsUnion
} from "./error-reporting/error-reporting.actions";
import * as fromRegister from "./register/register.reducer";
import * as fromChangePassword from "./change-password/change-password.reducer";
import * as fromDeleteAccount from "./delete/delete.reducer";
......@@ -22,117 +12,9 @@ import * as fromErrorReporting from "./error-reporting/error-reporting.reducer";
import * as fromResetPassword from "./reset-password/reset-password.reducer";
import * as fromResetPasswordVerify from "./reset-password/reset-password-verify/reset-password-verify.reducer";
import * as fromSetPassword from "./reset-password/set-password/set-password.reducer";
import {
ResetPasswordVerifyActionTypes,
ResetPasswordVerifyActionsUnion
} from "./reset-password/reset-password-verify/reset-password-verify.actions";
import {
SetPasswordSuccess,
SetPasswordActionTypes,
ForceSetPassword
} from "./reset-password/set-password/set-password.actions";
import * as fromManageBackupCode from "./manage-backup-code/manage-backup-code.reducer";
import {
ChangePasswordSubmitFormSuccess,
ChangePasswordActionTypes
} from "./change-password/change-password.actions";
export interface IAuthState {
email: string | null;
userId: number | null;
url: string | null;
userToken: string | null;
privateKey: string | null;
publicKey: string | null;
rememberMe: boolean;
optInErrorReporting: boolean;
/** Always redirect logged in user to set password page */
forceSetPassword: boolean;
}
export const initialState: IAuthState = {
email: null,
userId: null,
url: null,
userToken: null,
privateKey: null,
publicKey: null,
rememberMe: false,
optInErrorReporting: false,
forceSetPassword: false
};
export function authReducer(
state = initialState,
action:
| AccountActions
| RegisterAction
| RegisterSuccessAction
| ErrorReportingActionsUnion
| ResetPasswordVerifyActionsUnion
| SetPasswordSuccess
| ForceSetPassword
| ChangePasswordSubmitFormSuccess
): IAuthState {
switch (action.type) {
case AccountActionTypes.LOGIN:
case RegisterActionTypes.REGISTER:
// Clear any stale state (except the url)
return { ...initialState, url: state.url };
case AccountActionTypes.LOGIN_SUCCESS:
case RegisterActionTypes.REGISTER_SUCCESS:
case ResetPasswordVerifyActionTypes.VERIFY_AND_LOGIN_SUCCESS:
return {
...state,
email: action.payload.email,
userId: action.payload.userId,
userToken: action.payload.userToken,
privateKey: action.payload.privateKey,
publicKey: action.payload.publicKey,
rememberMe: action.payload.rememberMe,
optInErrorReporting: action.payload.optInErrorReporting
};
case ChangePasswordActionTypes.SUBMIT_FORM_SUCCESS:
return {
...state,
userToken: action.payload.token,
privateKey: action.payload.privateKey,
publicKey: action.payload.publicKey
};
case AccountActionTypes.SET_URL:
return {
...state,
url: action.payload
};
case SetPasswordActionTypes.SET_PASSWORD_SUCCESS:
return {
...state,
forceSetPassword: false
};
case ErrorReportingTypes.SAVE_FORM_SUCCESS:
return {
...state,
optInErrorReporting: action.payload.opt_in_error_reporting
};
case SetPasswordActionTypes.FORCE_SET_PASSWORD:
return {
...state,
forceSetPassword: true
};
default:
return state;
}
}
export interface IAccountState {
auth: IAuthState;
login: fromLogin.ILoginState;
register: fromRegister.IRegisterState;
confirmEmail: fromConfirmEmail.IConfirmEmailState;
......@@ -146,7 +28,6 @@ export interface IAccountState {
}
export const reducers: ActionReducerMap<IAccountState> = {
auth: authReducer,
login: fromLogin.reducer,
register: fromRegister.reducer,
confirmEmail: fromConfirmEmail.reducer,
......@@ -183,39 +64,6 @@ export const getLoginForm = createSelector(
fromLogin.getForm
);
export const selectAuthState = createSelector(
selectAccountState,
(state: IAccountState) => state.auth
);
export const getIsLoggedIn = createSelector(
selectAuthState,
(state: IAuthState) => (state.userToken ? true : false)
);
export const getToken = createSelector(
selectAuthState,
(state: IAuthState) => state.userToken
);
export const getEmail = createSelector(
selectAuthState,
(state: IAuthState) => state.email
);
export const getForceUserSetPassword = createSelector(
selectAuthState,
(state: IAuthState) => state.forceSetPassword && state.userToken // Sanity check user is logged in
);
export const getUserId = createSelector(
selectAuthState,
(state: IAuthState) => state.userId
);
export const getUrl = createSelector(
selectAuthState,
(state: IAuthState) => state.url
);
export const getOptInErrorReporting = createSelector(
selectAuthState,
(state: IAuthState) => state.optInErrorReporting
);
export const getLoginState = (state: IAccountState) => state.login;
export const selectRegisterState = createSelector(
......
......@@ -4,15 +4,18 @@ import * as fromErrorReporting from "./error-reporting.reducer";
import { Store, select } from "@ngrx/store";
import { SaveForm } from "./error-reporting.actions";
import { SetValueAction } from "ngrx-forms";
import { getOptInErrorReporting } from "../../app.reducers";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<app-error-reporting
[form]="form$ | async"
[hasStarted]="hasStarted$ | async"
[hasFinished]="hasFinished$ | async"
(submit)="submit()"
></app-error-reporting>`
template: `
<app-error-reporting
[form]="form$ | async"
[hasStarted]="hasStarted$ | async"
[hasFinished]="hasFinished$ | async"
(submit)="submit()"
></app-error-reporting>
`
})
export class ErrorReportingContainer implements OnInit {
form$ = this.store.pipe(select(fromAccount.getErrorReportingForm));
......@@ -26,7 +29,7 @@ export class ErrorReportingContainer implements OnInit {
constructor(private store: Store<any>) {
this.store
.pipe(select(fromAccount.getOptInErrorReporting))
.pipe(select(getOptInErrorReporting))
.subscribe(optIn => (this.optInErrorReporting = optIn));
}
......
......@@ -6,7 +6,7 @@
<app-text-link
caret="right"
id="btn-signup"
[link]="['/login']"
[link]="['/account/login']"
(click)="toggleDisplay()"
>
Already&nbsp;registered? Log&nbsp;in
......@@ -90,10 +90,7 @@
>
<li *ngIf="isEmailTaken" class="form-field__error">
There is already an account registered with this email address.
<app-text-link
(click)="goToLoginWith()"
caret="right"
>
<app-text-link (click)="goToLoginWith()" caret="right">
Log in?
</app-text-link>
</li>
......
<app-marketing-frame
headline="Regain peace of mind for your passwords"
tagline="Remember the backup code you saved or printed when you signed up? Here’s where you&nbsp;use&nbsp;it.">
tagline="Remember the backup code you saved or printed when you signed up? Here’s where you&nbsp;use&nbsp;it."
>
<div class="account-column__inner account-column__inner--right">
<div class="account-column__right-heading">
<h1 class="heading-medium">Reset&nbsp;Password</h1>
<div class="account-column__link">
<app-text-link
id="btn-signin"
[link]="['/login']"
>
<app-text-link id="btn-signin" [link]="['/account/login']">
Back to Login
</app-text-link>
</div>
......@@ -17,55 +14,76 @@
<div class="register-step__heading--completed u-margin-b-20">
Email
<span class="register-step__icon register-step__icon--active" [inlineSVG]="'../../assets/svg/check.svg'"></span>
<span
class="register-step__icon register-step__icon--active"
[inlineSVG]="'../../assets/svg/check.svg'"
></span>
</div>
<div class="register-step__heading--completed u-margin-b-20">
Confirm Email Address
<span class="register-step__icon register-step__icon--active" [inlineSVG]="'../../assets/svg/check.svg'"></span>
<span
class="register-step__icon register-step__icon--active"
[inlineSVG]="'../../assets/svg/check.svg'"
></span>
</div>
<div class="form-field form-field--large">
<div class="form-field__label">
Enter Backup Code
</div>
<p class="register-step__feedback">When you signed up for your account, you were given the option to print or save a PDF file that contained your
backup code. Pull that up and either scan the QR code or enter the 32-character code below.</p>
<div class="form-field__label">Enter Backup Code</div>
<p class="register-step__feedback">
When you signed up for your account, you were given the option to print
or save a PDF file that contained your backup code. Pull that up and
either scan the QR code or enter the 32-character code below.
</p>
</div>
<app-non-field-messages *ngIf="errorMessage || localErrorMessage" [messages]="[errorMessage, localErrorMessage]"></app-non-field-messages>
<app-non-field-messages
*ngIf="errorMessage || localErrorMessage"
[messages]="[errorMessage, localErrorMessage]"
></app-non-field-messages>
<div class="u-margin-b-20" *ngIf="!cameraError">
<button id="scan-qr-button" (click)="toggleScan()" class="button button--primary">Scan QR Code</button>
<button
id="scan-qr-button"
(click)="toggleScan()"
class="button button--primary"
>
Scan QR Code
</button>
<span class="text-next-to-button u-margin-l-20">or</span>
</div>
<div [class.u-invisible]="!showScanner" class="canvas-check-wrapper">
<canvas #canvas id="canvas" class="canvas"></canvas>
<div class="close-wrapper" *ngIf="showQuitButton && !hasStarted" (click)="toggleScan()">
<div