user managment

This commit is contained in:
2024-06-24 18:37:04 +02:00
parent bafef0f6b3
commit 0c7fc6fdf7
50 changed files with 2748 additions and 219 deletions
@@ -0,0 +1,19 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class apiAuthService {
ServeurURL = environment.ServeurURL;
ApiURL = this.ServeurURL+"/api";
constructor(private http: HttpClient){}
// authenticate
authenticate(email: string, password: string) {
return this.http.post<{token: string}>(this.ServeurURL+'/authenticate', {email, password});
}
}
@@ -0,0 +1,26 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { LotInfo } from '../model/lotInfo.interface';
import { SaleInfo } from '../model/saleInfo.interface';
@Injectable({
providedIn: 'root'
})
export class apiFavoriteService {
ServeurURL = environment.ServeurURL;
ApiURL = this.ServeurURL+"/api";
constructor(private http: HttpClient){}
//Favorites
saveFavorite(lotInfo: LotInfo, saleInfo: SaleInfo, picture: String, dateTime: string, buyProject: boolean, maxPrice: number, Note: string): Observable<any> {
return this.http.post(this.ApiURL+'/favorite/save', {lotInfo, saleInfo, picture, dateTime, buyProject, maxPrice, Note});
}
getAllFavorite(): Observable<any> {
return this.http.get(this.ApiURL+'/favorite/getAll');
}
}
@@ -0,0 +1,49 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { LotInfo } from '../model/lotInfo.interface';
import { Lot } from '../model/lot.interface';
@Injectable({
providedIn: 'root'
})
export class apiLotService {
ServeurURL = environment.ServeurURL;
ApiURL = this.ServeurURL+"/api";
constructor(private http: HttpClient){}
// Lot
getLotInfo(url: string): Observable<LotInfo> {
let encodeUrl = encodeURIComponent(url);
return this.http.get<LotInfo>(this.ApiURL+'/lot/getInfos/'+encodeUrl);
}
getPictures(url: string): Observable<String[]> {
let encodeUrl = encodeURIComponent(url);
return this.http.get<String[]>(this.ApiURL+'/lot/getPictures/'+encodeUrl);
}
getLotsBySale(_id: String): Observable<Lot[]> {
return this.http.get<Lot[]>(this.ApiURL+'/lot/getLotsBySale/'+_id);
}
// Lot CRUD
getLot(_id: String): Observable<Lot> {
return this.http.get<Lot>(this.ApiURL+'/lot/lot/'+_id);
}
saveLot(Lot: Lot): Observable<Lot> {
return this.http.post<Lot>(this.ApiURL+'/lot/lot', Lot);
}
updateLot(Lot: Lot): Observable<Lot> {
return this.http.put<Lot>(this.ApiURL+'/lot/lot/'+Lot._id, Lot);
}
deleteLot(_id: String): Observable<any> {
return this.http.delete<any>(this.ApiURL+'/lot/lot/'+_id);
}
}
@@ -1,34 +1,20 @@
import { Injectable, Inject } from '@angular/core';
import { Injectable} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { LotInfo } from './model/lotInfo.interface';
import { SaleInfo } from './model/saleInfo.interface';
import { Sale } from './model/sale.interface';
import { Lot } from './model/lot.interface';
import { SaleInfo } from '../model/saleInfo.interface';
import { Sale } from '../model/sale.interface';
@Injectable({
providedIn: 'root'
})
export class apiService {
ApiURL = "http://localhost:3000/api";
export class apiSaleService {
ServeurURL = environment.ServeurURL;
ApiURL = this.ServeurURL+"/api";
constructor(private http: HttpClient){}
// Lot
getLotInfo(url: string): Observable<LotInfo> {
let encodeUrl = encodeURIComponent(url);
return this.http.get<LotInfo>(this.ApiURL+'/lot/getInfos/'+encodeUrl);
}
getPictures(url: string): Observable<String[]> {
let encodeUrl = encodeURIComponent(url);
return this.http.get<String[]>(this.ApiURL+'/lot/getPictures/'+encodeUrl);
}
getLotsBySale(_id: String): Observable<Lot[]> {
return this.http.get<Lot[]>(this.ApiURL+'/lot/getLotsBySale/'+_id);
}
constructor(
private http: HttpClient){}
// Sale
getSaleInfos(url: string): Observable<SaleInfo> {
@@ -74,24 +60,18 @@ export class apiService {
return this.http.delete<any>(this.ApiURL+'/sale/sale/'+_id);
}
// Function DB Sale
// Function DB Sale
getAllSale(): Observable<SaleInfo[]> {
return this.http.get<SaleInfo[]>(this.ApiURL+'/sale/getAll');
return this.http.get<SaleInfo[]>(`${this.ApiURL}/sale/getAll`);
}
postProcessing(_id: String): Observable<any> {
return this.http.get<any>(this.ApiURL+'/sale/postProcessing/'+_id);
}
getSaleStatXsl(_id: String): Observable<any> {
return this.http.get<Blob>(this.ApiURL+'/sale/SaleStatXsl/'+_id, { responseType: 'blob' as 'json' });
}
//Favorites
saveFavorite(lotInfo: LotInfo, saleInfo: SaleInfo, picture: String, dateTime: string, buyProject: boolean, maxPrice: number, Note: string): Observable<any> {
return this.http.post(this.ApiURL+'/favorite/save', {lotInfo, saleInfo, picture, dateTime, buyProject, maxPrice, Note});
}
getAllFavorite(): Observable<any> {
return this.http.get(this.ApiURL+'/favorite/getAll');
}
}
@@ -0,0 +1,43 @@
import { Injectable} from '@angular/core';
import { HttpClient} from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { User } from '../model/user.interface';
@Injectable({
providedIn: 'root'
})
export class apiUserService {
ServeurURL = environment.ServeurURL;
ApiURL = this.ServeurURL+"/api";
constructor(
private http: HttpClient){}
// User CRUD
getUser(_id: String): Observable<User> {
return this.http.get<User>(this.ApiURL+'/user/user/'+_id);
}
saveUser(User: User): Observable<User> {
return this.http.post<User>(this.ApiURL+'/user/user/', User);
}
updateUser(User: User): Observable<User> {
return this.http.put<User>(this.ApiURL+'/user/user/'+User._id, User);
}
deleteUser(_id: String): Observable<any> {
return this.http.delete<any>(this.ApiURL+'/user/user/'+_id);
}
// User function
getCurrentUser(): Observable<User> {
return this.http.get<User>(this.ApiURL+'/user/current');
}
getAllUsers(): Observable<User[]> {
return this.http.get<User[]>(this.ApiURL+'/user/getAllUsers');
}
}
+47 -32
View File
@@ -1,10 +1,11 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { delay, map } from 'rxjs/operators';
import * as jwt_decode from 'jwt-decode';
import { apiAuthService } from './api/api.auth.service';
import { apiUserService } from './api/api.user.service';
import { User } from './model/user.interface';
import * as moment from 'moment';
import { environment } from '../../../environments/environment';
import { of, EMPTY } from 'rxjs';
@Injectable({
@@ -12,30 +13,40 @@ import { of, EMPTY } from 'rxjs';
})
export class AuthenticationService {
constructor(private http: HttpClient,
constructor(
private apiAuthService: apiAuthService,
private apiUserService: apiUserService,
@Inject('LOCALSTORAGE') private localStorage: Storage) {
}
login(email: string, password: string) {
return of(true)
.pipe(delay(1000),
map((/*response*/) => {
// set token property
// const decodedToken = jwt_decode(response['token']);
// store email and jwt token in local storage to keep user logged in between page refreshes
this.localStorage.setItem('currentUser', JSON.stringify({
token: 'aisdnaksjdn,axmnczm',
isAdmin: true,
email: 'john.doe@gmail.com',
id: '12312323232',
alias: 'john.doe@gmail.com'.split('@')[0],
expiration: moment().add(1, 'days').toDate(),
fullName: 'John Doe'
}));
return true;
return this.apiAuthService.authenticate(email, password).
pipe(map(response => {
// If the server returns a token, the login is successful
if (response.token) {
// Store user details and jwt token in local storage to keep user logged in between page refreshes
this.localStorage.setItem('currentUser', JSON.stringify({
token: response.token,
}));
this.apiUserService.getCurrentUser().subscribe((user: User) => {
console.log(user);
const Storeduser = this.localStorage.getItem('currentUser');
if(Storeduser) {
const currentUser = JSON.parse(Storeduser);
currentUser.isAdmin = user.isAdmin;
currentUser.email = user.email;
currentUser.id = user._id;
currentUser.alias = user.email.split('@')[0];
currentUser.fullName = user.username;
currentUser.expiration = moment().add(30, 'days').toDate();
this.localStorage.setItem('currentUser', JSON.stringify(currentUser));
}
});
return true;
}
return false;
}));
}
logout(): void {
@@ -45,16 +56,20 @@ export class AuthenticationService {
getCurrentUser(): any {
// TODO: Enable after implementation
// return JSON.parse(this.localStorage.getItem('currentUser'));
return {
token: 'aisdnaksjdn,axmnczm',
isAdmin: true,
email: 'john.doe@gmail.com',
id: '12312323232',
alias: 'john.doe@gmail.com'.split('@')[0],
expiration: moment().add(1, 'days').toDate(),
fullName: 'John Doe'
};
const user = this.localStorage.getItem('currentUser');
if (!user) {
return null;
}
return JSON.parse(user);
// return {
// token: JSON.parse(user).token,
// isAdmin: true,
// email: 'john.doe@gmail.com',
// id: '12312323232',
// alias: 'john.doe@gmail.com'.split('@')[0],
// expiration: moment().add(1, 'days').toDate(),
// fullName: 'John Doe'
// };
}
passwordResetRequest(email: string) {
@@ -2,7 +2,7 @@
export interface Bid {
timestamp: string;
amount: number;
auctioned_type: string;
auctioned_type?: string;
}
export interface Auctioned {
@@ -12,6 +12,14 @@ export interface Auctioned {
sold: boolean;
}
export interface PostProcessing {
nbrBids: number;
highestBid: number;
duration: number;
percentageAboveUnderLow: number;
percentageAboveUnderHigh: number;
}
export interface Lot {
_id: {
$oid: string;
@@ -20,10 +28,15 @@ export interface Lot {
platform: string;
timestamp: string;
lotNumber: string;
title?: string;
description?: string;
EstimateLow?: number;
EstimateHigh?: number;
RawData?: Object;
sale_id: {
$oid: string;
};
Bids?: Bid[];
auctioned?: Auctioned;
postProcessing?: PostProcessing;
}
@@ -2,10 +2,15 @@
export interface PostProcessing {
nbrLots: number;
duration: number;
bidsDuration: number;
durationPerLots: string;
totalAmount: number;
averageAmount: string;
medianAmount: string;
minAmount: string;
maxAmount: string;
unsoldLots: number;
unsoldPercentage: string;
}
export interface Sale {
@@ -0,0 +1,10 @@
export interface User {
_id: string;
email: string;
isAdmin: boolean;
isAgent?: boolean;
username: string;
expiration?: string;
password?: string;
confirmPassword?: string;
}
@@ -55,7 +55,7 @@ export class LoginComponent implements OnInit {
this.router.navigate(['/']);
},
error => {
this.notificationService.openSnackBar(error.error);
this.notificationService.openSnackBar(error.error.message);
this.loading = false;
}
);
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { apiService } from 'src/app/core/services/api.service';
import { apiFavoriteService } from 'src/app/core/services/api/api.favorite.service';
@Component({
selector: 'app-favorites-page',
@@ -16,7 +16,7 @@ export class FavoritesPageComponent implements OnInit {
constructor(
private router: Router,
private apiService: apiService) {}
private apiFavoriteService: apiFavoriteService) {}
openDialog(): void {
@@ -25,7 +25,7 @@ export class FavoritesPageComponent implements OnInit {
}
ngOnInit(): void {
this.apiService.getAllFavorite().subscribe((data: any) => {
this.apiFavoriteService.getAllFavorite().subscribe((data: any) => {
this.dataSource = data;
});
}
@@ -7,7 +7,9 @@ import * as moment from 'moment-timezone';
//Services
import { NotificationService } from 'src/app/core/services/notification.service';
import { apiService } from 'src/app/core/services/api.service';
import { apiLotService } from 'src/app/core/services/api/api.lot.service';
import { apiFavoriteService } from 'src/app/core/services/api/api.favorite.service';
import { apiSaleService } from 'src/app/core/services/api/api.sale.service';
// Models
import { LotInfo } from 'src/app/core/services/model/lotInfo.interface';
@@ -36,7 +38,9 @@ export class NewFavoritesPageComponent implements OnInit {
private ActivatedRoute: ActivatedRoute,
private router: Router,
private notificationService: NotificationService,
private apiService: apiService,) {
private apiLotService: apiLotService,
private apiSaleService: apiSaleService,
private apiFavoriteService: apiFavoriteService,) {
this.ActivatedRoute.params.subscribe(params => {
this.url = params['url'];
@@ -80,11 +84,11 @@ export class NewFavoritesPageComponent implements OnInit {
// this.date = moment(this.SaleInfo.date).tz('Europe/Paris').toDate();
// this.hour = moment(this.SaleInfo.date).tz('Europe/Paris').format('HH:mm');
this.apiService.getLotInfo(this.url).subscribe( lotInfo => {
this.apiLotService.getLotInfo(this.url).subscribe( lotInfo => {
console.log(lotInfo);
this.lotInfo = lotInfo;
this.apiService.getSaleInfos(this.lotInfo.saleInfo.url).subscribe( SaleInfo => {
this.apiSaleService.getSaleInfos(this.lotInfo.saleInfo.url).subscribe( SaleInfo => {
console.log(SaleInfo);
this.SaleInfo = SaleInfo;
@@ -99,7 +103,7 @@ export class NewFavoritesPageComponent implements OnInit {
}
);
this.apiService.getPictures(this.url).subscribe( pictures => {
this.apiLotService.getPictures(this.url).subscribe( pictures => {
this.images = pictures;
this.picture = pictures[0];
});
@@ -127,7 +131,7 @@ export class NewFavoritesPageComponent implements OnInit {
// Europe/Paris is the timezone of the user
let dateTime = moment.tz(`${this.date.toISOString().split('T')[0]}T${this.hour}`, 'Europe/Paris').format();
this.apiService.saveFavorite(this.lotInfo, this.SaleInfo, this.picture, dateTime, this.buyProject, this.maxPrice, this.Note).subscribe( res => {
this.apiFavoriteService.saveFavorite(this.lotInfo, this.SaleInfo, this.picture, dateTime, this.buyProject, this.maxPrice, this.Note).subscribe( res => {
this.notificationService.openSnackBar("Favorite saved");
this.router.navigate(['favorites']);
});
@@ -1,6 +1,7 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { apiService } from 'src/app/core/services/api.service';
import { apiLotService } from 'src/app/core/services/api/api.lot.service';
@Component({
selector: 'app-pictures-page',
@@ -20,7 +21,7 @@ export class PicturesPageComponent implements OnInit {
constructor(
private titleService: Title,
private apiService: apiService,
private apiLotService: apiLotService,
) {
}
@@ -43,7 +44,7 @@ export class PicturesPageComponent implements OnInit {
}
getPictures(): void {
this.apiService.getPictures(this.url).subscribe( Pictures => {
this.apiLotService.getPictures(this.url).subscribe( Pictures => {
this.images = [];
const newImages = [...this.images];
@@ -3,7 +3,7 @@ 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';
import { apiSaleService } from 'src/app/core/services/api/api.sale.service';
// Models
import { SaleInfo } from 'src/app/core/services/model/saleInfo.interface';
@@ -23,7 +23,7 @@ export class LoadingSaleDialogComponent implements OnInit {
hour: string = "";
constructor(
private apiService: apiService,
private apiSaleService: apiSaleService,
public dialogRef: MatDialogRef<LoadingSaleDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.SaleInfo = {
@@ -44,7 +44,7 @@ export class LoadingSaleDialogComponent implements OnInit {
this.url = this.data.url;
console.log(this.url);
this.apiService.getSaleInfos(this.url).subscribe( SaleInfo => {
this.apiSaleService.getSaleInfos(this.url).subscribe( SaleInfo => {
console.log(SaleInfo);
this.SaleInfo = SaleInfo;
@@ -70,7 +70,7 @@ export class LoadingSaleDialogComponent implements OnInit {
status: "ready"
}
this.apiService.saveSale(Sale).subscribe( Sale => {
this.apiSaleService.saveSale(Sale).subscribe( Sale => {
this.dialogRef.close(true);
});
}
@@ -0,0 +1,4 @@
.example-card {
margin-bottom: 8px;
}
@@ -0,0 +1,71 @@
<mat-card>
<mat-card-header>
<mat-card-title>Lot</mat-card-title>
<mat-card-subtitle>Lot informations</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<div fxLayout="row" fxLayoutGap="5px">
<mat-list>
<mat-list-item>
<span matListItemTitle>#</span>
<span matListItemLine>{{Lot.lotNumber}}</span>
</mat-list-item>
<mat-list-item>
<span matListItemTitle>Title</span>
<span matListItemLine>{{Lot.title}}</span>
</mat-list-item>
<mat-list-item>
<span matListItemTitle>Description</span>
<span matListItemLine [innerHTML]="getSafeDescription()"></span>
</mat-list-item>
<mat-list-item>
<span matListItemTitle>Estimate</span>
<span matListItemLine>Low: {{Lot.EstimateLow}} | High: {{Lot.EstimateHigh}} </span>
</mat-list-item>
</mat-list>
</div>
<div fxLayout="row" fxLayoutGap="5px">
<table mat-table [dataSource]="bids" 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="amount">
<th mat-header-cell *matHeaderCellDef >Amount</th>
<td mat-cell *matCellDef="let element">
{{element.amount}}
</td>
</ng-container>
<!-- Title Column -->
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef > Type </th>
<td mat-cell *matCellDef="let element">
{{element.auctioned_type}}
</td>
</ng-container>
<!-- Time Column -->
<ng-container matColumnDef="time">
<th mat-header-cell *matHeaderCellDef > Time </th>
<td mat-cell *matCellDef="let element">
{{element.timestamp | date:'HH:mm:ss':'Europe/Paris'}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[5, 10, 15]" showFirstLastButtons></mat-paginator>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-content>
<div fxLayout="row" fxLayoutGap="5px">
<button mat-button color="warn" (click)="cancel()">Close</button>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,76 @@
import { Component, OnInit, Inject, ViewChild } from '@angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';import * as moment from 'moment-timezone';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
//Services
import { apiLotService } from 'src/app/core/services/api/api.lot.service';
// Models
import { Lot, Bid } from 'src/app/core/services/model/lot.interface';
@Component({
selector: 'lot-detail-dialog-dialog',
templateUrl: './lot-detail-dialog.component.html',
styleUrls: ['./lot-detail-dialog.component.css']
})
export class LotDetailDialogComponent implements OnInit {
id: string;
Lot: Lot;
displayedColumns: string[] = ['amount', 'type', 'time'];
bids: MatTableDataSource<Bid> = new MatTableDataSource<Bid>();
@ViewChild(MatPaginator) paginator?: MatPaginator;
constructor(
private apiLotService: apiLotService,
public dialogRef: MatDialogRef<LotDetailDialogComponent>,
private sanitizer: DomSanitizer,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.id = data.id;
this.Lot = {
_id: { $oid: '' },
idPlatform: '',
platform: '',
timestamp: '',
lotNumber: '',
RawData: {},
sale_id: { $oid: '' },
Bids: [],
title: '',
description: '',
auctioned: {
timestamp: '',
amount: 0,
auctioned_type: '',
sold: false
}
};
}
ngOnInit(): void {
this.apiLotService.getLot(this.id).subscribe( Lot => {
this.Lot = Lot;
this.bids = new MatTableDataSource(Lot.Bids ?? []);
this.bids.paginator = this.paginator ?? null;
});
}
getSafeDescription(): SafeHtml {
if (this.Lot && this.Lot.description) {
return this.sanitizer.bypassSecurityTrustHtml(this.Lot.description.replace(/\n/g, '<br>'));
}
return '';
}
cancel(): void {
this.dialogRef.close(false);
}
}
@@ -0,0 +1,9 @@
.mat-mdc-row .mat-mdc-cell {
border-bottom: 1px solid transparent;
border-top: 1px solid transparent;
cursor: pointer;
}
.mat-mdc-row:hover .mat-mdc-cell {
border-color: currentColor;
}
@@ -17,16 +17,23 @@
</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>{{convertSecondsToHHMM(Sale.postProcessing?.bidsDuration ?? 0)}}</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>Max amount: {{Sale.postProcessing?.maxAmount | currency:'EUR':'symbol':'1.2-2'}}</p>
<p>Min amount: {{Sale.postProcessing?.minAmount | currency:'EUR':'symbol':'1.2-2'}}</p>
</div>
<div fxLayout="column" fxLayoutGap="2px">
<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>
<p>Unsold: {{Sale.postProcessing?.unsoldLots}} ({{Sale.postProcessing?.unsoldPercentage}}%)</p>
</div>
</div>
</div>
<div fxLayout="row" fxLayoutGap="2px">
<button mat-raised-button color="primary" (click)="downloadExcelStatsFile(id)">Excel</button>
</div>
</mat-card-content>
</mat-card>
@@ -48,12 +55,18 @@
<!-- Lotnum Column -->
<ng-container matColumnDef="lotNum">
<th mat-header-cell *matHeaderCellDef mat-sort-header="idPlatform">#</th>
<th mat-header-cell *matHeaderCellDef mat-sort-header="lotNumber">#</th>
<td mat-cell *matCellDef="let element">
{{element.lotNumber}}
</td>
</ng-container>
<!-- Picture Column -->
<ng-container matColumnDef="picture">
<th mat-header-cell *matHeaderCellDef> Picture </th>
<td mat-cell *matCellDef="let element"><img [src]="element.picture" alt="Picture" style="height: 60px"></td>
</ng-container>
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef mat-sort-header="title"> Title </th>
@@ -82,24 +95,48 @@
<ng-container matColumnDef="price">
<th mat-header-cell *matHeaderCellDef mat-sort-header="auctionedAmount"> Price </th>
<td mat-cell *matCellDef="let element">
{{element.auctionedAmount}}
<span [ngClass]="{'bold-text': element.auctionedAmount > 0}">{{element.auctionedAmount > 0 ? element.auctionedAmount : "-"}}</span>
</td>
</ng-container>
<!-- Price Column -->
<!-- nbrBids Column -->
<ng-container matColumnDef="nbrBids">
<th mat-header-cell *matHeaderCellDef mat-sort-header="bidsLength"> nbrBids </th>
<td mat-cell *matCellDef="let element">
{{element.bidsLength}}
{{element.postProcessing?.nbrBids}}
</td>
</ng-container>
<!-- duration Column -->
<ng-container matColumnDef="duration">
<th mat-header-cell *matHeaderCellDef mat-sort-header="duration"> Duration </th>
<td mat-cell *matCellDef="let element">
{{element.postProcessing?.duration}} s
</td>
</ng-container>
<!-- percentageAboveUnderLow Column -->
<ng-container matColumnDef="percentageAboveUnderLow">
<th mat-header-cell *matHeaderCellDef mat-sort-header="percentageAboveUnderLow">Above/Under Low</th>
<td mat-cell *matCellDef="let element">
{{element.postProcessing?.percentageAboveUnderLow}} %
</td>
</ng-container>
<!-- percentageAboveUnderHigh Column -->
<ng-container matColumnDef="percentageAboveUnderHigh">
<th mat-header-cell *matHeaderCellDef mat-sort-header="percentageAboveUnderHigh">Above/Under High</th>
<td mat-cell *matCellDef="let element">
{{element.postProcessing?.percentageAboveUnderHigh}} %
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="openDetailLot(row._id)"></tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[10, 50, 100]" showFirstLastButtons></mat-paginator>
<mat-paginator [pageSizeOptions]="[10, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-tab>
@@ -4,17 +4,18 @@ 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 { LotDetailDialogComponent } from './lot-detail-dialog/lot-detail-dialog.component';
import * as moment from 'moment';
// Services
import { apiService } from 'src/app/core/services/api.service';
import { apiSaleService } from 'src/app/core/services/api/api.sale.service';
import { apiLotService } from 'src/app/core/services/api/api.lot.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';
import { SaleInfo } from 'src/app/core/services/model/saleInfo.interface';
@Component({
selector: 'app-favorites-page',
@@ -27,8 +28,8 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
id: any = '';
Sale: Sale;
displayedColumns: string[] = ['lotNum', 'title', 'estimateLow', 'estimateHigh', 'price', 'nbrBids'];
displayedColumns: string[] = ['lotNum', 'picture', 'title', 'estimateLow', 'estimateHigh', 'price', 'nbrBids', 'duration', 'percentageAboveUnderLow', 'percentageAboveUnderHigh'];
lotList: MatTableDataSource<Lot> = new MatTableDataSource<Lot>();
@ViewChild(MatPaginator) paginator?: MatPaginator;
@ViewChild(MatSort) sort?: MatSort;
@@ -38,7 +39,8 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
private notificationService: NotificationService,
private router: Router,
public dialog: MatDialog,
private apiService: apiService) {
private apiSaleService: apiSaleService,
private apiLotService: apiLotService) {
this.Sale = {
_id: { $oid: '' },
@@ -53,10 +55,15 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
postProcessing: {
nbrLots: 0,
duration: 0,
bidsDuration: 0,
durationPerLots: '',
totalAmount: 0,
averageAmount: '',
medianAmount: ''
medianAmount: '',
minAmount: '',
maxAmount: '',
unsoldLots: 0,
unsoldPercentage: ''
}
}
@@ -76,17 +83,49 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
}
getSale(){
this.apiService.getSale(this.id).subscribe((sale: Sale) => {
this.apiSaleService.getSale(this.id).subscribe((sale: Sale) => {
this.Sale = sale;
});
}
getLotList(){
this.apiService.getLotsBySale(this.id).subscribe((lotList: Lot[]) => {
this.apiLotService.getLotsBySale(this.id).subscribe((lotList: Lot[]) => {
// adding the Bids length info
lotList = lotList.map((lot) => {
return {...lot, bidsLength: lot.Bids ? lot.Bids.length : 0};
return {...lot, bidsLength: lot.postProcessing ? lot.postProcessing.nbrBids : 0};
});
// adding the picture info
let path = '';
lotList = lotList.map((lot) => {
switch (lot.platform) {
case 'drouot':
path = 'https://cdn.drouot.com/d/image/lot?size=phare&path='+(lot.RawData as { photos?: { path: string }[] })?.photos?.[0]?.path;
return {...lot, picture: path ?? ''};
case 'interencheres':
path = (lot.RawData as { medias?: { lg: string }[] })?.medias?.[0]?.lg ?? '';
return {...lot, picture: path};
default:
return {...lot, picture: ''};
}
});
// adding the duration info
lotList = lotList.map((lot) => {
return {...lot, duration: lot.postProcessing ? lot.postProcessing.duration : 0};
});
// adding the percentageAboveUnderLow info
lotList = lotList.map((lot) => {
return {...lot, percentageAboveUnderLow: lot.postProcessing ? lot.postProcessing.percentageAboveUnderLow : 0};
});
// adding the percentageAboveUnderHigh info
lotList = lotList.map((lot) => {
return {...lot, percentageAboveUnderHigh: lot.postProcessing ? lot.postProcessing.percentageAboveUnderHigh : 0};
});
// adding the Auctionned ammount info
@@ -101,9 +140,9 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
});
}
getDurationInMinutes(duration: number): number {
return Math.floor(duration / 60);
}
// getDurationInMinutes(duration: number): number {
// return Math.floor(duration / 60);
// }
getTimePerLot(duration: number): string {
@@ -124,6 +163,30 @@ export class SaleDetailPageComponent implements OnInit, AfterViewInit {
return parseFloat(value || '0');
}
convertSecondsToHHMM(seconds: number): string {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
}
openDetailLot(idLot: string): void {
this.dialog.open(LotDetailDialogComponent, {
width: '80%',
data: {id: idLot}
});
}
downloadExcelStatsFile(_id: String): void {
this.apiSaleService.getSaleStatXsl(_id).subscribe((data: Blob) => {
const downloadURL = window.URL.createObjectURL(data);
const link = document.createElement('a');
link.href = downloadURL;
link.download = 'SaleStats.xlsx';
link.click();
});
}
}
@@ -63,31 +63,6 @@
<td mat-cell *matCellDef="let element"> {{element.platform}} </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> -->
<!-- Action Column -->
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef> Action </th>
@@ -97,6 +72,8 @@
<mat-option *ngIf="element.status == 'ready'" (click)="followSale(element)"><mat-icon>play_arrow</mat-icon> Follow</mat-option>
<mat-option *ngIf="element.status == 'following'" (click)="stopFollowSale(element)"><mat-icon>stop</mat-icon> Stop Following</mat-option>
<mat-option *ngIf="element.status == 'following'" (click)="resetToReady(element._id)">Reset to Ready</mat-option>
<mat-option (click)="navigateToSaleDetail(element._id)"><mat-icon>info</mat-icon> Details</mat-option>
<mat-option (click)="postProcessing(element._id)"><mat-icon>query_stats</mat-icon> Post-processing</mat-option>
<mat-option (click)="deleteSale(element._id)"><mat-icon>delete</mat-icon> Delete</mat-option>
</mat-select>
</td>
@@ -1,12 +1,13 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Title } from '@angular/platform-browser';
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 { apiSaleService } from 'src/app/core/services/api/api.sale.service';
import { Sale } from 'src/app/core/services/model/sale.interface';
@@ -15,7 +16,7 @@ import { Sale } from 'src/app/core/services/model/sale.interface';
templateUrl: './sales-page.component.html',
styleUrls: ['./sales-page.component.css']
})
export class SalesPageComponent implements OnInit {
export class SalesPageComponent implements OnInit,OnDestroy {
url: string = '';
refreshSalesId: any;
@@ -29,7 +30,8 @@ export class SalesPageComponent implements OnInit {
private notificationService: NotificationService,
private router: Router,
public dialog: MatDialog,
private apiService: apiService) {}
private apiSaleService: apiSaleService,
private titleService: Title) {}
openLoadingSale(): void {
const dialogRef = this.dialog.open(LoadingSaleDialogComponent, {
@@ -47,7 +49,7 @@ export class SalesPageComponent implements OnInit {
}
refreshSales(): void {
this.apiService.getAllSale().subscribe((data: any) => {
this.apiSaleService.getAllSale().subscribe((data: any) => {
console.log(data);
const today = moment().startOf('day');
@@ -62,15 +64,21 @@ export class SalesPageComponent implements OnInit {
}
ngOnInit(): void {
this.titleService.setTitle('Jucundus - Sales');
this.refreshSales();
this.refreshSalesId = setInterval(() => {
this.refreshSales();
}, 5000);
}
ngOnDestroy() {
if (this.refreshSalesId) {
clearInterval(this.refreshSalesId);
}
}
prepareSale(Sale: Sale): void {
this.apiService.prepareSale(Sale).subscribe( data => {
this.apiSaleService.prepareSale(Sale).subscribe( data => {
console.log(data);
this.refreshSales();
this.notificationService.openSnackBar("Prepare Sale");
@@ -80,7 +88,7 @@ export class SalesPageComponent implements OnInit {
followSale(Sale: Sale): void {
this.apiService.followSale(Sale).subscribe( data => {
this.apiSaleService.followSale(Sale).subscribe( data => {
console.log(data);
this.refreshSales();
this.notificationService.openSnackBar("Sale followed");
@@ -90,21 +98,21 @@ export class SalesPageComponent implements OnInit {
stopFollowSale(Sale: Sale): void {
Sale.status = "askStop";
this.apiService.updateSale(Sale).subscribe( data => {
this.apiSaleService.updateSale(Sale).subscribe( data => {
this.refreshSales();
this.notificationService.openSnackBar("Sale Stopping...");
})
}
deleteSale(_id: string): void {
this.apiService.deleteSale(_id).subscribe( data => {
this.apiSaleService.deleteSale(_id).subscribe( data => {
this.refreshSales();
this.notificationService.openSnackBar("Sale deleted");
})
}
resetToReady(_id: string): void {
this.apiService.resetSaleToReady(_id)
this.apiSaleService.resetSaleToReady(_id)
}
navigateToSaleDetail(id: string) {
@@ -114,7 +122,7 @@ export class SalesPageComponent implements OnInit {
}
postProcessing(id: string) {
this.apiService.postProcessing(id).subscribe( data => {
this.apiSaleService.postProcessing(id).subscribe( data => {
this.notificationService.openSnackBar("Sale processing");
})
}
@@ -5,13 +5,15 @@ 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 { LotDetailDialogComponent } from './sales-page/sale-detail-page/lot-detail-dialog/lot-detail-dialog.component';
import { SharedModule } from '../../shared/shared.module';
@NgModule({
declarations: [
SalesPageComponent,
LoadingSaleDialogComponent,
SaleDetailPageComponent
SaleDetailPageComponent,
LotDetailDialogComponent
],
imports: [
CommonModule,
@@ -0,0 +1,9 @@
.mat-mdc-row .mat-mdc-cell {
border-bottom: 1px solid transparent;
border-top: 1px solid transparent;
cursor: pointer;
}
.mat-mdc-row:hover .mat-mdc-cell {
border-color: currentColor;
}
@@ -0,0 +1,60 @@
<div class="container" fxLayout="row" fxLayoutAlign="center none">
<div fxFlex="95%">
<mat-toolbar>
<h2><a routerLink="/users">Users</a>/{{id !== '' ? 'Edit' : 'New'}}</h2>
</mat-toolbar>
<mat-card>
<mat-card-header>
<mat-card-title>Sale Detail</mat-card-title>
</mat-card-header>
<mat-card-content>
<form [formGroup]="userForm">
<div fxLayout="row" fxLayoutGap="5px">
<mat-form-field fxFlex="50">
<input matInput placeholder="Username" formControlName="username" required>
<mat-error *ngIf="userForm.get('username')?.hasError('required')">
Username is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="50">
<input matInput placeholder="Email" formControlName="email" required>
<mat-error *ngIf="userForm.get('email')?.hasError('email') && !userForm.get('email')?.hasError('required')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf="userForm.get('email')?.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="5px">
<mat-form-field fxFlex="50">
<input matInput placeholder="Password" formControlName="password">
<mat-error *ngIf="userForm.get('password')?.hasError('passwordLength')">
Password must be at least 8 characters long
</mat-error>
<mat-error *ngIf="userForm.get('password')?.hasError('mismatch') || userForm.get('confirmPassword')?.value === null">
Passwords do not match
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="50">
<input matInput placeholder="Confirm Password" formControlName="confirmPassword">
<mat-error *ngIf="userForm.errors?.['mismatch']">
Passwords do not match
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="5px">
<mat-checkbox name="isAdmin" formControlName="isAdmin">Admin</mat-checkbox>
<mat-checkbox name="isAgent" formControlName="isAgent">Agent</mat-checkbox>
</div>
<div fxLayout="row" fxLayoutGap="5px">
<button mat-raised-button color="primary" type="submit" [disabled]="!userForm.valid" (click)="save()">Save</button>
<button mat-raised-button color="warn" type="button" *ngIf="id" (click)="deleteUser()">Delete</button>
</div>
</form>
</mat-card-content>
</mat-card>
</div>
</div>
@@ -0,0 +1,123 @@
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router, ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ConfirmDialogComponent, ConfirmDialogModel } from 'src/app/shared/confirm-dialog/confirm-dialog.component';
// Services
import { NotificationService } from 'src/app/core/services/notification.service';
import { apiUserService } from 'src/app/core/services/api/api.user.service';
function passwordMatchValidator(g: FormGroup) {
const password = g.get('password')?.value;
const confirmPassword = g.get('confirmPassword')?.value;
if (password){
if (password.length < 8) {
g.get('password')?.setErrors({ passwordLength: true });
return { passwordLength: true };
}
if (password !== confirmPassword) {
g.get('confirmPassword')?.setErrors({ mismatch: true });
return { mismatch: true };
}
}
return null;
}
@Component({
selector: 'app-favorites-page',
templateUrl: './user-edit-page.component.html',
styleUrls: ['./user-edit-page.component.css']
})
export class UserEditPageComponent implements OnInit {
id: any = '';
userForm: FormGroup;
constructor(
private route: ActivatedRoute,
private notificationService: NotificationService,
private router: Router,
public dialog: MatDialog,
private apiUserService: apiUserService,
private fb: FormBuilder
) {
this.userForm = this.fb.group({
username: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
password: [''],
confirmPassword: [''],
isAdmin: [false],
isAgent: [false]
}, { validator: passwordMatchValidator });
}
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
this.id = params.get('id');
if(this.id) {
this.apiUserService.getUser(this.id).subscribe((data: any) => {
console.log(data);
// Update form values
this.userForm.patchValue({
username: data.username,
email: data.email,
isAdmin: data.isAdmin,
isAgent: data.isAgent
});
});
}
});
}
save(): void {
if (this.userForm.valid) {
let userData = this.userForm.value
console.log(userData);
if(this.id) {
userData._id = this.id;
// Edit User
this.apiUserService.updateUser(userData).subscribe((data: any) => {
this.notificationService.openSnackBar("User updated successfully");
this.router.navigate(['/users']);
});
} else {
// New User
this.apiUserService.saveUser(userData).subscribe((data: any) => {
this.notificationService.openSnackBar("User created successfully");
this.router.navigate(['/users']);
});
}
}
}
deleteUser(): void {
if (this.id) {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
width: '250px',
data: {title: 'Delete User ?', message: 'Are you sure you want to delete this user?'}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
// User clicked Yes
this.apiUserService.deleteUser(this.id).subscribe((data: any) => {
this.notificationService.openSnackBar("User deleted successfully");
this.router.navigate(['/users']);
});
}
});
}
}
}
@@ -1,18 +1,61 @@
<div class="container" fxLayout="row" fxLayoutAlign="center none">
<div fxFlex="95%">
<mat-toolbar>
<mat-toolbar-row>
<h2>Users</h2>
</mat-toolbar-row>
<mat-toolbar-row>
<button mat-raised-button color="primary" (click)="openUser('')">Add User</button>
</mat-toolbar-row>
</mat-toolbar>
<mat-card>
<mat-card-content>
<h2>Users</h2>
<div fxLayout="row" fxLayoutGap="5px">
<table mat-table [dataSource]="users" matSort class="mat-elevation-z8">
<div class="container" fxLayout="row" fxLayoutAlign="center none">
<div fxFlex="50%" class="text-center no-records animate">
<mat-icon>people_outline</mat-icon>
<p>No users exist.</p>
</div>
<mat-icon> </mat-icon>
</div>
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- username Column -->
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef mat-sort-header="username">Username</th>
<td mat-cell *matCellDef="let element">
{{element.username}}
</td>
</ng-container>
<!-- email Column -->
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef mat-sort-header="email"> Email </th>
<td mat-cell *matCellDef="let element">
{{element.email}}
</td>
</ng-container>
<!-- Admin Column -->
<ng-container matColumnDef="admin">
<th mat-header-cell *matHeaderCellDef mat-sort-header="isAdmin"> Admin </th>
<td mat-cell *matCellDef="let element">
<mat-icon *ngIf="element.isAdmin" style="color:green;">check</mat-icon>
</td>
</ng-container>
<!-- Agent Column -->
<ng-container matColumnDef="agent">
<th mat-header-cell *matHeaderCellDef mat-sort-header="isAgent"> Agent </th>
<td mat-cell *matCellDef="let element">
<mat-icon *ngIf="element.isAgent" style="color:green;">check</mat-icon>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="openUser(row._id)"></tr>
</table>
</div>
<mat-paginator [pageSizeOptions]="[10, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-card-content>
</mat-card>
@@ -1,8 +1,14 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { NGXLogger } from 'ngx-logger';
import { NotificationService } from 'src/app/core/services/notification.service';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { apiUserService } from 'src/app/core/services/api/api.user.service';
import { User } from 'src/app/core/services/model/user.interface';
@Component({
selector: 'app-user-list',
@@ -11,14 +17,38 @@ import { NotificationService } from 'src/app/core/services/notification.service'
})
export class UserListComponent implements OnInit {
displayedColumns: string[] = ['username', 'email', 'admin', 'agent'];
users : MatTableDataSource<User> = new MatTableDataSource<User>();
@ViewChild(MatPaginator) paginator?: MatPaginator;
@ViewChild(MatSort) sort?: MatSort;
constructor(
private logger: NGXLogger,
private notificationService: NotificationService,
private titleService: Title
private titleService: Title,
private router: Router,
private apiUserService: apiUserService,
) { }
ngOnInit() {
this.titleService.setTitle('Jucundus - Users');
this.logger.log('Users loaded');
this.refreshUsers()
}
refreshUsers(): void {
this.apiUserService.getAllUsers().subscribe((data: any) => {
console.log(data);
this.users = new MatTableDataSource(data);
this.users.paginator = this.paginator ?? null;
this.users.sort = this.sort ?? null;
this.notificationService.openSnackBar("Users loaded");
});
}
openUser(id: string): void {
this.router.navigate(['/users/edit', id]);
}
}
@@ -3,6 +3,7 @@ import { Routes, RouterModule } from '@angular/router';
import { LayoutComponent } from 'src/app/shared/layout/layout.component';
import { UserListComponent } from './user-list/user-list.component';
import { UserEditPageComponent } from './user-list/user-edit-page/user-edit-page.component';
const routes: Routes = [
{
@@ -10,6 +11,7 @@ const routes: Routes = [
component: LayoutComponent,
children: [
{ path: '', component: UserListComponent },
{ path: 'edit/:id', component: UserEditPageComponent },
]
}
];
@@ -3,6 +3,8 @@ import { CommonModule } from '@angular/common';
import { UsersRoutingModule } from './users-routing.module';
import { UserListComponent } from './user-list/user-list.component';
import { UserEditPageComponent } from './user-list/user-edit-page/user-edit-page.component';
import { SharedModule } from 'src/app/shared/shared.module';
@NgModule({
@@ -11,6 +13,9 @@ import { SharedModule } from 'src/app/shared/shared.module';
SharedModule,
UsersRoutingModule
],
declarations: [UserListComponent]
declarations: [
UserListComponent,
UserEditPageComponent
]
})
export class UsersModule { }
@@ -83,7 +83,12 @@
</mat-icon>
<p mat-line> Pictures </p>
</a>
<a mat-list-item [routerLink]="['/users']" routerLinkActive="active">
<mat-icon matListItemIcon>
people
</mat-icon>
<p mat-line> Users </p>
</a>
<!-- <a mat-list-item [routerLink]="['/customers']" routerLinkActive="active">
<mat-icon matListItemIcon>
@@ -91,16 +96,10 @@
</mat-icon>
<p mat-line> Customers </p>
</a>
<a mat-list-item [routerLink]="['/users']" routerLinkActive="active">
<mat-icon matListItemIcon>
people
</mat-icon>
<p mat-line> Users </p>
</a> -->
-->
<mat-divider></mat-divider>
<h3 mat-subheader>User</h3>
<a mat-list-item [routerLink]="['/account/profile']">
<mat-icon matListItemIcon>person</mat-icon>
+2 -1
View File
@@ -3,5 +3,6 @@ import { NgxLoggerLevel } from 'ngx-logger';
export const environment = {
production: true,
logLevel: NgxLoggerLevel.OFF,
serverLogLevel: NgxLoggerLevel.ERROR
serverLogLevel: NgxLoggerLevel.ERROR,
ServeurURL: "http://localhost:3000"
};
+2 -1
View File
@@ -8,5 +8,6 @@ import { NgxLoggerLevel } from 'ngx-logger';
export const environment = {
production: false,
logLevel: NgxLoggerLevel.TRACE,
serverLogLevel: NgxLoggerLevel.OFF
serverLogLevel: NgxLoggerLevel.OFF,
ServeurURL: "http://localhost:3000"
};