Commit 3c22a865 authored by Dirk Luijk's avatar Dirk Luijk

Added a lot to the frontend (blockchain / mine / peers)

parent 4a01b58a
import { Transaction } from './transaction';
export interface Block {
index: number;
timestamp: number;
transactions: Transaction[];
proof: number;
}
import { Block } from './block';
export interface Blockchain {
chain: Block[];
}
export * from './block';
export * from './blockchain';
export * from './transaction';
export * from './transaction-result';
export class TransactionResult {
export interface TransactionResult {
message: string;
}
export class Transaction {
export interface Transaction {
id: string;
from: string;
to: string;
......
......@@ -5,22 +5,22 @@
<nav class="mt-5">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link" [routerLink]="['dashboard']" routerLinkActive="active">Dashboard</a>
<a class="nav-link" [routerLink]="['transactions']" routerLinkActive="active">Pending transactions</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['transactions', 'pending']" routerLinkActive="active">Pending transactions</a>
<a class="nav-link" [routerLink]="['blockchain']" routerLinkActive="active">Blockchain</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['transactions', 'new']" routerLinkActive="active">New transaction</a>
<a class="nav-link" [routerLink]="['peers']" routerLinkActive="active">Peers</a>
</li>
</ul>
</nav>
<div class="row">
<div class="col-md-6">
<div class="col-md-8">
<router-outlet></router-outlet>
</div>
<div class="col-md-6">
<div class="col-md-4">
<app-messages></app-messages>
</div>
</div>
......
......@@ -5,27 +5,33 @@ import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { TransactionsComponent } from './transactions/transactions.component';
import { TransactionComponent } from './transaction/transaction.component';
import { TransactionService } from './api/transaction.service';
import { CreateTransactionComponent } from './transactions/create/create-transaction.component';
import { TransactionService } from './transactions/transaction.service';
import { MessagesComponent } from './messages/messages.component';
import { MessageService } from './messages/message.service';
import { DashboardComponent } from './dashboard/dashboard.component';
import { BlockchainComponent } from './blockchain/blockchain.component';
import { PendingTransactionsComponent } from './transactions/pending/pending-transactions.component';
import { BlockchainService } from './blockchain/blockchain.service';
import { PeersComponent } from './peers/peers.component';
import { PeersService } from './peers/peers.service';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'transactions/pending', component: TransactionsComponent },
{ path: 'transactions/new', component: TransactionComponent },
{ path: '', redirectTo: '/transactions/pending', pathMatch: 'full' },
{ path: 'transactions', component: PendingTransactionsComponent },
{ path: 'transactions/create', component: CreateTransactionComponent },
{ path: 'blockchain', component: BlockchainComponent },
{ path: 'peers', component: PeersComponent },
];
@NgModule({
declarations: [
AppComponent,
TransactionsComponent,
TransactionComponent,
PendingTransactionsComponent,
CreateTransactionComponent,
CreateTransactionComponent,
MessagesComponent,
DashboardComponent
BlockchainComponent,
PeersComponent
],
imports: [
BrowserModule,
......@@ -33,7 +39,7 @@ const routes: Routes = [
RouterModule.forRoot(routes, { useHash: true }),
HttpClientModule
],
providers: [TransactionService, MessageService],
providers: [TransactionService, MessageService, BlockchainService, PeersService],
bootstrap: [AppComponent]
})
export class AppModule {
......
<h3 class="mb-4">Blockchain</h3>
<p><button (click)="mine()" class="btn btn-primary btn-lg">Mine!</button></p>
<div *ngFor="let block of blockchain?.chain; trackBy: trackFn" class="block">
<h4 class="mb-3">
<span class="badge badge-primary">Block {{ block.index }}</span>
<span class="badge badge-secondary">{{ block.timestamp | date: 'mediumTime' }}</span>
<span class="badge badge-success">Proof {{ block.proof }}</span>
</h4>
<ng-container *ngIf="block.transactions.length === 0">No transactions.</ng-container>
<ng-container *ngIf="block.transactions.length > 0">
<div *ngFor="let transaction of block.transactions" class="transaction mt-3">
<p class="lead mb-0">{{ transaction.id }}</p>
<span class="badge badge-primary">from {{ transaction.from }}</span>
<span class="badge badge-secondary">to {{ transaction.to }}</span>
<span class="badge badge-info">{{ transaction.amount | currency: 'EUR'}}</span>
</div>
</ng-container>
</div>
.block {
border: 1px solid gray;
border-radius: 8px;
padding: 0.5rem 1rem;
display: block;
margin: 2rem 0;
}
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/switchMap';
import { Block, Blockchain } from '../api';
import { BlockchainService } from './blockchain.service';
@Component({
selector: 'app-blockchain',
templateUrl: './blockchain.component.html',
styleUrls: ['./blockchain.component.scss']
})
export class BlockchainComponent implements OnInit, OnDestroy {
blockchain: Blockchain;
private subscription: Subscription;
constructor(private blockchainService: BlockchainService) {}
ngOnInit(): void {
this.subscription = Observable.timer(0, 5000)
.switchMap(() => this.blockchainService.getBlockchain())
.subscribe(blockchain => this.blockchain = blockchain);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
trackFn(block: Block): number {
return block.index;
}
mine(): void {
this.blockchainService.doMine().subscribe(block => this.blockchain.chain.push(block));
}
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import { MessageService } from '../messages/message.service';
import { Block, Blockchain } from '../api';
@Injectable()
export class BlockchainService {
constructor(private http: HttpClient, private messageService: MessageService) {}
getBlockchain(): Observable<Blockchain> {
this.messageService.log('Fetching blockchain...');
return this.http.get<Blockchain>('/api/blockchain')
.do(blockchain => this.messageService.log(`Got blockchain with ${blockchain.chain.length} block(s)`));
}
doMine(): Observable<Block> {
this.messageService.log('Mining...');
return this.http.post<Block>('/api/mine', {})
.do(block => this.messageService.log(`Successfully mined block ${block.index} with ${block.transactions.length} transaction(s)`));
}
}
<h2>Top transactions</h2>
<div *ngIf="transactions.length === 0">No transactions available.</div>
<ul *ngIf="transactions.length > 0">
<li *ngFor="let transaction of transactions">
{{transaction.id}}
</li>
</ul>
import { Component, OnInit } from '@angular/core';
import { Transaction } from '../api/transaction';
import { TransactionService } from '../api/transaction.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html'
})
export class DashboardComponent implements OnInit {
transactions: Transaction[] = [];
constructor(private transactionService: TransactionService) { }
ngOnInit() {
this.getTransactions();
}
getTransactions(): void {
this.transactionService.getTransactions()
.subscribe(transactions => this.transactions = transactions.slice(0, 2));
}
}
......@@ -18,7 +18,7 @@ export class MessageService {
this.messages$ = this.messagesSubject.asObservable();
}
add(message: string): void {
log(message: string): void {
this.messages.push({
text: message,
time: new Date(),
......
<h2>Messages</h2>
<h3 class="mb-4">Messages</h3>
<div *ngIf="messages.length === 0">No messages.</div>
<div *ngIf="messages.length > 0">
<pre><div *ngFor="let message of messages">{{ message.time | date: 'mediumTime' }} - {{ message.text }}</div></pre>
<code><p *ngFor="let message of messages">{{ message.time | date: 'mediumTime' }} - {{ message.text }}</p></code>
<button class="btn btn-secondary btn-sm" (click)="clear()">Clear messages</button>
</div>
<h3 class="mb-4">Peers</h3>
<div *ngIf="peers.length === 0">
<p>No peers found.</p>
</div>
<div *ngIf="peers.length > 0">
<ul class="list-group">
<li class="list-group-item" *ngFor="let peer of peers">{{ peer }}</li>
</ul>
</div>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/switchMap';
import { PeersService } from './peers.service';
@Component({
selector: 'app-peers',
templateUrl: './peers.component.html',
styleUrls: ['./peers.component.scss']
})
export class PeersComponent implements OnInit, OnDestroy {
peers: string[] = [];
private subscription: Subscription;
constructor(private peersService: PeersService) { }
ngOnInit() {
this.subscription = Observable.timer(0, 5000)
.switchMap(() => this.peersService.getPeers())
.subscribe(peers => this.peers = peers);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { MessageService } from '../messages/message.service';
@Injectable()
export class PeersService {
constructor(private http: HttpClient, private messageService: MessageService) {}
getPeers(): Observable<string[]> {
this.messageService.log('Fetching peers...');
return this.http.get<string[]>('/api/peers')
.do(peers => this.messageService.log(`Got ${peers.length} peer(s)`));
}
}
import { Component } from '@angular/core';
import {Transaction} from '../api/transaction';
import { TransactionService } from '../api/transaction.service';
@Component({
selector: 'app-transaction',
templateUrl: './transaction.component.html'
})
export class TransactionComponent {
newTransaction: Transaction = new Transaction();
constructor(private transactionService: TransactionService) { }
submit(): void {
this.transactionService
.save(this.newTransaction)
.subscribe();
}
}
<h2>New transaction</h2>
<h3 class="mb-4">Create transaction</h3>
<form #form="ngForm" (submit)="submit()">
<div class="form-group">
......
import { Component } from '@angular/core';
import {Transaction} from '../../api/transaction';
import { TransactionService } from '../transaction.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-create-transaction',
templateUrl: './create-transaction.component.html'
})
export class CreateTransactionComponent {
newTransaction: Transaction = {
id: '',
from: '',
to: '',
amount: 0
};
constructor(private transactionService: TransactionService, private router: Router) { }
submit(): void {
this.transactionService
.save(this.newTransaction)
.subscribe(() => {
this.router.navigate(['transactions']);
});
}
}
<h3 class="mb-4">Pending transactions</h3>
<div *ngIf="transactions.length === 0" class="jumbotron">
<p class="lead">No pending transactions. <a [routerLink]="['create']">Let's create one!</a></p>
</div>
<div *ngIf="transactions.length > 0">
<p><a [routerLink]="['create']" class="btn btn-primary">New transaction</a></p>
<table class="table">
<tr>
<th>ID</th>
<th>From</th>
<th>To</th>
<th>Amount</th>
</tr>
<tr *ngFor="let transaction of transactions" [class.table-active]="transaction === selectedTransaction" (click)="onSelect(transaction)">
<td>{{transaction.id}}</td>
<td>{{transaction.from}}</td>
<td>{{transaction.to}}</td>
<td>{{transaction.amount | currency: 'EUR'}}</td>
</tr>
</table>
</div>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Component } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/switchMap';
import { Transaction } from '../api/transaction';
import { TransactionService } from '../api/transaction.service';
import { Transaction } from '../../api';
import { TransactionService } from '../transaction.service';
@Component({
selector: 'app-transactions',
templateUrl: './transactions.component.html'
selector: 'app-pending-transactions',
templateUrl: './pending-transactions.component.html'
})
export class TransactionsComponent implements OnInit, OnDestroy {
export class PendingTransactionsComponent {
selectedTransaction: Transaction;
transactions: Transaction[] = [];
......
......@@ -4,8 +4,8 @@ import { Observable } from 'rxjs/Observable';
import { MessageService } from '../messages/message.service';
import { Transaction } from './transaction';
import { TransactionResult } from './transaction-result';
import { Transaction } from '../api/transaction';
import { TransactionResult } from '../api/transaction-result';
import 'rxjs/add/operator/do';
......@@ -26,6 +26,6 @@ export class TransactionService {
}
private log(message: string) {
this.messageService.add(message);
this.messageService.log(message);
}
}
<h2>Pending transactions</h2>
<div *ngIf="transactions.length === 0">No transactions yet.</div>
<table class="table" *ngIf="transactions.length > 0">
<tr>
<th>ID</th>
<th>From</th>
<th>To</th>
<th>Amount</th>
</tr>
<tr *ngFor="let transaction of transactions" [class.table-active]="transaction === selectedTransaction" (click)="onSelect(transaction)">
<td>{{transaction.id}}</td>
<td>{{transaction.from}}</td>
<td>{{transaction.to}}</td>
<td>{{transaction.amount}}</td>
</tr>
</table>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment