first commit

This commit is contained in:
2024-05-16 16:05:41 +02:00
commit adf8283ae0
197 changed files with 26666 additions and 0 deletions
@@ -0,0 +1,4 @@
.example-card {
margin-bottom: 8px;
}
@@ -0,0 +1,31 @@
<mat-card>
<mat-card-header>
<mat-card-title>Sale</mat-card-title>
<mat-card-subtitle>Sale informations</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<div *ngIf="SaleInfo.title == ''" fxLayout="column" fxLayoutGap="5px">
<p-skeleton width="250px" height="20px"></p-skeleton>
<p-skeleton width="150px" height="20px"></p-skeleton>
<p-skeleton width="200px" height="20px"></p-skeleton>
<p-skeleton width="150px" height="20px"></p-skeleton>
</div>
<div *ngIf="SaleInfo.title != ''" fxLayout="column" fxLayoutGap="5px">
<p><strong>{{SaleInfo.title}}</strong></p>
<p><mat-icon>event</mat-icon>{{date | date:'dd/MM/yyyy' }} - {{hour}}</p>
<p><mat-icon>account_balance</mat-icon>{{SaleInfo.saleHouseName}}</p>
<p><mat-icon>location_on</mat-icon>{{SaleInfo.location}}</p>
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-content>
<div fxLayout="row" fxLayoutGap="5px">
<button mat-button color="warn" (click)="cancel()">Cancel</button>
<button mat-raised-button color="primary" (click)="save()">Save</button>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,68 @@
import { Component, OnInit, Inject } from '@angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import * as moment from 'moment-timezone';
//Services
import { apiService } from 'src/app/core/services/api.service';
// Models
import { SaleInfo } from 'src/app/core/services/model/saleInfo.interface';
@Component({
selector: 'loading-sale-dialog-dialog',
templateUrl: './loading-sale-dialog.component.html',
styleUrls: ['./loading-sale-dialog.component.css']
})
export class LoadingSaleDialogComponent implements OnInit {
url: string = '';
SaleInfo: SaleInfo;
date: Date;
hour: string = "";
constructor(
private apiService: apiService,
public dialogRef: MatDialogRef<LoadingSaleDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.SaleInfo = {
_id: "",
idPlatform: "",
platform: "",
url: "",
title: "",
date: "",
location: "",
saleHouseName: "",
status: ""
};
this.date = new Date();
}
ngOnInit(): void {
this.url = this.data.url;
console.log(this.url);
this.apiService.getSaleInfos(this.url).subscribe( SaleInfo => {
console.log(SaleInfo);
this.SaleInfo = SaleInfo;
//hour
// Europe/Paris is the timezone of the user
this.date = moment(this.SaleInfo.date).tz('Europe/Paris').toDate();
this.hour = moment(this.SaleInfo.date).tz('Europe/Paris').format('HH:mm');
}
);
}
save(): void {
this.apiService.saveSale(this.SaleInfo).subscribe( SaleInfo => {
this.dialogRef.close(true);
});
}
cancel(): void {
this.dialogRef.close(false);
}
}
@@ -0,0 +1,119 @@
<div class="container" fxLayout="row" fxLayoutAlign="center none">
<div fxFlex="95%">
<mat-card>
<mat-card-header>
<mat-card-title>Sale Detail</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="row" fxLayoutGap="5px">
<h2>{{Sale.title}}</h2>
</div>
<div fxLayout="row" fxLayoutGap="40px">
<div fxLayout="column" fxLayoutGap="2px">
<p><mat-icon>event</mat-icon> {{Sale.date | date:'dd/MM/yyyy' }} - {{Sale.date | date:'HH:mm'}} | </p>
<p><mat-icon>account_balance</mat-icon> {{Sale.saleHouseName}}</p>
<p><mat-icon>location_on</mat-icon> {{Sale.location}}</p>
</div>
<div fxLayout="column" fxLayoutGap="2px">
<p><mat-icon>tag</mat-icon>{{Sale.postProcessing?.nbrLots}} Lots</p>
<p><mat-icon>hourglass_bottom</mat-icon>{{getDurationInMinutes(Sale.postProcessing?.duration ?? 0)}} min</p>
<p><mat-icon>hourglass_bottom</mat-icon>/Lot {{getTimePerLot(parseToNumber(Sale.postProcessing?.durationPerLots ?? '0'))}}</p>
</div>
<div fxLayout="column" fxLayoutGap="2px">
<p>Total amount: {{Sale.postProcessing?.totalAmount | currency:'EUR':'symbol':'1.2-2'}}</p>
<p>Average amount: {{Sale.postProcessing?.averageAmount | currency:'EUR':'symbol':'1.2-2'}}</p>
<p>Median amount: {{Sale.postProcessing?.medianAmount | currency:'EUR':'symbol':'1.2-2'}}</p>
</div>
</div>
</mat-card-content>
</mat-card>
<mat-card style="margin-top: 10px;">
<mat-card-header>
<mat-card-title>Lots</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab>
<ng-template mat-tab-label>
Lots
</ng-template>
<div fxLayout="row" fxLayoutGap="5px">
<table mat-table [dataSource]="lotList" matSort class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- Lotnum Column -->
<ng-container matColumnDef="lotNum">
<th mat-header-cell *matHeaderCellDef mat-sort-header="idPlatform">#</th>
<td mat-cell *matCellDef="let element">
{{element.lotNumber}}
</td>
</ng-container>
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef mat-sort-header="title"> Title </th>
<td mat-cell *matCellDef="let element">
{{element.title ? element.title : "Lot "+element.lotNumber}}
</td>
</ng-container>
<!-- EstimateLow Column -->
<ng-container matColumnDef="estimateLow">
<th mat-header-cell *matHeaderCellDef mat-sort-header="EstimateLow"> Estimate Low </th>
<td mat-cell *matCellDef="let element">
{{element.EstimateLow ? element.EstimateLow : "-"}}
</td>
</ng-container>
<!-- EstimateHigh Column -->
<ng-container matColumnDef="estimateHigh">
<th mat-header-cell *matHeaderCellDef mat-sort-header="EstimateHigh"> Estimate High </th>
<td mat-cell *matCellDef="let element">
{{element.EstimateHigh ? element.EstimateHigh : "-"}}
</td>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<th mat-header-cell *matHeaderCellDef mat-sort-header="auctionedAmount"> Price </th>
<td mat-cell *matCellDef="let element">
{{element.auctionedAmount}}
</td>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="nbrBids">
<th mat-header-cell *matHeaderCellDef mat-sort-header="bidsLength"> nbrBids </th>
<td mat-cell *matCellDef="let element">
{{element.bidsLength}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[10, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-tab>
<mat-tab label="Graphs">
<div fxLayout="row" fxLayoutGap="5px">
</div>
</mat-tab>
</mat-tab-group>
</mat-card-content>
</mat-card>
</div>
</div>
@@ -0,0 +1,129 @@
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router, ActivatedRoute } from '@angular/router';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import * as moment from 'moment';
// Services
import { apiService } from 'src/app/core/services/api.service';
import { NotificationService } from 'src/app/core/services/notification.service';
//Models
import { Sale } from 'src/app/core/services/model/sale.interface';
import { Lot } from 'src/app/core/services/model/lot.interface';
@Component({
selector: 'app-favorites-page',
templateUrl: './sale-detail-page.component.html',
styleUrls: ['./sale-detail-page.component.css']
})
export class SaleDetailPageComponent implements OnInit, AfterViewInit {
id: any = '';
Sale: Sale;
displayedColumns: string[] = ['lotNum', 'title', 'estimateLow', 'estimateHigh', 'price', 'nbrBids'];
lotList: MatTableDataSource<Lot> = new MatTableDataSource<Lot>();
@ViewChild(MatPaginator) paginator?: MatPaginator;
@ViewChild(MatSort) sort?: MatSort;
constructor(
private route: ActivatedRoute,
private notificationService: NotificationService,
private router: Router,
public dialog: MatDialog,
private apiService: apiService) {
this.Sale = {
_id: { $oid: '' },
idPlatform: '',
platform: '',
url: '',
title: '',
date: '',
location: '',
saleHouseName: '',
status: '',
postProcessing: {
nbrLots: 0,
duration: 0,
durationPerLots: '',
totalAmount: 0,
averageAmount: '',
medianAmount: ''
}
}
}
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
this.id = params.get('id');
this.getSale();
this.getLotList();
});
}
ngAfterViewInit(): void {
}
getSale(){
this.apiService.getSale(this.id).subscribe((sale: Sale) => {
this.Sale = sale;
});
}
getLotList(){
this.apiService.getLotsBySale(this.id).subscribe((lotList: Lot[]) => {
// adding the Bids length info
lotList = lotList.map((lot) => {
return {...lot, bidsLength: lot.Bids ? lot.Bids.length : 0};
});
// adding the Auctionned ammount info
lotList = lotList.map((lot) => {
return {...lot, auctionedAmount: lot.auctioned?.amount ? lot.auctioned?.amount : 0};
});
console.log(lotList);
this.lotList = new MatTableDataSource(lotList);
this.lotList.paginator = this.paginator ?? null;
this.lotList.sort = this.sort ?? null;
});
}
getDurationInMinutes(duration: number): number {
return Math.floor(duration / 60);
}
getTimePerLot(duration: number): string {
const minutes = Math.floor((duration % 3600) / 60);
const seconds = duration % 60;
let returnString = '';
if (minutes > 0) {
returnString += minutes + 'm ';
}
returnString += seconds + 's';
return returnString;
}
parseToNumber(value: string | null): number {
return parseFloat(value || '0');
}
}
@@ -0,0 +1,3 @@
mat-icon {
color: rgb(200, 0, 0);
}
@@ -0,0 +1,162 @@
<div class="container" fxLayout="row" fxLayoutAlign="center none">
<div fxFlex="95%">
<mat-card>
<mat-card-header>
<mat-card-title>New Sale</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="row" fxLayoutGap="5px">
<mat-form-field>
<mat-label>Url</mat-label>
<input matInput placeholder="Ex. https://drouot.com/..." maxlength="255" st [(ngModel)]="url" >
</mat-form-field>
<button mat-raised-button color="primary" (click)="openLoadingSale()">Add</button>
</div>
</mat-card-content>
</mat-card>
<mat-card style="margin-top: 10px;">
<mat-card-header>
<mat-card-title>Sales</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab>
<ng-template mat-tab-label>
Current Sales
<span matBadge="{{futureSales.length}}" matBadgeOverlap="false" style="margin: 5px;"> </span>
</ng-template>
<div fxLayout="row" fxLayoutGap="5px">
<table mat-table [dataSource]="futureSales" class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef> Title </th>
<td mat-cell *matCellDef="let element">
<a href="{{element.url}}" target="_blank">{{element.title}}</a>
<div *ngIf="element.status == 'following'">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
</td>
</ng-container>
<!-- Date Column -->
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef> Date </th>
<td mat-cell *matCellDef="let element"> {{element.date | date:'dd/MM/yyyy' }} - {{element.date | date:'HH:mm'}} </td>
</ng-container>
<!-- Sale House Column -->
<ng-container matColumnDef="house">
<th mat-header-cell *matHeaderCellDef> Sale House </th>
<td mat-cell *matCellDef="let element"> {{element.saleHouseName}} </td>
</ng-container>
<!-- PLateform House Column -->
<ng-container matColumnDef="plateform">
<th mat-header-cell *matHeaderCellDef> Plateforme </th>
<td mat-cell *matCellDef="let element"> Interencheres </td>
</ng-container>
<!-- Prepare Column -->
<ng-container matColumnDef="prepare">
<th mat-header-cell *matHeaderCellDef> Prepare </th>
<td mat-cell *matCellDef="let element">
<button *ngIf="element.status == 'ready'" mat-button (click)="prepareSale(element)"><mat-icon>format_list_numbered</mat-icon></button>
</td>
</ng-container>
<!-- Follow Column -->
<ng-container matColumnDef="follow">
<th mat-header-cell *matHeaderCellDef> Follow </th>
<td mat-cell *matCellDef="let element">
<button *ngIf="element.status == 'ready'" mat-button (click)="followSale(element)"><mat-icon>play_arrow</mat-icon></button>
<button *ngIf="element.status == 'following'" mat-button (click)="stopFollowSale(element)"><mat-icon>stop</mat-icon></button>
<div *ngIf="element.status == 'askStop'"><mat-progress-bar mode="indeterminate"></mat-progress-bar></div>
</ng-container>
<!-- Delete Column -->
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef> Delete </th>
<td mat-cell *matCellDef="let element">
<button mat-button (click)="deleteSale(element._id)"><mat-icon>delete</mat-icon></button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-tab>
<mat-tab label="Old Sales">
<div fxLayout="row" fxLayoutGap="5px">
<table mat-table [dataSource]="pastSales" class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef> Title </th>
<td mat-cell *matCellDef="let element">
<a (click)="navigateToSaleDetail(element._id)">{{element.title}}</a>
</td>
</ng-container>
<!-- Date Column -->
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef> Date </th>
<td mat-cell *matCellDef="let element"> {{element.date | date:'dd/MM/yyyy' }} - {{element.date | date:'HH:mm'}} </td>
</ng-container>
<!-- Sale House Column -->
<ng-container matColumnDef="house">
<th mat-header-cell *matHeaderCellDef> Sale House </th>
<td mat-cell *matCellDef="let element"> {{element.saleHouseName}} </td>
</ng-container>
<!-- PLateform House Column -->
<ng-container matColumnDef="plateform">
<th mat-header-cell *matHeaderCellDef> Plateforme </th>
<td mat-cell *matCellDef="let element"> Interencheres </td>
</ng-container>
<!-- PostProcessing Column -->
<ng-container matColumnDef="postProcessing">
<th mat-header-cell *matHeaderCellDef> Post Processing </th>
<td mat-cell *matCellDef="let element">
<button mat-button (click)="postProcessing(element._id)"><mat-icon>query_stats</mat-icon></button>
</td>
</ng-container>
<!-- Delete Column -->
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef> Delete </th>
<td mat-cell *matCellDef="let element">
<button mat-button (click)="deleteSale(element._id)"><mat-icon>delete</mat-icon></button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumnsOld"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumnsOld;"></tr>
</table>
</div>
</mat-tab>
</mat-tab-group>
</mat-card-content>
</mat-card>
</div>
</div>
@@ -0,0 +1,118 @@
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { LoadingSaleDialogComponent } from './loading-sale-dialog/loading-sale-dialog.component';
import * as moment from 'moment';
// Services
import { apiService } from 'src/app/core/services/api.service';
import { NotificationService } from 'src/app/core/services/notification.service';
import { SaleInfo } from 'src/app/core/services/model/saleInfo.interface';
@Component({
selector: 'app-favorites-page',
templateUrl: './sales-page.component.html',
styleUrls: ['./sales-page.component.css']
})
export class SalesPageComponent implements OnInit {
url: string = '';
refreshSalesId: any;
displayedColumns: string[] = ['title', 'date', 'house', 'plateform', 'prepare', 'follow', 'delete'];
displayedColumnsOld: string[] = ['title', 'date', 'house', 'plateform', 'postProcessing', 'delete'];
futureSales = []
pastSales = []
constructor(
private notificationService: NotificationService,
private router: Router,
public dialog: MatDialog,
private apiService: apiService) {}
openLoadingSale(): void {
const dialogRef = this.dialog.open(LoadingSaleDialogComponent, {
width: '300px',
data: {url: this.url}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.refreshSales();
this.url = "";
this.notificationService.openSnackBar("Sale Added");
}
});
}
refreshSales(): void {
this.apiService.getAllSale().subscribe((data: any) => {
console.log(data);
const today = moment();
this.futureSales = data
.filter((element: SaleInfo) => moment(element.date).isAfter(today))
.sort((a: any, b: any) => moment(a.date).isAfter(b.date) ? 1 : -1);
this.pastSales = data
.filter((element: SaleInfo) => moment(element.date).isBefore(today))
.sort((a: any, b: any) => moment(a.date).isAfter(b.date) ? 1 : -1);
});
}
ngOnInit(): void {
this.refreshSales();
this.refreshSalesId = setInterval(() => {
this.refreshSales();
}, 5000);
}
prepareSale(saleInfo: SaleInfo): void {
this.apiService.prepareSale(saleInfo).subscribe( data => {
console.log(data);
this.refreshSales();
this.notificationService.openSnackBar("Prepare Sale");
})
}
followSale(saleInfo: SaleInfo): void {
this.apiService.followSale(saleInfo).subscribe( data => {
console.log(data);
this.refreshSales();
this.notificationService.openSnackBar("Sale followed");
})
}
stopFollowSale(saleInfo: SaleInfo): void {
saleInfo.status = "askStop";
this.apiService.updateSale(saleInfo).subscribe( data => {
this.refreshSales();
this.notificationService.openSnackBar("Sale Stopping...");
})
}
deleteSale(_id: string): void {
this.apiService.deleteSale(_id).subscribe( data => {
this.refreshSales();
this.notificationService.openSnackBar("Sale deleted");
})
}
navigateToSaleDetail(id: string) {
console.log(id);
clearInterval(this.refreshSalesId);
this.router.navigate(['/sales/detail', id]);
}
postProcessing(id: string) {
this.apiService.postProcessing(id).subscribe( data => {
this.notificationService.openSnackBar("Sale processing");
})
}
}
@@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LayoutComponent } from '../../shared/layout/layout.component';
import { SalesPageComponent } from './sales-page/sales-page.component';
import { SaleDetailPageComponent } from './sales-page/sale-detail-page/sale-detail-page.component';
const routes: Routes = [
{
path: '',
component: LayoutComponent,
children: [
{ path: '', component: SalesPageComponent },
{ path: 'detail/:id', component: SaleDetailPageComponent },
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SalesRoutingModule { }
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SalesRoutingModule } from './sales-routing.module';
import { SalesPageComponent } from './sales-page/sales-page.component';
import { LoadingSaleDialogComponent } from './sales-page/loading-sale-dialog/loading-sale-dialog.component';
import { SaleDetailPageComponent } from './sales-page/sale-detail-page/sale-detail-page.component';
import { SharedModule } from '../../shared/shared.module';
@NgModule({
declarations: [
SalesPageComponent,
LoadingSaleDialogComponent,
SaleDetailPageComponent
],
imports: [
CommonModule,
SharedModule,
SalesRoutingModule,
]
})
export class SalesModule { }