Browse Source

feat: add order page

pull/92/head
Mahmut Gundogdu 5 years ago
parent
commit
01ab01009f
  1. 3
      apps/angular/projects/ordering/src/lib/index.ts
  2. 5
      apps/angular/projects/ordering/src/lib/order-view-model.ts
  3. 8
      apps/angular/projects/ordering/src/lib/to-order-view-model.ts
  4. 21
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail-item/order-detail-item.component.ts
  5. 63
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.html
  6. 19
      apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.ts
  7. 59
      apps/angular/projects/ordering/src/pages/orders/orders.component.html
  8. 67
      apps/angular/projects/ordering/src/pages/orders/orders.component.ts
  9. 6
      apps/angular/projects/ordering/src/pages/orders/orders.module.ts
  10. 10
      apps/angular/src/environments/environment.prod.ts
  11. 9
      apps/angular/src/environments/environment.ts
  12. 5
      apps/angular/src/environments/my-environment.ts
  13. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml
  14. 2
      services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs

3
apps/angular/projects/ordering/src/lib/index.ts

@ -0,0 +1,3 @@
export * from './order-view-model';
export * from './proxy';
export * from './to-order-view-model';

5
apps/angular/projects/ordering/src/lib/order-view-model.ts

@ -0,0 +1,5 @@
import { OrderDto } from './proxy/orders';
export interface OrderViewModel extends OrderDto {
orderTotal: number;
}

8
apps/angular/projects/ordering/src/lib/to-order-view-model.ts

@ -0,0 +1,8 @@
import { OrderDto } from './proxy/orders';
import { OrderViewModel } from './order-view-model';
const mapItem = (x: OrderDto): OrderViewModel => {
const orderTotal = x.items?.reduce((acc, curr) => ( acc + (curr.unitPrice * curr.units)), 0) || 0;
return {...x, orderTotal};
};
export const toOrderViewModel = (orders: OrderDto[]) => orders.map(mapItem);

21
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail-item/order-detail-item.component.ts

@ -0,0 +1,21 @@
import { Component, Input } from '@angular/core';
@Component({
selector: 'lib-order-detail-item',
template: `
<div class='row'>
<div class='col-3'>
{{label}}
</div>
<b class='col-9'>
<ng-content></ng-content>
</b>
</div>
`,
styles: []
})
export class OrderDetailItemComponent {
@Input()
label = '';
}

63
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.html

@ -1,16 +1,67 @@
<abp-modal [visible]="visible && !!order" (visibleChange)='visibleChange.emit($event)' >
<abp-modal [visible]='visible' (visibleChange)='visibleChange.emit($event)' [options]='modalOption'>
<ng-template #abpHeader>
<h3>Modal Title</h3>
<h3>Order Detail</h3>
</ng-template>
<ng-template #abpBody>
<p>Modal content</p>
<div *ngIf='order'>
<div class='container'>
<lib-order-detail-item label='Order Number'>#{{order.orderNo}}</lib-order-detail-item>
<lib-order-detail-item label='Order Status'>{{order.orderStatus}}</lib-order-detail-item>
<lib-order-detail-item label='Buyer Name'>{{order.buyer.name}}</lib-order-detail-item>
<lib-order-detail-item label='Buyer Email'>{{order.buyer.email}}</lib-order-detail-item>
<lib-order-detail-item label='Address'>
<span *ngIf='order.address as address'>
{{address.description}} <br />
{{address.street}} <br />
{{address.zipCode}} <br />
{{address.city}} / {{address.country}} <br />
</span>
</lib-order-detail-item>
<lib-order-detail-item label='Payment Method'>{{order.paymentMethod}}</lib-order-detail-item>
<lib-order-detail-item label='Total'>{{order.orderTotal | currency}}</lib-order-detail-item>
</div>
<br><br><br>
<ngx-datatable [rows]='(order.items)' default>
<!-- TODO: localize column headers -->
<ngx-datatable-column name='ProductId' prop='productId'></ngx-datatable-column>
<ngx-datatable-column name='PictureUrl' prop='pictureUrl'>
<ng-template let-value='value' ngx-datatable-cell-template>
<img [src]="mediaServerUrl + '/product-images/' + value" width='80' />
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name='ProductName' prop='productName'></ngx-datatable-column>
<ngx-datatable-column name='UnitPrice' prop='unitPrice'>
<ng-template let-value='value' ngx-datatable-cell-template>
{{value | currency }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name='Units' prop='units'></ngx-datatable-column>
<ngx-datatable-column name='Discount' prop='discount'>
<ng-template let-value='value' ngx-datatable-cell-template>
{{value }} %
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name='Total Price'>
<ng-template let-row='row' ngx-datatable-cell-template>
{{(row.units * row.unitPrice) | currency }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>{{
<button type='button' class='btn btn-secondary' abpClose>{{
'AbpUi::Close' | abpLocalization
}}</button>
</ng-template>

19
apps/angular/projects/ordering/src/pages/orders/order-detail/order-detail.component.ts

@ -1,22 +1,17 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { OrderDto } from '../../../lib/proxy/orders';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { OrderViewModel } from '../../../lib/order-view-model';
import { environment } from '../../../../../../src/environments/environment';
@Component({
selector: 'lib-order-detail',
templateUrl: './order-detail.component.html'
})
export class OrderDetailComponent implements OnInit {
export class OrderDetailComponent {
modalOption = { size: 'xl' }
@Input()
visible: boolean;
@Input()
order: OrderDto | undefined;
order: OrderViewModel | undefined;
mediaServerUrl = environment.mediaServerUrl;
@Output() readonly visibleChange = new EventEmitter<boolean>();
constructor() { }
ngOnInit(): void {
}
}

59
apps/angular/projects/ordering/src/pages/orders/orders.component.html

@ -4,36 +4,63 @@
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">{{ 'AbpCatalog::Products' | abpLocalization }}</h5>
</div>
<div class="text-end col col-md-6">
<button class="btn btn-primary">{{ 'AbpCatalog::NewProduct' | abpLocalization }}</button>
<h5 class="card-title">{{ 'AbpOrdering::Orders' | abpLocalization }}</h5>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="(list$ | async)" default>
<!-- TODO: localize column headers -->
<ngx-datatable-column name="" [sortable]='false' prop="id" >
<ng-template let-id="value" let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="mr-1 fa fa-cog"></i>{{ 'AbpUi::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button
class="dropdown-item"
(click)='openModal(row)'
>
{{ 'AbpOrdering::Detail' | abpLocalization }}
</button>
<button
class="dropdown-item"
(click)='openModal(row)'
>
{{ 'AbpUi::Delete' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="OrderNo" prop="orderNo"></ngx-datatable-column>
<ngx-datatable-column name="OrderStatus" prop="orderStatus"></ngx-datatable-column>
<ngx-datatable-column name="OrderDate" prop="orderDate" >
<ng-template let-value="value" ngx-datatable-cell-template>
<span>{{ value | date }}</span>
<span>{{ value | date }}</span >
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Id" prop="id" >
<ng-template let-id="value" let-row="row" ngx-datatable-cell-template>
<abp-button (click)='openModal(id)'>
{{ 'AbpCatalog::Detail' | abpLocalization }}
</abp-button>
<ngx-datatable-column name="OrderTotal" prop="orderTotal" >
<ng-template let-value="value" ngx-datatable-cell-template>
<span>{{ value | currency }}</span >
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
<ngx-datatable-column name="OrderStatus" prop="orderStatus"></ngx-datatable-column>
<lib-order-detail [(visible)]='isModalVisible' [order]='selectedOrder'>
</lib-order-detail>
<ngx-datatable-column name="OrderStatus" prop="orderStatus"></ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<lib-order-detail [visible]='isModalVisible' (visibleChange)='closeModal($event)' [order]='selectedOrder' >
</lib-order-detail>

67
apps/angular/projects/ordering/src/pages/orders/orders.component.ts

@ -1,20 +1,73 @@
import { Component, OnInit } from '@angular/core';
import { OrderDto, OrderService } from '../../lib/proxy/orders';
import { OrderService } from '../../lib/proxy/orders';
import { OrderViewModel, toOrderViewModel } from '../../lib';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import { ListService } from '@abp/ng.core';
@Component({
selector: 'lib-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.css']
styleUrls: ['./orders.component.css'],
providers: [ListService],
})
export class OrdersComponent implements OnInit {
constructor(private orderService: OrderService) { }
list$ = this.orderService.getOrders({});
selectedOrder: OrderDto | undefined;
constructor(private service: OrderService,
public list: ListService,
private confirmationService: ConfirmationService) { }
selectedOrder: OrderViewModel | undefined;
isModalVisible = false;
ngOnInit(): void {}
items: OrderViewModel[];
count = 0;
ngOnInit(): void {
openModal(id: string) {
const ordersStreamCreator = query => this.service.getListPaged(query);
this.list.hookToQuery(ordersStreamCreator).subscribe(response => {
this.items = toOrderViewModel(response.items);
this.count = response.totalCount;
});
}
openModal(order: OrderViewModel) {
if (!order){
return;
}
this.selectedOrder = order;
this.isModalVisible = true;
}
closeModal(isVisible: boolean){
if (isVisible){
return;
}
this.selectedOrder = null;
this.isModalVisible = false;
}
setAsShipped(row: OrderViewModel) {
this.confirmationService
.warn('AbpOrdering::WillSetAsShipped', { key: '::AreYouSure', defaultValue: 'Are you sure?' })
.subscribe((status) => {
if (status !== Confirmation.Status.confirm) {
return;
}
this.service.setAsShipped(row.id).subscribe(() => {
this.list.get();
});
});
}
setAsCancelled(row: OrderViewModel){
this.confirmationService
.warn('AbpOrdering::WillSetAsCancelled', { key: '::AreYouSure', defaultValue: 'Are you sure?' })
.subscribe((status``) => {
if (status !== Confirmation.Status.confirm) {
return;
}
this.service.setAsCancelled(row.id, { paymentRequestId: undefined, paymentRequestStatus: undefined}).subscribe(() => {
this.list.get();
});
})
;
}
}

6
apps/angular/projects/ordering/src/pages/orders/orders.module.ts

@ -6,15 +6,19 @@ import { OrdersComponent } from './orders.component';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { CoreModule } from '@abp/ng.core';
import { OrderDetailComponent } from './order-detail/order-detail.component';
import { OrderDetailItemComponent } from './order-detail/order-detail-item/order-detail-item.component';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
declarations: [
OrdersComponent,
OrderDetailComponent
OrderDetailComponent,
OrderDetailItemComponent
],
imports: [
CommonModule,
NgbDropdownModule,
OrdersRoutingModule,
ThemeSharedModule,
CoreModule,

10
apps/angular/src/environments/environment.prod.ts

@ -1,4 +1,4 @@
import { Environment } from '@abp/ng.core';
import { MyEnvironment } from './my-environment';
const baseUrl = 'http://localhost:4200';
@ -22,8 +22,8 @@ export const environment = {
rootNamespace: 'EShopOnAbp',
},
},
remoteEnv:{
url: "/getEnvConfig",
mergeStrategy:'deepmerge'
remoteEnv: {
url: '/getEnvConfig',
mergeStrategy: 'deepmerge'
}
} as Environment;
} as MyEnvironment;

9
apps/angular/src/environments/environment.ts

@ -1,4 +1,4 @@
import { Environment } from '@abp/ng.core';
import { MyEnvironment } from './my-environment';
const baseUrl = 'http://localhost:4200';
@ -25,9 +25,12 @@ export const environment = {
url: 'https://localhost:44354',
rootNamespace: 'EShopOnAbp.CatalogService',
},
Ordering:{
Ordering: {
url: "https://localhost:44356",
rootNamespace: 'EShopOnAbp.OrderingService',
}
},
} as Environment;
mediaServerUrl:'https://localhost:44335'
} as MyEnvironment;

5
apps/angular/src/environments/my-environment.ts

@ -0,0 +1,5 @@
import { Environment } from '@abp/ng.core';
export interface MyEnvironment extends Environment{
mediaServerUrl?: string;
}

2
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml

@ -13,7 +13,7 @@
</abp-row>
@foreach (var order in Model.UserOrders)
{
var orderTotalString = order.Items.Sum(q => q.UnitPrice).ToString("C", new CultureInfo("en-US"));
var orderTotalString = order.Items.Sum(q => q.UnitPrice * q.Units).ToString("C", new CultureInfo("en-US"));
string addressString = $"{order.Address.Street} {order.Address.ZipCode} \n {order.Address.City}/{order.Address.Country}";
<div class="card">
<div class="card-header">

2
services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs

@ -43,7 +43,7 @@ public class OrderAppService : ApplicationService, IOrderAppService
return CreateOrderDtoMapping(orders);
}
[Authorize(OrderingServicePermissions.Orders.Default)]
//[Authorize(OrderingServicePermissions.Orders.Default)]
public async Task<List<OrderDto>> GetOrdersAsync(GetOrdersInput input)
{
ISpecification<Order> specification = SpecificationFactory.Create(input.Filter);

Loading…
Cancel
Save