Implement biz info form

This commit is contained in:
Rene Vergara 2022-01-22 07:49:22 -06:00
parent 5f80b1d912
commit f5a14bf7d7
11 changed files with 225 additions and 57 deletions

View file

@ -82,7 +82,7 @@ function hexToString(hexString) {
function sendPin(pin, address) { function sendPin(pin, address) {
//var memo = URLSafeBase64.encode(Buffer.from('ZGO pin: '.concat(pin))); //var memo = URLSafeBase64.encode(Buffer.from('ZGO pin: '.concat(pin)));
var memo = Buffer.from('ZGO pin: '.concat(pin)).toString('hex'); var memo = Buffer.from('ZGo PIN: '.concat(pin)).toString('hex');
//console.log(typeof(memo)); //console.log(typeof(memo));
var amounts = [ var amounts = [
{ {
@ -175,7 +175,8 @@ var blockInterval = setInterval( function() {
address: doc.address, address: doc.address,
blocktime: txData.blocktime, blocktime: txData.blocktime,
expiration: new Date(exptime * 1000), expiration: new Date(exptime * 1000),
amount: txData.amount amount: txData.amount,
session: doc.session
}); });
payment.save(function(error) { payment.save(function(error) {
@ -350,9 +351,8 @@ app.get('/api/getowner', (req, res, next) => {
}); });
app.post('/api/addowner', (req, res, next) => { app.post('/api/addowner', (req, res, next) => {
// TODO: confirm passing owner works
console.log('Post: /api/addowner'); console.log('Post: /api/addowner');
const owner = new ownermodel(req.body); const owner = new ownermodel(req.body.owner);
owner.save(); owner.save();
res.status(201).json({ res.status(201).json({
message: 'Owner added successfully' message: 'Owner added successfully'

View file

@ -13,7 +13,7 @@ const ownerSchema = mongoose.Schema({
city: {type: String, required: true}, city: {type: String, required: true},
state: {type: String, required: true}, state: {type: String, required: true},
postal: {type: String, required: true}, postal: {type: String, required: true},
phone: {type: String, required: true}, phone: {type: String},
website: {type: String}, website: {type: String},
paid: {type: Boolean, required: true, default: false} paid: {type: Boolean, required: true, default: false}
}); });

View file

@ -4,7 +4,8 @@ const paymentSchema = mongoose.Schema({
address: {type: String, required: true}, address: {type: String, required: true},
blocktime: {type: Number, required: true}, blocktime: {type: Number, required: true},
expiration: {type: Date, required: true}, expiration: {type: Date, required: true},
amount: {type: Number, required: true} amount: {type: Number, required: true},
session: {type: String, required: true}
}); });
module.exports = mongoose.model('Payment', paymentSchema); module.exports = mongoose.model('Payment', paymentSchema);

View file

@ -34,6 +34,7 @@ import { ScanComponent } from './scan/scan.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BusinessComponent } from './business/business.component'; import { BusinessComponent } from './business/business.component';
import { SearchOptionsPipe } from './searchoptions.pipe'; import { SearchOptionsPipe } from './searchoptions.pipe';
import { PaymentComponent } from './payment/payment.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -52,7 +53,8 @@ import { SearchOptionsPipe } from './searchoptions.pipe';
ScanComponent, ScanComponent,
ListOrdersComponent, ListOrdersComponent,
BusinessComponent, BusinessComponent,
SearchOptionsPipe SearchOptionsPipe,
PaymentComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View file

@ -2,6 +2,10 @@
font-family: 'Spartan', sans-serif; font-family: 'Spartan', sans-serif;
} }
mat-card.centercard{ mat-card.centercard{
max-width: 450px; max-width: 500px;
border: 1px solid #CCCCCC; border: 1px solid #CCCCCC;
} }
::ng-deep .mat-step-label{
font-size: 13px;
}

View file

@ -1,43 +1,78 @@
<app-header></app-header> <app-header></app-header>
<div align="center"> <div align="center">
<mat-card class="centercard" [formGroup]="bizForm"> <mat-card class="centercard">
<p>Business Information</p> <h3>Business sign-up</h3>
<mat-form-field appearance="outline"> <mat-vertical-stepper #stepper linear>
<mat-label>Business Name</mat-label> <mat-step label="Provide business info" editable="false">
<input matInput placeholder="Business Name" formControlName="name"> <p>We do not have a business associated with this Zcash address, please enter your information below:</p>
</mat-form-field> <mat-card [formGroup]="bizForm">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Address</mat-label> <mat-label>Business Name</mat-label>
<input matInput placeholder="Address" formControlName="street"> <input matInput placeholder="Business Name" formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>City</mat-label> <mat-label>Address</mat-label>
<input matInput placeholder="City" formControlName="city"> <input matInput placeholder="Address" formControlName="street">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>State/Province</mat-label> <mat-label>City</mat-label>
<input matInput placeholder="State or Province" formControlName="state"> <input matInput placeholder="City" formControlName="city">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Postal Code</mat-label> <mat-label>State/Province</mat-label>
<input matInput placeholder="Postal Code" formControlName="postal"> <input matInput placeholder="State or Province" formControlName="state">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Country</mat-label> <mat-label>Postal Code</mat-label>
<input matInput placeholder="Country" formControlName="country" [matAutocomplete]="auto"> <input matInput placeholder="Postal Code" formControlName="postal">
<mat-autocomplete #auto="matAutocomplete"> </mat-form-field>
<mat-option *ngFor="let ctry of countries | searchOptions:bizForm.get('country')!.value" [value]="ctry.name"> <mat-form-field appearance="outline">
{{ctry.name}} <mat-label>Country</mat-label>
</mat-option> <input matInput placeholder="Country" formControlName="country" [matAutocomplete]="auto">
</mat-autocomplete> <mat-autocomplete #auto="matAutocomplete">
</mat-form-field> <mat-option *ngFor="let ctry of countries | searchOptions:bizForm.get('country')!.value" [value]="ctry.name">
<mat-form-field appearance="outline"> {{ctry.name}}
<mat-label>E-mail</mat-label> </mat-option>
<input matInput placeholder="E-mail" formControlName="email"> </mat-autocomplete>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Website</mat-label> <mat-label>E-mail</mat-label>
<input matInput placeholder="Website" formControlName="website"> <input matInput type="email" placeholder="E-mail" formControlName="email">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Website</mat-label>
<input matInput placeholder="Website" formControlName="website">
</mat-form-field>
<mat-card-actions>
<button mat-raised-button color="primary" [disabled]="bizForm.invalid" (click)="save()">Save</button>
</mat-card-actions>
</mat-card>
</mat-step>
<mat-step label="Select your session" editable="false">
<p>Please select the length of session that you need:</p>
<mat-card [formGroup]="payForm">
<mat-form-field appearance="outline">
<mat-label>Session</mat-label>
<mat-select formControlName="session">
<mat-option *ngFor="let ticket of tickets" [value]="ticket.value">
{{ticket.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button color="primary" [disabled]="payForm.invalid" (click)="pay()">Pay</button>
</mat-card-actions>
</mat-card>
</mat-step>
<mat-step label="ZGo confirms your payment" editable="false">
<p>{{barMessage}}</p>
<mat-progress-bar
[mode]="barMode"
[value]="barValue">
</mat-progress-bar>
</mat-step>
</mat-vertical-stepper>
</mat-card> </mat-card>
</div> </div>

View file

@ -1,11 +1,18 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '@angular/forms'; import { FormBuilder, Validators, FormGroup, FormControl } from '@angular/forms';
import { MatDialog, MatDialogConfig} from '@angular/material/dialog';
import { ProgressBarMode } from '@angular/material/progress-bar';
import { Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { filter, startWith, map, switchMap } from 'rxjs/operators'; import { filter, startWith, map, switchMap } from 'rxjs/operators';
import { MatStepper } from '@angular/material/stepper';
import { Country } from '../country.model'; import { Country } from '../country.model';
import { Owner } from '../owner.model'; import { Owner } from '../owner.model';
import { User } from '../user.model';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
import { FullnodeService } from '../fullnode.service';
import { SearchOptionsPipe } from '../searchoptions.pipe'; import { SearchOptionsPipe } from '../searchoptions.pipe';
import { ScanComponent } from '../scan/scan.component';
@Component({ @Component({
selector: 'app-business', selector: 'app-business',
@ -14,16 +21,68 @@ import { SearchOptionsPipe } from '../searchoptions.pipe';
}) })
export class BusinessComponent implements OnInit { export class BusinessComponent implements OnInit {
@ViewChild('stepper', { static: false}) stepper: MatStepper|undefined;
nodeAddress: string = '';
tickets = [
{
value: 0.005,
viewValue: '1 day: 0.005 ZEC'
},{
value: 0.025,
viewValue: '1 week: 0.025 ZEC'
},{
value: 0.1,
viewValue: '1 month: 0.1 ZEC'
}
];
bizForm: FormGroup; bizForm: FormGroup;
payForm: FormGroup;
barMessage = 'Awaiting for transaction';
barMode: ProgressBarMode = 'indeterminate';
barValue = 0;
countries: Country[] = []; countries: Country[] = [];
owner: Owner = {
address: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0,
phone: '',
paid: false,
name: '',
street: '',
city: '',
state: '',
postal: '',
country: '',
email: '',
website: ''
}
public countriesUpdate: Observable<Country[]>; public countriesUpdate: Observable<Country[]>;
testSearch = 'uni'; public ownerUpdate: Observable<Owner>;
public addrUpdate: Observable<string>;
public userUpdate: Observable<User>;
sessionId = '';
ownerKnown = false;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
private userService: UserService private userService: UserService,
private fullnodeService: FullnodeService,
private dialog: MatDialog,
private router: Router
) { ) {
this.countriesUpdate = userService.countriesUpdate; this.countriesUpdate = userService.countriesUpdate;
this.ownerUpdate = userService.ownerUpdate;
this.userUpdate = userService.userUpdate;
this.userUpdate.subscribe(userInfo => {
this.sessionId = userInfo.session;
});
this.addrUpdate = fullnodeService.addrUpdate;
this.addrUpdate.subscribe(nodeAdd => {
this.nodeAddress = nodeAdd;
});
this.bizForm = fb.group({ this.bizForm = fb.group({
name: ['', Validators.required], name: ['', Validators.required],
street: ['', Validators.required], street: ['', Validators.required],
@ -31,16 +90,74 @@ export class BusinessComponent implements OnInit {
state: ['', Validators.required], state: ['', Validators.required],
postal: ['', Validators.required], postal: ['', Validators.required],
country: ['', Validators.required], country: ['', Validators.required],
email: ['', Validators.required], email: ['', [Validators.email, Validators.required]],
website: ['', Validators.required] website: ['']
});
this.payForm= fb.group({
session: ['', Validators.required]
}); });
this.userService.getCountries(); this.userService.getCountries();
this.countriesUpdate.subscribe((countries) => { this.countriesUpdate.subscribe((countries) => {
this.countries = countries; this.countries = countries;
}); });
this.ownerUpdate.subscribe((owner) => {
this.owner = owner;
});
} }
ngOnInit(): void { ngOnInit(): void {
} }
ngAfterViewInit(): void {
this.ownerUpdate.subscribe(ownerData => {
if(ownerData.name.length > 0 && this.stepper!.selectedIndex == 0){
this.stepper!.next();
}
});
}
save() {
this.owner = {
address: '',
currency: 'usd',
tax: false,
taxValue: 0,
vat: false,
vatValue: 0,
phone: '',
paid: false,
name: this.bizForm.get('name')!.value,
street: this.bizForm.get('street')!.value,
city: this.bizForm.get('city')!.value,
state: this.bizForm.get('state')!.value,
postal: this.bizForm.get('postal')!.value,
country: this.bizForm.get('country')!.value,
email: this.bizForm.get('email')!.value,
website: this.bizForm.get('website')!.value
};
this.userService.addOwner(this.owner);
this.stepper!.next();
}
pay(){
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.data = {
totalZec: this.payForm.get('session')!.value,
addr: this.nodeAddress,
session: this.sessionId,
pay: true
};
const dialogRef = this.dialog.open(ScanComponent, dialogConfig);
dialogRef.afterClosed().subscribe(val => {
console.log('Awaiting payment');
if(val){
this.stepper!.next();
}
});
}
} }

View file

@ -172,7 +172,7 @@ export class LoginComponent implements OnInit, AfterViewInit {
}); });
if (this.txs.length > 0) { if (this.txs.length > 0) {
this.barMode = 'determinate'; this.barMode = 'determinate';
this.barValue = (this.txs[0].confirmations / 6) * 100; this.barValue = (this.txs[0].confirmations / 2) * 100;
this.confirmedMemo = true; this.confirmedMemo = true;
this.barMessage = 'Login memo found, awaiting confirmations'; this.barMessage = 'Login memo found, awaiting confirmations';
} }
@ -187,7 +187,8 @@ export class LoginComponent implements OnInit, AfterViewInit {
dialogConfig.data = { dialogConfig.data = {
totalZec: 1e-8, totalZec: 1e-8,
addr: this.nodeAddress, addr: this.nodeAddress,
session: this.localToken session: this.localToken,
pay: false
}; };
const dialogRef = this.dialog.open(ScanComponent, dialogConfig); const dialogRef = this.dialog.open(ScanComponent, dialogConfig);

View file

@ -1,5 +1,5 @@
<div align="center" mat-dialog-title> <div align="center" mat-dialog-title>
<h4 class="text">Scan to connect your wallet</h4> <h4 class="text">Scan the QR code</h4>
</div> </div>
<mat-dialog-content> <mat-dialog-content>

View file

@ -17,17 +17,23 @@ export class ScanComponent implements OnInit{
total: number; total: number;
session: string; session: string;
codeString: string = ''; codeString: string = '';
pay: boolean = false;
zcashUrl: SafeUrl; zcashUrl: SafeUrl;
constructor( constructor(
private dialogRef: MatDialogRef<ScanComponent>, private dialogRef: MatDialogRef<ScanComponent>,
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
@Inject(MAT_DIALOG_DATA) public data: { totalZec: number, addr: string, session: string} @Inject(MAT_DIALOG_DATA) public data: { totalZec: number, addr: string, session: string, pay: boolean}
) { ) {
this.address = data.addr; this.address = data.addr;
this.total = data.totalZec; this.total = data.totalZec;
this.session = data.session; this.session = data.session;
this.codeString = `zcash:${this.address}?amount=${this.total.toFixed(8)}&memo=${URLSafeBase64.encode(Buffer.from('ZGO::'.concat(this.session)))}`; this.pay = data.pay;
if (this.pay) {
this.codeString = `zcash:${this.address}?amount=${this.total.toFixed(8)}&memo=${URLSafeBase64.encode(Buffer.from('ZGOp::'.concat(this.session)))}`;
} else {
this.codeString = `zcash:${this.address}?amount=${this.total.toFixed(8)}&memo=${URLSafeBase64.encode(Buffer.from('ZGO::'.concat(this.session)))}`;
}
this.zcashUrl = this.sanitizer.bypassSecurityTrustUrl(this.codeString); this.zcashUrl = this.sanitizer.bypassSecurityTrustUrl(this.codeString);
} }

View file

@ -143,10 +143,12 @@ export class UserService{
} }
addOwner(owner: Owner) { addOwner(owner: Owner) {
owner.address = this.dataStore.user.address;
let obs = this.http.post<{message: string}>(this.beUrl+'api/addowner', {owner: owner}, {headers: this.reqHeaders}); let obs = this.http.post<{message: string}>(this.beUrl+'api/addowner', {owner: owner}, {headers: this.reqHeaders});
obs.subscribe((responseData) => { obs.subscribe((responseData) => {
console.log(responseData.message); console.log(responseData.message);
this.getOwner(this.dataStore.user.address);
}); });
return obs; return obs;