Implement order creation and cancellation
This commit is contained in:
parent
af8ee5dc90
commit
dce8da391e
19 changed files with 228 additions and 36 deletions
|
@ -287,7 +287,35 @@ app.post('/api/order', (req, res, next) => {
|
|||
const order = new ordermodel(req.body.order);
|
||||
order.save();
|
||||
res.status(200).json({
|
||||
message: 'Order added'
|
||||
message: 'Order added',
|
||||
order: order
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/api/lineitem', (req, res, next) => {
|
||||
console.log('Post /api/lineitem');
|
||||
ordermodel.findByIdAndUpdate(req.body.order_id, { $push: {lines: req.body.line}}, function(err,docs) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
res.status(200).json({
|
||||
message: 'Item added to order'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.delete('/api/order/:id', (req, res, next) => {
|
||||
console.log('delete order endpoint', req.params.id);
|
||||
ordermodel.findByIdAndDelete(req.params.id, function (err, docs) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log(docs);
|
||||
res.status(200).json({
|
||||
message: 'Order deleted'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ const orderSchema = mongoose.Schema({
|
|||
closed: { type: Boolean, required: true, default:false },
|
||||
lines: [{
|
||||
qty: {type: Number, required: true, default: 1},
|
||||
item: { type: String, required: true},
|
||||
name: { type: String, required: true},
|
||||
cost: { type: Number, required: true, default: 0}
|
||||
}]
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ import { ItemCreateComponent } from './items/item-create/item-create.component';
|
|||
import { ItemDeleteComponent } from './items/item-delete/item-delete.component';
|
||||
import { ItemAddComponent} from './items/item-add/item-add.component';
|
||||
import { OrderComponent } from './order/order.component';
|
||||
import { CancelComponent } from './cancel/cancel.component';
|
||||
//import { NameDialogComponent } from './namedialog/namedialog.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
|
@ -33,7 +34,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|||
OrderComponent,
|
||||
ItemCreateComponent,
|
||||
ItemDeleteComponent,
|
||||
ItemAddComponent
|
||||
ItemAddComponent,
|
||||
CancelComponent
|
||||
//NameDialogComponent,
|
||||
],
|
||||
imports: [
|
||||
|
@ -56,6 +58,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent],
|
||||
entryComponents: [ItemCreateComponent, ItemDeleteComponent, ItemAddComponent]
|
||||
entryComponents: [ItemCreateComponent, ItemDeleteComponent, ItemAddComponent, CancelComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
3
src/app/cancel/cancel.component.css
Normal file
3
src/app/cancel/cancel.component.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.text {
|
||||
font-family: "Roboto-Mono", monospace;
|
||||
}
|
24
src/app/cancel/cancel.component.html
Normal file
24
src/app/cancel/cancel.component.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<h2 mat-dialog-title class="text">Cancel Order</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<p class="text">Are you sure you want to cancel the order?</p>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions>
|
||||
<table cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<button mat-raised-button color="primary" (click)="confirm()">
|
||||
Yes
|
||||
</button>
|
||||
|
||||
</td>
|
||||
<td align="right">
|
||||
<button mat-raised-button (click)="close()">
|
||||
No
|
||||
</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</mat-dialog-actions>
|
23
src/app/cancel/cancel.component.ts
Normal file
23
src/app/cancel/cancel.component.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { Inject, Component, OnInit, ViewEncapsulation} from '@angular/core';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cancel',
|
||||
templateUrl: './cancel.component.html',
|
||||
styleUrls: ['./cancel.component.css']
|
||||
})
|
||||
|
||||
export class CancelComponent {
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<CancelComponent>
|
||||
) {}
|
||||
|
||||
confirm() {
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
}
|
0
src/app/checkout/checkout.component.css
Normal file
0
src/app/checkout/checkout.component.css
Normal file
0
src/app/checkout/checkout.component.html
Normal file
0
src/app/checkout/checkout.component.html
Normal file
0
src/app/checkout/checkout.component.ts
Normal file
0
src/app/checkout/checkout.component.ts
Normal file
|
@ -1,3 +1,7 @@
|
|||
.text {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
}
|
||||
|
||||
input[type=number]{
|
||||
text-align: right;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<mat-dialog-content [formGroup]="orderForm">
|
||||
<p class="text">{{lineItem.name}}</p>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="Quantity" formControlName="qty">
|
||||
<input matInput type="number" placeholder="Quantity" formControlName="qty">
|
||||
</mat-form-field>
|
||||
</mat-dialog-content>
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
.text {
|
||||
font-family: 'Roboto-Mono', monospace;
|
||||
}
|
||||
|
||||
input[type=number]{
|
||||
text-align: right;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
font-family: 'Roboto-Mono', monospace;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-family: 'Roboto-Mono', monospace;
|
||||
}
|
||||
.small {
|
||||
font-size: 75%;
|
||||
}
|
||||
.icons {
|
||||
font-family: 'Material Icons';
|
||||
}
|
||||
|
@ -11,7 +17,7 @@
|
|||
}
|
||||
|
||||
img.icon{
|
||||
margin-bottom: -1px;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
div.card{
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
<div *ngIf="items.length > 0">
|
||||
<div class="card" *ngFor="let item of itemsUpdate | async">
|
||||
<mat-card>
|
||||
<mat-card-title class="card">
|
||||
<table cellspacing="0" width="100%">
|
||||
<table cellspacing="0" width="100%" class="text">
|
||||
<tr>
|
||||
<td>{{item.name}}</td>
|
||||
<td align="right">
|
||||
<p class="price">{{item.cost | currency: 'USD'}}</p>
|
||||
<p class="price"><img class="icon" src="/assets/zec.png" width="12px" />{{(item.cost/price) | number: '1.0-6'}}</p>
|
||||
<p class="price"><img class="icon" src="/assets/zec-roboto.png" width="10px" />{{(item.cost/price) | number: '1.0-6'}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle class="card">
|
||||
<p>{{item.description}}</p>
|
||||
</mat-card-subtitle>
|
||||
<div align="center">
|
||||
<p class="text small">{{item.description}}</p>
|
||||
</div>
|
||||
<mat-card-actions>
|
||||
<table cellspacing="0" width="100%">
|
||||
<tr>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
.text {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-family: "Roboto-Mono", monospace;
|
||||
}
|
||||
|
||||
img.icon{
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,41 @@
|
|||
<p *ngIf="order.address.length == 0">No open order!</p>
|
||||
<mat-card class="text" *ngIf="order.address.length > 0">
|
||||
<div align="center">
|
||||
<mat-card-title>
|
||||
{{order._id}}
|
||||
<table cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td>Order Total:</td>
|
||||
<td align="right">
|
||||
<p class="text">{{total | currency: 'USD'}}</p>
|
||||
<p class="text"><img class="icon" src="/assets/zec-roboto.png" width="14px" />{{(total/price) | number: '1.0-6'}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</mat-card-title>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Qty.</th>
|
||||
<th>Items</th>
|
||||
</tr>
|
||||
<tr *ngFor="let item of order.lines">
|
||||
<td>{{item.qty}}</td>
|
||||
<td align="right">{{item.qty}}</td>
|
||||
<td>{{item.name}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<mat-card-actions>
|
||||
<table cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<button mat-raised-button class="text" (click)="cancelOrder()">Cancel</button>
|
||||
</td>
|
||||
<td align="right">
|
||||
<button mat-raised-button class="text" color="primary">Checkout</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog, MatDialogConfig} from '@angular/material/dialog';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Order } from './order.model';
|
||||
import { FullnodeService } from '../fullnode.service';
|
||||
import { UserService } from '../user.service';
|
||||
import { OrderService } from './order.service';
|
||||
import { CancelComponent } from '../cancel/cancel.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-order',
|
||||
|
@ -14,20 +16,50 @@ import { OrderService } from './order.service';
|
|||
export class OrderComponent implements OnInit{
|
||||
public order: Order = {address: '', session: '', timestamp: '', closed: false, lines: [{qty: 1, name: '', cost: 0}]};
|
||||
public price: number = 1;
|
||||
public total: number = 0;
|
||||
public orderUpdate: Observable<Order>;
|
||||
public priceUpdate: Observable<number>;
|
||||
public totalUpdate: Observable<number>;
|
||||
|
||||
constructor(
|
||||
public fullnodeService: FullnodeService,
|
||||
public orderService: OrderService
|
||||
public orderService: OrderService,
|
||||
private dialog: MatDialog
|
||||
) {
|
||||
this.priceUpdate = fullnodeService.priceUpdate;
|
||||
this.priceUpdate.subscribe((price) => {
|
||||
this.price = price;
|
||||
});
|
||||
this.orderUpdate = orderService.orderUpdate;
|
||||
this.orderUpdate.subscribe((order) => {
|
||||
this.order = order;
|
||||
});
|
||||
this.totalUpdate = orderService.totalUpdate;
|
||||
this.totalUpdate.subscribe((total) => {
|
||||
this.total = total;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
cancelOrder() {
|
||||
const dialogConfig = new MatDialogConfig();
|
||||
|
||||
dialogConfig.disableClose = true;
|
||||
dialogConfig.autoFocus = true;
|
||||
|
||||
const dialogRef = this.dialog.open(CancelComponent, dialogConfig);
|
||||
dialogRef.afterClosed().subscribe((val) => {
|
||||
if (val) {
|
||||
console.log('Canceling');
|
||||
this.orderService.cancelOrder(this.order._id!).subscribe((response) => {
|
||||
this.orderService.getOrder();
|
||||
});;
|
||||
} else {
|
||||
console.log('Returning to page');
|
||||
}
|
||||
this.orderService.getOrder();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import { LineItem} from '../items/lineitem.model';
|
|||
@Injectable({providedIn: 'root'})
|
||||
|
||||
export class OrderService {
|
||||
private dataStore: { user: User, order: Order } = {
|
||||
private dataStore: { total:number, user: User, order: Order } = {
|
||||
total: 0,
|
||||
user:{
|
||||
address: '',
|
||||
session: '',
|
||||
|
@ -31,6 +32,8 @@ export class OrderService {
|
|||
};
|
||||
private _orderUpdated: BehaviorSubject<Order> = new BehaviorSubject(this.dataStore.order);
|
||||
public readonly orderUpdate: Observable<Order> = this._orderUpdated.asObservable();
|
||||
private _totalUpdated: BehaviorSubject<number> = new BehaviorSubject(this.dataStore.total);
|
||||
public readonly totalUpdate: Observable<number> = this._totalUpdated.asObservable();
|
||||
public userUpdate: Observable<User>;
|
||||
|
||||
constructor(
|
||||
|
@ -41,11 +44,12 @@ export class OrderService {
|
|||
this.userUpdate.subscribe((user) => {
|
||||
this.dataStore.user = user;
|
||||
//console.log('OS: const', user);
|
||||
this.getOrder(this.dataStore.user.session);
|
||||
this.getOrder();
|
||||
});
|
||||
}
|
||||
|
||||
getOrder(session: string) {
|
||||
getOrder() {
|
||||
var session = this.dataStore.user.session;
|
||||
const params = new HttpParams().append('session', session);
|
||||
let obs = this.http.get<{message: string, order: any}>('http://localhost:3000/api/order', { headers:{}, params:params, observe: 'response'});
|
||||
|
||||
|
@ -53,6 +57,11 @@ export class OrderService {
|
|||
if (OrderDataResponse.status == 200) {
|
||||
this.dataStore.order = OrderDataResponse.body!.order;
|
||||
this._orderUpdated.next(Object.assign({}, this.dataStore).order);
|
||||
this.dataStore.total = 0;
|
||||
for(var line of this.dataStore.order.lines) {
|
||||
this.dataStore.total += line.qty * line.cost;
|
||||
}
|
||||
this._totalUpdated.next(Object.assign({}, this.dataStore).total);
|
||||
} else {
|
||||
console.log('No order found');
|
||||
}
|
||||
|
@ -62,30 +71,57 @@ export class OrderService {
|
|||
}
|
||||
|
||||
addToOrder(lineItem: LineItem) {
|
||||
if (this.dataStore.order.address.length == 0) {
|
||||
console.log('No open order, creating...', lineItem);
|
||||
this.createOrder();
|
||||
if(this.dataStore.order._id != null) {
|
||||
let obs = this.http.post<{message: string}>('http://localhost:3000/api/lineitem', { order_id: this.dataStore.order._id, line: lineItem });
|
||||
obs.subscribe((orderData) => {
|
||||
this.getOrder();
|
||||
});
|
||||
} else {
|
||||
console.log('Open order, adding...', lineItem);
|
||||
this.createOrder(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
createOrder(lineItem: LineItem) {
|
||||
var order:Order = {
|
||||
address: this.dataStore.user.address,
|
||||
session: this.dataStore.user.session,
|
||||
closed: false,
|
||||
lines: []
|
||||
};
|
||||
let obs = this.http.post<{message: string}>('http://localhost:3000/api/order', {order: order});
|
||||
|
||||
let obs = this.http.post<{message: string, order: Order}>('http://localhost:3000/api/order', {order: order});
|
||||
obs.subscribe((orderData) => {
|
||||
console.log('Create order', orderData);
|
||||
this.getOrder(this.dataStore.user.session);
|
||||
this.dataStore.order = orderData.order;
|
||||
this._orderUpdated.next(Object.assign({}, this.dataStore).order);
|
||||
this.addToOrder(lineItem);
|
||||
});
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
cancelOrder(id: string) {
|
||||
let obs = this.http.delete<{message: string}>('http://localhost:3000/api/order/'+id);
|
||||
|
||||
obs.subscribe((OrderResponse) => {
|
||||
console.log('Order deleted');
|
||||
//this.getOrder();
|
||||
this.dataStore.order = {
|
||||
address: '',
|
||||
session: '',
|
||||
timestamp: '',
|
||||
closed: false,
|
||||
lines: [
|
||||
{
|
||||
qty: 1,
|
||||
name: '',
|
||||
cost:0
|
||||
}
|
||||
]
|
||||
};
|
||||
this._orderUpdated.next(Object.assign({}, this.dataStore).order);
|
||||
});
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
BIN
src/assets/zec-roboto.png
Normal file
BIN
src/assets/zec-roboto.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 767 B |
Loading…
Reference in a new issue