Skip to content

Commit

Permalink
update credential list and show
Browse files Browse the repository at this point in the history
Signed-off-by: Mirko Mollik <[email protected]>
  • Loading branch information
cre8 committed Aug 7, 2024
1 parent 2ae7caf commit 38674f4
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 174 deletions.
10 changes: 6 additions & 4 deletions apps/holder-app/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ export const routes: Routes = [
{
path: 'credentials',
component: CredentialsListComponent,
},
{
path: 'credentials/:id',
component: CredentialsShowComponent,
children: [
{
path: ':id',
component: CredentialsShowComponent,
},
],
},
{
path: 'history',
Expand Down
2 changes: 1 addition & 1 deletion deploys/issuer/config/issuer-backend/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "German Government",
"locale": "en-US",
"logo": {
"url": "https://www.bmi.bund.de/SharedDocs/bilder/DE/schmuckbilder/moderne-verwaltung/paesse-ausweise/personalausweis_vorderseite_ab_august_2021.jpg?__blob=poster&v=2"
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flagge_Deutschland.jpg/640px-Flagge_Deutschland.jpg"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,56 @@
<div fxLayout="row" fxLayoutAlign="space-between center">
<h3 *ngIf="type === 'all'">Credentials</h3>
<h3 *ngIf="type === 'archived'">Archived credentials</h3>
<button
id="menu"
mat-icon-button
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="show('archived')" *ngIf="type === 'all'">
<mat-icon>archive</mat-icon>
<span>Archived Credentials</span>
</button>
<button mat-menu-item (click)="show('all')" *ngIf="type === 'archived'">
<mat-icon>verified</mat-icon>
<span>Valid Credentials</span>
</button>
<button mat-menu-item (click)="render = 'card'" *ngIf="render !== 'card'">
<mat-icon>credit_card</mat-icon>
<span>Show list</span>
</button>
<button mat-menu-item (click)="render = 'image'" *ngIf="render !== 'image'">
<mat-icon>list</mat-icon>
<span>Show cards</span>
</button>
</mat-menu>
</div>
<mat-form-field appearance="outline" id="search">
<mat-label>Search</mat-label>
<input matInput type="text" [formControl]="search" />
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<div fxLayout="column" fxLayoutGap="16px">
@for (credential of credentials; track credential) {
<img
*ngIf="render === 'image'"
[routerLink]="credential.id"
class="image"
[alt]="credential.display.background_image!.alt_text"
[src]="credential.display.background_image!.url"
/>
<div
*ngIf="render === 'card'"
[routerLink]="credential.id"
class="card"
fxLayout="row"
fxLayoutGap="16px"
fxLayoutAlign="start center"
[ngStyle]="{
'background-color': credential.display.background_color,
color: credential.display.text_color
}"
>
<div fxLayout="row" fxLayoutAlign="space-between start">
<div fxFlex="100" fxFlex.gt-sm="30" *ngIf="!(mobile && credentialShown)">
<div fxLayout="row" fxLayoutAlign="space-between center">
<h3 *ngIf="type === 'all'">Credentials</h3>
<h3 *ngIf="type === 'archived'">Archived credentials</h3>
<button
id="menu"
mat-icon-button
[matMenuTriggerFor]="menu"
aria-label="Example icon-button with a menu"
>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="show('archived')" *ngIf="type === 'all'">
<mat-icon>archive</mat-icon>
<span>Archived Credentials</span>
</button>
<button mat-menu-item (click)="show('all')" *ngIf="type === 'archived'">
<mat-icon>verified</mat-icon>
<span>Valid Credentials</span>
</button>
</mat-menu>
</div>
<mat-form-field appearance="outline" id="search">
<mat-label>Search</mat-label>
<input matInput type="text" [formControl]="search" />
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<div fxLayout="column" fxLayoutGap="16px">
<mat-nav-list>
@for (credential of credentials; track credential) {
<a mat-list-item [routerLink]="credential.id">
<img
[src]="credential.display.background_image!.url"
matListItemAvatar
alt="Credential"
/>
<div matListItemTitle>{{ credential.display.name }}</div>
<div matListItemLine>{{ credential.issuer.name }}</div>
</a>
}
</mat-nav-list>
</div>
<div
[ngStyle]="{
'background-image':
'url(' + credential.display.background_image!.url + ')'
}"
class="icon"
></div>
<div>
<h4>{{ credential.display.name }}</h4>
<span>{{ credential.issuer.name }}</span>
*ngIf="credentials.length === 0"
fxLayout="column"
fxLayoutAlign="center center"
>
<p>No credentials found</p>
</div>
</div>
}
</div>
<div
*ngIf="credentials.length === 0"
fxLayout="column"
fxLayoutAlign="center center"
>
<p>No credentials found</p>
<div fxShow.gt-sm="true" fxFlex.gt-sm="70" *ngIf="credentialShown">
<router-outlet></router-outlet>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,6 @@
display: block;
}

.mat-mdc-list-item-icon {
margin: 0;
}

.image {
margin: 16px 0;
height: 200px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 10px;
}

.card {
border-radius: 10px;
background-color: #D7E3FF;
padding: 10px;

.icon {
width: 50px;
height: 50px;
border-radius: 5px;
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}
h4 {
margin: 0;
}
}

#search {
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import { Component, OnInit } from '@angular/core';
import { CredentialResponse, CredentialsApiService } from '../../api/';
import { firstValueFrom } from 'rxjs';
import { filter, firstValueFrom } from 'rxjs';
import { MatListModule } from '@angular/material/list';
import { CredentialsShowComponent } from '../credentials-show/credentials-show.component';
import { MatCardModule } from '@angular/material/card';
import { CommonModule } from '@angular/common';
import { CredentialsSupportedDisplay } from '@sphereon/oid4vci-common';
import { RouterLink } from '@angular/router';
import {
ActivatedRoute,
NavigationEnd,
Router,
RouterLink,
RouterModule,
} from '@angular/router';
import { FlexLayoutModule } from 'ng-flex-layout';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { BreakpointObserver } from '@angular/cdk/layout';
import { CredentialsService } from '../credentials.service';

export interface CredentialList extends CredentialResponse {
display: CredentialsSupportedDisplay;
Expand All @@ -35,6 +43,7 @@ type ShowType = 'all' | 'archived';
MatButtonModule,
ReactiveFormsModule,
MatInputModule,
RouterModule,
],
templateUrl: './credentials-list.component.html',
styleUrl: './credentials-list.component.scss',
Expand All @@ -44,14 +53,36 @@ export class CredentialsListComponent implements OnInit {

search: FormControl = new FormControl('');

render: 'image' | 'card' = 'card';

type: ShowType = 'all';

constructor(private credentialsApiService: CredentialsApiService) {}
credentialShown = false;
mobile = false;

constructor(
private credentialsApiService: CredentialsApiService,
private route: ActivatedRoute,
private router: Router,
breakpointObserver: BreakpointObserver,
private credentialsService: CredentialsService
) {
breakpointObserver
.observe('(max-width: 599px)')
.subscribe((result) => (this.mobile = result.matches));
}

async ngOnInit(): Promise<void> {
this.loadCredentials();
this.credentialShown = this.route.firstChild !== null;
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe(() => (this.credentialShown = this.route.firstChild !== null));

this.credentialsService.deletedEmitter.subscribe(
(credentialId) =>
(this.credentials = this.credentials.filter(
(credential) => credential.id !== credentialId
))
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,72 @@
<div *ngIf="credential" id="credential">
<div fxLayout="row" fxLayoutAlign="space-between center">
<div fxLayout="row" fxLayoutGap="16px" fxLayoutAlign="start center">
<button mat-icon-button [routerLink]="'../'">
<mat-icon>arrow_back</mat-icon>
</button>
<h3 *ngIf="metadata.display">{{ metadata.display![0].name }}</h3>
<div *ngIf="credential" id="credential" fxLayout="column" fxLayoutGap="16px">
<div
fxLayout="column"
fxLayout.gt-sm="row"
fxLayoutAlign="start stretch"
fxLayoutGap="16px"
>
<img
*ngIf="metadata.display"
class="image"
[alt]="metadata.display![0].logo?.alt_text"
[src]="metadata.display![0].background_image!.url"
alt="Credential image"
/>
<div class="header" fxFlexOrder.lt-sm="-1">
<div fxLayout="row" fxLayoutGap="16px" fxLayoutAlign="end center">
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="copyRaw()">
<mat-icon>content_copy</mat-icon>
<span>Raw credential</span>
</button>
<button mat-menu-item (click)="delete()">
<mat-icon>delete</mat-icon>
<span>Delete</span>
</button>
</mat-menu>
</div>
<div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<img
*ngIf="credential.issuer.logo"
[src]="credential.issuer.logo.url"
[alt]="credential.issuer.logo.alt_text"
class="issuer-image"
/>
<mat-card-title>{{ credential.issuer.name }}</mat-card-title>
</div>
<h3 *ngIf="metadata.display">{{ metadata.display![0].name }}</h3>
</div>
</div>
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="copyRaw()">
<mat-icon>content_copy</mat-icon>
<span>Raw credential</span>
</button>
<button mat-menu-item (click)="delete()">
<mat-icon>delete</mat-icon>
<span>Delete</span>
</button>
</mat-menu>
</div>
<img
*ngIf="metadata.display"
class="image"
[alt]="metadata.display![0].logo?.alt_text"
[src]="metadata.display![0].background_image!.url"
/>
<mat-card>
<mat-card-header>
<img
mat-card-avatar
*ngIf="credential.issuer.logo"
[src]="credential.issuer.logo.url"
[alt]="credential.issuer.logo.alt_text"
/>
<mat-card-title>{{ credential.issuer.name }}</mat-card-title>
<mat-card-subtitle *ngIf="status !== 'valid'" class="error-state">{{
status
}}</mat-card-subtitle>
<mat-card-title>Claims</mat-card-title>
</mat-card-header>
<mat-list>
@for (claim of claims; track claim) {
<mat-list-item>
<span matListItemTitle>{{ claim.key }}</span>
<span matListItemLine>{{ claim.value }}</span>
<span matListItemTitle>{{ claim.value }}</span>
<span matListItemLine>{{ claim.key }}</span>
</mat-list-item>
}
<mat-divider></mat-divider>
<mat-list-item>
<span matListItemTitle>Issuance Date</span>
<span matListItemLine>{{
getClaimAsNumber('iat') * 1000 | date : 'medium'
}}</span>
</mat-list-item>
<mat-list-item *ngIf="getClaim('exp')">
<span matListItemTitle>Expiration Date</span>
<span matListItemLine>{{
getClaimAsNumber('exp') * 1000 | date : 'medium'
}}</span>
</mat-list-item>
</mat-list>
</mat-card>
<!-- <pre>{{ metadata | json }}</pre> -->
<mat-list>
<mat-list-item>
<span matListItemTitle>{{
getClaimAsNumber('iat') * 1000 | date : 'medium'
}}</span>
<span matListItemLine>Issuance Date</span>
</mat-list-item>
<mat-list-item *ngIf="getClaim('exp')">
<span matListItemTitle>{{
getClaimAsNumber('exp') * 1000 | date : 'medium'
}}</span>
<span matListItemLine>Expiration Date</span>
</mat-list-item>
</mat-list>
</div>
Loading

0 comments on commit 38674f4

Please sign in to comment.