New component for receipts on order lists

This commit is contained in:
Rene V. Vergara A. 2022-07-25 16:42:56 -05:00
parent 7ef92aee12
commit 7930d6410b
12 changed files with 572 additions and 178 deletions

View file

@ -42,6 +42,7 @@ import { ReceiptQRComponent } from './receipt-qr/receipt-qr.component';
import { InvoiceComponent } from './invoice/invoice.component'; import { InvoiceComponent } from './invoice/invoice.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { PromptInvoiceComponent } from './prompt-invoice/prompt-invoice.component'; import { PromptInvoiceComponent } from './prompt-invoice/prompt-invoice.component';
import { PromptReceiptComponent } from './prompt-receipt/prompt-receipt.component';
import { NotifierComponent } from './notifier/notifier.component'; import { NotifierComponent } from './notifier/notifier.component';
@NgModule({ @NgModule({
@ -67,6 +68,7 @@ import { NotifierComponent } from './notifier/notifier.component';
ReceiptQRComponent, ReceiptQRComponent,
InvoiceComponent, InvoiceComponent,
PromptInvoiceComponent, PromptInvoiceComponent,
PromptReceiptComponent,
NotifierComponent NotifierComponent
], ],
imports: [ imports: [

View file

@ -3,6 +3,12 @@
font-family: Roboto Mono !important; font-family: Roboto Mono !important;
} }
.zecSign {
margin-bottom: -4px;
font-size: 18px;
height: 18px;
}
.invoiceHeader { .invoiceHeader {
display: flex; display: flex;
font-family: Spartan; font-family: Spartan;
@ -21,7 +27,6 @@
font-family: Roboto Mono !important; font-family: Roboto Mono !important;
padding: 10px; padding: 10px;
max-width: 600px; max-width: 600px;
background: #ebecf0;
} }
.invoiceHdrTxt1 { .invoiceHdrTxt1 {
@ -98,8 +103,6 @@
float: right; float: right;
} }
.zecData { .zecData {
width: auto; width: auto;
font-family: Spartan !important; font-family: Spartan !important;

View file

@ -1,111 +1,116 @@
<div style="display: flex;
<div class="invoiceHeader"> justify-content: center;
<img class="logo" src="/assets/logo-new-white.png" height="40px" /> align-items: center;">
{{name}} <div class="container">
</div> <div class="invoiceHeader">
<div class="invoiceDetail" <img class="logo" src="/assets/logo-new-white.png" height="40px" />
*ngIf="!error" {{name}}
id="invoice">
<div class="invoiceHdrTxt1">Invoice</div>
<div class="invoiceHdrTxt2">Order ID: {{orderId}}</div>
<div class="invoiceHdrTxt3">Date:{{order.timestamp | date}}
</div> </div>
<div style="height: 10px;"></div> <div class="invoiceDetail"
<div class="zecData">Zcash Price: {{order.price | number: '1.02' | currency: order.currency.toUpperCase()}}</div> *ngIf="!error"
<div style="height: 2px;"></div> id="invoice">
<div class="zecData">Total: <img class="total" src="/assets/zec_rv.png" height="18px" />{{order.totalZec | number: '1.08'}} <div class="invoiceHdrTxt1">Invoice</div>
<div class="invoiceHdrTxt2">Order ID: {{orderId}}</div>
<div class="invoiceHdrTxt3">Date:{{order.timestamp | date}}
</div> </div>
<div> <div style="height: 10px;"></div>
<div style="height: 10px;"></div> <div class="zecData">Zcash Price: {{order.price | number: '1.02' | currency: order.currency.toUpperCase()}}</div>
<table style="width: 100%;" <div style="height: 2px;"></div>
cellspacing="0"> <div class="zecData">Total: <img class="zecSign" src="/assets/zec_rv.png" />{{order.totalZec | number: '1.08'}}
<tr class="invoice-title"> </div>
<th width="55%" <div>
class="detailTitle1"> <div style="height: 10px;"></div>
Item <table style="width: 100%;"
</th> cellspacing="0">
<th width="15%" <tr class="invoice-title">
class="detailTitle1"> <th width="55%"
Qty. class="detailTitle1">
</th> Item
<th width="30%" </th>
class="detailTitle2"> <th width="15%"
Price ({{order.currency.toUpperCase()}}) class="detailTitle1">
</th> Qty.
</tr> </th>
<tr class="invoice-detail" <th width="30%"
*ngFor="let item of order.lines"> class="detailTitle2">
<td width="55%" Price ({{order.currency.toUpperCase()}})
align="left"> </th>
{{item.name}} </tr>
</td> <tr class="invoice-detail"
<td width="15%" *ngFor="let item of order.lines">
align="center"> <td width="55%"
{{item.qty}} align="left">
</td> {{item.name}}
<td width="30%" </td>
align="right"> <td width="15%"
{{( item.qty * item.cost ) | number : '1.02' | currency: order.currency.toUpperCase()}} align="center">
</td> {{item.qty}}
</tr> </td>
<tr class="invoice-title"> <td width="30%"
<th width="55%" align="right">
class="detailLineRight"> {{( item.qty * item.cost ) | number : '1.02' | currency: order.currency.toUpperCase()}}
Invoice Total: </td>
</th> </tr>
<th width="15%" <tr class="invoice-title">
class="detailLineLeft"> <th width="55%"
class="detailLineRight">
Invoice Total:
</th>
<th width="15%"
class="detailLineLeft">
</th> </th>
<th width="30%" <th width="30%"
class="detailLineRight"> class="detailLineRight">
{{ order.total | number : '1.02' | currency: order.currency.toUpperCase()}} {{ order.total | currency: order.currency.toUpperCase()}}
</th> </th>
</tr> </tr>
</table> </table>
<div style="height: 15px;"></div> <div style="height: 15px;"></div>
<table> <table>
<tr> <tr>
<td width="75%" <td width="75%"
style="font-size: 20px; style="font-size: 20px;
font-weight: 700; font-weight: 700;
font-style: italic; font-style: italic;
text-align: center;"> text-align: center;">
<p *ngIf="order.paid"> <p *ngIf="order.paid">
<fa-icon [icon]="faCheck" <fa-icon [icon]="faCheck"
color="primary"></fa-icon>&nbsp;Payment confirmed</p> color="primary"></fa-icon>&nbsp;Payment confirmed</p>
<p *ngIf="!order.paid"> <p *ngIf="!order.paid">
<fa-icon [style]="getIconStyle(order)" <fa-icon [style]="getIconStyle(order)"
[icon]="faHourglass"></fa-icon>&nbsp;Payment pending!!</p> [icon]="faHourglass"></fa-icon>&nbsp;Payment pending!!</p>
</td> </td>
<td width="25%"> <td width="25%">
<div style="text-align: right;" <div style="text-align: right;"
id="payment-qr" id="payment-qr"
*ngIf="!order.paid"></div> *ngIf="!order.paid"></div>
</td> </td>
</tr> </tr>
</table> </table>
</div>
</div>
<div align="center" *ngIf="error">
<div style="height: 10px;"></div>
<div style="font-family: Spartan !important;
font-size: 20px;
padding: 4px;
height: 24px;">
Incorrect Invoice ID.
</div>
<div style="font-family: Spartan !important;
font-size: 16px;
padding: 4px;">
No information available.
</div>
<div style="height: 10px;"></div>
<mat-card-actions>
<div align="center">
<button mat-raised-button [routerLink]="['/']" color="primary">OK</button>
</div> </div>
</mat-card-actions> </div>
<div align="center" *ngIf="error">
<div style="height: 10px;"></div>
<div style="font-family: Spartan !important;
font-size: 20px;
padding: 4px;
height: 24px;">
Incorrect Invoice ID.
</div>
<div style="font-family: Spartan !important;
font-size: 16px;
padding: 4px;">
No information available.
</div>
<div style="height: 10px;"></div>
<mat-card-actions>
<div align="center">
<button mat-raised-button [routerLink]="['/']" color="primary">OK</button>
</div>
</mat-card-actions>
</div>
</div>
</div> </div>

View file

@ -122,6 +122,20 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div style="display: flex;
justify-content: space-between;
padding: 5px;
height: 25px;
background: lightblue;
cursor: pointer;">
<button style="background: #ff5722;
color: white;"
(click)="invoice(order)">Invoice</button>
<button style="background: #ff5722;
color: white;"
(click)="receipt(order)">Receipt</button>
</div>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
<p class="text" *ngIf = "orders.length <= 0">No orders</p> <p class="text" *ngIf = "orders.length <= 0">No orders</p>

View file

@ -3,9 +3,13 @@ import { Observable } from 'rxjs';
import { Order } from '../order/order.model'; import { Order } from '../order/order.model';
import { FullnodeService } from '../fullnode.service'; import { FullnodeService } from '../fullnode.service';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
import {Owner} from '../owner.model'; import { Owner } from '../owner.model';
import { OrderService } from '../order/order.service'; import { OrderService } from '../order/order.service';
import { MatDialog, MatDialogConfig} from '@angular/material/dialog';
import { PromptInvoiceComponent } from '../prompt-invoice/prompt-invoice.component';
import { PromptReceiptComponent } from '../prompt-receipt/prompt-receipt.component';
import { faTimes } from '@fortawesome/free-solid-svg-icons'; import { faTimes } from '@fortawesome/free-solid-svg-icons';
import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; import { faTimesCircle } from '@fortawesome/free-solid-svg-icons';
import { faCheck } from '@fortawesome/free-solid-svg-icons'; import { faCheck } from '@fortawesome/free-solid-svg-icons';
@ -20,12 +24,14 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons';
}) })
export class ListOrdersComponent implements OnInit, OnDestroy{ export class ListOrdersComponent implements OnInit, OnDestroy{
// orderId;
public todayTotal: number = 0; public todayTotal: number = 0;
public total: number = 0; public total: number = 0;
public orders: Order[] = []; public orders: Order[] = [];
public ownerUpdate: Observable<Owner>; public ownerUpdate: Observable<Owner>;
public ordersUpdate: Observable<Order[]>; public ordersUpdate: Observable<Order[]>;
// ------------------------------------ // ------------------------------------
// //
faTimes = faTimes; faTimes = faTimes;
@ -40,8 +46,9 @@ export class ListOrdersComponent implements OnInit, OnDestroy{
constructor( constructor(
public orderService: OrderService, public orderService: OrderService,
public userService: UserService public userService: UserService,
){ private dialog: MatDialog)
{
this.ownerUpdate = userService.ownerUpdate; this.ownerUpdate = userService.ownerUpdate;
this.orderService.getAllOrders(); this.orderService.getAllOrders();
this.ordersUpdate = orderService.allOrdersUpdate; this.ordersUpdate = orderService.allOrdersUpdate;
@ -83,4 +90,46 @@ export class ListOrdersComponent implements OnInit, OnDestroy{
} }
invoice(order : Order) {
// var zec = this.total/this.price;
// this.order.totalZec = parseFloat(zec.toFixed(8));
const dialogConfig = new MatDialogConfig();
console.log("Order data:");
console.log(order);
console.log("order.total = " + order.total);
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.data = {
orderId: order._id
};
const dialogRef = this.dialog.open(PromptInvoiceComponent, dialogConfig);
dialogRef.afterClosed().subscribe((val) => {
console.log('Returning to order list');
});
}
receipt(order : Order) {
// var zec = this.total/this.price;
// this.order.totalZec = parseFloat(zec.toFixed(8));
const dialogConfig = new MatDialogConfig();
console.log("Order data:");
console.log(order);
console.log("order.total = " + order.total);
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.data = {
orderId: order._id
};
const dialogRef = this.dialog.open(PromptReceiptComponent, dialogConfig);
dialogRef.afterClosed().subscribe((val) => {
console.log('Returning to order list');
});
}
} }

View file

@ -0,0 +1,49 @@
::ng-deep .invoice {
font-family: "Spartan";
background: #ff5722;
font-weight: 700;
font-size: 18px;
text-align: center;
color: white;
line-height: 20px;
padding: 10px;
}
::ng-deep .invoice-content {
font-family: Roboto mono;
display: flex;
justify-content: center;
font-size: 16px;
}
.copy-button {
color: dodgerblue;
font-size: 20px;
margin: auto;
}
.urlLabel {
font-family: "Spartan";
font-size: 14px;
color: dimgray;
}
.urlDetail {
font-family: "Spartan";
font-size: 14px;
color: black;
}
.urlCopyBtn {
cursor: pointer;
}
.qr-code{
border-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}

View file

@ -0,0 +1,57 @@
<div class="container" style="margin-top: 10px;">
<div class="invoice" >
Send the receipt link to your client:
</div>
<table style="width:100%;
margin-top: 10px;">
<thead style="width: 100%;">
<tr>
<th class="urlLabel"
style="text-align: left;"
width="94%">Receipt URL:
</th>
<th></th>
</tr>
</thead>
<tbody>
<td class="urlDetail"
style="text-align: left;"
width="94%">
<div>
<textarea
style="border: none;
outline: none;
width: 95%;"
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="4">{{ receiptUrl }}
</textarea>
</div>
</td>
<td class="urlCopyBtn">
<a (click)='copyUrl()' >
<fa-icon [icon]="faCopy"
class="copy-button">
</fa-icon>
</a>
</td>
</tbody>
</table>
<mat-dialog-actions>
<table cellspacing="0" width="100%">
<tr>
<td align="right">
<button mat-raised-button class="text" (click)="close()">
<mat-icon class="icon">close</mat-icon>Close
</button>
</td>
</tr>
</table>
</mat-dialog-actions>
</div>

View file

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PromptReceiptComponent } from './prompt-receipt.component';
describe('PromptReceiptComponent', () => {
let component: PromptReceiptComponent;
let fixture: ComponentFixture<PromptReceiptComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PromptReceiptComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PromptReceiptComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,62 @@
import { Inject, Component, OnInit} from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import { NotifierService } from '../notifier.service';
import { faCopy } from '@fortawesome/free-solid-svg-icons';
var URLSafeBase64 = require('urlsafe-base64');
var Buffer = require('buffer/').Buffer;
@Component({
selector: 'app-prompt-receipt',
templateUrl: './prompt-receipt.component.html',
styleUrls: ['./prompt-receipt.component.css']
})
export class PromptReceiptComponent implements OnInit {
orderId: string;
receiptUrl: string;
// ------------------------------------
//
faCopy = faCopy;
// ------------------------------------
constructor(
private dialogRef: MatDialogRef<PromptReceiptComponent>,
@Inject(MAT_DIALOG_DATA) public data: {orderId: string},
private notifierService : NotifierService ) {
this.orderId = data.orderId;
this.receiptUrl = 'https://app.zgo.cash/receipt/'+this.orderId;
}
ngOnInit(): void {
}
confirm() {
this.dialogRef.close(true);
}
close() {
this.dialogRef.close(false);
}
copyUrl() {
// console.log("Inside copyUrl()");
if (navigator.clipboard) {
};
try {
navigator.clipboard.writeText(this.receiptUrl);
this.notifierService
.showNotification("Receipt's URL copied to Clipboard!!","Close",'success');
} catch (err) {
// console.error("Error", err);
this.notifierService
.showNotification("Functionality not available for your browser. Use send button instead.","Close",'error');
}
}
}

View file

@ -1,36 +1,112 @@
* {
font-family: 'Spartan', sans-serif; .invoice {
font-family: Roboto Mono !important;
} }
.spacer{ .zecSign {
flex: 1 1 auto; margin-bottom: -4px;
font-size: 18px;
height: 18px;
} }
.mat-card{
font-family: 'Spartan', sans-serif; .invoiceHeader {
border: 1px solid #FF7522; display: flex;
width: 80%; font-family: Spartan;
text-align: left; font-weight: 700;
margin: 5px; font-size: 26px;
max-width: 500px; color: white;
justify-content: space-between;
line-height: 40px;
padding: 10px;
vertical-align: center;
max-width: 600px;
background: #ff5722;
} }
.mat-card-title{
font-size: 16px; .invoiceDetail {
font-family: Roboto Mono !important;
padding: 10px;
max-width: 600px;
}
.invoiceHdrTxt1 {
font-family: Spartan !important;
text-align: center;
font-size: 30px;
font-weight: 700; font-weight: 700;
} }
.mat-card-subtitle{
font-size: 12px; .invoiceHdrTxt2 {
font-weight: 200; font-family: Spartan !important;
text-align: center;
font-size: 16px;
font-weight: 400;
} }
.mat-card-content{
font-size: 14px; .invoiceHdrTxt3 {
text-align: justify; font-family: Spartan !important;
text-align: center;
font-size: 12px;
font-weight: 300;
} }
span.tt{
font-family: 'Roboto-Mono', monospace; .detailTitle1 {
border-top: solid 2px;
border-bottom: solid 2px;
border-color: navy;
text-align: left;
} }
img.total{
margin-bottom:-2px; .detailTitle2 {
border-top: solid 2px;
border-bottom: solid 2px;
border-color: navy;
text-align: right;
} }
.small{
font-size: 10px; .detailLineRight {
border-top: solid 2px;
border-bottom: solid 2px;
border-color: navy;
text-align: right;
}
.detailLineLeft {
border-top: solid 2px;
border-bottom: solid 2px;
border-color: navy;
text-align: right;
}
.invoice-title {
font-size: 16px;
font-weight: 700;
background: lightcyan;
line-height: 30px;
padding: 5px;
}
.invoice-detail {
line-height: 20px;
font-size: 16px;
font-weight: 400;
padding-top: 4px;
padding-bottom: 4px;
}
.invoice-total {
margin-top: 40px;
}
.qrcode {
display: flex;
float: right;
}
.zecData {
width: auto;
font-family: Spartan !important;
font-size: 16px;
font-weight: 700;
text-align: right;
} }

View file

@ -1,44 +1,95 @@
<mat-toolbar color="primary"> <div style="display: flex;
<span align="center"> justify-content: center;
<img class="logo" src="/assets/logo-new-white.png" height="40px" /> align-items: center;">
</span> <div class="container">
<span class="spacer"></span> <div class="invoiceHeader">
<span align="center"> <img class="logo" src="/assets/logo-new-white.png" height="40px" />
<p class="text">{{name}}</p> {{name}}
</span> </div>
</mat-toolbar> <div class="invoiceDetail"
<div align="center"> *ngIf="!error"
<mat-card> id="invoice">
<mat-card-title> <div class="invoiceHdrTxt1">Receipt</div>
Total: <img class="total" src="/assets/spartan-zec.png" height="18px" />{{order.totalZec | number: '1.0-6'}} <div class="invoiceHdrTxt2">Order ID: {{orderId}}</div>
</mat-card-title> <div class="invoiceHdrTxt3">Date:{{order.timestamp | date}}
<mat-card-subtitle> </div>
{{order.timestamp | date}} <div style="height: 10px;"></div>
</mat-card-subtitle> <div class="zecData">Zcash Price: {{order.price | number: '1.02' | currency: order.currency.toUpperCase()}}</div>
<mat-card-content> <div style="height: 2px;"></div>
<p class="small">Order ID: {{orderId}}</p> <div class="zecData">Total: <img class="zecSign" src="/assets/zec_rv.png" />{{order.totalZec | number: '1.08'}}
<p>Zcash Price: {{order.price | currency: order.currency.toUpperCase()}}</p> </div>
<div align="center"> <div>
<table> <div style="height: 10px;"></div>
<tr> <table style="width: 100%;"
<th align="left"> cellspacing="0">
Item <tr class="invoice-title">
</th> <th width="55%"
<th align="center"> class="detailTitle1">
Qty. Item
</th> </th>
<th align="right"> <th width="15%"
Price ({{order.currency.toUpperCase()}}) class="detailTitle1">
</th> Qty.
</tr> </th>
<tr *ngFor="let item of order.lines"> <th width="30%"
<td align="left">{{item.name}}</td> class="detailTitle2">
<td align="center">{{item.qty}}</td> Price ({{order.currency.toUpperCase()}})
<td align="right">{{(item.qty * item.cost) | currency: order.currency.toUpperCase()}} </td> </th>
<tr> </tr>
</table> <tr class="invoice-detail"
*ngFor="let item of order.lines">
<td width="55%"
align="left">
{{item.name}}
</td>
<td width="15%"
align="center">
{{item.qty}}
</td>
<td width="30%"
align="right">
{{( item.qty * item.cost ) | number : '1.02' | currency: order.currency.toUpperCase()}}
</td>
</tr>
<tr class="invoice-title">
<th width="55%"
class="detailLineRight">
Total:
</th>
<th width="15%"
class="detailLineLeft">
</th>
<th width="30%"
class="detailLineRight">
{{ order.total | currency: order.currency.toUpperCase()}}
</th>
</tr>
</table>
<div style="height: 15px;"></div>
</div>
</div> </div>
</mat-card-content> <div align="center" *ngIf="error">
</mat-card> <div style="height: 10px;"></div>
<div style="font-family: Spartan !important;
font-size: 20px;
padding: 4px;
height: 24px;">
Incorrect Receipt ID.
</div>
<div style="font-family: Spartan !important;
font-size: 16px;
padding: 4px;">
No information available.
</div>
<div style="height: 10px;"></div>
<mat-card-actions>
<div align="center">
<button mat-raised-button [routerLink]="['/']" color="primary">OK</button>
</div>
</mat-card-actions>
</div>
</div>
</div> </div>

View file

@ -14,6 +14,7 @@ export class ReceiptComponent implements OnInit {
public orderUpdate: Observable<Order>; public orderUpdate: Observable<Order>;
public nameUpdate: Observable<string>; public nameUpdate: Observable<string>;
name: string = ''; name: string = '';
error: boolean = false;
order:Order = { order:Order = {
address: '', address: '',
session: '', session: '',