Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
Yûki VACHOT 2021-12-13 20:03:33 +01:00
commit 027a34ac70
27 changed files with 243 additions and 114 deletions

View file

@ -18,7 +18,7 @@
<!-- filtre textuelle-->
<div style="margin: 10px 0px 20px 2%;">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="filtre...">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="Rechercher par mots-clés...">
</div>
<!-- visible + interests + période -->

View file

@ -134,11 +134,7 @@ export class PageAdListAdminComponent implements AfterViewInit
const config = {
width: '30%',
height: '90%',
data: {
images: advert.images,
width: 300,
height: 800,
}
data: { images: advert.images }
};
this.dialog
.open(PopupVisualizeImagesAdminComponent, config)

View file

@ -5,9 +5,16 @@
</button>
</div>
<div style="text-align: center; justify-content: center">
<carousel [images]="tabImages"
cellsToShow="1"
[height]="height"
[width]="width"></carousel>
</div>
<mat-grid-list cols="12" rowHeight="500">
<mat-grid-tile colspan="1" rowspan="1" (click)="onPrecedent()">
<button> < </button>
</mat-grid-tile>
<mat-grid-tile colspan="10" rowspan="1">
<img [src]="tabImages[index].base64" [alt]="tabImages[index].description">
</mat-grid-tile>
<mat-grid-tile colspan="1" rowspan="1" (click)="onSuivant()">
<button> > </button>
</mat-grid-tile>
</mat-grid-list>

View file

@ -11,8 +11,8 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
export class PopupVisualizeImagesAdminComponent implements OnInit
{
tabImages = [];
width: number = 0;
height: number = 0;
index: number = 0;
nbImage: number = 0;
constructor( public dialogRef: MatDialogRef<PopupVisualizeImagesAdminComponent>,
@ -21,15 +21,18 @@ export class PopupVisualizeImagesAdminComponent implements OnInit
ngOnInit(): void
{
this.width = this.data.width*0.8;
this.height = this.data.height*0.8;
this.tabImages = this.data.images;
this.nbImage = this.tabImages.length;
}
for(let couple of this.data.images)
{
const elt = { path: "assets/pub/"+couple.url };
this.tabImages.push(elt);
}
console.log(this.tabImages);
onPrecedent(): void
{
if(this.index !== 0) this.index -= 1;
}
onSuivant(): void
{
if(this.index !== (this.nbImage-1)) this.index += 1;
}
}

View file

@ -20,7 +20,7 @@
</mat-chip>
<input
placeholder="Tapez un tag et pressez 'Entré' pour l'inserer"
placeholder="Tapez un centre d'intérêt et pressez 'Entrer' pour l'inserer"
#tagInput
[formControl]="formControl"
[matAutocomplete]="auto"

View file

@ -6,7 +6,6 @@ import {MessageService} from "../../../utils/services/message/message.service";
import {map, startWith} from "rxjs/operators";
import {MatChipInputEvent} from "@angular/material/chips";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {FictitiousUtilsService} from "../../../utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service";
@ -28,8 +27,7 @@ export class InputInterestsAdminComponent implements OnInit
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
constructor( private fictitiousUtilsService: FictitiousUtilsService,
private messageService: MessageService ) {}
constructor( private messageService: MessageService ) {}
ngOnInit(): void
@ -38,16 +36,26 @@ export class InputInterestsAdminComponent implements OnInit
startWith(null),
map((fruit: string | null) => fruit ? this._filter(fruit) : this.allInterests.slice()));
// --- FAUX CODE ---
this.allInterests = this.fictitiousUtilsService.getTags();
this.allInterests.sort();
this.messageService
.get("misc/getInterests")
.subscribe( retour => {
if(retour.status !== "success") {
console.log(retour);
}
else {
this.allInterests = [];
for(let elt of retour.data) this.allInterests.push(elt.interest);
this.allInterests.sort();
}
});
}
add(event: MatChipInputEvent): void
{
const value = (event.value || '').trim();
if (value && (this.allInterests.indexOf(value) !== -1))
if (value && (this.allInterests.indexOf(value) !== -1) && (!this.myInterests.includes(value)))
{
this.myInterests.push(value);
event.chipInput!.clear();
@ -67,7 +75,8 @@ export class InputInterestsAdminComponent implements OnInit
selected(event: MatAutocompleteSelectedEvent): void
{
this.myInterests.push(event.option.viewValue);
const value = event.option.viewValue;
if(!this.myInterests.includes(value))this.myInterests.push(value);
this.tagInput.nativeElement.value = '';
this.formControl.setValue(null);
this.eventEmitter.emit(this.myInterests);

View file

@ -23,7 +23,7 @@
<!-- filtre textuelle-->
<div style="margin: 10px 0px 20px 2%;">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="filtre...">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="Rechercher par mots-clés...">
</div>
<!-- role + actif + période -->

View file

@ -31,7 +31,7 @@
<!-- Deconnexion -->
<button mat-button class="btnDeconnexion" (click)="onDeconnexion()" routerLink="/">
Deconnexion
Déconnexion
</button>
</nav>

View file

@ -1,4 +1,4 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {Component, ElementRef, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
@Component({
selector: 'app-drag-and-drop',
@ -8,15 +8,16 @@ import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
export class DragAndDropComponent
{
@ViewChild("fileDropRef", { static: false }) fileDropEl: ElementRef;
files: any[] = [];
info_image = "Vos annonces seront affichées dans un rectangle de rapport 1/5 avec: \n • 1 la largeur du rectangle \n • 5 la hauteur du rectangle" ;
files: any[] = [];
@Output() eventEmitter = new EventEmitter<any>();
/**
* on file drop handler
*/
onFileDropped($event) {
this.prepareFilesList($event);
this.eventEmitter.emit(this.files);
}
/**
@ -24,6 +25,7 @@ export class DragAndDropComponent
*/
fileBrowseHandler(files) {
this.prepareFilesList(files);
this.eventEmitter.emit(this.files);
}
/**

View file

@ -6,7 +6,6 @@ import {map, startWith} from "rxjs/operators";
import {MatChipInputEvent} from "@angular/material/chips";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {MessageService} from "../../../utils/services/message/message.service";
import {FictitiousUtilsService} from "../../../utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service";
@ -28,8 +27,7 @@ export class InputInterestsAdComponent implements OnInit
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
constructor( private fictitiousUtilsService: FictitiousUtilsService,
private messageService: MessageService ) {}
constructor( private messageService: MessageService ) {}
ngOnInit(): void
@ -56,7 +54,7 @@ export class InputInterestsAdComponent implements OnInit
add(event: MatChipInputEvent): void
{
const value = (event.value || '').trim();
if (value && (this.allTags.indexOf(value) !== -1))
if (value && (this.allTags.indexOf(value) !== -1) && (!this.myTags.includes(value)))
{
this.myTags.push(value);
event.chipInput!.clear();
@ -76,7 +74,8 @@ export class InputInterestsAdComponent implements OnInit
selected(event: MatAutocompleteSelectedEvent): void
{
this.myTags.push(event.option.viewValue);
const value = event.option.viewValue;
if(!this.myTags.includes(value))this.myTags.push(value);
this.tagInput.nativeElement.value = '';
this.formControl.setValue(null);
this.eventEmitter.emit(this.myTags);

View file

@ -2,7 +2,7 @@ import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {MatSort} from "@angular/material/sort";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MatTableDataSource} from "@angular/material/table";
import {Advert, AdvertWithCountViews} from "../../../utils/interfaces/advert";
import {AdvertWithCountViews} from "../../../utils/interfaces/advert";
import {MatDialog} from "@angular/material/dialog";
import {PopupAddOrUpdateAdComponent} from "../popup-add-or-update-ad/popup-add-or-update-ad.component";
import {MatSnackBar} from "@angular/material/snack-bar";
@ -100,19 +100,23 @@ export class PageAdListAdvertiserComponent implements AfterViewInit
onVisualizeImages(advert: AdvertWithCountViews)
{
const config = {
width: '30%',
height: '90%',
data: {
images: advert.images,
width: 300,
height: 800,
}
};
this.dialog
.open(PopupVisualizeImagesAdvertiserComponent, config)
.afterClosed()
.subscribe(retour => {});
if(advert.images.length !== 0)
{
const config = {
width: '30%',
height: '90%',
data: { images: advert.images }
};
this.dialog
.open(PopupVisualizeImagesAdvertiserComponent, config)
.afterClosed()
.subscribe(retour => {});
}
else {
const config = { duration: 2000, panelClass: "custom-class" };
const message = "Cette annonce ne contient aucune image" ;
this.snackBar.open( message, "", config);
}
}
@ -122,7 +126,12 @@ export class PageAdListAdvertiserComponent implements AfterViewInit
width: '75%',
height: '80%',
panelClass: 'custom-dialog-container',
data: { action: "add", advert: null, allVideoCategorie: this.allVideoCategorie }
data: {
action: "add",
advert: null,
allVideoCategorie: this.allVideoCategorie,
allTitle: this.tabAdvertWithCountViews.map(x => x.title)
}
};
this.dialog
.open(PopupAddOrUpdateAdComponent, config)
@ -150,7 +159,12 @@ export class PageAdListAdvertiserComponent implements AfterViewInit
width: '75%',
height: '80%',
panelClass: 'custom-dialog-container',
data: { action: "update", advert: advertToUpdate, allVideoCategorie: this.allVideoCategorie }
data: {
action: "update",
advert: advertToUpdate,
allVideoCategorie: this.allVideoCategorie,
allTitle: this.tabAdvertWithCountViews.map(x => x.title)
}
};
this.dialog
.open(PopupAddOrUpdateAdComponent, config)

View file

@ -59,7 +59,7 @@
<!-- nouvelles images -->
<div class="col-6" style="overflow-x: hidden; overflow-y: scroll; max-height: 70vh;">
<app-drag-and-drop></app-drag-and-drop>
<app-drag-and-drop (eventEmitter)="onReceiveNewImages($event)"></app-drag-and-drop>
</div>
</div>
@ -67,6 +67,10 @@
<br><mat-divider></mat-divider>
<!-- message d'erreur -->
<div *ngIf="hasError" style="text-align: center; margin-bottom: 20px;">
<span class="mat-error">{{errorMessage}}</span>
</div>
<!-- Actions -->
<mat-dialog-actions align="end">

View file

@ -5,6 +5,8 @@ import {MessageService} from "../../../utils/services/message/message.service";
import {ThemeService} from "../../../utils/services/theme/theme.service";
const ADVERT_VIDE: Advert = {
_id: "",
userId: "",
@ -31,9 +33,14 @@ export class PopupAddOrUpdateAdComponent implements OnInit
advert: any;
title: string = "" ;
allVideoCategorie = [];
tabWaitingFile: File[] = []; // fichiers selectionnés mais pas encore "validés"
tabSelectedFile: File[] = []; // fichier "validés"
_event;
allTitle = [];
tabOfNewImagesBase64 = [];
tabOfNewImagesName = [];
hasError: boolean = false;
errorMessage: string = "" ;
constructor( public dialogRef: MatDialogRef<PopupAddOrUpdateAdComponent>,
@ -44,7 +51,8 @@ export class PopupAddOrUpdateAdComponent implements OnInit
ngOnInit(): void
{
this.allVideoCategorie = this.data.allVideoCategorie
this.allVideoCategorie = this.data.allVideoCategorie;
this.allTitle = this.data.allTitle.slice();
if(this.data.action === "add")
{
this.advert = Object.assign({}, ADVERT_VIDE);
@ -56,43 +64,61 @@ export class PopupAddOrUpdateAdComponent implements OnInit
this.advert = Object.assign({}, this.data.advert);
this.advert.interests = this.data.advert.interests.slice();
this.title = "Modifier annonce" ;
const indexOldTitle = this.allTitle.findIndex(title => title == this.advert.title);
this.allTitle.splice(indexOldTitle, 1);
}
}
onValidate(): void
{
// On transforme 'this.user.interests' en tableau de 'videoCategorie'
let interests = []; // tableau de videoCategorie
for(let interest of this.advert.interests)
this.checkField();
if(!this.hasError)
{
for(let videoCategorie of this.allVideoCategorie)
// preparation des donnees
this.prepareAdvertInterests();
this.prepareAdvertImages();
// si creation
if (this.data.action === "add")
{
if(videoCategorie.interest === interest) {
interests.push(videoCategorie);
break;
}
this.messageService
.post("ad/create", this.advert)
.subscribe(ret => this.onCreateCallback(ret), err => this.onCreateCallback(err));
}
// si update
else
{
const id = this.advert.id;
Reflect.deleteProperty(this.advert, "id");
Reflect.deleteProperty(this.advert, "_id");
this.messageService
.put("ad/update/" + id, this.advert)
.subscribe(ret => this.onUpdateCallback(ret, id), err => this.onUpdateCallback(err, id));
}
}
this.advert.interests = interests;
}
if(this.data.action === "add")
checkField()
{
if(this.advert.title.length === 0) {
this.errorMessage = "Veuillez remplir le champ 'titre'" ;
this.hasError = true;
}
else if(this.allTitle.includes(this.advert.title))
{
this.messageService
.post("ad/create", this.advert)
.subscribe(ret => this.onCreateCallback(ret), err => this.onCreateCallback(err));
this.errorMessage = "Ce titre est déjà pris" ;
this.hasError = true;
}
else {
const id = this.advert.id;
Reflect.deleteProperty(this.advert, "id");
Reflect.deleteProperty(this.advert, "_id");
this.messageService
.put("ad/update/"+id, this.advert)
.subscribe(ret => this.onUpdateCallback(ret,id), err => this.onUpdateCallback(err,id));
this.errorMessage = "";
this.hasError = false;
}
}
onCreateCallback(retour: any): void
{
if(retour.status !== "success") {
@ -127,8 +153,65 @@ export class PopupAddOrUpdateAdComponent implements OnInit
onRemoveImgAlreadyPresent(image)
{
const index = this.advert.images.indexOf(image);
console.log("idx: " + index);
this.advert.images.slice(index, 1);
this.advert.images.splice(index, 1);
}
onReceiveNewImages(files: any): void
{
this.tabOfNewImagesBase64 = [];
this.tabOfNewImagesName = [];
if(files)
{
for(let file of files)
{
if(file)
{
const reader = new FileReader();
reader.onload = this.handleReaderLoaded.bind(this);
this.tabOfNewImagesName.push(file.name)
reader.readAsBinaryString(file);
}
}
}
}
handleReaderLoaded(e)
{
this.tabOfNewImagesBase64.push('data:image/png;base64,' + btoa(e.target.result))
}
// Met bien en forme les "images" avant d'être envoyer
prepareAdvertImages(): void
{
for(let i=0; i<this.tabOfNewImagesName.length ; i++)
{
let newImagePrepared = {
base64: this.tabOfNewImagesBase64[i],
url: "",
description: this.tabOfNewImagesName[i],
type: 0,
};
this.advert.images.push(newImagePrepared);
}
}
// Met bien en forme les "interests" avant d'être envoyer
prepareAdvertInterests(): void
{
let interests = [];
for (let interest of this.advert.interests) {
for (let videoCategorie of this.allVideoCategorie) {
if (videoCategorie.interest === interest) {
interests.push(videoCategorie);
break;
}
}
}
this.advert.interests = interests;
}
}

View file

@ -17,7 +17,7 @@
<!-- Tags -->
<div class="row myRow">
<div class="col-6 myLabel"> Tags: </div>
<div class="col-6 myLabel"> Centre d'intérêt :</div>
<div class="col-6 myValue" style="border-left: solid 1px #e6e6e6">
<div *ngFor="let tag of advert.interests"> • {{tag}} </div>
</div>

View file

@ -5,9 +5,16 @@
</button>
</div>
<div style="text-align: center; justify-content: center">
<carousel [images]="tabImages"
cellsToShow="1"
[height]="height"
[width]="width"></carousel>
</div>
<mat-grid-list cols="12" rowHeight="500">
<mat-grid-tile colspan="1" rowspan="1" (click)="onPrecedent()">
<button> < </button>
</mat-grid-tile>
<mat-grid-tile colspan="10" rowspan="1">
<img [src]="tabImages[index].base64" [alt]="tabImages[index].description">
</mat-grid-tile>
<mat-grid-tile colspan="1" rowspan="1" (click)="onSuivant()">
<button> > </button>
</mat-grid-tile>
</mat-grid-list>

View file

@ -11,8 +11,8 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
export class PopupVisualizeImagesAdvertiserComponent implements OnInit
{
tabImages = [];
width: number = 0;
height: number = 0;
index: number = 0;
nbImage: number = 0;
constructor( public dialogRef: MatDialogRef<PopupVisualizeImagesAdvertiserComponent>,
@ -21,15 +21,18 @@ export class PopupVisualizeImagesAdvertiserComponent implements OnInit
ngOnInit(): void
{
this.width = this.data.width;
this.height = this.data.height;
this.tabImages = this.data.images;
this.nbImage = this.tabImages.length;
}
for(let couple of this.data.images)
{
const elt = { path: "assets/pub/"+couple.url };
this.tabImages.push(elt);
}
console.log(this.tabImages);
onPrecedent(): void
{
if(this.index !== 0) this.index -= 1;
}
onSuivant(): void
{
if(this.index !== (this.nbImage-1)) this.index += 1;
}
}

View file

@ -35,7 +35,7 @@
<!-- Deconnexion -->
<button mat-button class="btnDeconnexion" (click)="onDeconnexion()" routerLink="/">
Deconnexion
Déconnexion
</button>
</nav>

View file

@ -2,7 +2,7 @@
<!-- ------------------------------------------------------------------------------------ -->
<mat-label>Tags</mat-label>
<mat-label>Centres d'intérêt</mat-label>
<!-- ------------------------------------------------------------------------------------ -->
@ -20,7 +20,7 @@
</mat-chip>
<input
placeholder="Tapez un tag et pressez 'Entré' pour l'inserer"
placeholder="Tapez un centre d'intérêt et pressez 'Entrer' pour l'inserer"
#tagInput
[formControl]="formControl"
[matAutocomplete]="auto"

View file

@ -55,7 +55,7 @@ export class InputInterestsRegisterComponent implements OnInit
add(event: MatChipInputEvent): void
{
const value = (event.value || '').trim();
if (value && (this.allInterests.indexOf(value) !== -1))
if (value && (this.allInterests.indexOf(value) !== -1) && (!this.myInterests.includes(value)))
{
this.myInterests.push(value);
event.chipInput!.clear();
@ -75,7 +75,8 @@ export class InputInterestsRegisterComponent implements OnInit
selected(event: MatAutocompleteSelectedEvent): void
{
this.myInterests.push(event.option.viewValue);
const value = event.option.viewValue;
if(!this.myInterests.includes(value))this.myInterests.push(value);
this.tagInput.nativeElement.value = '';
this.formControl.setValue(null);
this.eventEmitter.emit(this.myInterests);

View file

@ -7,7 +7,7 @@
<!-- ---------------------------------------------------------------------------------- -->
<div style="text-align: center">
<input (keyup)="applyFilter($event)" placeholder="filtre...">
<input (keyup)="applyFilter($event)" placeholder="Rechercher par mots clés...">
</div>
<br>

View file

@ -4,7 +4,7 @@
<!-- Search bar -->
<div class="row searchBarContainer">
<div style="text-align: center">
<input type="search" placeholder="recherche..." class="inputSearchBar" [(ngModel)]="search" (ngModelChange)="whileSearch()">
<input type="search" placeholder="Rechercher..." class="inputSearchBar" [(ngModel)]="search" (ngModelChange)="whileSearch()">
</div>
</div>

View file

@ -11,7 +11,7 @@
<div style="text-align: right ; margin: 0px; padding: 0px">
<button mat-button (click)="onAnnuler()">Annuler</button>
<button mat-button (click)="onValider()">
<span *ngIf="action === 'create'"> Creer </span>
<span *ngIf="action === 'create'"> Créer </span>
<span *ngIf="action === 'update'"> Modifier </span>
</button>
</div>

View file

@ -16,7 +16,7 @@
</mat-chip>
<input
placeholder="Tapez centres d'intérêt"
placeholder="Tapez un centre d'intérêt"
#tagInput
[formControl]="formControl"
[matAutocomplete]="auto"

View file

@ -55,7 +55,7 @@ export class InputInterestsProfilComponent implements OnInit
add(event: MatChipInputEvent): void
{
const value = (event.value || '').trim();
if (value && (this.allInterests.indexOf(value) !== -1))
if (value && (this.allInterests.indexOf(value) !== -1) && (!this.myInterests.includes(value)))
{
this.myInterests.push(value);
event.chipInput!.clear();
@ -75,7 +75,8 @@ export class InputInterestsProfilComponent implements OnInit
selected(event: MatAutocompleteSelectedEvent): void
{
this.myInterests.push(event.option.viewValue);
const value = event.option.viewValue;
if(!this.myInterests.includes(value))this.myInterests.push(value);
this.tagInput.nativeElement.value = '';
this.formControl.setValue(null);
this.eventEmitter.emit(this.myInterests);

View file

@ -16,7 +16,7 @@
<!-- Search bar -->
<div class="input-group" style="width: 100%; margin: 0 auto;">
<div class="form-outline" style="width: 100%; margin: 0 auto;">
<input type="search" placeholder="recherche..." class="inputSearchBar" [(ngModel)]="search"/>
<input type="search" placeholder="Rechercher..." class="inputSearchBar" [(ngModel)]="search"/>
<button mat-icon-button (click)="onSearch()">
<mat-icon>search</mat-icon>
</button>

View file

@ -35,7 +35,7 @@
<!-- Deconnexion -->
<button mat-button class="btnDeconnexion" (click)="onDeconnexion()" routerLink="/">
Deconnexion
Déconnexion
</button>
</nav>

View file

@ -17,7 +17,7 @@
<!-- Search bar -->
<div class="input-group" style="width: 100%; margin: 0 auto;">
<div class="form-outline" style="width: 100%; margin: 0 auto;">
<input type="search" placeholder="recherche..." class="inputSearchBar"/>
<input type="search" placeholder="Rechercher..." class="inputSearchBar"/>
<button mat-icon-button (click)="onSearch()">
<mat-icon>search</mat-icon>
</button>