@xit/utility
Version:
Composants et services de la zone Utility des applications XiT
1 lines • 231 kB
Source Map (JSON)
{"version":3,"file":"xit-utility.mjs","sources":["../../../projects/utility/src/lib/utility-config.ts","../../../projects/utility/src/lib/log/log.service.ts","../../../projects/utility/src/lib/error/error.service.ts","../../../projects/utility/src/lib/country/country.service.ts","../../../projects/utility/src/lib/address/address-form/address-form.component.ts","../../../projects/utility/src/lib/address/address-form/address-form.component.html","../../../projects/utility/src/lib/address/address.component.ts","../../../projects/utility/src/lib/address/address.component.html","../../../projects/utility/src/lib/breadcrumb/breadcrumb.component.ts","../../../projects/utility/src/lib/breadcrumb/breadcrumb.component.html","../../../projects/utility/src/lib/file/file.service.ts","../../../projects/utility/src/lib/file/canvas/canvas.directive.ts","../../../projects/utility/src/lib/file/canvas/canvas.module.ts","../../../projects/utility/src/lib/file/carousel/carousel-body-reference.component.ts","../../../projects/utility/src/lib/file/carousel/carousel-slide-portal.directive.ts","../../../projects/utility/src/lib/file/carousel/carousel-body.component.ts","../../../projects/utility/src/lib/file/carousel/carousel-body.component.html","../../../projects/utility/src/lib/file/carousel/carousel-slide-content.directive.ts","../../../projects/utility/src/lib/file/carousel/carousel-slide.component.ts","../../../projects/utility/src/lib/file/carousel/carousel-slide.component.html","../../../projects/utility/src/lib/file/carousel/carousel-slide-change-event.model.ts","../../../projects/utility/src/lib/file/carousel/carousel-group.component.ts","../../../projects/utility/src/lib/file/carousel/carousel-group.component.html","../../../projects/utility/src/lib/file/viewer/remove-dialog.component.ts","../../../projects/utility/src/lib/file/viewer/remove-dialog.component.html","../../../projects/utility/src/lib/file/viewer/rename-dialog.component.ts","../../../projects/utility/src/lib/file/viewer/rename-dialog.component.html","../../../projects/utility/src/lib/shared/error/error.component.ts","../../../projects/utility/src/lib/shared/error/error.component.html","../../../projects/utility/src/lib/file/viewer/viewer-dialog.component.ts","../../../projects/utility/src/lib/file/viewer/viewer-dialog.component.html","../../../projects/utility/src/lib/file/viewer/viewer.directive.ts","../../../projects/utility/src/lib/file/carousel/carousel.component.ts","../../../projects/utility/src/lib/file/carousel/carousel.component.html","../../../projects/utility/src/lib/file/viewer/viewer.module.ts","../../../projects/utility/src/lib/file/carousel/carousel.module.ts","../../../projects/utility/src/lib/location/location.service.ts","../../../projects/utility/src/lib/notification/notification.service.ts","../../../projects/utility/src/lib/report/report.service.ts","../../../projects/utility/src/lib/setting/setting.service.ts","../../../projects/utility/src/lib/wallet/wallet.service.ts","../../../projects/utility/src/lib/wallet/wallet.component.ts","../../../projects/utility/src/lib/wallet/wallet.component.html","../../../projects/utility/src/lib/address/address-remove/address-remove.component.ts","../../../projects/utility/src/lib/address/address-remove/address-remove.component.html","../../../projects/utility/src/lib/wallet/wallet-add/wallet-add.component.ts","../../../projects/utility/src/lib/wallet/wallet-add/wallet-add.component.html","../../../projects/utility/src/lib/wallet/wallet-edit/wallet-edit.component.ts","../../../projects/utility/src/lib/wallet/wallet-edit/wallet-edit.component.html","../../../projects/utility/src/lib/wallet/wallet-remove/wallet-remove.component.ts","../../../projects/utility/src/lib/wallet/wallet-remove/wallet-remove.component.html","../../../projects/utility/src/lib/utility.module.ts","../../../projects/utility/src/public_api.ts","../../../projects/utility/src/xit-utility.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nexport const UTILITY_CONFIG = new InjectionToken<UtilityConfig>('UtilityConfig');\r\n\r\nexport interface LocationConfig {\r\n default: any;\r\n url: string;\r\n key: string;\r\n}\r\n\r\nexport interface StripeConfig {\r\n key: string;\r\n}\r\n\r\nexport interface UtilityServicesConfig {\r\n captchas: string;\r\n countries: string;\r\n emails: string;\r\n files: string;\r\n notifications: string;\r\n reports: string;\r\n settings: string;\r\n wallets: string;\r\n}\r\n\r\nexport interface UtilityConfig {\r\n location: LocationConfig;\r\n services: UtilityServicesConfig;\r\n stripe: StripeConfig;\r\n url: string;\r\n version: string;\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class LogService {\r\n /**\r\n * Conserve une trace de l'action\r\n * @param operation - nom de l'opération à logguer\r\n * @param data - donnée associée à l'opération\r\n */\r\n log(operation: string, data?: any): void {\r\n console.log(operation, data || '');\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Observable } from 'rxjs';\r\n\r\nimport { LogService } from '../log/log.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class ErrorService {\r\n constructor(private logService: LogService) { }\r\n\r\n /**\r\n * Capture l'erreur de la requête Http.\r\n * Fait en sorte que l'application continue.\r\n * @param operation - nom de l'operation qui a caus� l'erreur\r\n */\r\n handleError<T>(operation = 'operation') {\r\n return (value: any): Observable<T> => {\r\n this.logService.log(`${operation} failed: ${value.message}`);\r\n return new Observable<T>(observer => observer.error(value));\r\n };\r\n }\r\n}\r\n","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Dictionary } from '@xit/dto';\r\nimport { Observable } from 'rxjs';\r\nimport { catchError, tap, shareReplay } from 'rxjs/operators';\r\n\r\nimport { ErrorService } from '../error/error.service';\r\nimport { LogService } from '../log/log.service';\r\nimport { UTILITY_CONFIG, UtilityConfig } from '../utility-config';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class CountryService {\r\n private countryUrl: string;\r\n private countries$: Observable<Array<Dictionary<string>>>;\r\n\r\n constructor(\r\n @Inject(UTILITY_CONFIG) private config: UtilityConfig,\r\n private http: HttpClient,\r\n private errorService: ErrorService,\r\n private logService: LogService\r\n ) {\r\n this.countryUrl = `${this.config.url}/${this.config.version}/${this.config.services.countries}`;\r\n }\r\n\r\n countriesByRegion(region: string, langs: Array<string>): Observable<Array<Dictionary<string>>> {\r\n if (!this.countries$) {\r\n const operation = 'Country service (countries)';\r\n this.countries$ = this.http\r\n .get<Array<Dictionary<string>>>(`${this.countryUrl}/regions/${region}/langs/${langs.join()}`)\r\n .pipe(\r\n shareReplay(1),\r\n tap((c: Array<Dictionary<string>>) => this.logService.log(operation, c)),\r\n catchError(this.errorService.handleError<Array<Dictionary<string>>>(operation))\r\n );\r\n }\r\n return this.countries$;\r\n }\r\n}\r\n","import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core';\r\nimport { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';\r\nimport { Address, Dictionary } from '@xit/dto';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\nimport { CountryService } from '../../country/country.service';\r\n\r\n@Component({\r\n selector: 'xit-address-form',\r\n templateUrl: 'address-form.component.html',\r\n styleUrls: ['address-form.component.scss'],\r\n providers: [CountryService]\r\n})\r\nexport class AddressFormComponent implements OnInit, OnDestroy {\r\n private _address: Address;\r\n private destroy: Subject<boolean>;\r\n formAddress: FormGroup;\r\n countries: Array<any>;\r\n loadingCountries: boolean;\r\n\r\n @Input()\r\n saving: boolean;\r\n\r\n @Input()\r\n get address(): Address {\r\n return this._address;\r\n }\r\n set address(value: Address) {\r\n this._address = value;\r\n this.init();\r\n }\r\n\r\n @Output() canceled: EventEmitter<Address>;\r\n\r\n @Output() submitted: EventEmitter<Address>;\r\n\r\n constructor(\r\n private formBuilder: FormBuilder,\r\n private countryService: CountryService\r\n ) {\r\n this.loadingCountries = false;\r\n this.destroy = new Subject<boolean>();\r\n this.canceled = new EventEmitter<Address>();\r\n this.submitted = new EventEmitter<Address>();\r\n this.formAddress = this.formBuilder.group({\r\n country: [{ value: '', disabled: true }, [Validators.required]],\r\n default: [false, [Validators.required]],\r\n locality: ['', [Validators.required]],\r\n postalCode: ['', [Validators.required, Validators.maxLength(5), Validators.pattern(/^988\\d{2}$/)]],\r\n state: [''],\r\n streetAddress: ['', [Validators.required]]\r\n });\r\n }\r\n\r\n getControls(): Array<AbstractControl> {\r\n const controls = new Array<AbstractControl>();\r\n const countryControl = this.formAddress.get('country');\r\n const defaultControl = this.formAddress.get('default');\r\n const localityControl = this.formAddress.get('locality');\r\n const postalCodeControl = this.formAddress.get('postalCode');\r\n const stateControl = this.formAddress.get('state');\r\n const streetAddressControl = this.formAddress.get('streetAddress');\r\n if (countryControl) {\r\n controls.push(countryControl);\r\n }\r\n if (defaultControl) {\r\n controls.push(defaultControl);\r\n }\r\n if (localityControl) {\r\n controls.push(localityControl);\r\n }\r\n if (postalCodeControl) {\r\n controls.push(postalCodeControl);\r\n }\r\n if (stateControl) {\r\n controls.push(stateControl);\r\n }\r\n if (streetAddressControl) {\r\n controls.push(streetAddressControl);\r\n }\r\n return controls;\r\n }\r\n\r\n private init(): void {\r\n if (this.address) {\r\n this.formAddress.setValue({\r\n country: this.address.country,\r\n default: this.address.default,\r\n locality: this.address.locality,\r\n postalCode: this.address.postalCode,\r\n state: this.address.state,\r\n streetAddress: this.address.streetAddress\r\n });\r\n }\r\n }\r\n\r\n ngOnInit(): void {\r\n this.loadingCountries = true;\r\n this.countryService.countriesByRegion('oceania', ['fr'])\r\n .pipe(takeUntil(this.destroy))\r\n .subscribe(\r\n (result: Array<Dictionary<string>>) => {\r\n this.countries = result.sort(\r\n (a: Dictionary<string>, b: Dictionary<string>) => a.fr.localeCompare(b.fr, 'fr', { ignorePunctuation: true })\r\n );\r\n this.formAddress.controls['country'].enable();\r\n this.loadingCountries = false;\r\n },\r\n () => this.loadingCountries = false\r\n );\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroy.next(true);\r\n }\r\n\r\n cancel(): void {\r\n this.init();\r\n this.getControls().forEach((a: AbstractControl) => a.markAsPristine());\r\n this.canceled.emit(this.address);\r\n }\r\n\r\n submit(): void {\r\n if (this.formAddress.valid) {\r\n const address = <Address>{ ...this.address };\r\n const countryControl = this.formAddress.get('country');\r\n const defaultControl = this.formAddress.get('default');\r\n const localityControl = this.formAddress.get('locality');\r\n const postalCodeControl = this.formAddress.get('postalCode');\r\n const stateControl = this.formAddress.get('state');\r\n const streetAddressControl = this.formAddress.get('streetAddress');\r\n if (countryControl) {\r\n address.country = countryControl.value;\r\n }\r\n if (defaultControl) {\r\n address.default = defaultControl.value;\r\n }\r\n if (localityControl) {\r\n address.locality = localityControl.value;\r\n }\r\n if (postalCodeControl) {\r\n address.postalCode = postalCodeControl.value;\r\n }\r\n if (stateControl) {\r\n address.state = stateControl.value;\r\n }\r\n if (streetAddressControl) {\r\n address.streetAddress = streetAddressControl.value;\r\n }\r\n this.submitted.emit(address);\r\n }\r\n }\r\n}\r\n","<form [formGroup]=\"formAddress\" cdkTrapFocus>\r\n <div class=\"address-form-content\">\r\n <div class=\"address-form-fields\">\r\n <mat-form-field appearance=\"outline\" [color]=\"'primary'\">\r\n <mat-label><span i18n=\"street address text|Nom de rue@@streetAddressText\">Nom de rue</span></mat-label>\r\n <input\r\n #addressElement\r\n matInput\r\n cdkFocusInitial\r\n required\r\n id=\"adressAutoComplete\"\r\n placeholder=\"Cherchez un nom de rue\"\r\n formControlName=\"streetAddress\"\r\n maxlength=\"50\">\r\n <mat-error *ngIf=\"formAddress?.get('streetAddress')?.hasError('required')\">\r\n <span i18n=\"required street address|Une adresse est obligatoire@@requiredStreetAddress\">Une adresse est obligatoire</span>\r\n </mat-error>\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" [color]=\"'primary'\">\r\n <mat-label><span i18n=\"postal code text|Code postal@@postalCodeText\">Code postal</span></mat-label>\r\n <input\r\n #postalCode\r\n matInput\r\n required\r\n placeholder=\"Saisissez un code postal\"\r\n formControlName=\"postalCode\"\r\n maxlength=\"5\">\r\n <mat-hint align=\"end\">{{ postalCode.value?.length || 0 }}<span i18n=\"postal code max length|/5@@postalCodeMaxLength\">/5</span></mat-hint>\r\n <mat-error *ngIf=\"formAddress?.get('postalCode')?.hasError('required')\">\r\n <span i18n=\"required postal code|Un code postal est obligatoire@@requiredPostalCode\">Un code postal est obligatoire</span>\r\n </mat-error>\r\n <mat-error *ngIf=\"formAddress?.get('postalCode')?.hasError('pattern')\">\r\n <span i18n=\"invalid postal code|Le code postal n'est pas valide@@invalidPostalCode\">Le code postal n'est pas valide</span>\r\n </mat-error>\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" [color]=\"'primary'\">\r\n <mat-label><span i18n=\"locality text|Ville@@localityText\">Ville</span></mat-label>\r\n <input\r\n matInput\r\n required\r\n placeholder=\"Saisissez une ville\"\r\n formControlName=\"locality\"\r\n maxlength=\"30\">\r\n <mat-error *ngIf=\"formAddress?.get('locality')?.hasError('required')\">\r\n <span i18n=\"required locality|Une ville est obligatoire@@requiredLocality\">Une ville est obligatoire</span>\r\n </mat-error>\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" [color]=\"'primary'\">\r\n <mat-label><span i18n=\"state text|Région@@stateText\">Région</span></mat-label>\r\n <input\r\n matInput\r\n placeholder=\"Saisissez une région\"\r\n formControlName=\"state\"\r\n maxlength=\"30\">\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" [color]=\"'primary'\">\r\n <mat-label><span i18n=\"country text|Pays@@countryText\">Pays</span></mat-label>\r\n <mat-select\r\n required\r\n placeholder=\"Choisissez un pays\"\r\n formControlName=\"country\">\r\n <mat-option *ngFor=\"let country of countries\" [value]=\"country.fr\">\r\n <span>{{ country.fr }}</span>\r\n </mat-option>\r\n </mat-select>\r\n <mat-spinner matSuffix *ngIf=\"loadingCountries\" mode=\"indeterminate\" diameter=\"17\"></mat-spinner>\r\n <mat-error *ngIf=\"formAddress?.get('country')?.hasError('required')\">\r\n <span i18n=\"required country|Un pays est obligatoire@@requiredCountry\">Un pays est obligatoire</span>\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n</form>\r\n","import { Component, OnInit, OnDestroy } from '@angular/core';\r\n// import { Component, Input, Output, EventEmitter, Renderer2, OnInit, OnDestroy } from '@angular/core';\r\n// import { MatDialog } from '@angular/material/dialog';\r\n// import { MatSnackBar } from '@angular/material/snack-bar';\r\n// import { Address, AddressForm, User, Claim } from '@xit/dto';\r\n// import { UserService } from '@xit/identity';\r\n// import { Subject } from 'rxjs/Subject';\r\n// import { first } from 'rxjs/operators/first';\r\n// import { switchMap } from 'rxjs/operators/switchMap';\r\n// import { takeUntil } from 'rxjs/operators';\r\n\r\n// import { AddressFormComponent } from './address-form/address-form.component';\r\n// import { AddressRemoveComponent } from './address-remove/address-remove.component';\r\n// import { ErrorComponent } from '../shared/error/error.component';\r\n// import { LocationService } from '../location/location.service';\r\n\r\n@Component({\r\n selector: 'xit-address',\r\n templateUrl: './address.component.html',\r\n styleUrls: ['./address.component.scss']\r\n})\r\nexport class AddressComponent implements OnInit, OnDestroy {\r\n// private _canAdd: boolean;\r\n// private _canEdit: boolean;\r\n// private _canRemove: boolean;\r\n// private _user: User;\r\n// private destroy: Subject<boolean>;\r\n// address: Address;\r\n\r\n// @Input('canAdd')\r\n// get canAdd(): boolean {\r\n// return this.user && ((this._canAdd === undefined || this._canAdd === null) ? true : this._canAdd);\r\n// }\r\n// set canAdd(value: boolean) {\r\n// this._canAdd = value;\r\n// }\r\n\r\n// @Input('canEdit')\r\n// get canEdit(): boolean {\r\n// return (this._canEdit === undefined || this._canEdit === null) ? true : this._canEdit;\r\n// }\r\n// set canEdit(value: boolean) {\r\n// this._canEdit = value;\r\n// }\r\n\r\n// @Input('canRemove')\r\n// get canRemove(): boolean {\r\n// return (this._canRemove === undefined || this._canRemove === null) ? true : this._canRemove;\r\n// }\r\n// set canRemove(value: boolean) {\r\n// this._canRemove = value;\r\n// }\r\n\r\n// @Input()\r\n// color: string;\r\n\r\n// @Input('user')\r\n// get user(): User {\r\n// return this._user;\r\n// }\r\n// set user(user: User) {\r\n// this._user = user;\r\n// if (this._user && this._user.address) {\r\n// if (!(this._user.address instanceof Array)) {\r\n// this._user.address = [this._user.address as Address];\r\n// }\r\n// if (!this.address && this._user.address.length > 0) {\r\n// const index = this._user.address.findIndex(a => a.default);\r\n// this.address = this._user.address[(index === -1) ? 0 : index];\r\n// this.change.emit(this.address);\r\n// }\r\n// }\r\n// }\r\n\r\n// @Output()\r\n// add: EventEmitter<boolean>;\r\n\r\n// @Output()\r\n// change: EventEmitter<Address>;\r\n\r\n// @Output()\r\n// remove: EventEmitter<boolean>;\r\n\r\n// @Output()\r\n// update: EventEmitter<boolean>;\r\n\r\n// constructor(\r\n// private dialog: MatDialog,\r\n// private snackBar: MatSnackBar,\r\n// private renderer: Renderer2,\r\n// private locationService: LocationService,\r\n// private userService: UserService\r\n// ) {\r\n// this.destroy = new Subject<boolean>();\r\n// this.add = new EventEmitter<boolean>();\r\n// this.change = new EventEmitter<Address>();\r\n// this.update = new EventEmitter<boolean>();\r\n// this.remove = new EventEmitter<boolean>();\r\n// }\r\n\r\n ngOnInit(): void {\r\n // this.locationService.addOpenStreetMapTags(this.renderer);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n // this.destroy.next(true);\r\n // this.locationService.removeOpenStreetMapTags(this.renderer);\r\n }\r\n\r\n// addAddress(): void {\r\n// if (this.canAdd) {\r\n// const dialogRef = this.dialog.open(AddressFormComponent, {\r\n// minWidth: 320,\r\n// data: {\r\n// address: {} as Address,\r\n// color: this.color,\r\n// title: 'Ajoutez une adresse',\r\n// dirty: false\r\n// } as AddressForm\r\n// });\r\n// dialogRef.afterClosed()\r\n// .pipe(takeUntil(this.destroy))\r\n// .subscribe((result: AddressForm) => {\r\n// if (this.canAdd && result && result.dirty && result.address) {\r\n// const claims = new Array<Claim>();\r\n// // Si l'adresse devient celle par défaut, on passe les autres à l'état 'false'\r\n// if (result.address.default && this.user.address && this.user.address instanceof Array) {\r\n// this.user.address.forEach((a: Address) => a.default = false);\r\n// }\r\n// // Transforme l'adresse en donnée utilisateur\r\n// claims.push({\r\n// type: 'address',\r\n// value: JSON.stringify(result.address),\r\n// valueType: 'json'\r\n// } as Claim);\r\n// // Ajoute l'adresse aux données de l'utilisateur\r\n// this.userService.addClaims(this.user.sub, claims)\r\n// .pipe(\r\n// first(),\r\n// switchMap((u: any) => this.userService.getUserData(u.id))\r\n// )\r\n// .subscribe(\r\n// (u: User) => {\r\n// this.add.emit(true);\r\n// this.user = u;\r\n// if (u && u.address && u.address instanceof Array) {\r\n// const index = u.address.findIndex((a: Address) => a.streetAddress === result.address.streetAddress);\r\n// if (index !== -1) {\r\n// this.address = u.address[index];\r\n// this.change.emit(this.address);\r\n// }\r\n// this.snackBar.open(`L'adresse [${this.address.streetAddress}] a été ajoutée`);\r\n// }\r\n// },\r\n// (response: any) => {\r\n// this.add.emit(false);\r\n// this.snackBar.openFromComponent(ErrorComponent, {\r\n// duration: 0,\r\n// data: (response.error) ? response.error.Message : response.message\r\n// });\r\n// }\r\n// );\r\n// }\r\n// });\r\n// }\r\n// }\r\n\r\n// addressChange(value: Address): void {\r\n// this.address = value;\r\n// this.change.emit(this.address);\r\n// }\r\n\r\n// editAddress(): void {\r\n// if (this.canEdit) {\r\n// const dialogRef = this.dialog.open(AddressFormComponent, {\r\n// minWidth: 320,\r\n// data: {\r\n// address: { ...this.address },\r\n// color: this.color,\r\n// title: 'Modifiez une adresse',\r\n// dirty: false\r\n// } as AddressForm\r\n// });\r\n// dialogRef.afterClosed()\r\n// .pipe(takeUntil(this.destroy))\r\n// .subscribe((result: AddressForm) => {\r\n// if (this.canEdit && result && result.dirty && result.address && this.user.address instanceof Array) {\r\n// const claims = new Array<Claim>();\r\n// // Si l'adresse devient celle par défaut, on passe les autres à l'état 'false'\r\n// if (result.address.default) {\r\n// this.user.address.forEach((a: Address) => a.default = false);\r\n// }\r\n// // Remplace l'adresse par celle modifiée\r\n// this.user.address.splice(\r\n// this.user.address.findIndex((a: Address) => this.address.streetAddress === a.streetAddress)\r\n// , 1\r\n// , result.address\r\n// );\r\n// // Transforme les adresses en objets de type Claim\r\n// for (const address of this.user.address) {\r\n// claims.push({\r\n// type: 'address',\r\n// value: JSON.stringify(address),\r\n// valueType: 'json'\r\n// } as Claim);\r\n// }\r\n// // Les adresses n'ont pas d'identifiants et les Claim sont immuables\r\n// // donc toutes les adresses seront supprimées puis recrées\r\n// this.userService.updateClaims(this.user.sub, claims)\r\n// .pipe(\r\n// first(),\r\n// switchMap((u: any) => this.userService.getUserData(u.id))\r\n// )\r\n// .subscribe(\r\n// (u: User) => {\r\n// this.update.emit(true);\r\n// this.user = u;\r\n// if (u && u.address && u.address instanceof Array) {\r\n// const index = u.address.findIndex((a: Address) => a.streetAddress === result.address.streetAddress);\r\n// if (index !== -1) {\r\n// this.address = u.address[index];\r\n// this.change.emit(this.address);\r\n// }\r\n// this.snackBar.open(`L'adresse [${this.address.streetAddress}] a été modifiée`);\r\n// }\r\n// },\r\n// (response: any) => {\r\n// this.update.emit(false);\r\n// this.snackBar.openFromComponent(ErrorComponent, {\r\n// duration: 0,\r\n// data: (response.error) ? response.error.Message : response.message\r\n// });\r\n// }\r\n// );\r\n// }\r\n// });\r\n// }\r\n// }\r\n\r\n// removeAddress(): void {\r\n// if (this.canRemove) {\r\n// const dialogRef = this.dialog.open(AddressRemoveComponent, {\r\n// minWidth: 320,\r\n// data: {\r\n// address: { ...this.address },\r\n// color: this.color,\r\n// confirm: false\r\n// }\r\n// });\r\n// dialogRef.afterClosed()\r\n// .pipe(takeUntil(this.destroy))\r\n// .subscribe((result: any) => {\r\n// if (this.canRemove && result && result.confirm) {\r\n// this.userService.removeClaims(this.user.sub, [{\r\n// type: 'address',\r\n// value: JSON.stringify(result.address),\r\n// valueType: 'json'\r\n// } as Claim])\r\n// .pipe(\r\n// first(),\r\n// switchMap((u: any) => this.userService.getUserData(u.id))\r\n// )\r\n// .subscribe(\r\n// (u: User) => {\r\n// this.remove.emit(true);\r\n// this.user = u;\r\n// if (u && u.address && u.address instanceof Array && u.address.length > 0) {\r\n// const index = u.address.findIndex(a => a.default);\r\n// this.address = u.address[(index === -1) ? 0 : index];\r\n// this.change.emit(this.address);\r\n// }\r\n// this.snackBar.open(`L'adresse [${result.address.streetAddress}] a été supprimée`);\r\n// },\r\n// (response: any) => {\r\n// this.remove.emit(false);\r\n// this.snackBar.openFromComponent(ErrorComponent, {\r\n// duration: 0,\r\n// data: (response.error) ? response.error.Message : response.message\r\n// });\r\n// }\r\n// );\r\n// }\r\n// });\r\n// }\r\n// }\r\n\r\n// trackByIndex(index: number, address: Address) {\r\n// return index;\r\n// }\r\n}\r\n","<!-- <div class=\"address-content\">\r\n <h3 i18n=\"address selection title|Sélectionnez une adresse@@addressSelectionTitle\">Sélectionnez une adresse</h3>\r\n <div *ngIf=\"user?.address\">\r\n <mat-form-field appearance=\"standard\" [color]=\"color || 'primary'\">\r\n <mat-label><span i18n=\"address book text|Votre carnet d'adresse@@addressBookText\">Votre carnet d'adresse</span></mat-label>\r\n <mat-select placeholder=\"Choisissez une adresse\" [ngModel]=\"address\" (ngModelChange)=\"addressChange($event)\">\r\n <mat-option *ngFor=\"let a of user?.address; trackBy: trackByIndex;\" [value]=\"a\">\r\n <span>{{ a?.streetAddress }}</span>\r\n <span i18n=\"default address|Adresse par défaut@@defaultAddress\" *ngIf=\"a?.default\"> (défaut)</span>\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n <h3 i18n=\"detail address|Adresse complète@@detailAddress\">Adresse complète</h3>\r\n <div *ngIf=\"!address\">\r\n <span i18n=\"empty address|Aucune adresse@@emptyAddress\">Aucune adresse sélectionnée</span>\r\n </div>\r\n <div *ngIf=\"address\">\r\n <div class=\"mat-body-2\">{{ address?.streetAddress }}</div>\r\n <div class=\"mat-body-1\">\r\n <span>{{ address?.postalCode }}</span>\r\n <span i18n=\"address separator|Séparateur d'adresse@@addressSeparator\">, </span>\r\n <span>{{ address?.locality }}</span>\r\n </div>\r\n <div class=\"mat-body-1\" *ngIf=\"address?.state\">{{ address?.state }}</div>\r\n <div class=\"mat-body-1\">{{ address?.country }}</div>\r\n </div>\r\n </div>\r\n <div class=\"empty-address-book\" *ngIf=\"!user?.address\">\r\n <span i18n=\"empty address book|Votre carnet d'adresse est vide@@emptyAddressBook\">Votre carnet d'adresse est vide</span>\r\n </div>\r\n</div>\r\n<div class=\"address-actions\" *ngIf=\"canAdd || canEdit || canRemove\">\r\n <div *ngIf=\"address\">\r\n <button mat-icon-button type=\"button\" (click)=\"removeAddress()\" *ngIf=\"canRemove\">\r\n <fa-icon [icon]=\"['fas', 'trash']\" size=\"lg\"></fa-icon>\r\n </button>\r\n <button mat-icon-button type=\"button\" (click)=\"editAddress()\" *ngIf=\"canEdit\">\r\n <fa-icon [icon]=\"['fas', 'pen']\" size=\"lg\"></fa-icon>\r\n </button>\r\n </div>\r\n <button mat-icon-button type=\"button\" (click)=\"addAddress()\" *ngIf=\"canAdd\">\r\n <fa-icon [icon]=\"['fas', 'plus']\" size=\"lg\"></fa-icon>\r\n </button>\r\n</div> -->\r\n","import { Component, HostBinding, Input, OnInit } from '@angular/core';\r\nimport { Router, ActivatedRoute, NavigationEnd, Event } from '@angular/router';\r\nimport { FaIconLibrary } from '@fortawesome/angular-fontawesome';\r\nimport { faAngleRight } from '@fortawesome/pro-duotone-svg-icons';\r\nimport { Breadcrumb } from '@xit/dto';\r\nimport { filter } from 'rxjs/operators';\r\n\r\nexport const ROUTE_DATA_BREADCRUMB = 'breadcrumb';\r\n\r\n@Component({\r\n selector: 'xit-breadcrumb',\r\n templateUrl: './breadcrumb.component.html',\r\n styleUrls: ['./breadcrumb.component.scss']\r\n})\r\nexport class BreadcrumbComponent implements OnInit {\r\n private _homeLabel: string;\r\n private _useParams: boolean;\r\n breadcrumbs: Array<Breadcrumb>;\r\n\r\n @HostBinding('class.xit-breadcrumb')\r\n get class() {\r\n return true;\r\n }\r\n\r\n @Input()\r\n get homeLabel() {\r\n return this._homeLabel || 'Accueil';\r\n }\r\n set homeLabel(value: string) {\r\n this._homeLabel = value;\r\n }\r\n\r\n @Input()\r\n get useParams() {\r\n return this._useParams || false;\r\n }\r\n set useParams(value: boolean) {\r\n this._useParams = value;\r\n }\r\n\r\n constructor(\r\n private activatedRoute: ActivatedRoute,\r\n private library: FaIconLibrary,\r\n private router: Router\r\n ) {\r\n this.breadcrumbs = new Array<Breadcrumb>();\r\n this.library.addIcons(faAngleRight);\r\n }\r\n\r\n ngOnInit() {\r\n // subscribe to the NavigationEnd event\r\n this.router.events\r\n .pipe(\r\n filter((event: Event) => event instanceof NavigationEnd)\r\n )\r\n .subscribe(() => this.breadcrumbs = this.getBreadcrumbs(this.activatedRoute.root));\r\n }\r\n\r\n trackByIndex(index: number, value: any) {\r\n return index;\r\n }\r\n\r\n private getBreadcrumbs(\r\n route: ActivatedRoute,\r\n url: string = '',\r\n breadcrumbs: Array<Breadcrumb> = new Array<Breadcrumb>()\r\n ): Array<Breadcrumb> {\r\n // get the child routes\r\n const children = route.children;\r\n // return if there are no more children\r\n if (children.length === 0) {\r\n return breadcrumbs;\r\n }\r\n // iterate over each children\r\n for (const child of children) {\r\n // verify the custom data property 'breadcrumb' is specified on the route\r\n if (!child.snapshot.data.hasOwnProperty(ROUTE_DATA_BREADCRUMB)) {\r\n return this.getBreadcrumbs(child, url, breadcrumbs);\r\n }\r\n // get the route's URL segment\r\n const routeURL = child.snapshot\r\n .pathFromRoot\r\n .map(v => v.url.map(segment => segment.toString()).join('/'))\r\n .join('/');\r\n // append route URL to URL\r\n // url += `/${routeURL}`;\r\n // add breadcrumb\r\n const breadcrumb: Breadcrumb = {\r\n label: child.snapshot.data[ROUTE_DATA_BREADCRUMB],\r\n params: child.snapshot.params,\r\n url: routeURL\r\n };\r\n if (breadcrumbs.findIndex((b: Breadcrumb) => b.label === breadcrumb.label) === -1) {\r\n breadcrumbs.push(breadcrumb);\r\n }\r\n // recursive\r\n return this.getBreadcrumbs(child, url, breadcrumbs);\r\n }\r\n }\r\n}\r\n","<ol>\r\n <li><a routerLink=\"\">{{ homeLabel }}</a></li>\r\n <li *ngFor=\"let breadcrumb of breadcrumbs; trackBy: trackByIndex;\">\r\n <fa-duotone-icon [icon]=\"['fad', 'angle-right']\"></fa-duotone-icon>\r\n <a [routerLink]=\"[breadcrumb.url]\" [queryParams]=\"((useParams) ? breadcrumb.params : null)\">{{ breadcrumb.label }}</a>\r\n </li>\r\n</ol>\r\n","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { FileInfo } from '@xit/dto';\r\nimport { Observable } from 'rxjs';\r\nimport { catchError, first, map, tap } from 'rxjs/operators';\r\n\r\nimport { ErrorService } from '../error/error.service';\r\nimport { LogService } from '../log/log.service';\r\nimport { UTILITY_CONFIG, UtilityConfig } from '../utility-config';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class FileService {\r\n private fileUrl: string;\r\n\r\n constructor(\r\n @Inject(UTILITY_CONFIG) private config: UtilityConfig,\r\n private http: HttpClient,\r\n private errorService: ErrorService,\r\n private logService: LogService\r\n ) {\r\n // tslint:disable-next-line:max-line-length\r\n this.fileUrl = `${this.config.url}/${this.config.version}/${this.config.services.files}`;\r\n }\r\n\r\n getById(id: string): Observable<FileInfo> {\r\n const operation = 'File service (getById)';\r\n return this.http.get<FileInfo>(`${this.fileUrl}/${id}`)\r\n .pipe(\r\n map((response: any) => ({\r\n data: response.body,\r\n height: response.headers.get('xit-file-height'),\r\n name: response.headers.get('xit-file-name'),\r\n width: response.headers.get('xit-file-width')\r\n } as FileInfo)),\r\n tap((result: FileInfo) => this.logService.log(operation, result)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n\r\n getFileInfo(id: string): Observable<FileInfo> {\r\n const operation = 'File service (getFileInfo)';\r\n return this.http\r\n .get(`${this.fileUrl}/${id}/infos`)\r\n .pipe(\r\n tap((result: FileInfo) => this.logService.log(operation, result)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n\r\n download(id: string, startCallback?: () => void, endCallback?: () => void): void {\r\n const operation = 'File service (download)';\r\n if (startCallback) {\r\n startCallback();\r\n }\r\n this.http\r\n .get(`${this.fileUrl}/${id}/download`, {\r\n observe: 'response',\r\n responseType: 'blob' as 'blob'\r\n })\r\n .pipe(\r\n first(),\r\n tap((data: any) => this.logService.log(operation, data)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n )\r\n .subscribe((response: any) => {\r\n if (endCallback) {\r\n endCallback();\r\n }\r\n const url = window.URL.createObjectURL(response.body);\r\n const a = document.createElement('a');\r\n a.setAttribute('style', 'display: none');\r\n a.href = url;\r\n a.download = response.headers.get('xit-file-name');\r\n document.body.appendChild(a);\r\n a.click();\r\n window.URL.revokeObjectURL(url);\r\n a.remove();\r\n });\r\n }\r\n\r\n rename(id: string, name: string): Observable<FileInfo> {\r\n const operation = 'File service (rename)';\r\n return this.http\r\n .put(`${this.fileUrl}/${id}/rename`, JSON.stringify(name))\r\n .pipe(\r\n first(),\r\n tap((data: FileInfo) => this.logService.log(operation, data)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n\r\n resize(id: string, q?: number, w?: number, h?: number, s?: string): Observable<FileInfo> {\r\n const operation = 'File service (resize)';\r\n const params = new Array<string>();\r\n if (q) {\r\n params.push(`q=${q}`);\r\n }\r\n if (w) {\r\n params.push(`w=${w}`);\r\n }\r\n if (h) {\r\n params.push(`h=${h}`);\r\n }\r\n if (s) {\r\n params.push(`s=${s}`);\r\n }\r\n return this.http\r\n .get(`${this.fileUrl}/${id}/resize${(params.length > 0) ? '?'.concat(params.join('&')) : ''}`, {\r\n observe: 'response',\r\n responseType: 'blob' as 'blob'\r\n })\r\n .pipe(\r\n map((response: any) => ({\r\n data: response.body,\r\n height: response.headers.get('xit-file-height'),\r\n name: response.headers.get('xit-file-name'),\r\n width: response.headers.get('xit-file-width')\r\n } as FileInfo)),\r\n tap((data: FileInfo) => this.logService.log(operation, data)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n\r\n crop(id: string, q?: number, x?: number, y?: number, w?: number, h?: number, s?: string): Observable<FileInfo> {\r\n const operation = 'File service (crop)';\r\n const params = new Array<string>();\r\n if (q) {\r\n params.push(`q=${q}`);\r\n }\r\n if (x) {\r\n params.push(`x=${x}`);\r\n }\r\n if (y) {\r\n params.push(`y=${y}`);\r\n }\r\n if (w) {\r\n params.push(`w=${w}`);\r\n }\r\n if (h) {\r\n params.push(`h=${h}`);\r\n }\r\n if (s) {\r\n params.push(`s=${s}`);\r\n }\r\n return this.http\r\n .get(`${this.fileUrl}/${id}/crop${(params.length > 0) ? '?'.concat(params.join('&')) : ''}`, {\r\n observe: 'response',\r\n responseType: 'blob' as 'blob'\r\n })\r\n .pipe(\r\n map((response: any) => ({\r\n data: response.body,\r\n height: response.headers.get('xit-file-height'),\r\n name: response.headers.get('xit-file-name'),\r\n width: response.headers.get('xit-file-width')\r\n } as FileInfo)),\r\n tap((data: FileInfo) => this.logService.log(operation, data)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n\r\n resizeAndCrop(id: string, q?: number, x?: number, y?: number, w?: number, h?: number, s?: string): Observable<FileInfo> {\r\n const operation = 'File service (resizeAndCrop)';\r\n const params = new Array<string>();\r\n if (q) {\r\n params.push(`q=${q}`);\r\n }\r\n if (x) {\r\n params.push(`x=${x}`);\r\n }\r\n if (y) {\r\n params.push(`y=${y}`);\r\n }\r\n if (w) {\r\n params.push(`w=${w}`);\r\n }\r\n if (h) {\r\n params.push(`h=${h}`);\r\n }\r\n if (s) {\r\n params.push(`s=${s}`);\r\n }\r\n return this.http\r\n .get(`${this.fileUrl}/${id}/resizeandcrop${(params.length > 0) ? '?'.concat(params.join('&')) : ''}`, {\r\n observe: 'response',\r\n responseType: 'blob' as 'blob'\r\n })\r\n .pipe(\r\n map((response: any) => ({\r\n data: response.body,\r\n height: response.headers.get('xit-file-height'),\r\n name: response.headers.get('xit-file-name'),\r\n width: response.headers.get('xit-file-width')\r\n } as FileInfo)),\r\n tap((data: FileInfo) => this.logService.log(operation, data)),\r\n catchError(this.errorService.handleError<FileInfo>(operation))\r\n );\r\n }\r\n}\r\n","import {\r\n Directive,\r\n Input,\r\n Output,\r\n EventEmitter,\r\n ElementRef,\r\n HostBinding,\r\n OnInit,\r\n OnDestroy\r\n} from '@angular/core';\r\nimport { MediaObserver } from '@angular/flex-layout';\r\nimport { FileInfo } from '@xit/dto';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\nimport { FileService } from '../file.service';\r\n\r\nexport type PhotoType = 'resize' | 'crop';\r\n\r\n@Directive({\r\n selector: 'canvas[xit-canvas], canvas[xitCanvas]',\r\n exportAs: 'xitCanvas'\r\n})\r\nexport class CanvasDirective implements OnInit, OnDestroy {\r\n private _fileId: string;\r\n private destroy: Subject<boolean>;\r\n private file: FileInfo | null;\r\n private loaded: boolean;\r\n\r\n @HostBinding('class.xit-canvas')\r\n hostClass: boolean = true;\r\n\r\n @Input('fileId')\r\n get fileId() {\r\n return this._fileId;\r\n }\r\n set fileId(value: string) {\r\n if (this._fileId !== value) {\r\n this._fileId = value;\r\n if (value) {\r\n this.loadFile();\r\n }\r\n }\r\n }\r\n\r\n @Input()\r\n original: boolean;\r\n\r\n @Input()\r\n type: PhotoType;\r\n\r\n @Output()\r\n change: EventEmitter<FileInfo>;\r\n\r\n @Output()\r\n loading: EventEmitter<boolean>;\r\n\r\n constructor(\r\n private mediaObserver: MediaObserver,\r\n private elementRef: ElementRef,\r\n private fileService: FileService\r\n ) {\r\n // elementRef.nativeElement.classList.add('xit-canvas');\r\n this.change = new EventEmitter<FileInfo>();\r\n this.destroy = new Subject<boolean>();\r\n this.loaded = false;\r\n this.loading = new EventEmitter<boolean>();\r\n }\r\n\r\n ngOnInit(): void {\r\n this.mediaObserver.media$\r\n .pipe(takeUntil(this.destroy))\r\n .subscribe(() => {\r\n if (this.loaded && this.fileId) {\r\n this.loadFile();\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroy.next(true);\r\n }\r\n\r\n private loadFile(): void {\r\n // Le settimeout permet au DOM de se créer avant de dessiner le canvas (pour le redimensionnement)\r\n setTimeout(() => {\r\n // const canvas = this.elementRef.nativeElement as HTMLCanvasElement;\r\n const service = (this.type === 'crop')\r\n ? this.fileService.resizeAndCrop\r\n (\r\n this.fileId,\r\n this.original ? undefined : 95,\r\n 0,\r\n 0,\r\n this.original ? undefined : this.elementRef.nativeElement.clientWidth,\r\n this.original ? undefined : this.elementRef.nativeElement.clientHeight,\r\n this.original ? `${window.innerWidth}x${window.innerHeight}` : undefined\r\n )\r\n : this.fileService.resize\r\n (\r\n