Commit 4bb45a35 authored by Pieterjan Vanhoof's avatar Pieterjan Vanhoof Committed by GitHub

Add sending and receiving modals (#54)

- Added sending modal
- Added receiving modal
- Added build and send functions to the API service
- Removed send/receive from wallet menu
- Fixed login (only returns status code 200 when OK)
parents a17b5dd1 14bbbb2d
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
"@angular/platform-browser-dynamic": "^4.1.2", "@angular/platform-browser-dynamic": "^4.1.2",
"@angular/platform-server": "^4.1.2", "@angular/platform-server": "^4.1.2",
"@angular/router": "^4.1.2", "@angular/router": "^4.1.2",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.25",
"angular2-material-datepicker": "^0.5.0", "angular2-material-datepicker": "^0.5.0",
"bootstrap": "^4.0.0-alpha.6", "bootstrap": "^4.0.0-alpha.6",
"core-js": "^2.4.1", "core-js": "^2.4.1",
......
...@@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'; ...@@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { HttpModule } from '@angular/http'; import { HttpModule } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import { SharedModule } from './shared/shared.module'; import { SharedModule } from './shared/shared.module';
...@@ -14,6 +15,9 @@ import { LoginComponent } from './login/login.component'; ...@@ -14,6 +15,9 @@ import { LoginComponent } from './login/login.component';
import { ApiService } from './shared/services/api.service'; import { ApiService } from './shared/services/api.service';
import { GlobalService } from './shared/services/global.service'; import { GlobalService } from './shared/services/global.service';
import { SendComponent } from './wallet/send/send.component';
import { ReceiveComponent } from './wallet/receive/receive.component';
@NgModule({ @NgModule({
imports: [ imports: [
...@@ -23,11 +27,18 @@ import { GlobalService } from './shared/services/global.service'; ...@@ -23,11 +27,18 @@ import { GlobalService } from './shared/services/global.service';
ReactiveFormsModule, ReactiveFormsModule,
FormsModule, FormsModule,
HttpModule, HttpModule,
NgbModule.forRoot(),
SharedModule.forRoot() SharedModule.forRoot()
], ],
declarations: [ declarations: [
AppComponent, AppComponent,
LoginComponent LoginComponent,
SendComponent,
ReceiveComponent
],
entryComponents: [
SendComponent,
ReceiveComponent
], ],
providers: [ ApiService, GlobalService ], providers: [ ApiService, GlobalService ],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
......
...@@ -83,7 +83,6 @@ export class LoginComponent implements OnInit { ...@@ -83,7 +83,6 @@ export class LoginComponent implements OnInit {
.subscribe( .subscribe(
response => { response => {
if (response.status >= 200 && response.status < 400) { if (response.status >= 200 && response.status < 400) {
let responseMessage = response.json();
this.globalService.setWalletName(walletLoad.name) this.globalService.setWalletName(walletLoad.name)
this.globalService.setCoinType(1); this.globalService.setCoinType(1);
this.router.navigate(['/wallet']); this.router.navigate(['/wallet']);
......
export class TransactionBuilding {
constructor(walletName: string, coinType: number, accountName: string, password: string, destinationAddress: string, amount: string, feeType: string, allowUnconfirmed: boolean) {
this.walletName = walletName;
this.coinType = coinType;
this.accountName = accountName;
this.password = password;
this.destinationAddress = destinationAddress;
this.amount = amount;
this.feeType = feeType;
this.allowUnconfirmed = allowUnconfirmed;
}
walletName: string;
coinType: number;
accountName: string;
password: string;
destinationAddress: string;
amount: string;
feeType: string;
allowUnconfirmed: boolean;
}
export class TransactionSending {
constructor(hex: string) {
this.hex = hex;
}
hex: string;
}
...@@ -5,10 +5,24 @@ import { Pipe, PipeTransform } from '@angular/core'; ...@@ -5,10 +5,24 @@ import { Pipe, PipeTransform } from '@angular/core';
}) })
export class CoinNotationPipe implements PipeTransform { export class CoinNotationPipe implements PipeTransform {
private coinUnit = "BTC";
private coinNotation: number;
transform(value: any): any { transform(value: any): any {
if (!value) return value; if (!value) return value;
let coinNotation = Number(value).toFixed(8); this.coinNotation = value;
return coinNotation;
switch (this.coinUnit) {
case "BTC":
this.coinNotation = Number(value.toFixed(8));
return this.coinNotation = this.coinNotation / 100000000;
case "mBTC":
this.coinNotation = Number(value.toFixed(8));
return this.coinNotation = this.coinNotation / 100000;
case "uBTC":
this.coinNotation = Number(value.toFixed(8));
return this.coinNotation = this.coinNotation / 100;
}
} }
} }
...@@ -9,6 +9,8 @@ import { WalletRecovery } from '../classes/wallet-recovery'; ...@@ -9,6 +9,8 @@ import { WalletRecovery } from '../classes/wallet-recovery';
import { WalletLoad } from '../classes/wallet-load'; import { WalletLoad } from '../classes/wallet-load';
import { WalletInfo } from '../classes/wallet-info'; import { WalletInfo } from '../classes/wallet-info';
import { Mnemonic } from '../classes/mnemonic'; import { Mnemonic } from '../classes/mnemonic';
import { TransactionBuilding } from '../classes/transaction-building';
import { TransactionSending } from '../classes/transaction-sending';
/** /**
* For information on the API specification have a look at our Github: * For information on the API specification have a look at our Github:
...@@ -106,4 +108,16 @@ export class ApiService { ...@@ -106,4 +108,16 @@ export class ApiService {
.get(this.webApiUrl + '/wallet/address', new RequestOptions({headers: this.headers, search: params})) .get(this.webApiUrl + '/wallet/address', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response); .map((response: Response) => response);
} }
buildTransaction(data: TransactionBuilding): Observable<any> {
return this.http
.post(this.webApiUrl + '/wallet/build-transaction/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
sendTransaction(data: TransactionSending): Observable<any> {
return this.http
.post(this.webApiUrl + '/wallet/send-transaction/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row" id="transactions">
<div class="col"> <div class="col">
<div>Transactions</div> <div>Transactions</div>
<table *ngIf="transactions; else noTransactions"> <table *ngIf="transactions; else noTransactions">
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<!--<td *ngIf="{{ transaction.amount }} < 0">SENT</td> <!--<td *ngIf="{{ transaction.amount }} < 0">SENT</td>
<td *ngIf="{{ transaction.amount }} > 0">RECEIVED</td>--> <td *ngIf="{{ transaction.amount }} > 0">RECEIVED</td>-->
<td *ngIf="i<5">{{ transaction.timestamp }}</td> <td *ngIf="i<5">{{ transaction.timestamp }}</td>
<td *ngIf="i<5">{{ transaction.amount }}</td> <td *ngIf="i<5">{{ transaction.amount | coinNotation | coinAbbreviation }}</td>
<td *ngIf="i<5">{{ transaction.confirmed }}</td> <td *ngIf="i<5">{{ transaction.confirmed }}</td>
<td *ngIf="i<5">{{ transaction.txId }}</td> <td *ngIf="i<5">{{ transaction.txId }}</td>
</tr> </tr>
......
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';
import { ApiService } from '../../shared/services/api.service'; import { ApiService } from '../../shared/services/api.service';
import { GlobalService } from '../../shared/services/global.service'; import { GlobalService } from '../../shared/services/global.service';
import { WalletInfo } from '../../shared/classes/wallet-info'; import { WalletInfo } from '../../shared/classes/wallet-info';
import { SendComponent } from '../send/send.component';
import { ReceiveComponent } from '../receive/receive.component';
@Component({ @Component({
selector: 'dashboard-component', selector: 'dashboard-component',
templateUrl: './dashboard.component.html', templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css'], styleUrls: ['./dashboard.component.css']
}) })
export class DashboardComponent { export class DashboardComponent {
constructor(private apiService: ApiService, private globalService: GlobalService) {} constructor(private apiService: ApiService, private globalService: GlobalService, private modalService: NgbModal) {}
private balanceResponse: any; private balanceResponse: any;
private confirmedBalance: number; private confirmedBalance: number;
...@@ -24,11 +29,11 @@ export class DashboardComponent { ...@@ -24,11 +29,11 @@ export class DashboardComponent {
}; };
private openSendDialog() { private openSendDialog() {
const modalRef = this.modalService.open(SendComponent);
}; };
private openReceiveDialog() { private openReceiveDialog() {
const modalRef = this.modalService.open(ReceiveComponent);
}; };
private getWalletBalance() { private getWalletBalance() {
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<!--<td *ngIf="{{ transaction.amount }} < 0; else received">SENT</td> <!--<td *ngIf="{{ transaction.amount }} < 0; else received">SENT</td>
<td #received>RECEIVED</td>--> <td #received>RECEIVED</td>-->
<td>{{ transaction.timestamp }}</td> <td>{{ transaction.timestamp }}</td>
<td>{{ transaction.amount }}</td> <td>{{ transaction.amount | coinNotation | coinAbbreviation }}</td>
<td>{{ transaction.confirmed }}</td> <td>{{ transaction.confirmed }}</td>
<td>{{ transaction.txId }}</td> <td>{{ transaction.txId }}</td>
</tr> </tr>
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
<div class="container"> <div class="container">
<ul class="navbar-nav mr-auto" routerLinkActive="active"> <ul class="navbar-nav mr-auto" routerLinkActive="active">
<li class="nav-item"><a class="nav-link" routerLink="dashboard">Dashboard</a></li> <li class="nav-item"><a class="nav-link" routerLink="dashboard">Dashboard</a></li>
<li class="nav-item"><a class="nav-link" routerLink="send">Send</a></li>
<li class="nav-item"><a class="nav-link" routerLink="receive">Receive</a></li>
<li class="nav-item"><a class="nav-link" routerLink="history">History</a></li> <li class="nav-item"><a class="nav-link" routerLink="history">History</a></li>
<li class="nav-item"><a class="nav-link" (click)="logOut()">Logout</a></li> <li class="nav-item"><a class="nav-link" (click)="logOut()">Logout</a></li>
</ul> </ul>
......
<div class="content-wrapper"> <div class="content-wrapper" id="receiveForm">
<h1>Receive</h1> <h1>Receive</h1>
<div> <div>
<div> <div>
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<td>{{ address }}</td> <td>{{ address }}</td>
</tr> </tr>
</table> </table>
<button type="button" class="btn" (click)="activeModal.close('Close click')">Close</button>
</div> </div>
</div> </div>
</div> </div>
...@@ -5,6 +5,8 @@ import { GlobalService } from '../../shared/services/global.service'; ...@@ -5,6 +5,8 @@ import { GlobalService } from '../../shared/services/global.service';
import { WalletInfo } from '../../shared/classes/wallet-info'; import { WalletInfo } from '../../shared/classes/wallet-info';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';
@Component({ @Component({
selector: 'receive-component', selector: 'receive-component',
templateUrl: './receive.component.html', templateUrl: './receive.component.html',
...@@ -12,7 +14,7 @@ import { WalletInfo } from '../../shared/classes/wallet-info'; ...@@ -12,7 +14,7 @@ import { WalletInfo } from '../../shared/classes/wallet-info';
}) })
export class ReceiveComponent { export class ReceiveComponent {
constructor(private apiService: ApiService, private globalService: GlobalService) {} constructor(private apiService: ApiService, private globalService: GlobalService, public activeModal: NgbActiveModal) {}
private address: any; private address: any;
private errorMessage: string; private errorMessage: string;
......
<div class="content-wrapper"> <div class="content-wrapper" id="sendForm">
<h1>Send</h1> <h1>Send</h1>
<form (ngSubmit)="onSubmit()" #sendForm="ngForm"> <form [formGroup]="sendForm" (ngSubmit)="send()">
<div class="form-group"> <div class="form-group">
<label for="toAddress">Pay To: </label> <label>Pay To: </label>
<input type="text" class="form-control" id="name" required name="toAddress"> <input class="form-control" formControlName="address" type="text" placeholder="Please enter the recipients address.">
<div *ngIf="formErrors.address" class="alert alert-danger">{{formErrors.address}}</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="amount">Amount</label> <label>Amount</label>
<input type="text" class="form-control" id="amount" required name="amount"> <input class="form-control" formControlName="amount" type="text" placeholder="Please enter the amount you want to send.">
<div *ngIf="formErrors.amount" class="alert alert-danger">{{formErrors.amount}}</div>
</div> </div>
<button type="submit" class="btn btn-success">Submit</button> <button type="submit" [disabled]="!sendForm.valid" class="btn btn-success">Send</button>
<button type="button" class="btn" (click)="activeModal.close('Close click')">Close</button>
</form> </form>
</div> </div>
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ApiService } from '../../shared/services/api.service'; import { ApiService } from '../../shared/services/api.service';
import { GlobalService } from '../../shared/services/global.service';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';
import { TransactionBuilding } from '../../shared/classes/transaction-building';
import { TransactionSending } from '../../shared/classes/transaction-sending';
@Component({ @Component({
selector: 'send-component', selector: 'send-component',
...@@ -8,6 +15,104 @@ import { ApiService } from '../../shared/services/api.service'; ...@@ -8,6 +15,104 @@ import { ApiService } from '../../shared/services/api.service';
}) })
export class SendComponent { export class SendComponent {
constructor(private apiService: ApiService) {} constructor(private apiService: ApiService, private globalService: GlobalService, public activeModal: NgbActiveModal, private fb: FormBuilder) {
this.buildSendForm();
}
private sendForm: FormGroup;
private responseMessage: any;
private errorMessage: string;
private buildSendForm(): void {
this.sendForm = this.fb.group({
"address": ["", Validators.required],
"amount": ["", Validators.required]
});
this.sendForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.sendForm) { return; }
const form = this.sendForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'address': '',
'amount': ''
};
validationMessages = {
'address': {
'required': 'An address is required.'
},
'amount': {
'required': 'An amount is required.'
}
};
private send() {
let transaction = new TransactionBuilding(
this.globalService.getWalletName(),
this.globalService.getCoinType(),
"account 0",
"123",
this.sendForm.get("address").value,
this.sendForm.get("amount").value,
"medium",
true
);
this.apiService
.buildTransaction(transaction)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
this.responseMessage = response.json();
console.log(this.responseMessage);
}
},
error => {
if (error.status >= 400) {
this.errorMessage = error;
console.log(this.errorMessage);
}
},
() => this.sendTransaction(this.responseMessage.hex)
);
};
private sendTransaction(hex: string) {
let transaction = new TransactionSending(hex);
this.apiService
.sendTransaction(transaction)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
console.log(response.status);
this.activeModal.close("Close clicked");
}
},
error => {
if (error.status >= 400) {
this.errorMessage = error;
console.log(this.errorMessage);
}
}
);
}
} }
...@@ -13,8 +13,6 @@ const routes: Routes = [ ...@@ -13,8 +13,6 @@ const routes: Routes = [
children: [ children: [
{ path: '', redirectTo:'dashboard', pathMatch:'full' }, { path: '', redirectTo:'dashboard', pathMatch:'full' },
{ path: 'dashboard', component: DashboardComponent}, { path: 'dashboard', component: DashboardComponent},
{ path: 'send', component: SendComponent},
{ path: 'receive', component: ReceiveComponent},
{ path: 'history', component: HistoryComponent} { path: 'history', component: HistoryComponent}
] ]
}, },
......
...@@ -5,8 +5,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; ...@@ -5,8 +5,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { WalletComponent } from './wallet.component'; import { WalletComponent } from './wallet.component';
import { MenuComponent } from './menu/menu.component'; import { MenuComponent } from './menu/menu.component';
import { DashboardComponent } from './dashboard/dashboard.component'; import { DashboardComponent } from './dashboard/dashboard.component';
import { SendComponent } from './send/send.component';
import { ReceiveComponent } from './receive/receive.component';
import { HistoryComponent } from './history/history.component'; import { HistoryComponent } from './history/history.component';
import {SharedModule} from '../shared/shared.module'; import {SharedModule} from '../shared/shared.module';
...@@ -24,8 +22,6 @@ import { WalletRoutingModule } from './wallet-routing.module'; ...@@ -24,8 +22,6 @@ import { WalletRoutingModule } from './wallet-routing.module';
WalletComponent, WalletComponent,
MenuComponent, MenuComponent,
DashboardComponent, DashboardComponent,
ReceiveComponent,
SendComponent,
HistoryComponent HistoryComponent
], ],
exports: [] exports: []
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
font-family: "Lato"; font-family: "Lato";
} }
/* Temporary min td with */
td {
min-width: 150px;
}
.content-wrapper { .content-wrapper {
width: 100%; width: 100%;
height: 100%; height: 100%;
......
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