diff --git a/src/app/backend.service.ts b/src/app/backend.service.ts index 38e8a51..c1aa87f 100644 --- a/src/app/backend.service.ts +++ b/src/app/backend.service.ts @@ -5,7 +5,7 @@ import { BehaviorSubject } from 'rxjs'; /* * 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. */ @@ -31,11 +31,14 @@ export interface IPaymentMethod { } export enum PaymentStatus { - CANCELLED = -2, - REQUESTED = -1, - PENDING = 0, - UNCONFIRMED = 1, - DONE = 2, + TOOLITTLE = -3, + TOOLATE = -2, + CANCELLED = -1, + REQUESTED = 0, + PENDING = 1, + UNCONFIRMED = 2, + DONE = 3, + TOOMUCH = 4 } export interface IInvoice { selector: string; @@ -43,7 +46,7 @@ export interface IInvoice { receiveAddress: string; paidWith?: CryptoUnits; paid?: number; - transcationHashes?: string[]; + transcationHash?: string; cart?: ICart[]; totalPrice?: number; currency: string; @@ -62,16 +65,32 @@ export class BackendService { SERVER_URL = 'http://localhost:2009'; - invoice: IInvoice | null = null; + // Fill with empty data + invoice: IInvoice = { + selector: '', + paymentMethods: [], + receiveAddress: '', + paid: 0, + currency: 'USD', + dueBy: Date.now(), + successUrl: '', + cancelUrl: '' + }; invoiceUpdate: BehaviorSubject; + // This value is s + confirmations: number; + constructor( private socket: Socket, private http: HttpClient ) { + this.confirmations = 0; this.invoiceUpdate = new BehaviorSubject(null); this.socket.on('status', (data: any) => { console.log('Status has been updated to: ', data); + this.invoice.status = data; + this.invoiceUpdate.next(this.invoice); }); this.socket.on('subscribe', (success: boolean) => { if (success) { console.log('We\'re getting the progress of this invoice!'); } @@ -92,17 +111,24 @@ export class BackendService { else { console.log('Failed to subscribe'); } }); + this.socket.on('confirmationUpdate', (update: any) => { + this.confirmations = update.count; + }); + this.socket.emit('subscribe', { selector }); } updateInvoice(): void { if (this.invoice !== undefined || this.invoice !== null) { - this.setInvoice(this.invoice?.selector!); + this.setInvoice(this.invoice.selector); } } setInvoice(selector: string): Promise { return new Promise(async (resolve, reject) => { + if (selector === undefined || selector === 'undefined' || selector === '') { + reject(); + } this.http.get(this.SERVER_URL + '/invoice/' + selector, { observe: 'body', responseType: 'json' @@ -118,10 +144,32 @@ export class BackendService { setPaymentMethod(method: CryptoUnits): Promise { return new Promise(async (resolve, reject) => { + if (this.invoice === null) { reject('Invoice is not set!'); return; } + this.http.post(`${this.SERVER_URL}/invoice/${this.invoice?.selector}/setmethod`, { method }, { responseType: 'json' }).toPromise().then(() => { - this.setInvoice(this.invoice!!.selector); + this.setInvoice(this.invoice.selector); + }).catch(err => { + reject(err); + }); + }); + } + + getConfirmation(): Promise { + return new Promise(async (resolve, reject) => { + if (this.invoice === null || this.invoice.status !== PaymentStatus.UNCONFIRMED) { + reject('Invoice is not set!'); + return; + } + + this.http.get(`${this.SERVER_URL}/invoice/${this.invoice.selector}/confirmation`, { + observe: 'body', + responseType: 'json' + }).toPromise().then((res: any) => { + this.confirmations = res.confirmation; + this.invoiceUpdate.next(this.invoice); + resolve(res.confirmation); }).catch(err => { reject(err); }); @@ -150,7 +198,7 @@ export class BackendService { findCryptoBySymbol(symbol: string): string | null { for (const coin in CryptoUnits) { - // @ts-ignore: This actually works but I thing it's too hacky for TS. Allow me this one, please? + // @ts-ignore: This actually works but I think it's too hacky for TS. Allow me this one, please. if (CryptoUnits[coin] === symbol.toUpperCase()) { return coin.charAt(0).toUpperCase() + coin.toLowerCase().slice(1); } @@ -173,7 +221,13 @@ export class BackendService { case PaymentStatus.DONE: return 'Paid'; case PaymentStatus.CANCELLED: - return 'Cancelled'; + return 'Cancelled by user'; + case PaymentStatus.TOOLATE: + return 'Expired'; + case PaymentStatus.TOOLITTLE: + return 'Paid too little'; + case PaymentStatus.TOOMUCH: + return 'Paid too much'; default: return 'Unknown'; } diff --git a/src/app/header/header.component.css b/src/app/header/header.component.css index 4b43824..ea17433 100644 --- a/src/app/header/header.component.css +++ b/src/app/header/header.component.css @@ -12,9 +12,10 @@ border-bottom-right-radius: 0; } -.header h2 { - font-weight: bolder; - width: fit-content; +.header img { + height: 3rem; + margin-top: 0.5rem; + margin-bottom: 1rem; grid-column: 1; } diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index 26b262b..8d81742 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -1,4 +1,4 @@
-

LibrePay

+ Cancel payment
\ No newline at end of file diff --git a/src/app/payment/payment.component.css b/src/app/payment/payment.component.css index 4e09810..1188699 100644 --- a/src/app/payment/payment.component.css +++ b/src/app/payment/payment.component.css @@ -3,15 +3,41 @@ padding: 0; width: 100%; height: 500px; - background-color: hsl(0, 0%, 11%); + background-color: #1c1c1c; border-radius: 8px; transform: translateY(-8px); } +/* Apply effect when invoice expired */ +.invalid { + filter: grayscale(1); +} +.invalid .qrWrapper, .invalid .data { + filter: blur(10px); + animation: blurFade 0.2s ease; + cursor: not-allowed; + user-select: none; +} +.invalid svg, .invalid img { + display: none; +} + +@keyframes blurFade { + from { filter: blur(0) } + to { filter: blur(10px) } +} + .request { transform: translateY(-40px); } +.loader { + position: absolute; + display: inline; + transform: translateY(-24px) translateX(32px); +} + +/* Styles for payment screen (not for payment choosing) */ .main { display: grid; height: 400px; @@ -38,6 +64,18 @@ z-index: 2; } +.alert { + text-align: center; + background-color: #C03A08; + color: #fff; + padding: 1rem; + border-radius: 8px; + border: 3px solid #a93206; +} +.alert p { + margin: 0; +} + @keyframes coinRoll { 0% { transform: translateY(96px) rotate(-45deg) scale(0.5); @@ -65,6 +103,11 @@ grid-row: 4; } +.price { + font-size: 10pt; + font-weight: light; +} + .main h3 { line-height: 0; } diff --git a/src/app/payment/payment.component.html b/src/app/payment/payment.component.html index 2b59911..6fada5b 100644 --- a/src/app/payment/payment.component.html +++ b/src/app/payment/payment.component.html @@ -1,6 +1,6 @@

Choose your
payment method

-

{{ this.backend.invoice!!.totalPrice!!.toFixed(2) }} €

+

{{ this.backend.invoice.totalPrice!.toFixed(2) }} €

  • @@ -12,12 +12,12 @@
-
+
Send to -

{{ this.backend.invoice!.receiveAddress }}

+

{{ this.backend.invoice?.receiveAddress }}

Amount -

{{ this.backend.getAmount() }} BTC

+

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

Status -

{{ this.backend.getStatus() }}

+

+ {{ status }} +
+ + + + + +
+

+ Confirmations: {{ this.backend.confirmations }}
+
+ +
+

This invoice expired +
You cannot pay this invoice anymore. Please try to request a new invoice.

+
+
+

Looks like you paid too much. +
Technically this invoice is paid but we would like to pay the rest back. Since sending back funds is complicated we would like you to contact support@example.org

+
+
+

Looks like you paid not the requested amount of money. +
You cannot pay twice! Since sending back funds is complicated we would like you to contact support@example.org

\ No newline at end of file diff --git a/src/app/payment/payment.component.ts b/src/app/payment/payment.component.ts index 24cb7b1..dc93a0c 100644 --- a/src/app/payment/payment.component.ts +++ b/src/app/payment/payment.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { BackendService, IInvoice, CryptoUnits, PaymentStatus, IPaymentMethod } from '../backend.service'; + +import { BackendService, CryptoUnits } from '../backend.service'; @Component({ selector: 'app-payment', @@ -10,13 +11,17 @@ import { BackendService, IInvoice, CryptoUnits, PaymentStatus, IPaymentMethod } export class PaymentComponent implements OnInit { paymentSelector = ''; + confirmations = 0; choosenPaymentMethod = CryptoUnits.BITCOIN; + status: string; ready = false; constructor( public backend: BackendService, private route: ActivatedRoute - ) { } + ) { + this.status = this.backend.getStatus(); + } ngOnInit(): void { this.route.params.subscribe(params => { @@ -24,14 +29,19 @@ export class PaymentComponent implements OnInit { this.backend.subscribeTo(this.paymentSelector); this.get(); }); + + this.backend.invoiceUpdate.subscribe(newInvoice => { + this.status = this.backend.getStatus(); + }); } - chooseMethod(coin: CryptoUnits) { + chooseMethod(coin: CryptoUnits): void { this.backend.setPaymentMethod(coin); } async get(): Promise { await this.backend.setInvoice(this.paymentSelector); + this.backend.getConfirmation().catch(); this.ready = true; } diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..3b57be4 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/index.html b/src/index.html index 513ec6e..d97dd2c 100644 --- a/src/index.html +++ b/src/index.html @@ -8,6 +8,7 @@ +