Basic WebSocket implementaion
Downgrade to Socket.io 2.3.0
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
.bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: #F7A12F;
|
||||
z-index: -999;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0 auto;
|
||||
transform: translateY(20vh);
|
||||
transform-origin: center;
|
||||
min-width: 900px;
|
||||
width: 50vw;
|
||||
|
||||
/* Shadow */
|
||||
box-shadow:
|
||||
0 -0.5px 2.8px -9px rgba(0, 0, 0, 0.39)
|
||||
;
|
||||
}
|
||||
|
||||
.content * {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,5 +1 @@
|
||||
<div class="bg"></div>
|
||||
<div class="content">
|
||||
<app-header></app-header>
|
||||
<app-payment></app-payment>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
@@ -5,16 +5,31 @@ import { AppComponent } from './app.component';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { PaymentComponent } from './payment/payment.component';
|
||||
import { QRCodeModule } from 'angularx-qrcode';
|
||||
import { PayComponent } from './pay/pay.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { HelloComponent } from './hello/hello.component';
|
||||
import { SocketIoConfig, SocketIoModule } from 'ngx-socket-io';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AppRoutingModule } from 'src/routes';
|
||||
import { NotFoundComponent } from './not-found/not-found.component';
|
||||
|
||||
const config: SocketIoConfig = { url: 'http://localhost:2009', options: {} };
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HeaderComponent,
|
||||
PaymentComponent
|
||||
PaymentComponent,
|
||||
PayComponent,
|
||||
HelloComponent,
|
||||
NotFoundComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
QRCodeModule
|
||||
QRCodeModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
SocketIoModule.forRoot(config)
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
|
||||
16
src/app/backend.service.spec.ts
Normal file
16
src/app/backend.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BackendService } from './backend.service';
|
||||
|
||||
describe('BackendService', () => {
|
||||
let service: BackendService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(BackendService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
94
src/app/backend.service.ts
Normal file
94
src/app/backend.service.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Socket } from 'ngx-socket-io';
|
||||
|
||||
/*
|
||||
* The following interfaces are copied from the backend.
|
||||
*
|
||||
* Checkout src/helper/types.ts and src/models/invoice/invoice.interface.ts
|
||||
* (in the backend repository) for more information.
|
||||
*/
|
||||
export enum CryptoUnits {
|
||||
BITCOIN = 'BTC',
|
||||
BITCOINCASH = 'BCH',
|
||||
ETHEREUM = 'ETH',
|
||||
LITECOIN = 'LTC',
|
||||
DOGECOIN = 'DOGE',
|
||||
MONERO = 'XMR'
|
||||
}
|
||||
|
||||
export interface ICart {
|
||||
price: number;
|
||||
name: string;
|
||||
image: string;
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
export interface IPaymentMethod {
|
||||
method: any;
|
||||
amount: number
|
||||
}
|
||||
|
||||
export enum PaymentStatus {
|
||||
PENDING = 0,
|
||||
PARTIALLY = 1,
|
||||
UNCONFIRMED = 2,
|
||||
DONE = 3,
|
||||
CANCELLED = 4
|
||||
}
|
||||
|
||||
export interface IInvoice {
|
||||
selector: string;
|
||||
paymentMethods: IPaymentMethod[];
|
||||
receiveAddress: string;
|
||||
paidWith?: CryptoUnits;
|
||||
paid?: number;
|
||||
transcationHashes?: string[];
|
||||
cart?: ICart[];
|
||||
totalPrice?: number;
|
||||
currency: string;
|
||||
dueBy: number;
|
||||
status?: PaymentStatus;
|
||||
email?: string;
|
||||
successUrl: string;
|
||||
cancelUrl: string;
|
||||
createdAt?: number;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BackendService {
|
||||
|
||||
SERVER_URL = 'http://localhost:2009';
|
||||
|
||||
constructor(
|
||||
private socket: Socket,
|
||||
private http: HttpClient
|
||||
) {
|
||||
this.socket.on('status', (data: any) => {
|
||||
console.log('Status has been updated to: ', data);
|
||||
});
|
||||
this.socket.on('subscribe', (success: boolean) => {
|
||||
if (success) { console.log('We\'re getting the progress of this invoice!'); }
|
||||
else { console.log('Subscription failed'); }
|
||||
});
|
||||
}
|
||||
|
||||
subscribeTo(selector: string) {
|
||||
this.socket.emit('subscribe', { selector });
|
||||
}
|
||||
|
||||
getInvoice(selector: string): Promise<IInvoice> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.http.get(this.SERVER_URL + '/invoice/' + selector, {
|
||||
observe: 'body',
|
||||
responseType: 'json'
|
||||
}).toPromise().then((invoice) => {
|
||||
resolve(invoice as IInvoice);
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
0
src/app/hello/hello.component.css
Normal file
0
src/app/hello/hello.component.css
Normal file
1
src/app/hello/hello.component.html
Normal file
1
src/app/hello/hello.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>hello works!</p>
|
||||
25
src/app/hello/hello.component.spec.ts
Normal file
25
src/app/hello/hello.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HelloComponent } from './hello.component';
|
||||
|
||||
describe('HelloComponent', () => {
|
||||
let component: HelloComponent;
|
||||
let fixture: ComponentFixture<HelloComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HelloComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HelloComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/hello/hello.component.ts
Normal file
15
src/app/hello/hello.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hello',
|
||||
templateUrl: './hello.component.html',
|
||||
styleUrls: ['./hello.component.css']
|
||||
})
|
||||
export class HelloComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
0
src/app/not-found/not-found.component.css
Normal file
0
src/app/not-found/not-found.component.css
Normal file
1
src/app/not-found/not-found.component.html
Normal file
1
src/app/not-found/not-found.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>not-found works!</p>
|
||||
25
src/app/not-found/not-found.component.spec.ts
Normal file
25
src/app/not-found/not-found.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NotFoundComponent } from './not-found.component';
|
||||
|
||||
describe('NotFoundComponent', () => {
|
||||
let component: NotFoundComponent;
|
||||
let fixture: ComponentFixture<NotFoundComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ NotFoundComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NotFoundComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/not-found/not-found.component.ts
Normal file
15
src/app/not-found/not-found.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-not-found',
|
||||
templateUrl: './not-found.component.html',
|
||||
styleUrls: ['./not-found.component.css']
|
||||
})
|
||||
export class NotFoundComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
26
src/app/pay/pay.component.css
Normal file
26
src/app/pay/pay.component.css
Normal file
@@ -0,0 +1,26 @@
|
||||
.bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: #F7A12F;
|
||||
z-index: -999;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0 auto;
|
||||
transform: translateY(20vh);
|
||||
transform-origin: center;
|
||||
min-width: 900px;
|
||||
width: 50vw;
|
||||
|
||||
/* Shadow */
|
||||
box-shadow:
|
||||
0 -0.5px 2.8px -9px rgba(0, 0, 0, 0.39)
|
||||
;
|
||||
}
|
||||
|
||||
.content * {
|
||||
width: 100%;
|
||||
}
|
||||
5
src/app/pay/pay.component.html
Normal file
5
src/app/pay/pay.component.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="bg"></div>
|
||||
<div class="content">
|
||||
<app-header></app-header>
|
||||
<app-payment></app-payment>
|
||||
</div>
|
||||
25
src/app/pay/pay.component.spec.ts
Normal file
25
src/app/pay/pay.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PayComponent } from './pay.component';
|
||||
|
||||
describe('PayComponent', () => {
|
||||
let component: PayComponent;
|
||||
let fixture: ComponentFixture<PayComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PayComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PayComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/pay/pay.component.ts
Normal file
15
src/app/pay/pay.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pay',
|
||||
templateUrl: './pay.component.html',
|
||||
styleUrls: ['./pay.component.css']
|
||||
})
|
||||
export class PayComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="qr">
|
||||
<img src="assets/Bitcoin.svg">
|
||||
<qrcode
|
||||
[qrdata]="'bitcoin:1QFrbboisCYgeBdowGAuCTK3r2YnZuApYd'"
|
||||
[qrdata]="'bitcoin:' + invoice!!.receiveAddress"
|
||||
[width]="256"
|
||||
[errorCorrectionLevel]="'M'"
|
||||
[elementType]="'svg'"
|
||||
@@ -12,16 +12,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data">
|
||||
<div class="data" *ngIf="ready">
|
||||
<!-- Payment data -->
|
||||
<span id="target">Send to
|
||||
<h3>1QFrbboisCYgeBdowGAuCTK3r2YnZuApYd</h3>
|
||||
<h3>{{ invoice!!.receiveAddress }}</h3>
|
||||
</span>
|
||||
<span id="amount">Amount
|
||||
<h3>0.00133700 BTC</h3>
|
||||
<h3>{{ getAmount() }} BTC</h3>
|
||||
</span>
|
||||
<span id="status">Status
|
||||
<h3>Pending</h3>
|
||||
<h3>{{ getStatus() }}</h3>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BackendService, IInvoice, CryptoUnits, PaymentStatus } from '../backend.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-payment',
|
||||
@@ -7,9 +9,50 @@ import { Component, OnInit } from '@angular/core';
|
||||
})
|
||||
export class PaymentComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
paymentSelector = '';
|
||||
choosenPaymentMethod = CryptoUnits.BITCOIN;
|
||||
ready = false;
|
||||
invoice: IInvoice | null = null;
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private route: ActivatedRoute
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.params.subscribe(params => {
|
||||
this.paymentSelector = params.id;
|
||||
this.backend.subscribeTo(this.paymentSelector);
|
||||
this.get();
|
||||
});
|
||||
}
|
||||
|
||||
async get() {
|
||||
this.invoice = await this.backend.getInvoice(this.paymentSelector);
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
getAmount() {
|
||||
return this.invoice?.paymentMethods.find(item => {
|
||||
return item.method === CryptoUnits.BITCOIN;
|
||||
})?.amount.toFixed(8);
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
switch (this.invoice?.status) {
|
||||
case PaymentStatus.PENDING:
|
||||
return 'Pending';
|
||||
case PaymentStatus.PARTIALLY:
|
||||
return 'Partly';
|
||||
case PaymentStatus.UNCONFIRMED:
|
||||
return 'Unconfirmed';
|
||||
case PaymentStatus.DONE:
|
||||
return 'Paid';
|
||||
case PaymentStatus.CANCELLED:
|
||||
return 'Cancelled';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
17
src/routes.ts
Normal file
17
src/routes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { HelloComponent } from "./app/hello/hello.component";
|
||||
import { NotFoundComponent } from "./app/not-found/not-found.component";
|
||||
import { PayComponent } from "./app/pay/pay.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'pay/:id', component: PayComponent, data: { title: 'Payment' } },
|
||||
{ path: '', component: HelloComponent },
|
||||
{ path: '**', component: NotFoundComponent }
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
Reference in New Issue
Block a user