Merge branch 'master' into dev

This commit is contained in:
Rene Vergara 2022-01-14 16:17:41 -06:00
commit f6a41f3893
24 changed files with 280 additions and 118 deletions

View file

@ -10,6 +10,7 @@ const itemmodel = require('./models/item');
const ordermodel = require('./models/order'); const ordermodel = require('./models/order');
const pricemodel = require('./models/price'); const pricemodel = require('./models/price');
const txmodel = require('./models/tx'); const txmodel = require('./models/tx');
const zecTxModel = require('./models/zectxs.js');
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const stdrpc = require('stdrpc'); const stdrpc = require('stdrpc');
const CoinGecko = require('coingecko-api'); const CoinGecko = require('coingecko-api');
@ -99,12 +100,14 @@ var blockInterval = setInterval( function() {
var re = /.*ZGO::(.*)\sReply-To:\s(z\w+)/; var re = /.*ZGO::(.*)\sReply-To:\s(z\w+)/;
async.each (txs, function(txData, callback) { async.each (txs, function(txData, callback) {
var memo = hexToString(txData.memo).replace(/\0/g, ''); var memo = hexToString(txData.memo).replace(/\0/g, '');
txmodel.updateOne({txid: txData.txid}, { confirmations: txData.confirmations, amount:txData.amount, memo: memo}, {new:true, upsert:true}, function(err,docs) { if (!txData.change) {
zecTxModel.updateOne({txid: txData.txid}, { txid: txData.txid, confirmations: txData.confirmations, amount:txData.amount, memo: memo}, {new:true, upsert:true}, function(err,docs) {
if (err) { if (err) {
console.log(err); console.log(err);
} }
}); });
if (re.test(memo)) { }
if (re.test(memo) && txData.confirmations < 100) {
//console.log('Processing tx:', memo); //console.log('Processing tx:', memo);
var match = re.exec(memo); var match = re.exec(memo);
if (match != null) { if (match != null) {
@ -114,16 +117,14 @@ var blockInterval = setInterval( function() {
var amount = txData.amount; var amount = txData.amount;
var expiration = blocktime; var expiration = blocktime;
//console.log(' ', session, blocktime); //console.log(' ', session, blocktime);
txmodel.updateOne({txid: txData.txid}, { address: address, session: session, confirmations: txData.confirmations, amount:txData.amount, memo: memo}, {new:true, upsert:true}, function(err,docs) { txmodel.updateOne({txid: txData.txid}, { txid: txData.txid, address: address, session: session, confirmations: txData.confirmations, amount:txData.amount, memo: memo}, {new:true, upsert:true}, function(err,docs) {
if (err) { if (err) {
console.log(err); console.log(err);
} }
}); });
if (txData.confirmations >= 6 ) { if (txData.confirmations >= 6 ) {
usermodel.findOne({address: address, session: session, blocktime: blocktime}).then(function(doc){ usermodel.findOne({address: address, session: session, blocktime: blocktime}).then(function(doc){
if (doc != null) { if (doc == null){
console.log('Found user');
} else {
console.log('User not found', session, blocktime, amount); console.log('User not found', session, blocktime, amount);
if (amount >= 0.001 && amount < 0.005){ if (amount >= 0.001 && amount < 0.005){
expiration = blocktime + 3600; expiration = blocktime + 3600;
@ -152,9 +153,7 @@ var blockInterval = setInterval( function() {
} }
}); });
ownermodel.findOne({address: address}).then(function (oDoc) { ownermodel.findOne({address: address}).then(function (oDoc) {
if (oDoc != null) { if (oDoc == null) {
console.log('Found owner');
} else {
console.log('Owner not found', session); console.log('Owner not found', session);
var owner = new ownermodel({ var owner = new ownermodel({
address: address, address: address,
@ -183,7 +182,7 @@ var blockInterval = setInterval( function() {
}); });
}); });
}, 90000); }, 75000);
app.use(cors()); app.use(cors());
app.options('*', cors()); app.options('*', cors());
@ -349,6 +348,7 @@ app.post('/api/updateowner', (req, res, next) => {
if (err) { if (err) {
console.log(err); console.log(err);
} else { } else {
console.log(docs);
res.status(201).json({ res.status(201).json({
message: 'Owner updated', message: 'Owner updated',
owner: docs owner: docs
@ -421,7 +421,7 @@ app.delete('/api/item/:id', (req, res, next) => {
app.get('/api/price', (req, res, next) => { app.get('/api/price', (req, res, next) => {
console.log('Get /api/price'); console.log('Get /api/price');
const price = pricemodel.findOne({currency: 'usd'}).then((document) => { const price = pricemodel.findOne({currency: req.query.currency}).then((document) => {
if (document != null) { if (document != null) {
res.status(200).json({ res.status(200).json({
message: 'price found!', message: 'price found!',
@ -495,6 +495,7 @@ app.post('/api/order', (req, res, next) => {
session: req.body.order.session, session: req.body.order.session,
price: req.body.order.price, price: req.body.order.price,
total: req.body.order.total, total: req.body.order.total,
currency: req.body.order.currency,
totalZec: req.body.order.totalZec, totalZec: req.body.order.totalZec,
closed: req.body.order.closed closed: req.body.order.closed
}, function(err, docs) { }, function(err, docs) {

View file

@ -6,6 +6,7 @@ const orderSchema = mongoose.Schema({
timestamp: {type: Date, required: true, default: Date.now}, timestamp: {type: Date, required: true, default: Date.now},
closed: { type: Boolean, required: true, default:false }, closed: { type: Boolean, required: true, default:false },
price: { type: Number, required: true}, price: { type: Number, required: true},
currency: {type: String, required: true},
total: { type: Number}, total: { type: Number},
totalZec: {type: Number}, totalZec: {type: Number},
lines: [{ lines: [{

View file

@ -2,7 +2,12 @@ const mongoose = require('mongoose');
const ownerSchema = mongoose.Schema({ const ownerSchema = mongoose.Schema({
address: {type: String, required:true, unique:true}, address: {type: String, required:true, unique:true},
name: {type: String, required:true} name: {type: String, required:true},
currency: {type: String, required:true, default: 'usd'},
tax: {type: Boolean, required: true, default: false},
taxValue: {type: Number },
vat: {type: Boolean, required:true, default: false},
vatValue: {type: Number }
}); });
module.exports = mongoose.model('Owner', ownerSchema); module.exports = mongoose.model('Owner', ownerSchema);

View file

@ -5,7 +5,7 @@ const txSchema = mongoose.Schema({
session: {type: String, required:true}, session: {type: String, required:true},
confirmations: {type: Number, required:true}, confirmations: {type: Number, required:true},
amount: {type: Number, required:true}, amount: {type: Number, required:true},
txid: {type:String, required:true}, txid: {type:String, required:true, unique: true},
memo: {type:String} memo: {type:String}
}); });

12
backend/models/zectxs.js Normal file
View file

@ -0,0 +1,12 @@
const mongoose = require('mongoose');
const ZecTxSchema = mongoose.Schema({
address: {type: String},
session: {type: String, required:true},
confirmations: {type: Number, required:true},
amount: {type: Number, required:true},
txid: {type:String, required:true, unique: true},
memo: {type:String}
});
module.exports = mongoose.model('ZecTx', ZecTxSchema);

View file

@ -12,6 +12,8 @@ import { MatIconModule } from '@angular/material/icon';
import { MatDividerModule } from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider';
import { MatListModule } from '@angular/material/list'; import { MatListModule } from '@angular/material/list';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatStepperModule } from '@angular/material/stepper';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -63,6 +65,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
MatDividerModule, MatDividerModule,
MatListModule, MatListModule,
MatSelectModule, MatSelectModule,
MatProgressBarModule,
MatStepperModule,
BrowserAnimationsModule BrowserAnimationsModule
], ],
exports: [ exports: [

View file

@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
import {Subject, Subscription, BehaviorSubject, Observable} from 'rxjs'; import {Subject, Subscription, BehaviorSubject, Observable} from 'rxjs';
import {HttpClient, HttpParams, HttpHeaders} from '@angular/common/http'; import {HttpClient, HttpParams, HttpHeaders} from '@angular/common/http';
import {UserService} from './user.service'; import {UserService} from './user.service';
import { Owner } from './owner.model';
//import {User} from './user.model'; //import {User} from './user.model';
@ -17,15 +18,30 @@ export class FullnodeService{
public readonly heightUpdate: Observable<number> = this._heightUpdated.asObservable(); public readonly heightUpdate: Observable<number> = this._heightUpdated.asObservable();
public readonly memoUpdate: Observable<string[]> = this._memoUpdated.asObservable(); public readonly memoUpdate: Observable<string[]> = this._memoUpdated.asObservable();
public readonly priceUpdate: Observable<number> = this._priceUpdated.asObservable(); public readonly priceUpdate: Observable<number> = this._priceUpdated.asObservable();
public readonly ownerUpdate: Observable<Owner>;
private UserSub: Subscription = new Subscription(); private UserSub: Subscription = new Subscription();
private apiKey = 'Le2adeic8Thah4Aeng4daem6i'; private apiKey = 'Le2adeic8Thah4Aeng4daem6i';
private reqHeaders: HttpHeaders; private reqHeaders: HttpHeaders;
private owner: Owner = {
_id: '',
name: '',
address: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
};
constructor(private http: HttpClient, public userService: UserService){ constructor(private http: HttpClient, public userService: UserService){
this.reqHeaders = new HttpHeaders().set('Authorization', this.apiKey); this.reqHeaders = new HttpHeaders().set('Authorization', this.apiKey);
this.ownerUpdate = userService.ownerUpdate;
this.getAddr(); this.getAddr();
this.getHeight(); this.getHeight();
this.getPrice(); this.ownerUpdate.subscribe((owner) => {
this.owner = owner;
this.getPrice(this.owner.currency);
});
} }
getHeight(){ getHeight(){
@ -38,8 +54,8 @@ export class FullnodeService{
return obs; return obs;
} }
getPrice(){ getPrice(currency: string){
var currency = 'usd'; //var currency = 'usd';
const params = new HttpParams().append('currency', currency); const params = new HttpParams().append('currency', currency);
let obs = this.http.get<{message: string, price: any}>(this.beUrl+'api/price', { headers:this.reqHeaders, params: params, observe: 'response'}); let obs = this.http.get<{message: string, price: any}>(this.beUrl+'api/price', { headers:this.reqHeaders, params: params, observe: 'response'});
obs.subscribe((PriceData) => { obs.subscribe((PriceData) => {
@ -55,16 +71,6 @@ export class FullnodeService{
return obs; return obs;
} }
hexToString(hexString: string) {
var str = '';
for (var n=0; n < hexString.length; n +=2) {
str += String.fromCharCode(parseInt(hexString.substr(n, 2), 16));
}
return str;
}
getAddr() { getAddr() {
let obs = this.http.get<{message: string, addr: string}>(this.beUrl+'api/getaddr', { headers: this.reqHeaders }); let obs = this.http.get<{message: string, addr: string}>(this.beUrl+'api/getaddr', { headers: this.reqHeaders });

View file

@ -4,6 +4,7 @@
</span> </span>
<span class="spacer"></span> <span class="spacer"></span>
<span align="center"> <span align="center">
<p class="mini text">Currency: {{ getCurrency() }}</p>
<p class="mini text">Last block:</p> <p class="mini text">Last block:</p>
<p class="mini text">{{heightUpdate | async}}</p> <p class="mini text">{{heightUpdate | async}}</p>
</span> </span>

View file

@ -15,7 +15,16 @@ import {Owner} from '../owner.model';
export class HeaderComponent implements OnInit, OnDestroy { export class HeaderComponent implements OnInit, OnDestroy {
public height = 0; public height = 0;
private owner: Owner= {_id:'', address: 'none', name:''}; private owner: Owner= {
_id:'',
address: 'none',
name:'',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
};
private session: string | null = ''; private session: string | null = '';
public heightUpdate: Observable<number>; public heightUpdate: Observable<number>;
public ownerUpdate: Observable<Owner>; public ownerUpdate: Observable<Owner>;
@ -41,6 +50,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
ngOnDestroy(){ ngOnDestroy(){
} }
getCurrency(){
return this.owner.currency.toUpperCase();
}
} }

View file

@ -1,15 +1,18 @@
<h2 mat-dialog-title class="text">Add item</h2> <h2 mat-dialog-title class="text">Add item</h2>
<mat-dialog-content [formGroup]="form"> <mat-dialog-content [formGroup]="form">
<mat-form-field class="text"> <mat-form-field class="text" appearance="outline">
<mat-label>Item</mat-label>
<input type="hidden" formControlName="id"> <input type="hidden" formControlName="id">
<input matInput placeholder="Item" formControlName="name"> <input matInput placeholder="Item" formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field class="text"> <mat-form-field class="text" appearance="outline">
<mat-label>Description</mat-label>
<textarea matInput placeholder="Description" formControlName="description"></textarea> <textarea matInput placeholder="Description" formControlName="description"></textarea>
</mat-form-field> </mat-form-field>
<mat-form-field class="text"> <mat-form-field class="text" appearance="outline">
<input matInput type="number" placeholder="Price in USD" formControlName="cost"> <mat-label>Price</mat-label>
<input matInput type="number" placeholder="Price" formControlName="cost">
<div *ngIf="!form.controls['cost'].valid && form.controls['cost'].touched"> <div *ngIf="!form.controls['cost'].valid && form.controls['cost'].touched">
<div *ngIf="form.controls['cost'].errors?.pattern">Use only numbers</div> <div *ngIf="form.controls['cost'].errors?.pattern">Use only numbers</div>
</div> </div>

View file

@ -5,7 +5,7 @@
<tr> <tr>
<td>{{item.name}}</td> <td>{{item.name}}</td>
<td align="right"> <td align="right">
<p class="price">{{item.cost | currency: 'USD'}}</p> <p class="price">{{item.cost | currency: getCurrency() }}</p>
<p class="price"><img class="icon" src="/assets/zec-roboto.png" width="10px" />{{(item.cost/price) | number: '1.0-6'}}</p> <p class="price"><img class="icon" src="/assets/zec-roboto.png" width="10px" />{{(item.cost/price) | number: '1.0-6'}}</p>
</td> </td>
</tr> </tr>

View file

@ -20,7 +20,16 @@ import { ItemAddComponent } from '../item-add/item-add.component';
export class ItemListComponent implements OnInit{ export class ItemListComponent implements OnInit{
public items: Item[] = []; public items: Item[] = [];
private owner: Owner = {_id: '', name: '', address: ''}; private owner: Owner = {
_id: '',
name: '',
address: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
};
public price: number = 1; public price: number = 1;
public ownerUpdate: Observable<Owner>; public ownerUpdate: Observable<Owner>;
public itemsUpdate: Observable<Item[]>; public itemsUpdate: Observable<Item[]>;
@ -38,7 +47,7 @@ export class ItemListComponent implements OnInit{
this.priceUpdate = fullnodeService.priceUpdate; this.priceUpdate = fullnodeService.priceUpdate;
this.ownerUpdate.subscribe((owner) => { this.ownerUpdate.subscribe((owner) => {
this.owner = owner; this.owner = owner;
console.log('owner address', this.owner.address); fullnodeService.getPrice(this.owner.currency);
itemService.getItems(this.owner.address); itemService.getItems(this.owner.address);
this.itemsUpdate.subscribe((items) => { this.itemsUpdate.subscribe((items) => {
this.items = items; this.items = items;
@ -151,5 +160,9 @@ export class ItemListComponent implements OnInit{
this.itemService.getItems(this.owner.address); this.itemService.getItems(this.owner.address);
}); });
} }
getCurrency(){
return this.owner.currency.toUpperCase();
}
} }

View file

@ -32,7 +32,7 @@
</mat-panel-description> </mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<p class="text">Order: {{order._id}}</p> <p class="text">Order: {{order._id}}</p>
<p class="text">Zcash price: {{order.price | currency: 'USD'}}</p> <p class="text">Zcash price: {{order.price | currency: order.currency.toUpperCase()}}</p>
<mat-list> <mat-list>
<mat-list-item class="text small" *ngFor="let item of order.lines">{{item.qty}} x {{item.name}}</mat-list-item> <mat-list-item class="text small" *ngFor="let item of order.lines">{{item.qty}} x {{item.name}}</mat-list-item>
</mat-list> </mat-list>

View file

@ -7,48 +7,11 @@
<div align="center"> <div align="center">
<mat-card class="centercard"> <mat-card class="centercard">
<h3>The Zcash Register</h3> <h3>The Zcash Register</h3>
<div width="75%" align="left" *ngIf="!confirmedMemo"> <mat-vertical-stepper #stepper linear>
<ol> <mat-step label="Log in with a shielded memo" editable="false">
<li> <mat-card [formGroup]="entryForm">
Select your session length.
</li>
<li>
Confirm you've sent your shielded memo.
</li>
<li>
Wait for confirmation of your transaction on the Zcash blockchain (~10 minutes).
</li>
<li>
Enter the PIN provided by ZGo to your wallet to confirm ownership.
</li>
</ol>
</div>
<div width="75%" *ngIf="confirmedMemo">
<p>Expecting confirmation around block {{targetBlock}}.</p>
</div>
</mat-card>
<mat-card [formGroup]="pinForm" *ngIf="prompt">
<h4>
Check your wallet
</h4>
<mat-form-field appearance="outline">
<mat-label>PIN</mat-label>
<input matInput formControlName="pinValue">
</mat-form-field>
<mat-card-actions>
<button mat-raised-button color="primary" [disabled]="!pinForm.valid" (click)="confirmPin()">
Confirm
</button>
</mat-card-actions>
</mat-card>
<mat-card class="alert-success" *ngIf = "txs.length > 0">
<h4>Login received!</h4>
<mat-list>
<mat-list-item *ngFor="let tx of txsUpdate | async">It needs {{6 - tx.confirmations}} more confirmations.</mat-list-item>
</mat-list>
</mat-card>
<mat-card class="centercard" [formGroup]="entryForm" *ngIf="!prompt && txs.length <=0">
<div align="center" id="info"> <div align="center" id="info">
<p>Select your session length and confirm once you've sent your memo:</p>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Session length</mat-label> <mat-label>Session length</mat-label>
<mat-select formControlName="selectedSession"> <mat-select formControlName="selectedSession">
@ -57,12 +20,38 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<p *ngIf="pinError">Wrong pin!</p>
<mat-card-actions> <mat-card-actions>
<button mat-raised-button color="primary" [disabled]="!entryForm.valid" (click)="login()"> <button mat-raised-button color="primary" [disabled]="!entryForm.valid" (click)="login(stepper)">
<mat-icon class="icon">login</mat-icon><span class="bigbutton">Log in</span> <mat-icon class="icon">login</mat-icon><span class="bigbutton">Log in</span>
</button> </button>
</mat-card-actions> </mat-card-actions>
</div> </div>
</mat-card> </mat-card>
</mat-step>
<mat-step label="ZGo confirms your login on the Zcash blockhain:" editable="false">
<p>{{barMessage}}</p>
<mat-progress-bar
[mode]="barMode"
[value]="barValue">
</mat-progress-bar>
</mat-step>
<mat-step label="Enter the PIN sent by ZGo to confirm wallet ownership:">
<mat-card [formGroup]="pinForm">
<h4>
Check your wallet
</h4>
<mat-form-field appearance="outline">
<mat-label>PIN</mat-label>
<input matInput formControlName="pinValue">
</mat-form-field>
<p *ngIf="pinError">Wrong pin!</p>
<mat-card-actions>
<button mat-raised-button color="primary" [disabled]="!pinForm.valid" (click)="confirmPin()">
Confirm
</button>
</mat-card-actions>
</mat-card>
</mat-step>
</mat-vertical-stepper>
</mat-card>
</div> </div>

View file

@ -1,7 +1,9 @@
import { Component, OnInit, OnDestroy, Injectable, ChangeDetectorRef } from '@angular/core'; import { Component, OnInit, OnDestroy, Injectable, ChangeDetectorRef, ViewChild, AfterViewInit } from '@angular/core';
import { CanActivate, Router, RouterStateSnapshot, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router'; import { CanActivate, Router, RouterStateSnapshot, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router';
import { MatDialog, MatDialogConfig} from '@angular/material/dialog'; import { MatDialog, MatDialogConfig} from '@angular/material/dialog';
import { FormBuilder, Validators, FormGroup, FormControl } from '@angular/forms'; import { FormBuilder, Validators, FormGroup, FormControl } from '@angular/forms';
import { ProgressBarMode } from '@angular/material/progress-bar';
import { MatStepper } from '@angular/material/stepper';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
import { FullnodeService } from '../fullnode.service'; import { FullnodeService } from '../fullnode.service';
import { ScanComponent} from '../scan/scan.component'; import { ScanComponent} from '../scan/scan.component';
@ -21,7 +23,7 @@ var Buffer = require('buffer/').Buffer;
styleUrls: ['./login.component.css'] styleUrls: ['./login.component.css']
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit, AfterViewInit {
txs: Tx[] = []; txs: Tx[] = [];
intervalHolder: any; intervalHolder: any;
nodeAddress: string = ''; nodeAddress: string = '';
@ -57,10 +59,15 @@ export class LoginComponent implements OnInit {
prompt: boolean = false; prompt: boolean = false;
confirmedMemo: boolean = false; confirmedMemo: boolean = false;
targetBlock: number = 0; targetBlock: number = 0;
barMode: ProgressBarMode = 'indeterminate';
barValue = 0;
barMessage = 'Scanning blockchain for login memo, please wait.';
@ViewChild('stepper') private myStepper?: MatStepper;
entryForm: FormGroup; entryForm: FormGroup;
pinForm: FormGroup; pinForm: FormGroup;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
@ -89,7 +96,8 @@ export class LoginComponent implements OnInit {
}); });
} }
ngOnInit(){ ngAfterViewInit(){
//console.log('Step', this.myStepper);
this.pinError = false; this.pinError = false;
//console.log('Activated route data in Component:::', this.activatedRoute.data); //console.log('Activated route data in Component:::', this.activatedRoute.data);
this.activatedRoute.data.subscribe((addrData) => { this.activatedRoute.data.subscribe((addrData) => {
@ -105,12 +113,15 @@ export class LoginComponent implements OnInit {
} }
this.loginCheck(); this.loginCheck();
}); });
}
ngOnInit(){
this.intervalHolder = setInterval(() => { this.intervalHolder = setInterval(() => {
this.fullnodeService.getHeight(); this.fullnodeService.getHeight();
//this.userService.findUser(); //this.userService.findUser();
this.loginCheck(); this.loginCheck();
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}, 1000 * 75); }, 1000 * 60);
} }
loginCheck(){ loginCheck(){
@ -122,16 +133,24 @@ export class LoginComponent implements OnInit {
}); });
this.userUpdate.subscribe((user) => { this.userUpdate.subscribe((user) => {
if (user.expiration > today) { if (user.expiration > today) {
this.prompt = true; if(this.myStepper!.selectedIndex === 1){
console.log('Log in found in blockchain!'); this.myStepper!.next();
}
//console.log('Log in found in blockchain!');
if (user.validated) { if (user.validated) {
this.router.navigate(['/shop']); this.router.navigate(['/shop']);
} }
} }
}); });
if (this.txs.length > 0) {
this.barMode = 'determinate';
this.barValue = (this.txs[0].confirmations / 6) * 100;
this.confirmedMemo = true;
this.barMessage = 'Login memo found, awaiting confirmations';
}
} }
login() { login(stepper: MatStepper) {
//console.log('Dropdown:', this.entryForm.value.selectedSession); //console.log('Dropdown:', this.entryForm.value.selectedSession);
const dialogConfig = new MatDialogConfig(); const dialogConfig = new MatDialogConfig();
@ -146,10 +165,9 @@ export class LoginComponent implements OnInit {
const dialogRef = this.dialog.open(ScanComponent, dialogConfig); const dialogRef = this.dialog.open(ScanComponent, dialogConfig);
dialogRef.afterClosed().subscribe((val) => { dialogRef.afterClosed().subscribe((val) => {
console.log('Awaiting confirmation'); console.log('Awaiting confirmation');
this.confirmedMemo = val; if(val){
this.heightUpdate.pipe(take(1)).subscribe(block => { stepper.next();
this.targetBlock = block + 10; }
});
}); });
} }

View file

@ -8,7 +8,7 @@
<tr> <tr>
<td>Order Total:</td> <td>Order Total:</td>
<td align="right"> <td align="right">
<p class="number">{{total | currency: 'USD'}}</p> <p class="number">{{total | currency: getCurrency()}}</p>
<p class="number"><img class="icon" src="/assets/zec-roboto.png" width="14px" />{{(total/price) | number: '1.0-6'}}</p> <p class="number"><img class="icon" src="/assets/zec-roboto.png" width="14px" />{{(total/price) | number: '1.0-6'}}</p>
</td> </td>
</tr> </tr>

View file

@ -15,7 +15,23 @@ import { CheckoutComponent} from '../checkout/checkout.component';
}) })
export class OrderComponent implements OnInit{ export class OrderComponent implements OnInit{
public order: Order = {address: '', session: '', timestamp: '', closed: false, price:0, total:0, totalZec: 0, lines: [{qty: 1, name: '', cost: 0}]}; public order: Order = {
address: '',
session: '',
timestamp: '',
closed: false,
currency: '',
price:0,
total:0,
totalZec: 0,
lines: [
{
qty: 1,
name: '',
cost: 0
}
]
};
public price: number = 1; public price: number = 1;
public total: number = 0; public total: number = 0;
public orderUpdate: Observable<Order>; public orderUpdate: Observable<Order>;
@ -87,4 +103,8 @@ export class OrderComponent implements OnInit{
} }
}); });
} }
getCurrency(){
return this.order.currency.toUpperCase();
}
} }

View file

@ -6,6 +6,7 @@ export interface Order {
session: string, session: string,
timestamp?: string, timestamp?: string,
closed: boolean, closed: boolean,
currency: string,
price?: number, price?: number,
total: number, total: number,
totalZec: number, totalZec: number,

View file

@ -5,13 +5,14 @@ import { Order } from './order.model';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
import { FullnodeService } from '../fullnode.service'; import { FullnodeService } from '../fullnode.service';
import { User } from '../user.model'; import { User } from '../user.model';
import { Owner } from '../owner.model';
import { LineItem} from '../items/lineitem.model'; import { LineItem} from '../items/lineitem.model';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class OrderService { export class OrderService {
beUrl = 'http://localhost:3000/'; beUrl = 'http://localhost:3000/';
private dataStore: {allOrders: Order[], user: User, order: Order } = { private dataStore: {allOrders: Order[], user: User, order: Order, owner: Owner } = {
allOrders: [], allOrders: [],
user:{ user:{
address: '', address: '',
@ -21,11 +22,22 @@ export class OrderService {
pin: '', pin: '',
validated: false validated: false
}, },
owner: {
_id: '',
name: '',
address: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
},
order: { order: {
address: '', address: '',
session: '', session: '',
timestamp: '', timestamp: '',
closed: false, closed: false,
currency: '',
price: 0, price: 0,
total: 0, total: 0,
totalZec: 0, totalZec: 0,
@ -45,6 +57,7 @@ export class OrderService {
private _allOrdersUpdated: BehaviorSubject<Order[]> = new BehaviorSubject(this.dataStore.allOrders); private _allOrdersUpdated: BehaviorSubject<Order[]> = new BehaviorSubject(this.dataStore.allOrders);
public readonly allOrdersUpdate: Observable<Order[]> = this._allOrdersUpdated.asObservable(); public readonly allOrdersUpdate: Observable<Order[]> = this._allOrdersUpdated.asObservable();
public userUpdate: Observable<User>; public userUpdate: Observable<User>;
public ownerUpdate: Observable<Owner>;
private apiKey = 'Le2adeic8Thah4Aeng4daem6i'; private apiKey = 'Le2adeic8Thah4Aeng4daem6i';
private reqHeaders: HttpHeaders; private reqHeaders: HttpHeaders;
@ -55,11 +68,15 @@ export class OrderService {
) { ) {
this.reqHeaders = new HttpHeaders().set('Authorization', this.apiKey); this.reqHeaders = new HttpHeaders().set('Authorization', this.apiKey);
this.userUpdate = userService.userUpdate; this.userUpdate = userService.userUpdate;
this.ownerUpdate = userService.ownerUpdate;
this.userUpdate.subscribe((user) => { this.userUpdate.subscribe((user) => {
this.dataStore.user = user; this.dataStore.user = user;
//console.log('OS: const', user); //console.log('OS: const', user);
this.getOrder(); this.getOrder();
}); });
this.ownerUpdate.subscribe((owner) => {
this.dataStore.owner = owner;
});
} }
getOrder() { getOrder() {
@ -116,6 +133,7 @@ export class OrderService {
var order:Order = { var order:Order = {
address: this.dataStore.user.address, address: this.dataStore.user.address,
session: this.dataStore.user.session, session: this.dataStore.user.session,
currency: this.dataStore.owner.currency,
closed: false, closed: false,
totalZec: 0, totalZec: 0,
price: 0, price: 0,
@ -144,6 +162,7 @@ export class OrderService {
session: '', session: '',
timestamp: '', timestamp: '',
closed: false, closed: false,
currency: '',
total: 0, total: 0,
totalZec: 0, totalZec: 0,
price: 0, price: 0,
@ -174,6 +193,7 @@ export class OrderService {
session: '', session: '',
timestamp: '', timestamp: '',
closed: false, closed: false,
currency: '',
price: 0, price: 0,
total: 0, total: 0,
totalZec: 0, totalZec: 0,

View file

@ -2,4 +2,9 @@ export interface Owner {
_id?: string; _id?: string;
address: string; address: string;
name: string; name: string;
currency: string;
tax: boolean;
taxValue: number;
vat: boolean;
vatValue: number;
} }

View file

@ -1,9 +1,18 @@
<h2 mat-dialog-title class="text">Settings</h2> <h2 mat-dialog-title class="text">Settings</h2>
<mat-dialog-content [formGroup]="settingsForm"> <mat-dialog-content [formGroup]="settingsForm">
<mat-form-field> <mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input matInput placeholder="Name" formControlName="name"> <input matInput placeholder="Name" formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Currency</mat-label>
<mat-select formControlName="currency">
<mat-option *ngFor="let coin of coins" [value]="coin.symbol">
{{coin.label}}
</mat-option>
</mat-select>
</mat-form-field>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>

View file

@ -14,6 +14,24 @@ export class SettingsComponent implements OnInit {
settingsForm: FormGroup; settingsForm: FormGroup;
owner: Owner; owner: Owner;
coins = [
{
label: 'US Dollar',
symbol: 'usd'
},{
label: 'Euro',
symbol: 'eur'
},{
label: 'British Pound',
symbol: 'gbp'
},{
label: 'Canadian Dollar',
symbol: 'cad'
},{
label: 'Australian Dollar',
symbol: 'aud'
}
];
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
@ -21,7 +39,8 @@ export class SettingsComponent implements OnInit {
@Inject(MAT_DIALOG_DATA) public data: Owner @Inject(MAT_DIALOG_DATA) public data: Owner
) { ) {
this.settingsForm = fb.group({ this.settingsForm = fb.group({
name: [data.name, Validators.required] name: [data.name, Validators.required],
currency: [data.currency, Validators.required]
}); });
this.owner = data; this.owner = data;
} }
@ -35,6 +54,7 @@ export class SettingsComponent implements OnInit {
save() { save() {
this.owner.name = this.settingsForm.value.name; this.owner.name = this.settingsForm.value.name;
this.owner.currency = this.settingsForm.value.currency;
this.dialogRef.close(this.owner); this.dialogRef.close(this.owner);
} }
} }

View file

@ -20,7 +20,12 @@ export class UserService{
}, },
owner: { owner: {
address: '', address: '',
name: '' name: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
}, },
txs : [] txs : []
}; };
@ -112,7 +117,16 @@ export class UserService{
} }
addOwner(address: string) { addOwner(address: string) {
const owner: Owner={_id: '', address: address, name: 'Zgo-'.concat(address.substring(0,5))}; const owner: Owner={
_id: '',
address: address,
name: 'Zgo-'.concat(address.substring(0,5)),
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
};
let obs = this.http.post<{message: string}>(this.beUrl+'api/addowner', {address: owner.address, name: owner.name}, {headers: this.reqHeaders}); let obs = this.http.post<{message: string}>(this.beUrl+'api/addowner', {address: owner.address, name: owner.name}, {headers: this.reqHeaders});
obs.subscribe((responseData) => { obs.subscribe((responseData) => {

View file

@ -28,7 +28,16 @@ export class ViewerComponent implements OnInit {
pin: '', pin: '',
validated: false validated: false
}; };
private owner: Owner= {_id:'', address: 'none', name:''}; private owner: Owner= {
_id:'',
address: 'none',
name:'',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0
};
public addrUpdate: Observable<string>; public addrUpdate: Observable<string>;
public ownerUpdate: Observable<Owner>; public ownerUpdate: Observable<Owner>;
public userUpdate: Observable<User>; public userUpdate: Observable<User>;
@ -87,8 +96,9 @@ export class ViewerComponent implements OnInit {
const dialogRef = this.dialog.open(SettingsComponent, dialogConfig); const dialogRef = this.dialog.open(SettingsComponent, dialogConfig);
dialogRef.afterClosed().subscribe((val) => { dialogRef.afterClosed().subscribe((val) => {
if (val != null) { if (val != null) {
console.log('Saving settings'); //console.log('Saving settings', val);
this.userService.updateOwner(val); this.userService.updateOwner(val);
this.fullnodeService.getPrice(val.currency);
} }
}); });
} }