[PM-7901] added new card view (#10321)

* added new card view
This commit is contained in:
Jason Ng 2024-07-30 15:54:45 -04:00 committed by GitHub
parent cbac5fde11
commit 80af356fd1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 186 additions and 62 deletions

View File

@ -3,10 +3,8 @@
<h2 bitTypography="h6">{{ "additionalOptions" | i18n }}</h2> <h2 bitTypography="h6">{{ "additionalOptions" | i18n }}</h2>
</bit-section-header> </bit-section-header>
<bit-card> <bit-card>
<label class="tw-text-xs tw-text-muted tw-select-none">
{{ "note" | i18n }}
</label>
<bit-form-field> <bit-form-field>
<bit-label>{{ "note" | i18n }}</bit-label>
<textarea readonly bitInput aria-readonly="true">{{ notes }}</textarea> <textarea readonly bitInput aria-readonly="true">{{ notes }}</textarea>
<button <button
bitSuffix bitSuffix

View File

@ -0,0 +1,83 @@
<bit-section>
<bit-section-header>
<h2 bitTypography="h6">{{ setSectionTitle }}</h2>
</bit-section-header>
<bit-card>
<bit-form-field>
<bit-label>{{ "cardholderName" | i18n }}</bit-label>
<input
readonly
bitInput
type="text"
[value]="card.cardholderName"
aria-readonly="true"
data-testid="cardholder-name"
/>
</bit-form-field>
<bit-form-field *ngIf="card.number" [disableMargin]="!card.expiration && !card.code">
<bit-label>{{ "number" | i18n }}</bit-label>
<input
readonly
bitInput
type="password"
[value]="card.number"
aria-readonly="true"
data-testid="cardholder-number"
/>
<button
bitSuffix
type="button"
bitIconButton
bitPasswordInputToggle
data-testid="toggle-number"
></button>
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="card.number"
showToast
[appA11yTitle]="'copyValue' | i18n"
data-testid="copy-number"
></button>
</bit-form-field>
<bit-form-field *ngIf="card.expiration" [disableMargin]="!card.code">
<bit-label>{{ "expiration" | i18n }}</bit-label>
<input
readonly
bitInput
type="text"
[value]="card.expiration"
aria-readonly="true"
data-testid="cardholder-expiration"
/>
</bit-form-field>
<bit-form-field *ngIf="card.code" disableMargin>
<bit-label>{{ "securityCode" | i18n }}</bit-label>
<input
readonly
bitInput
type="password"
[value]="card.code"
aria-readonly="true"
data-testid="cardholder-code"
/>
<button
bitSuffix
type="button"
bitIconButton
bitPasswordInputToggle
data-testid="toggle-code"
></button>
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="card.code"
showToast
[appA11yTitle]="'copyValue' | i18n"
data-testid="copy-code"
></button>
</bit-form-field>
</bit-card>
</bit-section>

View File

@ -0,0 +1,45 @@
import { CommonModule } from "@angular/common";
import { Component, Input } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
import {
CardComponent,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
FormFieldModule,
IconButtonModule,
} from "@bitwarden/components";
import { OrgIconDirective } from "../../components/org-icon.directive";
@Component({
selector: "app-card-details-view",
templateUrl: "card-details-view.component.html",
standalone: true,
imports: [
CommonModule,
JslibModule,
CardComponent,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
OrgIconDirective,
FormFieldModule,
IconButtonModule,
],
})
export class CardDetailsComponent {
@Input() card: CardView;
constructor(private i18nService: I18nService) {}
get setSectionTitle() {
if (this.card.brand && this.card.brand !== "Other") {
return this.i18nService.t("cardBrandDetails", this.card.brand);
}
return this.i18nService.t("cardDetails");
}
}

View File

@ -8,6 +8,11 @@
> >
</app-item-details-v2> </app-item-details-v2>
<!-- CARD DETAILS -->
<ng-container *ngIf="hasCard">
<app-card-details-view [card]="cipher.card"></app-card-details-view>
</ng-container>
<!-- IDENTITY SECTIONS --> <!-- IDENTITY SECTIONS -->
<app-view-identity-sections *ngIf="cipher.identity" [cipher]="cipher"> <app-view-identity-sections *ngIf="cipher.identity" [cipher]="cipher">
</app-view-identity-sections> </app-view-identity-sections>

View File

@ -19,6 +19,7 @@ import { PopupPageComponent } from "../../../../apps/browser/src/platform/popup/
import { AdditionalOptionsComponent } from "./additional-options/additional-options.component"; import { AdditionalOptionsComponent } from "./additional-options/additional-options.component";
import { AttachmentsV2ViewComponent } from "./attachments/attachments-v2-view.component"; import { AttachmentsV2ViewComponent } from "./attachments/attachments-v2-view.component";
import { CardDetailsComponent } from "./card-details/card-details-view.component";
import { CustomFieldV2Component } from "./custom-fields/custom-fields-v2.component"; import { CustomFieldV2Component } from "./custom-fields/custom-fields-v2.component";
import { ItemDetailsV2Component } from "./item-details/item-details-v2.component"; import { ItemDetailsV2Component } from "./item-details/item-details-v2.component";
import { ItemHistoryV2Component } from "./item-history/item-history-v2.component"; import { ItemHistoryV2Component } from "./item-history/item-history-v2.component";
@ -40,6 +41,7 @@ import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-ide
AttachmentsV2ViewComponent, AttachmentsV2ViewComponent,
ItemHistoryV2Component, ItemHistoryV2Component,
CustomFieldV2Component, CustomFieldV2Component,
CardDetailsComponent,
ViewIdentitySectionsComponent, ViewIdentitySectionsComponent,
], ],
}) })
@ -64,6 +66,11 @@ export class CipherViewComponent implements OnInit {
this.destroyed$.complete(); this.destroyed$.complete();
} }
get hasCard() {
const { cardholderName, code, expMonth, expYear, brand, number } = this.cipher.card;
return cardholderName || code || expMonth || expYear || brand || number;
}
async loadCipherData() { async loadCipherData() {
if (this.cipher.collectionIds.length > 0) { if (this.cipher.collectionIds.length > 0) {
this.collections$ = this.collectionService this.collections$ = this.collectionService

View File

@ -8,65 +8,51 @@
*ngFor="let field of fields; let last = last" *ngFor="let field of fields; let last = last"
[ngClass]="{ 'tw-mb-4': !last }" [ngClass]="{ 'tw-mb-4': !last }"
> >
<ng-container *ngIf="field.type === fieldType.Text"> <bit-form-field *ngIf="field.type === fieldType.Text">
<label class="tw-text-xs tw-text-muted tw-select-none"> <bit-label>{{ field.name }}</bit-label>
{{ field.name }} <input readonly bitInput type="text" [value]="field.value" aria-readonly="true" />
</label> <button
<bit-form-field> bitIconButton="bwi-clone"
<input readonly bitInput type="text" [value]="field.value" aria-readonly="true" /> bitSuffix
<button type="button"
bitIconButton="bwi-clone" [appCopyClick]="field.value"
bitSuffix showToast
type="button" [appA11yTitle]="'copyValue' | i18n"
[appCopyClick]="field.value" ></button>
showToast </bit-form-field>
[appA11yTitle]="'copyValue' | i18n" <bit-form-field *ngIf="field.type === fieldType.Hidden">
></button> <bit-label>{{ field.name }}</bit-label>
</bit-form-field> <input readonly bitInput type="password" [value]="field.value" aria-readonly="true" />
</ng-container> <button bitSuffix type="button" bitIconButton bitPasswordInputToggle></button>
<ng-container *ngIf="field.type === fieldType.Hidden"> <button
<label class="tw-text-xs tw-text-muted tw-select-none"> bitIconButton="bwi-clone"
{{ field.name }} bitSuffix
</label> type="button"
<bit-form-field> [appCopyClick]="field.value"
<input readonly bitInput type="password" [value]="field.value" aria-readonly="true" /> showToast
<button bitSuffix type="button" bitIconButton bitPasswordInputToggle></button> [appA11yTitle]="'copyValue' | i18n"
<button ></button>
bitIconButton="bwi-clone" </bit-form-field>
bitSuffix <bit-form-control *ngIf="field.type === fieldType.Boolean">
type="button" <input
[appCopyClick]="field.value" bitCheckbox
showToast type="checkbox"
[appA11yTitle]="'copyValue' | i18n" [checked]="field.value === 'true'"
></button> aria-readonly="true"
</bit-form-field> disabled
</ng-container> />
<ng-container *ngIf="field.type === fieldType.Boolean"> <bit-label> {{ field.name }} </bit-label>
<bit-form-control> </bit-form-control>
<input <bit-form-field *ngIf="field.type === fieldType.Linked">
bitCheckbox <bit-label> {{ "linked" | i18n }}: {{ field.name }} </bit-label>
type="checkbox" <input
[checked]="field.value === 'true'" readonly
aria-readonly="true" bitInput
disabled type="text"
/> [value]="getLinkedType(field.linkedId)"
<bit-label> {{ field.name }} </bit-label> aria-readonly="true"
</bit-form-control> />
</ng-container> </bit-form-field>
<ng-container *ngIf="field.type === fieldType.Linked">
<label class="tw-text-xs tw-text-muted tw-select-none">
{{ "linked" | i18n }}: {{ field.name }}
</label>
<bit-form-field>
<input
readonly
bitInput
type="text"
[value]="getLinkedType(field.linkedId)"
aria-readonly="true"
/>
</bit-form-field>
</ng-container>
</div> </div>
</bit-card> </bit-card>
</bit-section> </bit-section>