mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 09:13:33 +00:00
[PM-8214] New Device Verification Notice UI (#12360)
* starting * setup first page for new device verification notice * update designs for first page. rename components and files * added second page for new device verification notice * update notice page one with bit radio buttons. routing logic. user email * updated routing for new device verification notice to show before vault based on flags, and can navigate back to vault after submission * fix translations. added remind me later link and nav to page 2 * sync the design for mobile and web * update routes in desktop * updated styles for desktop * moved new device verification notice guard * update types for new device notice page one * add null check to page one * types * types for page one, page two, service, and guard * types * update component and guard for null check * add navigation to two step login btn and account email btn * remove empty file * update fill of icons to support light & dark modes * add question mark to email access verification copy * remove unused map * use links for navigation elements - an empty href is needed so the links are keyboard accessible * remove clip path from exclamation svg - No noticeable difference in the end result * inline email message into markup --------- Co-authored-by: Nick Krantz <nick@livefront.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<p class="tw-text-center" bitTypography="body1">
|
||||
{{ "newDeviceVerificationNoticeContentPage1" | i18n }}
|
||||
</p>
|
||||
|
||||
<bit-card
|
||||
class="tw-pb-0"
|
||||
[ngClass]="{
|
||||
'tw-flex tw-flex-col tw-items-center !tw-rounded-b-none': isDesktop,
|
||||
'md:tw-flex md:tw-flex-col md:tw-items-center md:!tw-rounded-b-none': !isDesktop,
|
||||
}"
|
||||
>
|
||||
<p bitTypography="body2" class="text-muted md:tw-w-9/12">
|
||||
{{ "newDeviceVerificationNoticePageOneFormContent" | i18n: this.currentEmail }}
|
||||
</p>
|
||||
|
||||
<bit-radio-group formControlName="hasEmailAccess" class="md:tw-w-9/12">
|
||||
<bit-radio-button id="option_A" [value]="0">
|
||||
<bit-label>{{ "newDeviceVerificationNoticePageOneEmailAccessNo" | i18n }}</bit-label>
|
||||
</bit-radio-button>
|
||||
<bit-radio-button id="option_B" [value]="1">
|
||||
<bit-label>{{ "newDeviceVerificationNoticePageOneEmailAccessYes" | i18n }}</bit-label>
|
||||
</bit-radio-button>
|
||||
</bit-radio-group>
|
||||
</bit-card>
|
||||
|
||||
<button bitButton type="submit" buttonType="primary" class="tw-w-full tw-mt-4">
|
||||
{{ "continue" | i18n }}
|
||||
</button>
|
||||
</form>
|
||||
@@ -0,0 +1,82 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, ReactiveFormsModule } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
RadioButtonModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { NewDeviceVerificationNoticeService } from "./../../services/new-device-verification-notice.service";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "app-new-device-verification-notice-page-one",
|
||||
templateUrl: "./new-device-verification-notice-page-one.component.html",
|
||||
imports: [
|
||||
CardComponent,
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
TypographyModule,
|
||||
ButtonModule,
|
||||
RadioButtonModule,
|
||||
FormFieldModule,
|
||||
AsyncActionsModule,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
})
|
||||
export class NewDeviceVerificationNoticePageOneComponent implements OnInit {
|
||||
protected formGroup = this.formBuilder.group({
|
||||
hasEmailAccess: new FormControl(0),
|
||||
});
|
||||
protected isDesktop: boolean;
|
||||
readonly currentAcct$: Observable<Account | null> = this.accountService.activeAccount$;
|
||||
protected currentEmail: string = "";
|
||||
private currentUserId: UserId | null = null;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private newDeviceVerificationNoticeService: NewDeviceVerificationNoticeService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
) {
|
||||
this.isDesktop = this.platformUtilsService.getClientType() === ClientType.Desktop;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const currentAcct = await firstValueFrom(this.currentAcct$);
|
||||
if (!currentAcct) {
|
||||
return;
|
||||
}
|
||||
this.currentEmail = currentAcct.email;
|
||||
this.currentUserId = currentAcct.id;
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
if (this.formGroup.controls.hasEmailAccess.value === 0) {
|
||||
await this.router.navigate(["new-device-notice/setup"]);
|
||||
} else if (this.formGroup.controls.hasEmailAccess.value === 1) {
|
||||
await this.newDeviceVerificationNoticeService.updateNewDeviceVerificationNoticeState(
|
||||
this.currentUserId,
|
||||
{
|
||||
last_dismissal: new Date(),
|
||||
permanent_dismissal: false,
|
||||
},
|
||||
);
|
||||
|
||||
await this.router.navigate(["/vault"]);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<p class="tw-text-center" bitTypography="body1">
|
||||
{{ "newDeviceVerificationNoticeContentPage2" | i18n }}
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="#"
|
||||
bitButton
|
||||
(click)="navigateToTwoStepLogin($event)"
|
||||
buttonType="primary"
|
||||
class="tw-w-full tw-mt-4"
|
||||
>
|
||||
{{ "turnOnTwoStepLogin" | i18n }}
|
||||
<i
|
||||
class="bwi bwi-external-link bwi-lg bwi-fw"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'md:tw-hidden': !isDesktop }"
|
||||
>
|
||||
</i>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
bitButton
|
||||
(click)="navigateToChangeAcctEmail($event)"
|
||||
buttonType="secondary"
|
||||
class="tw-w-full tw-mt-4"
|
||||
>
|
||||
{{ "changeAcctEmail" | i18n }}
|
||||
<i
|
||||
class="bwi bwi-external-link bwi-lg bwi-fw"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'md:tw-hidden': !isDesktop }"
|
||||
></i>
|
||||
</a>
|
||||
|
||||
<div class="tw-flex tw-justify-center tw-mt-6">
|
||||
<a bitLink linkType="primary" (click)="remindMeLaterSelect()">
|
||||
{{ "remindMeLater" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,95 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import {
|
||||
Environment,
|
||||
EnvironmentService,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { ButtonModule, LinkModule, TypographyModule } from "@bitwarden/components";
|
||||
|
||||
import { NewDeviceVerificationNoticeService } from "../../services/new-device-verification-notice.service";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "app-new-device-verification-notice-page-two",
|
||||
templateUrl: "./new-device-verification-notice-page-two.component.html",
|
||||
imports: [CommonModule, JslibModule, TypographyModule, ButtonModule, LinkModule],
|
||||
})
|
||||
export class NewDeviceVerificationNoticePageTwoComponent implements OnInit {
|
||||
protected isWeb: boolean;
|
||||
protected isDesktop: boolean;
|
||||
readonly currentAcct$: Observable<Account | null> = this.accountService.activeAccount$;
|
||||
private currentUserId: UserId | null = null;
|
||||
private env$: Observable<Environment> = this.environmentService.environment$;
|
||||
|
||||
constructor(
|
||||
private newDeviceVerificationNoticeService: NewDeviceVerificationNoticeService,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private environmentService: EnvironmentService,
|
||||
) {
|
||||
this.isWeb = this.platformUtilsService.getClientType() === ClientType.Web;
|
||||
this.isDesktop = this.platformUtilsService.getClientType() === ClientType.Desktop;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const currentAcct = await firstValueFrom(this.currentAcct$);
|
||||
if (!currentAcct) {
|
||||
return;
|
||||
}
|
||||
this.currentUserId = currentAcct.id;
|
||||
}
|
||||
|
||||
async navigateToTwoStepLogin(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
const env = await firstValueFrom(this.env$);
|
||||
const url = env.getWebVaultUrl();
|
||||
|
||||
if (this.isWeb) {
|
||||
await this.router.navigate(["/settings/security/two-factor"], {
|
||||
queryParams: { fromNewDeviceVerification: true },
|
||||
});
|
||||
} else {
|
||||
this.platformUtilsService.launchUri(
|
||||
url + "/#/settings/security/two-factor/?fromNewDeviceVerification=true",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async navigateToChangeAcctEmail(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
const env = await firstValueFrom(this.env$);
|
||||
const url = env.getWebVaultUrl();
|
||||
if (this.isWeb) {
|
||||
await this.router.navigate(["/settings/account"], {
|
||||
queryParams: { fromNewDeviceVerification: true },
|
||||
});
|
||||
} else {
|
||||
this.platformUtilsService.launchUri(
|
||||
url + "/#/settings/account/?fromNewDeviceVerification=true",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async remindMeLaterSelect() {
|
||||
await this.newDeviceVerificationNoticeService.updateNewDeviceVerificationNoticeState(
|
||||
this.currentUserId,
|
||||
{
|
||||
last_dismissal: new Date(),
|
||||
permanent_dismissal: false,
|
||||
},
|
||||
);
|
||||
|
||||
await this.router.navigate(["/vault"]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user