diff --git a/package-lock.json b/package-lock.json index ffb354d..359b040 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7527,6 +7527,14 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "ng-push-ivy": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ng-push-ivy/-/ng-push-ivy-1.0.7.tgz", + "integrity": "sha512-uUzIKBc6LA9Bw0sl7aj6x3eUr2UcCbXEw1PKpLFZ2OxzbnAhqh3IVX4ah0PRiDpfscFhmGUR2amLo19njAbMVg==", + "requires": { + "tslib": "^2.0.0" + } + }, "ngx-socket-io": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ngx-socket-io/-/ngx-socket-io-3.2.0.tgz", diff --git a/package.json b/package.json index 0ac198c..f7db27c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@angular/platform-browser-dynamic": "~11.0.5", "@angular/router": "~11.0.5", "angularx-qrcode": "^10.0.11", + "ng-push-ivy": "^1.0.7", "ngx-socket-io": "^3.2.0", "rxjs": "~6.6.0", "tslib": "^2.0.0", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 06874cd..b0f97f4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -13,6 +13,7 @@ import { HttpClientModule } from '@angular/common/http'; import { AppRoutingModule } from 'src/routes'; import { NotFoundComponent } from './not-found/not-found.component'; import { CartComponent } from './cart/cart.component'; +import { PushNotificationsModule } from 'ng-push-ivy'; const config: SocketIoConfig = { url: 'http://localhost:2009', options: {} }; @@ -31,7 +32,8 @@ const config: SocketIoConfig = { url: 'http://localhost:2009', options: {} }; QRCodeModule, HttpClientModule, AppRoutingModule, - SocketIoModule.forRoot(config) + SocketIoModule.forRoot(config), + PushNotificationsModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/backend.service.ts b/src/app/backend.service.ts index 466164f..44eb161 100644 --- a/src/app/backend.service.ts +++ b/src/app/backend.service.ts @@ -66,7 +66,7 @@ export interface IInvoice { }) export class BackendService { - SERVER_URL = 'http://localhost:2009'; + SERVER_URL = 'http://192.168.178.26:2009'; // Fill with empty data invoice: IInvoice = { @@ -138,7 +138,7 @@ export class BackendService { setInvoice(selector: string): Promise { return new Promise(async (resolve, reject) => { if (selector === undefined || selector === 'undefined' || selector === '') { - reject(); + reject('There is no selector. Please set one before calling setInvoice(...)'); return; } @@ -147,7 +147,6 @@ export class BackendService { responseType: 'json' }).toPromise().then((invoice) => { this.invoice = invoice as IInvoice; - this.invoiceUpdate.next(this.invoice); resolve(this.invoice); }).catch(err => { reject(err); @@ -224,7 +223,14 @@ export class BackendService { /** * @returns Path to icon in assets folder */ - getIcon(unit: CryptoUnits): string { + getIcon(unit?: CryptoUnits): string { + if (unit === undefined) { + if (this.invoice.paymentMethod === undefined) { + return 'assets/Bitcoin.svg'; + } + + unit = this.invoice.paymentMethod; + } switch (unit) { case CryptoUnits.BITCOIN: return 'assets/Bitcoin.svg'; @@ -241,7 +247,15 @@ export class BackendService { } } - findCryptoBySymbol(symbol: string): string | null { + findCryptoBySymbol(symbol?: string): string | null { + if (symbol === undefined) { + if (this.invoice.paymentMethod === undefined) { + return null; + } + + symbol = this.invoice.paymentMethod; + } + for (const coin in CryptoUnits) { // @ts-ignore: This actually works but I think it's too hacky for TS. Allow me this one, please. if (CryptoUnits[coin] === symbol.toUpperCase()) { diff --git a/src/app/cart/cart.component.css b/src/app/cart/cart.component.css index ea5aeff..d0d0a5b 100644 --- a/src/app/cart/cart.component.css +++ b/src/app/cart/cart.component.css @@ -47,4 +47,9 @@ .price { text-align: right; margin: auto; +} + +.quantity { + font-weight: lighter; + font-size: 10pt; } \ No newline at end of file diff --git a/src/app/cart/cart.component.html b/src/app/cart/cart.component.html index 862ef10..6d8f3cb 100644 --- a/src/app/cart/cart.component.html +++ b/src/app/cart/cart.component.html @@ -2,8 +2,8 @@ diff --git a/src/app/payment/payment.component.html b/src/app/payment/payment.component.html index b6e0eda..caaf04c 100644 --- a/src/app/payment/payment.component.html +++ b/src/app/payment/payment.component.html @@ -25,9 +25,9 @@
- + {{ this.backend.invoice?.receiveAddress }} Amount -

{{ this.backend.getAmount() }} BTC | {{ this.backend.invoice.totalPrice!.toFixed(2) }} {{ this.backend.currencyPrefix() }}

+

{{ this.backend.getAmount() }} {{ this.backend.invoice.paymentMethod }} | {{ this.backend.invoice.totalPrice!.toFixed(2) }} {{ this.backend.currencyPrefix() }}

Status

diff --git a/src/app/payment/payment.component.ts b/src/app/payment/payment.component.ts index 1b43b55..dec0c21 100644 --- a/src/app/payment/payment.component.ts +++ b/src/app/payment/payment.component.ts @@ -1,7 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { PushNotificationsService } from 'ng-push-ivy'; -import { BackendService, CryptoUnits } from '../backend.service'; +import { BackendService, CryptoUnits, PaymentStatus } from '../backend.service'; import { StateService } from '../state.service'; @Component({ @@ -15,6 +16,7 @@ export class PaymentComponent implements OnInit { confirmations = 0; status: string; ready = false; + emittedNotification = false; // XYZ class (will be xyz-out if cart is shown for example) xyzClass: string; @@ -23,7 +25,8 @@ export class PaymentComponent implements OnInit { constructor( public backend: BackendService, public state: StateService, - private route: ActivatedRoute + private route: ActivatedRoute, + private push: PushNotificationsService ) { this.status = this.backend.getStatus(); this.hideMain = false; @@ -49,9 +52,31 @@ export class PaymentComponent implements OnInit { this.xyzClass = 'xyz-in'; }, 600); } - }) + }); this.backend.invoiceUpdate.subscribe(newInvoice => { + if (newInvoice?.status === PaymentStatus.UNCONFIRMED) { + this.push.requestPermission(); + } + if (newInvoice?.status === PaymentStatus.DONE) { + if (this.emittedNotification) { return; } + this.push.create('Transaction confirmed!', { + body: 'Your transaction just got confirmed.', + lang: 'en', + icon: this.backend.getIcon(), + sticky: true, + vibrate: [250, 400, 250], + sound: 'assets/pay_success.mp3' + }).subscribe( + (res: any) => { + console.log('Success'); + }, + (err: any) => { + console.error('Error:', err); + } + ); + this.emittedNotification = true; + } this.status = this.backend.getStatus(); }); } @@ -61,7 +86,8 @@ export class PaymentComponent implements OnInit { } async get(): Promise { - await this.backend.setInvoice(this.paymentSelector); + const res = await this.backend.setInvoice(this.paymentSelector); + this.status = this.backend.getStatus(); this.backend.getConfirmation().catch(); this.ready = true; } diff --git a/src/app/state.service.ts b/src/app/state.service.ts index 6fb8c69..ebcaa43 100644 --- a/src/app/state.service.ts +++ b/src/app/state.service.ts @@ -14,13 +14,13 @@ export class StateService { constructor(private backend: BackendService) { this.showCart = new BehaviorSubject(false); - + this.backend.invoiceUpdate.subscribe(invoice => { this.showCart.next(false); // Hide cart if status changes }); } - toggleCart() { + toggleCart(): void { this.showCart.next(!this.showCart.value); } } diff --git a/src/assets/pay_success.mp3 b/src/assets/pay_success.mp3 new file mode 100644 index 0000000..6b3df9d Binary files /dev/null and b/src/assets/pay_success.mp3 differ