Implement checkout
This commit is contained in:
parent
dce8da391e
commit
251fa5d327
11 changed files with 150 additions and 18 deletions
|
@ -21,6 +21,7 @@ import { ItemDeleteComponent } from './items/item-delete/item-delete.component';
|
||||||
import { ItemAddComponent} from './items/item-add/item-add.component';
|
import { ItemAddComponent} from './items/item-add/item-add.component';
|
||||||
import { OrderComponent } from './order/order.component';
|
import { OrderComponent } from './order/order.component';
|
||||||
import { CancelComponent } from './cancel/cancel.component';
|
import { CancelComponent } from './cancel/cancel.component';
|
||||||
|
import { CheckoutComponent } from './checkout/checkout.component';
|
||||||
//import { NameDialogComponent } from './namedialog/namedialog.component';
|
//import { NameDialogComponent } from './namedialog/namedialog.component';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
@ -35,8 +36,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
ItemCreateComponent,
|
ItemCreateComponent,
|
||||||
ItemDeleteComponent,
|
ItemDeleteComponent,
|
||||||
ItemAddComponent,
|
ItemAddComponent,
|
||||||
CancelComponent
|
CancelComponent,
|
||||||
//NameDialogComponent,
|
CheckoutComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -58,6 +59,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
entryComponents: [ItemCreateComponent, ItemDeleteComponent, ItemAddComponent, CancelComponent]
|
entryComponents: [ItemCreateComponent, ItemDeleteComponent, ItemAddComponent, CancelComponent, CheckoutComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
.text {
|
||||||
|
font-family: "Roboto-Mono", monospace;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<div align="center" mat-dialog-title>
|
||||||
|
<h2 class="text">Scan to make payment</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-dialog-content>
|
||||||
|
<div align="center" id="checkout-qr"></div>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<table cellspacing="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button mat-raised-button color="primary" (click)="confirm()">
|
||||||
|
<mat-icon>verified_user</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<button mat-raised-button (click)="close()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</mat-dialog-actions>
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Inject, Component, OnInit, ViewEncapsulation} from '@angular/core';
|
||||||
|
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||||
|
var QRCode = require('easyqrcodejs');
|
||||||
|
var URLSafeBase64 = require('urlsafe-base64');
|
||||||
|
var Buffer = require('buffer/').Buffer;
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-checkout',
|
||||||
|
templateUrl: './checkout.component.html',
|
||||||
|
styleUrls: ['./checkout.component.css']
|
||||||
|
})
|
||||||
|
|
||||||
|
export class CheckoutComponent implements OnInit{
|
||||||
|
address: string;
|
||||||
|
total: number;
|
||||||
|
orderId: string;
|
||||||
|
codeString: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private dialogRef: MatDialogRef<CheckoutComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: { totalZec: number, addr: string, orderId: string}
|
||||||
|
) {
|
||||||
|
this.address = data.addr;
|
||||||
|
this.total = data.totalZec;
|
||||||
|
this.orderId = data.orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.codeString = `zcash:${this.address}?amount=${this.total.toFixed(6)}&memo=${URLSafeBase64.encode(Buffer.from('Z-Go Order '.concat(this.orderId)))}`;
|
||||||
|
var qrcode = new QRCode(document.getElementById("checkout-qr"), {
|
||||||
|
text: this.codeString,
|
||||||
|
logo: "/assets/zcash.png",
|
||||||
|
logoWidth: 80,
|
||||||
|
logoHeight: 80
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,12 @@
|
||||||
<mat-toolbar color="primary">
|
<mat-toolbar color="primary">
|
||||||
<span>
|
<span>
|
||||||
<a routerLink = "/">
|
<a routerLink = "/">
|
||||||
Zgo!
|
Z Go!
|
||||||
</a>
|
</a>
|
||||||
<p class="mini">Last block seen: {{heightUpdate | async}}</p>
|
<p class="mini">Last block seen: {{heightUpdate | async}}</p>
|
||||||
</span>
|
</span>
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<span align="center">
|
<span align="center">
|
||||||
<div>{{(ownerUpdate | async)!.name}}</div>
|
<div>{{ shortenZaddr((ownerUpdate | async)!.address) }}</div>
|
||||||
<div class="mini">{{ shortenZaddr((ownerUpdate | async)!.address) }}</div>
|
|
||||||
</span>
|
</span>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|
|
@ -50,6 +50,9 @@ export class ItemListComponent implements OnInit{
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
|
this.itemsUpdate.subscribe((items) => {
|
||||||
|
this.items = items;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openDialog(){
|
openDialog(){
|
||||||
|
@ -67,6 +70,9 @@ export class ItemListComponent implements OnInit{
|
||||||
this.itemService.addItem(item);
|
this.itemService.addItem(item);
|
||||||
}
|
}
|
||||||
this.itemService.getItems(this.owner.address);
|
this.itemService.getItems(this.owner.address);
|
||||||
|
this.itemsUpdate.subscribe((items) => {
|
||||||
|
this.items = items;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +120,12 @@ export class ItemListComponent implements OnInit{
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
console.log('Deleting', val);
|
console.log('Deleting', val);
|
||||||
this.itemService.deleteItem(val);
|
this.itemService.deleteItem(val);
|
||||||
|
this.items = [];
|
||||||
}
|
}
|
||||||
this.itemService.getItems(this.owner.address);
|
this.itemService.getItems(this.owner.address);
|
||||||
|
this.itemsUpdate.subscribe((items) => {
|
||||||
|
this.items = items;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,13 @@ export class ItemService{
|
||||||
private dataStore: { items: Item[] } = { items: [] } ;
|
private dataStore: { items: Item[] } = { items: [] } ;
|
||||||
private _itemsUpdated: BehaviorSubject<Item[]> = new BehaviorSubject(this.dataStore.items);
|
private _itemsUpdated: BehaviorSubject<Item[]> = new BehaviorSubject(this.dataStore.items);
|
||||||
public readonly itemsUpdated: Observable<Item[]> = this._itemsUpdated.asObservable();
|
public readonly itemsUpdated: Observable<Item[]> = this._itemsUpdated.asObservable();
|
||||||
|
private address:string = '';
|
||||||
|
|
||||||
constructor(private http: HttpClient){
|
constructor(private http: HttpClient){
|
||||||
}
|
}
|
||||||
|
|
||||||
getItems(addr: string){
|
getItems(addr: string){
|
||||||
|
this.address = addr;
|
||||||
const params = new HttpParams().append('address', addr);
|
const params = new HttpParams().append('address', addr);
|
||||||
let obs = this.http.get<{message: string, items: any}>('http://localhost:3000/api/getitems', { headers:{}, params: params, observe: 'response'});
|
let obs = this.http.get<{message: string, items: any}>('http://localhost:3000/api/getitems', { headers:{}, params: params, observe: 'response'});
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ export class ItemService{
|
||||||
|
|
||||||
obs.subscribe((ItemResponse) => {
|
obs.subscribe((ItemResponse) => {
|
||||||
console.log('Item added');
|
console.log('Item added');
|
||||||
|
this.getItems(this.address);
|
||||||
});
|
});
|
||||||
|
|
||||||
return obs;
|
return obs;
|
||||||
|
@ -45,6 +48,7 @@ export class ItemService{
|
||||||
|
|
||||||
obs.subscribe((ItemResponse) => {
|
obs.subscribe((ItemResponse) => {
|
||||||
console.log('Item deleted');
|
console.log('Item deleted');
|
||||||
|
this.getItems(this.address);
|
||||||
});
|
});
|
||||||
|
|
||||||
return obs;
|
return obs;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
* {
|
* {
|
||||||
font-family: 'Roboto Mono', monospace;
|
font-family: 'Roboto-Mono', monospace;
|
||||||
|
}
|
||||||
|
mat-card.coolcard{
|
||||||
|
background-color: #FF5722;
|
||||||
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,46 @@
|
||||||
<br>
|
<br>
|
||||||
<div align="center">
|
<div align="center" class="text">
|
||||||
<h1>Welcome to Zgo!</h1>
|
<mat-card class="coolcard">
|
||||||
|
<h3>
|
||||||
|
<pre>
|
||||||
|
__||__ _____ _
|
||||||
|
|___ / / ____| | |
|
||||||
|
/ / | | __ ___ | |
|
||||||
|
/ / | | |_ |/ _ \| |
|
||||||
|
/ /__ | |__| | (_) |_|
|
||||||
|
/__ _| \_____|\___/(_)
|
||||||
|
||
|
||||||
|
</pre>
|
||||||
|
</h3>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
<table>
|
<div align="center">
|
||||||
|
<table width="80%">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col span="1" style="width: 75%;">
|
<col span="1" style="width: 75%;">
|
||||||
<col span="1" style="width: 25%;">
|
<col span="1" style="width: 25%;">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<p>A non-custodial point-of-sale application, powered by Zcash.</p>
|
<mat-card>
|
||||||
|
<p>A non-custodial point-of-sale application, powered by Zcash!</p>
|
||||||
|
<ul>
|
||||||
|
<li>Your Zcash shielded address is your login.</li>
|
||||||
|
<li>Your customer pays directly to your wallet.</li>
|
||||||
|
</ul>
|
||||||
|
</mat-card>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
<mat-card>
|
||||||
<div align="center" id="info">
|
<div align="center" id="info">
|
||||||
<p>
|
<p>
|
||||||
Ensure you include your Reply-To shielded address!
|
Ensure you include your Reply-To shielded address!
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
Your shielded address is your username and all payments will be sent to it.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<br>
|
<br>
|
||||||
<div align="center" id="qrcode"></div>
|
<div align="center" id="qrcode"></div>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
<div align="center">
|
||||||
<p *ngIf="order.address.length == 0">No open order!</p>
|
<p *ngIf="order.address.length == 0">No open order!</p>
|
||||||
|
</div>
|
||||||
<mat-card class="text" *ngIf="order.address.length > 0">
|
<mat-card class="text" *ngIf="order.address.length > 0">
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<mat-card-title>
|
<mat-card-title>
|
||||||
{{order._id}}
|
|
||||||
<table cellspacing="0" width="100%">
|
<table cellspacing="0" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>Order Total:</td>
|
<td>Order Total:</td>
|
||||||
|
@ -31,8 +32,7 @@
|
||||||
<button mat-raised-button class="text" (click)="cancelOrder()">Cancel</button>
|
<button mat-raised-button class="text" (click)="cancelOrder()">Cancel</button>
|
||||||
</td>
|
</td>
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<button mat-raised-button class="text" color="primary">Checkout</button>
|
<button mat-raised-button class="text" color="primary" (click)="checkout()">Checkout</button>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { FullnodeService } from '../fullnode.service';
|
||||||
import { UserService } from '../user.service';
|
import { UserService } from '../user.service';
|
||||||
import { OrderService } from './order.service';
|
import { OrderService } from './order.service';
|
||||||
import { CancelComponent } from '../cancel/cancel.component';
|
import { CancelComponent } from '../cancel/cancel.component';
|
||||||
|
import { CheckoutComponent} from '../checkout/checkout.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-order',
|
selector: 'app-order',
|
||||||
|
@ -62,4 +63,25 @@ export class OrderComponent implements OnInit{
|
||||||
this.orderService.getOrder();
|
this.orderService.getOrder();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkout() {
|
||||||
|
const dialogConfig = new MatDialogConfig();
|
||||||
|
|
||||||
|
dialogConfig.disableClose = true;
|
||||||
|
dialogConfig.autoFocus = true;
|
||||||
|
dialogConfig.data = {
|
||||||
|
totalZec: this.total/this.price,
|
||||||
|
addr: this.order.address,
|
||||||
|
orderId: this.order._id
|
||||||
|
};
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(CheckoutComponent, dialogConfig);
|
||||||
|
dialogRef.afterClosed().subscribe((val) => {
|
||||||
|
if (val) {
|
||||||
|
console.log('Payment confirmed!');
|
||||||
|
} else {
|
||||||
|
console.log('Returning to order');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue