chore(deps): upgrade Angular 19 → 20

- ng update @angular/core@20 @angular/cli@20 @angular/material@20 @angular-eslint@20 @angular/google-maps@20
- Remove ng-chartist (abandoned, incompatible with Angular 20): replace <x-chartist> with <app-bars-chart> in dropzones-bar and jumps-by-month
- Migrate all constructor injection to inject() function (ng generate @angular/core:inject, 67 files)
- TypeScript 5.5 → 5.9.3
- DOCUMENT import moved from @angular/common to @angular/core (automatic migration)
- tsconfig moduleResolution updated to "bundler"
This commit is contained in:
2026-04-26 06:40:13 +02:00
parent 5400294d45
commit be5f5775ef
78 changed files with 5080 additions and 3886 deletions
+2 -4
View File
@@ -1,13 +1,11 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class ApiService {
constructor(
private http: HttpClient
) { }
private http = inject(HttpClient);
/*private formatErrors(error: any) {
return throwError(error.error);
+20 -20
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
@@ -8,10 +8,9 @@ import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class ApplicationsService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
query(config: ApplicationListConfig): Observable<ApplicationList> {
// Convert any filters over to Angular's URLSearchParams
@@ -19,36 +18,37 @@ export class ApplicationsService {
apikey: config.filters.apikey,
author: config.filters.author,
limit: config.filters.limit,
offset: config.filters.offset
offset: config.filters.offset,
};
return this.apiService
.get(
`${this._apiDomain}/applications` + ((config.type === 'feed') ? '/feed' : ''),
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this.apiService.get(
`${this._apiDomain}/applications` + (config.type === 'feed' ? '/feed' : ''),
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(slug: string): Observable<Application> {
return this.apiService.get(`${this._apiDomain}/applications/${slug}`)
.pipe(map(data => data.application));
return this.apiService.get(`${this._apiDomain}/applications/${slug}`).pipe(map((data) => data.application));
}
destroy(slug: string): Observable<boolean> {
return this.apiService.delete(`${this._apiDomain}/applications/${slug}`).pipe(map(data => data.deleted));
return this.apiService.delete(`${this._apiDomain}/applications/${slug}`).pipe(map((data) => data.deleted));
}
save(application: Application): Observable<Application> {
if (application.slug) {
// If we're updating an existing application
return this.apiService.put(`${this._apiDomain}/applications/${application.slug}`, { application: application })
.pipe(map(data => data.application));
return this.apiService
.put(`${this._apiDomain}/applications/${application.slug}`, { application: application })
.pipe(map((data) => data.application));
} else {
// Otherwise, create a new application
return this.apiService.post(`${this._apiDomain}/applications/`, { application: application })
.pipe(map(data => data.application));
return this.apiService
.post(`${this._apiDomain}/applications/`, { application: application })
.pipe(map((data) => data.application));
}
}
}
+27 -22
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -8,22 +8,22 @@ import { Article, ArticleList, ArticleListConfig, ArticleListFilters, ArticlePag
@Injectable({ providedIn: 'root' })
export class ArticlesService {
private apiService = inject(ApiService);
private _apiDomain = '/cms';
constructor(
private apiService: ApiService
) { }
query(config: ArticleListConfig): Observable<ArticleList> {
// Convert any filters over to Angular's URLSearchParams
const params: ArticleListFilters = {} as ArticleListFilters;
Object.assign(params, config.filters);
return this.apiService
.get(
`${this._apiDomain}/articles` + ((config.type === 'feed') ? '/feed' : ''),
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this.apiService.get(
`${this._apiDomain}/articles` + (config.type === 'feed' ? '/feed' : ''),
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(slug: string): Observable<ArticlePageData> {
@@ -34,33 +34,39 @@ export class ArticlesService {
}));*/
return this.apiService.get(`${this._apiDomain}/articles/${slug}`);
}
getAll(): Observable<Array<Article>> {
return this.apiService.get(`${this._apiDomain}/articles`).pipe(map(data => data.articles));
return this.apiService.get(`${this._apiDomain}/articles`).pipe(map((data) => data.articles));
}
create(article: Article): Observable<Article> {
return this.apiService.post(`${this._apiDomain}/articles/`, { article: article }).pipe(map(data => data.article));
return this.apiService
.post(`${this._apiDomain}/articles/`, { article: article })
.pipe(map((data) => data.article));
}
update(article: Article): Observable<Article> {
return this.apiService.put(`${this._apiDomain}/articles/${article.slug}`, { article: article }).pipe(map(data => data.article));
return this.apiService
.put(`${this._apiDomain}/articles/${article.slug}`, { article: article })
.pipe(map((data) => data.article));
}
destroy(slug: string): Observable<boolean> {
return this.apiService.delete(`${this._apiDomain}/articles/${slug}`).pipe(map(data => data.deleted));
return this.apiService.delete(`${this._apiDomain}/articles/${slug}`).pipe(map((data) => data.deleted));
}
save(article: Article): Observable<Article> {
// If we're updating an existing article
if (article.slug) {
return this.apiService.put(`${this._apiDomain}/articles/${article.slug}`, { article: article })
.pipe(map(data => data.article));
return this.apiService
.put(`${this._apiDomain}/articles/${article.slug}`, { article: article })
.pipe(map((data) => data.article));
// Otherwise, create a new article
} else {
return this.apiService.post(`${this._apiDomain}/articles/`, { article: article })
.pipe(map(data => data.article));
return this.apiService
.post(`${this._apiDomain}/articles/`, { article: article })
.pipe(map((data) => data.article));
}
}
@@ -71,5 +77,4 @@ export class ArticlesService {
unfavorite(slug: string): Observable<Article> {
return this.apiService.delete(`${this._apiDomain}/articles/${slug}/favorite`);
}
}
@@ -1,26 +1,41 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiService } from '../api.service';
import {
HWActivityStat, HWClan, HWClanList, HWClanListConfig,
HWClanListFilters, HWClanPageData, HWGuildClan,
HWMember
HWActivityStat,
HWClan,
HWClanList,
HWClanListConfig,
HWClanListFilters,
HWClanPageData,
HWGuildClan,
HWMember,
} from '@models';
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
@Injectable({ providedIn: 'root' })
export class HWClanService {
private apiService = inject(ApiService);
private _apiDomain = '/herowars';
constructor(
private apiService: ApiService
) { }
private _resetActivity(): HWActivityStat {
const activity: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
const activity: HWActivityStat = {
activity: 0,
prestige: 0,
titanite: 0,
war: 0,
adventure: 0,
gifts: 0,
score: 0,
scoreGifts: 0,
warGifts: 0,
rewards: 0,
};
return activity;
}
@@ -28,13 +43,14 @@ export class HWClanService {
// Convert any filters over to Angular's URLSearchParams
const params: HWClanListFilters = {} as HWClanListFilters;
Object.assign(params, config.filters);
return this.apiService
.get(
`${this._apiDomain}/clans`,
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this.apiService.get(
`${this._apiDomain}/clans`,
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(id: string): Observable<HWClanPageData> {
@@ -42,31 +58,35 @@ export class HWClanService {
}
getAll(): Observable<Array<HWClan>> {
return this.apiService.get(`${this._apiDomain}/clans`).pipe(map(data => data.clans));
return this.apiService.get(`${this._apiDomain}/clans`).pipe(map((data) => data.clans));
}
create(clan: HWClan): Observable<HWClan> {
return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map(data => data.clan));
return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map((data) => data.clan));
}
update(clan: HWClan): Observable<HWClan> {
return this.apiService.put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
return this.apiService
.put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan })
.pipe(map((data) => data.clan));
}
destroy(id: string): Observable<boolean> {
return this.apiService.delete(`${this._apiDomain}/clans/${id}`).pipe(map(data => data.deleted));
return this.apiService.delete(`${this._apiDomain}/clans/${id}`).pipe(map((data) => data.deleted));
}
save(clan: HWClan): Observable<HWClan> {
// If we're updating an existing clan
if (clan.id) {
return this.apiService.put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
return this.apiService
.put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan })
.pipe(map((data) => data.clan));
// Otherwise, create a new clan
} else {
return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map(data => data.clan));
return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map((data) => data.clan));
}
}
loadClan(): HWGuildClan {
const guildClan: HWGuildClan = {} as HWGuildClan;
Object.assign(guildClan, guildData.clan);
@@ -77,7 +97,7 @@ export class HWClanService {
return guildClan;
}
loadClanStats(clan: HWGuildClan, members: HWMember[]): HWGuildClan {
members.map((member: HWMember) => {
clan.sumTotal.adventure += member.adventureSum;
@@ -86,42 +106,42 @@ export class HWClanService {
clan.todayTotal.activity += member.stat.todayActivity;
clan.todayTotal.prestige += member.stat.todayPrestige;
clan.todayTotal.titanite += member.stat.todayDungeonActivity;
clan.todayTotal.score += (member.stat.todayDungeonActivity + member.stat.todayActivity + member.stat.todayPrestige);
clan.todayTotal.score +=
member.stat.todayDungeonActivity + member.stat.todayActivity + member.stat.todayPrestige;
clan.sumTotal.activity += member.stat.activitySum;
clan.sumTotal.prestige += member.stat.prestigeSum;
clan.sumTotal.titanite += member.stat.dungeonActivitySum;
clan.sumTotal.score += member.score;
clan.sumTotal.warGifts += member.warGifts;
});
clan.sumTotal.scoreGifts = (clan.giftsCount - Math.floor(clan.sumTotal.warGifts));
clan.todayAverages.activity = (clan.todayTotal.activity / members.length);
clan.todayAverages.prestige = (clan.todayTotal.prestige / members.length);
clan.todayAverages.titanite = (clan.todayTotal.titanite / members.length);
clan.todayAverages.score = (clan.todayTotal.score / members.length);
clan.sumAverages.activity = (clan.sumTotal.activity / members.length);
clan.sumAverages.prestige = (clan.sumTotal.prestige / members.length);
clan.sumAverages.titanite = (clan.sumTotal.titanite / members.length);
clan.sumTotal.scoreGifts = clan.giftsCount - Math.floor(clan.sumTotal.warGifts);
clan.todayAverages.activity = clan.todayTotal.activity / members.length;
clan.todayAverages.prestige = clan.todayTotal.prestige / members.length;
clan.todayAverages.titanite = clan.todayTotal.titanite / members.length;
clan.todayAverages.score = clan.todayTotal.score / members.length;
clan.sumAverages.activity = clan.sumTotal.activity / members.length;
clan.sumAverages.prestige = clan.sumTotal.prestige / members.length;
clan.sumAverages.titanite = clan.sumTotal.titanite / members.length;
if (clan.league === '3') {
clan.sumAverages.war = (clan.sumTotal.war / 10);
clan.sumAverages.war = clan.sumTotal.war / 10;
} else if (clan.league === '2') {
clan.sumAverages.war = (clan.sumTotal.war / 15);
clan.sumAverages.war = clan.sumTotal.war / 15;
} else if (clan.league === '1') {
clan.sumAverages.war = (clan.sumTotal.war / 20);
clan.sumAverages.war = clan.sumTotal.war / 20;
}
clan.sumAverages.adventure = (clan.sumTotal.adventure / members.length);
clan.sumAverages.gifts = (clan.sumTotal.gifts / members.length);
clan.sumAverages.score = (clan.sumTotal.score / members.length);
clan.sumAverages.scoreGifts = (clan.sumTotal.scoreGifts / members.length);
clan.sumAverages.warGifts = (clan.sumTotal.warGifts / members.length);
clan.sumAverages.adventure = clan.sumTotal.adventure / members.length;
clan.sumAverages.gifts = clan.sumTotal.gifts / members.length;
clan.sumAverages.score = clan.sumTotal.score / members.length;
clan.sumAverages.scoreGifts = clan.sumTotal.scoreGifts / members.length;
clan.sumAverages.warGifts = clan.sumTotal.warGifts / members.length;
members.map((data) => {
data.scoreGifts = ((data.score / clan.sumTotal.score) * clan.sumTotal.scoreGifts);
data.rewards = Math.floor((data.scoreGifts + data.warGifts));
data.scoreGifts = (data.score / clan.sumTotal.score) * clan.sumTotal.scoreGifts;
data.rewards = Math.floor(data.scoreGifts + data.warGifts);
clan.sumTotal.rewards += data.rewards;
return data;
});
clan.sumAverages.rewards = (clan.sumTotal.rewards / members.length);
clan.sumAverages.rewards = clan.sumTotal.rewards / members.length;
return clan;
}
}
@@ -1,36 +1,41 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiService, UtilitiesService } from '@services';
import {
HWGuildClan, HWWeekStat,
HWMember, HWMemberList, HWMemberListConfig,
HWMemberListFilters, HWMemberPageData, HWMemberStat
HWGuildClan,
HWWeekStat,
HWMember,
HWMemberList,
HWMemberListConfig,
HWMemberListFilters,
HWMemberPageData,
HWMemberStat,
} from '@models';
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
@Injectable({ providedIn: 'root' })
export class HWMemberService {
private _apiService = inject(ApiService);
private _utilitiesService = inject(UtilitiesService);
private _apiDomain = '/herowars';
constructor(
private _apiService: ApiService,
private _utilitiesService: UtilitiesService
) { }
query(config: HWMemberListConfig): Observable<HWMemberList> {
// Convert any filters over to Angular's URLSearchParams
const params: HWMemberListFilters = {} as HWMemberListFilters;
Object.assign(params, config.filters);
return this._apiService
.get(
`${this._apiDomain}/members`,
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this._apiService.get(
`${this._apiDomain}/members`,
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(id: string): Observable<HWMemberPageData> {
@@ -38,35 +43,43 @@ export class HWMemberService {
}
getAll(): Observable<Array<HWMember>> {
return this._apiService.get(`${this._apiDomain}/members`).pipe(map(data => data.members));
return this._apiService.get(`${this._apiDomain}/members`).pipe(map((data) => data.members));
}
create(member: HWMember): Observable<HWMember> {
return this._apiService.post(`${this._apiDomain}/members/`, { member: member }).pipe(map(data => data.member));
return this._apiService
.post(`${this._apiDomain}/members/`, { member: member })
.pipe(map((data) => data.member));
}
update(member: HWMember): Observable<HWMember> {
return this._apiService.put(`${this._apiDomain}/members/${member.id}`, { member: member }).pipe(map(data => data.member));
return this._apiService
.put(`${this._apiDomain}/members/${member.id}`, { member: member })
.pipe(map((data) => data.member));
}
destroy(id: string): Observable<boolean> {
return this._apiService.delete(`${this._apiDomain}/members/${id}`).pipe(map(data => data.deleted));
return this._apiService.delete(`${this._apiDomain}/members/${id}`).pipe(map((data) => data.deleted));
}
save(member: HWMember): Observable<HWMember> {
// If we're updating an existing member
if (member.id) {
return this._apiService.put(`${this._apiDomain}/members/${member.id}`, { member: member }).pipe(map(data => data.member));
return this._apiService
.put(`${this._apiDomain}/members/${member.id}`, { member: member })
.pipe(map((data) => data.member));
// Otherwise, create a new member
} else {
return this._apiService.post(`${this._apiDomain}/members/`, { member: member }).pipe(map(data => data.member));
return this._apiService
.post(`${this._apiDomain}/members/`, { member: member })
.pipe(map((data) => data.member));
}
}
loadMembers(clan: HWGuildClan): HWMember[] {
const guildMembers: HWMember[] = [];
const now = new Date();
const oneDayInSec = (24 * 60 * 60);
const oneDayInSec = 24 * 60 * 60;
const daysToKick = parseInt(guildData.clan.daysToKick);
for (const data of Object.entries(guildData.clan.members)) {
const member: HWMember = {} as HWMember;
@@ -76,47 +89,56 @@ export class HWMemberService {
} else {
member.champion = false;
}
member.heroes = { power: 0, teams: []};
member.titans = { power: 0, teams: []};
member.heroes = { power: 0, teams: [] };
member.titans = { power: 0, teams: [] };
guildMembers.push(member);
}
guildMembers.map((data: HWMember) => {
const last = new Date((parseInt(data.lastLoginTime) * 1000));
const exp = new Date(last.getTime() + ((daysToKick * oneDayInSec) * 1000));
const diff = Math.floor(((exp.getTime() - now.getTime()) / 1000));
const daysLeft = Math.floor((diff / oneDayInSec));
const last = new Date(parseInt(data.lastLoginTime) * 1000);
const exp = new Date(last.getTime() + daysToKick * oneDayInSec * 1000);
const diff = Math.floor((exp.getTime() - now.getTime()) / 1000);
const daysLeft = Math.floor(diff / oneDayInSec);
let timeLeft = diff;
if (daysLeft >= 1) {
timeLeft = (diff - (daysLeft * oneDayInSec));
timeLeft = diff - daysLeft * oneDayInSec;
}
data.inactivity = {
daysLeft: daysLeft,
timeLeft: timeLeft,
dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
dropDate: Math.floor((exp.getTime() / 1000))
dropDate: Math.floor(exp.getTime() / 1000),
};
data.raids = [];
data.raidsInfo = {
variationAvg: 0,
variationSum: 0
variationSum: 0,
};
data.stat = {} as HWMemberStat;
let index = guildData.membersStat.findIndex(stat => stat.userId === data.id);
let index = guildData.membersStat.findIndex((stat) => stat.userId === data.id);
if (index !== -1) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
const { userId, ...memberStatWithoutUserId } = guildData.membersStat[index] as any;
Object.assign(data.stat, memberStatWithoutUserId);
}
index = guildStatistics.stat.findIndex(stat => stat.id === data.id);
index = guildStatistics.stat.findIndex((stat) => stat.id === data.id);
if (index !== -1) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
const { id, ...weekStatSource } = guildStatistics.stat[index] as any;
const stat: HWWeekStat = {} as HWWeekStat;
Object.assign(stat, weekStatSource);
data.weekStat = stat;
data.adventureSum = guildStatistics.stat[index].adventureStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
data.adventureSum = guildStatistics.stat[index].adventureStat.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0,
);
data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0,
);
data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0,
);
} else {
data.weekStat = {} as HWWeekStat;
data.adventureSum = 0;
@@ -124,8 +146,8 @@ export class HWMemberService {
data.clanWarSum = 0;
}
data.score = (data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum);
data.warGifts = (((clan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20);
data.score = data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum;
data.warGifts = ((clan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20;
data.scoreGifts = 0;
data.rewards = 0;
return data;
@@ -133,5 +155,4 @@ export class HWMemberService {
return guildMembers;
}
}
+3 -5
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
@@ -7,10 +7,9 @@ import { AeronefsPageData, CanopiesPageData, DropZonesPageData, JumpsPageData }
@Injectable({ providedIn: 'root' })
export class PagesService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
getAeronefsPage(): Observable<AeronefsPageData> {
return this.apiService.get(`${this._apiDomain}/pages/aeronefs`).pipe(take(1));
@@ -27,5 +26,4 @@ export class PagesService {
getJumpsPage(): Observable<JumpsPageData> {
return this.apiService.get(`${this._apiDomain}/pages/jumps`).pipe(take(1));
}
}
+33 -19
View File
@@ -1,29 +1,36 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiService } from './api.service';
import { Product, ProductList, ProductListConfig, ProductListFilters, ProductPageData, ProductsPageData } from '@models';
import {
Product,
ProductList,
ProductListConfig,
ProductListFilters,
ProductPageData,
ProductsPageData,
} from '@models';
@Injectable({ providedIn: 'root' })
export class ProductsService {
private apiService = inject(ApiService);
private _apiDomain = '/ecommerce';
constructor(
private apiService: ApiService
) { }
query(config: ProductListConfig): Observable<ProductList> {
// Convert any filters over to Angular's URLSearchParams
const params: ProductListFilters = {} as ProductListFilters;
Object.assign(params, config.filters);
return this.apiService
.get(
`${this._apiDomain}/products` + ((config.type === 'feed') ? '/feed' : ''),
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this.apiService.get(
`${this._apiDomain}/products` + (config.type === 'feed' ? '/feed' : ''),
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(slug: string): Observable<ProductsPageData> {
@@ -35,7 +42,7 @@ export class ProductsService {
}
getAll(): Observable<Array<Product>> {
return this.apiService.get(`${this._apiDomain}/products`).pipe(map(data => data.products));
return this.apiService.get(`${this._apiDomain}/products`).pipe(map((data) => data.products));
}
getAllByCategory(category: string): Observable<ProductsPageData> {
@@ -43,26 +50,33 @@ export class ProductsService {
}
create(product: Product): Observable<Product> {
return this.apiService.post(`${this._apiDomain}/products/`, { product: product }).pipe(map(data => data.product));
return this.apiService
.post(`${this._apiDomain}/products/`, { product: product })
.pipe(map((data) => data.product));
}
update(product: Product): Observable<Product> {
return this.apiService.put(`${this._apiDomain}/products/${product.slug}`, { product: product }).pipe(map(data => data.product));
return this.apiService
.put(`${this._apiDomain}/products/${product.slug}`, { product: product })
.pipe(map((data) => data.product));
}
destroy(slug: string): Observable<boolean> {
return this.apiService.delete(`${this._apiDomain}/products/${slug}`).pipe(map(data => data.deleted));
return this.apiService.delete(`${this._apiDomain}/products/${slug}`).pipe(map((data) => data.deleted));
}
save(product: Product): Observable<Product> {
// If we're updating an existing product
if (product.slug) {
return this.apiService.put(`${this._apiDomain}/products/${product.slug}`, { product: product }).pipe(map(data => data.product));
return this.apiService
.put(`${this._apiDomain}/products/${product.slug}`, { product: product })
.pipe(map((data) => data.product));
// Otherwise, create a new product
} else {
return this.apiService.post(`${this._apiDomain}/products/`, { product: product }).pipe(map(data => data.product));
return this.apiService
.post(`${this._apiDomain}/products/`, { product: product })
.pipe(map((data) => data.product));
}
}
}
+5 -6
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { ApiService } from '@services';
@@ -7,13 +7,13 @@ import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class ProfilesService {
private apiService = inject(ApiService);
private _apiDomain = '/cms';
constructor(
private apiService: ApiService
) { }
get(username: string): Observable<Profile> {
return this.apiService.get(`${this._apiDomain}/profiles/${username}`)
return this.apiService
.get(`${this._apiDomain}/profiles/${username}`)
.pipe(map((data: { profile: Profile }) => data.profile));
}
@@ -24,5 +24,4 @@ export class ProfilesService {
unfollow(username: string): Observable<Profile> {
return this.apiService.delete(`${this._apiDomain}/profiles/${username}/follow`);
}
}
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -7,19 +7,15 @@ import { AeronefByImat, AeronefByYear } from '@models';
@Injectable({ providedIn: 'root' })
export class AeronefsService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
getAllByImat(): Observable<Array<AeronefByImat>> {
return this.apiService.get(`${this._apiDomain}/aeronefs/allByImat`)
.pipe(map(data => data.aeronefs));
return this.apiService.get(`${this._apiDomain}/aeronefs/allByImat`).pipe(map((data) => data.aeronefs));
}
getAllByImatByYear(): Observable<Array<AeronefByYear>> {
return this.apiService.get(`${this._apiDomain}/aeronefs/allByImatByYear`)
.pipe(map(data => data.aeronefs));
return this.apiService.get(`${this._apiDomain}/aeronefs/allByImatByYear`).pipe(map((data) => data.aeronefs));
}
}
}
@@ -1,22 +1,20 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { CalculatorResult, WeightSizeRange, weightSizes } from '@models';
import { UtilitiesService } from '@services';
@Injectable({ providedIn: 'root' })
export class CalculatorService {
private _utilitiesService = inject(UtilitiesService);
public coeffKgLbs: number = this._utilitiesService.getCoeffKgLbs();
public coeffFtM: number = this._utilitiesService.getCoeffFtM();
constructor(
private _utilitiesService: UtilitiesService
) { }
private _getTableColumn(jumps: number): number {
let column: number = 0;
weightSizes[0].ranges.some((range: WeightSizeRange) => {
if (jumps >= range.start && jumps <= range.end) {
column = (range.num-1)
column = range.num - 1;
return true;
}
return false;
@@ -40,11 +38,11 @@ export class CalculatorService {
}
private _isInRange(nb: number, range: WeightSizeRange): boolean {
return (nb >= range.start && nb <= range.end);
return nb >= range.start && nb <= range.end;
}
private _reduceLimit(surface: number, percentOff: number): number {
return Math.ceil(surface * (100 - percentOff) / 100);
return Math.ceil((surface * (100 - percentOff)) / 100);
}
public canopySizeCalc(weight: number, jumps: number): CalculatorResult {
@@ -54,12 +52,12 @@ export class CalculatorService {
const maxRange = 1600;
const result: CalculatorResult = {
min: 59,
min11: 34
min11: 34,
};
if (jumps > maxRange) {
return result;
}
const index: number = (this._getTableLine(weight) - this._getTableLine(0));
const index: number = this._getTableLine(weight) - this._getTableLine(0);
result.min = weightSizes[index].ranges[this._getTableColumn(jumps)].value!;
result.min11 = this._reduceLimit(result.min, 11);
@@ -67,7 +65,7 @@ export class CalculatorService {
}
public convertFeet2Meters(size: number): number {
return (size * this._utilitiesService.getCoeffFtM());
return size * this._utilitiesService.getCoeffFtM();
}
public getCanopySizes(weight: number, reduce = false): number[] {
@@ -77,11 +75,11 @@ export class CalculatorService {
if (weight > 110) {
weight = 110;
}
const line = (weight - this._getTableLine(0));
const line = weight - this._getTableLine(0);
const data = weightSizes[line];
if (reduce) {
return data.ranges.map((range: WeightSizeRange): number => {
return Math.ceil(range.value! * (100 - 11) / 100);
return Math.ceil((range.value! * (100 - 11)) / 100);
});
} else {
return data.ranges.map((range: WeightSizeRange): number => {
@@ -91,7 +89,7 @@ export class CalculatorService {
}
public getCharge(canopySize: number, nakedWeight: number, equipementWeight: number): number {
return (((nakedWeight + equipementWeight) * this.coeffKgLbs) / canopySize);
return ((nakedWeight + equipementWeight) * this.coeffKgLbs) / canopySize;
}
public getRangeNum(jumps: number): number {
@@ -125,5 +123,4 @@ export class CalculatorService {
return color;
}
}
}
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -7,29 +7,25 @@ import { CanopyBySize, CanopyByYear, CanopyModelBySize, CanopyModelByYear } from
@Injectable({ providedIn: 'root' })
export class CanopiesService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
getAllBySize(): Observable<Array<CanopyBySize>> {
return this.apiService.get(`${this._apiDomain}/canopies/allBySize`)
.pipe(map(data => data.canopies));
return this.apiService.get(`${this._apiDomain}/canopies/allBySize`).pipe(map((data) => data.canopies));
}
getAllBySizeByYear(): Observable<Array<CanopyByYear>> {
return this.apiService.get(`${this._apiDomain}/canopies/allBySizeByYear`)
.pipe(map(data => data.canopies));
return this.apiService.get(`${this._apiDomain}/canopies/allBySizeByYear`).pipe(map((data) => data.canopies));
}
getAllBySizeByModel(): Observable<Array<CanopyModelBySize>> {
return this.apiService.get(`${this._apiDomain}/canopies/allBySizeByModel`)
.pipe(map(data => data.canopies));
return this.apiService.get(`${this._apiDomain}/canopies/allBySizeByModel`).pipe(map((data) => data.canopies));
}
getAllBySizeByModelByYear(): Observable<Array<CanopyModelByYear>> {
return this.apiService.get(`${this._apiDomain}/canopies/allBySizeByModelByYear`)
.pipe(map(data => data.canopies));
return this.apiService
.get(`${this._apiDomain}/canopies/allBySizeByModelByYear`)
.pipe(map((data) => data.canopies));
}
}
}
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -7,19 +7,15 @@ import { DropZoneByOaci, DropZoneByYear } from '@models';
@Injectable({ providedIn: 'root' })
export class DropZonesService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
getAllByOaci(): Observable<Array<DropZoneByOaci>> {
return this.apiService.get(`${this._apiDomain}/dropzones/allByOaci`)
.pipe(map(data => data.dropzones));
return this.apiService.get(`${this._apiDomain}/dropzones/allByOaci`).pipe(map((data) => data.dropzones));
}
getAllByOaciByYear(): Observable<Array<DropZoneByYear>> {
return this.apiService.get(`${this._apiDomain}/dropzones/allByOaciByYear`)
.pipe(map(data => data.dropzones));
return this.apiService.get(`${this._apiDomain}/dropzones/allByOaciByYear`).pipe(map((data) => data.dropzones));
}
}
}
+66 -39
View File
@@ -1,21 +1,29 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiService } from '../api.service';
import {
Jump, JumpByCategorie, JumpByDate, JumpByDay, JumpByModule, JumpFile,
JumpList, JumpListConfig, JumpListFilters, JumpPageData,
X2Data, SkydiverIdJumps
Jump,
JumpByCategorie,
JumpByDate,
JumpByDay,
JumpByModule,
JumpFile,
JumpList,
JumpListConfig,
JumpListFilters,
JumpPageData,
X2Data,
SkydiverIdJumps,
} from '@models';
@Injectable({ providedIn: 'root' })
export class JumpsService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
query(config: JumpListConfig): Observable<JumpList> {
// Convert any filters over to Angular's URLSearchParams
@@ -49,13 +57,14 @@ export class JumpsService {
*/
const params: JumpListFilters = {} as JumpListFilters;
Object.assign(params, config.filters);
return this.apiService
.get(
`${this._apiDomain}/jumps`,
new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params })
);
return this.apiService.get(
`${this._apiDomain}/jumps`,
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
);
}
get(slug: string): Observable<JumpPageData> {
@@ -67,79 +76,98 @@ export class JumpsService {
}
getAll(): Observable<Array<Jump>> {
return this.apiService.get(`${this._apiDomain}/jumps`).pipe(map(data => data.jumps));
return this.apiService.get(`${this._apiDomain}/jumps`).pipe(map((data) => data.jumps));
}
getAllByDate(): Observable<Array<JumpByDate>> {
return this.apiService.get(`${this._apiDomain}/jumps/allByDate`).pipe(map(data => data.jumps));
return this.apiService.get(`${this._apiDomain}/jumps/allByDate`).pipe(map((data) => data.jumps));
}
getAllByCategorie(): Observable<Array<JumpByCategorie>> {
return this.apiService.get(`${this._apiDomain}/jumps/allByCategorie`).pipe(map(data => data.jumps));
return this.apiService.get(`${this._apiDomain}/jumps/allByCategorie`).pipe(map((data) => data.jumps));
}
getAllByDay(config: JumpListConfig): Observable<Array<JumpByDay>> {
const params: JumpListFilters = {} as JumpListFilters;
Object.assign(params, config.filters);
return this.apiService.get(`${this._apiDomain}/jumps/allByDay`, new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params }))
.pipe(map(data => data.days));
return this.apiService
.get(
`${this._apiDomain}/jumps/allByDay`,
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
)
.pipe(map((data) => data.days));
}
getAllByModule(): Observable<Array<JumpByModule>> {
return this.apiService.get(`${this._apiDomain}/jumps/allByModule`).pipe(map(data => data.jumps));
return this.apiService.get(`${this._apiDomain}/jumps/allByModule`).pipe(map((data) => data.jumps));
}
getAllFromSkydiverIdApi(config: JumpListConfig): Observable<SkydiverIdJumps> {
const params: JumpListFilters = {} as JumpListFilters;
Object.assign(params, config.filters);
return this.apiService.get(`${this._apiDomain}/jumps/allFromSkydiverIdApi`, new HttpParams({ fromObject: <{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}>params }))
.pipe(map(data => data.jumps));
return this.apiService
.get(
`${this._apiDomain}/jumps/allFromSkydiverIdApi`,
new HttpParams({ fromObject: <
{
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
}
>params }),
)
.pipe(map((data) => data.jumps));
}
getLastJump(): Observable<Jump> {
return this.apiService.get(`${this._apiDomain}/jumps/last`).pipe(map(data => data.jump));
return this.apiService.get(`${this._apiDomain}/jumps/last`).pipe(map((data) => data.jump));
}
create(jump: Jump): Observable<Jump> {
return this.apiService.post(`${this._apiDomain}/jumps/`, { jump: jump }).pipe(map(data => data.jump));
return this.apiService.post(`${this._apiDomain}/jumps/`, { jump: jump }).pipe(map((data) => data.jump));
}
update(jump: Jump): Observable<Jump> {
return this.apiService.put(`${this._apiDomain}/jumps/${jump.slug}`, { jump: jump }).pipe(map(data => data.jump));
return this.apiService
.put(`${this._apiDomain}/jumps/${jump.slug}`, { jump: jump })
.pipe(map((data) => data.jump));
}
destroy(slug: string): Observable<boolean> {
return this.apiService.delete(`${this._apiDomain}/jumps/${slug}`).pipe(map(data => data.deleted));
return this.apiService.delete(`${this._apiDomain}/jumps/${slug}`).pipe(map((data) => data.deleted));
}
save(jump: Jump): Observable<Jump> {
// If we're updating an existing jump
if (jump.slug) {
return this.apiService.put(`${this._apiDomain}/jumps/${jump.slug}`, { jump: jump }).pipe(map(data => data.jump));
return this.apiService
.put(`${this._apiDomain}/jumps/${jump.slug}`, { jump: jump })
.pipe(map((data) => data.jump));
// Otherwise, create a new jump
} else {
return this.apiService.post(`${this._apiDomain}/jumps/`, { jump: jump }).pipe(map(data => data.jump));
return this.apiService.post(`${this._apiDomain}/jumps/`, { jump: jump }).pipe(map((data) => data.jump));
}
}
saveX2Data(slug: string, file: JumpFile, data: X2Data): Observable<Jump> {
return this.apiService.post(`${this._apiDomain}/jumps/data/${slug}`, { file: file, data: data })
.pipe(map(data => data.jump));
return this.apiService
.post(`${this._apiDomain}/jumps/data/${slug}`, { file: file, data: data })
.pipe(map((data) => data.jump));
}
saveFile(slug: string, file: JumpFile): Observable<JumpFile> {
return this.apiService.post(`${this._apiDomain}/jumps/file/${slug}`, { file: file })
.pipe(map(data => data.file));
return this.apiService
.post(`${this._apiDomain}/jumps/file/${slug}`, { file: file })
.pipe(map((data) => data.file));
}
saveKml(slug: string, file: JumpFile): Observable<JumpFile> {
return this.apiService.post(`${this._apiDomain}/jumps/kml/${slug}`, { file: file })
.pipe(map(data => data.file));
return this.apiService
.post(`${this._apiDomain}/jumps/kml/${slug}`, { file: file })
.pipe(map((data) => data.file));
}
getAeronefs() {
@@ -163,5 +191,4 @@ export class JumpsService {
]
*/
}
}
+10 -9
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -7,22 +7,23 @@ import { Qcm, QcmCategory, QcmQuestion } from '@models';
@Injectable({ providedIn: 'root' })
export class QcmService {
private apiService = inject(ApiService);
private _apiDomain = '/skydive';
constructor(
private apiService: ApiService
) { }
get(type: string): Observable<Qcm> {
return this.apiService.get(`${this._apiDomain}/qcm/type/${type}`).pipe(map(data => data.qcm));
return this.apiService.get(`${this._apiDomain}/qcm/type/${type}`).pipe(map((data) => data.qcm));
}
saveChoices(question: object): Observable<QcmQuestion> {
return this.apiService.post(`${this._apiDomain}/qcm/choices`, { question: question })
.pipe(map(data => data.question));
return this.apiService
.post(`${this._apiDomain}/qcm/choices`, { question: question })
.pipe(map((data) => data.question));
}
saveQuestions(category: object): Observable<QcmCategory> {
return this.apiService.post(`${this._apiDomain}/qcm/questions`, { category: category })
.pipe(map(data => data.category));
return this.apiService
.post(`${this._apiDomain}/qcm/questions`, { category: category })
.pipe(map((data) => data.category));
}
}
+15 -14
View File
@@ -1,5 +1,5 @@
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { Injectable, OnDestroy, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, ReplaySubject, Subscription } from 'rxjs';
import { distinctUntilChanged, take, tap } from 'rxjs/operators';
@@ -8,6 +8,9 @@ import { JwtService } from '@services';
@Injectable({ providedIn: 'root' })
export class UserService implements OnDestroy {
private readonly http = inject(HttpClient);
private readonly jwtService = inject(JwtService);
private _subcriptions: Array<Subscription> = new Array<Subscription>();
private _user: Subscription = new Subscription();
private currentUserSubject = new BehaviorSubject<User>({} as User);
@@ -16,12 +19,7 @@ export class UserService implements OnDestroy {
private isAuthenticatedSubject = new ReplaySubject<boolean>(1);
public isAuthenticated = this.isAuthenticatedSubject.asObservable();
private _apiDomain = '/cms';
constructor(
private readonly http: HttpClient,
private readonly jwtService: JwtService
) { }
ngOnDestroy() {
this._subcriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
@@ -32,10 +30,12 @@ export class UserService implements OnDestroy {
populate() {
// If JWT detected, attempt to get & store user's info
if (this.jwtService.getToken()) {
const user$: Observable<{ user: User }> = this.http.get<{ user: User }>(`${this._apiDomain}/user`).pipe(take(1));
const user$: Observable<{ user: User }> = this.http
.get<{ user: User }>(`${this._apiDomain}/user`)
.pipe(take(1));
this._user = user$.subscribe({
next: (data) => this.setAuth(data.user),
error: () => this.purgeAuth()
error: () => this.purgeAuth(),
});
this._subcriptions.push(this._user);
} else {
@@ -62,9 +62,11 @@ export class UserService implements OnDestroy {
this.isAuthenticatedSubject.next(false);
}
attemptAuth(type: string, credentials?: { email: string; password: string; }): Observable<{ user: User }> {
const route = (type === 'login') ? '/login' : '';
const user$: Observable<{ user: User }> = this.http.post<{ user: User }>(`${this._apiDomain}/user${route}`, { user: credentials });
attemptAuth(type: string, credentials?: { email: string; password: string }): Observable<{ user: User }> {
const route = type === 'login' ? '/login' : '';
const user$: Observable<{ user: User }> = this.http.post<{ user: User }>(`${this._apiDomain}/user${route}`, {
user: credentials,
});
/*return user$.pipe(map(
(data: any) => {
this.setAuth(data.user);
@@ -79,7 +81,7 @@ export class UserService implements OnDestroy {
}
canAdministrate(): boolean {
return (this.currentUserSubject.value.role == 'Admin') ? true : false;
return this.currentUserSubject.value.role == 'Admin' ? true : false;
}
// Update the user on the server (email, pass, etc)
@@ -90,5 +92,4 @@ export class UserService implements OnDestroy {
}),
);
}
}
+124 -100
View File
@@ -1,6 +1,5 @@
import { Injectable } from '@angular/core';
import { Chart } from 'chart.js';
import { Configuration } from 'ng-chartist';
import { BarConfig, CircleConfig, DoughnutConfig, LineConfig } from '@models';
@@ -9,7 +8,7 @@ export class UtilitiesService {
private _coeffKgLbs: number = 2.20462;
private _coeffFtM: number = 0.092903;
constructor() { }
constructor() {}
getCoeffKgLbs(): number {
return this._coeffKgLbs;
@@ -19,19 +18,6 @@ export class UtilitiesService {
return this._coeffFtM;
}
getBarConfig(): Configuration {
const config: Configuration = {
type: 'Bar',
data: {
'labels': [],
'series': []
},
options: {},
responsiveOptions: []
};
return config;
}
getChartColors(): string[] {
const colors: string[] = [
'ct-color-a',
@@ -59,22 +45,19 @@ export class UtilitiesService {
'ct-color-w',
'ct-color-x',
'ct-color-y',
'ct-color-z'
'ct-color-z',
];
return colors;
}
getCurrentDateFr(): string {
return new Date().toLocaleDateString('fr');
return new Date().toLocaleDateString('fr');
}
secondsToDuration(seconds: number, delimiter: string = ':'): string {
return [
Math.floor(seconds / 60 / 60),
Math.floor(seconds / 60 % 60),
Math.floor(seconds % 60)
].join(delimiter)
.replace(/\b(\d)\b/g, "0$1")//.replace(/^00\:/, '')
return [Math.floor(seconds / 60 / 60), Math.floor((seconds / 60) % 60), Math.floor(seconds % 60)]
.join(delimiter)
.replace(/\b(\d)\b/g, '0$1'); //.replace(/^00\:/, '')
}
getSeriesColors(opacity: number, palette: string = 'all', offset: number = 0): string[] {
@@ -101,7 +84,7 @@ export class UtilitiesService {
`rgba(143, 202, 202, ${opacity})`,
`rgba(204, 226, 203, ${opacity})`,
`rgba(182, 207, 182, ${opacity})`,
`rgba(151, 193, 169, ${opacity})`
`rgba(151, 193, 169, ${opacity})`,
];
break;
case 'red':
@@ -114,7 +97,7 @@ export class UtilitiesService {
`rgba(228, 145, 122, ${opacity})`,
`rgba(238, 168, 148, ${opacity})`,
`rgba(247, 192, 175, ${opacity})`,
`rgba(255, 215, 203, ${opacity})`
`rgba(255, 215, 203, ${opacity})`,
];
break;
case 'green':
@@ -127,7 +110,7 @@ export class UtilitiesService {
`rgba(134, 187, 142, ${opacity})`,
`rgba(156, 203, 163, ${opacity})`,
`rgba(179, 219, 184, ${opacity})`,
`rgba(201, 235, 205, ${opacity})`
`rgba(201, 235, 205, ${opacity})`,
];
break;
case 'blue':
@@ -140,7 +123,7 @@ export class UtilitiesService {
`rgba(127, 170, 198, ${opacity})`,
`rgba(148, 190, 217, ${opacity})`,
`rgba(171, 210, 236, ${opacity})`,
`rgba(193, 231, 255, ${opacity})`
`rgba(193, 231, 255, ${opacity})`,
];
break;
case 'all':
@@ -197,7 +180,7 @@ export class UtilitiesService {
`rgba(217, 202, 174, ${opacity})`,
`rgba(151, 136, 199, ${opacity})`,
`rgba(212, 206, 112, ${opacity})`,
`rgba(255, 255, 255, ${opacity})`
`rgba(255, 255, 255, ${opacity})`,
];
if (offset > 0 && offset < colors.length) {
colors = colors.slice(offset);
@@ -216,8 +199,8 @@ export class UtilitiesService {
label: 'Nombre total de sauts',
backgroundColor: this.getSeriesColors(0.8),
borderColor: this.getSeriesColors(1), // 'rgba(255, 255, 255, 1)'
borderWidth: 2
}
borderWidth: 2,
},
],
circleChartOptions: {
cutout: '90%',
@@ -226,25 +209,27 @@ export class UtilitiesService {
//spacing: -10,
borderJoinStyle: 'round',
borderRadius: 10,
borderWidth: 0
}
borderWidth: 0,
},
},
plugins: {
legend: {
display: false,
position: 'left'
}
position: 'left',
},
},
responsive: true,
maintainAspectRatio: false,
animation: {
onProgress: function (this: Chart) {
const width = this.width, height = this.height, ctx = this.ctx;
const width = this.width,
height = this.height,
ctx = this.ctx;
const count: number = parseInt(this.data.datasets[0].data[0]!.toString());
const diff: number = parseInt(this.data.datasets[0].data[1]!.toString());
const total: number = (count + diff);
const percent: number = Math.round((count/total*100));
const lineHeight = (height / 8);
const total: number = count + diff;
const percent: number = Math.round((count / total) * 100);
const lineHeight = height / 8;
ctx.restore();
let fontSize = (height / 120).toFixed(2);
ctx.font = `${fontSize}em sans-serif`;
@@ -255,7 +240,7 @@ export class UtilitiesService {
let text = this.data.datasets[0].label!;
let textX = Math.round((width - ctx.measureText(text).width) / 2);
let textY = height / 2;
ctx.fillText(text, textX, (textY-lineHeight));
ctx.fillText(text, textX, textY - lineHeight);
text = `${percent}%`;
textX = Math.round((width - ctx.measureText(text).width) / 2);
textY = height / 2;
@@ -269,17 +254,19 @@ export class UtilitiesService {
text = `${count} / ${total}`;
textX = Math.round((width - ctx.measureText(text).width) / 2);
textY = height / 2;
ctx.fillText(text, textX, (textY+lineHeight));
ctx.fillText(text, textX, textY + lineHeight);
ctx.save();
//console.log(width, height, fontSize);
},
onComplete: function (this: Chart) {
const width = this.width, height = this.height, ctx = this.ctx;
const width = this.width,
height = this.height,
ctx = this.ctx;
const count: number = parseInt(this.data.datasets[0].data[0]!.toString());
const diff: number = parseInt(this.data.datasets[0].data[1]!.toString());
const total: number = (count + diff);
const percent: number = Math.round((count/total*100));
const lineHeight = (height / 8);
const total: number = count + diff;
const percent: number = Math.round((count / total) * 100);
const lineHeight = height / 8;
ctx.restore();
let fontSize = (height / 120).toFixed(2);
ctx.font = `${fontSize}em sans-serif`;
@@ -291,7 +278,7 @@ export class UtilitiesService {
let text = this.data.datasets[0].label!;
let textX = Math.round((width - ctx.measureText(text).width) / 2);
let textY = height / 2;
ctx.fillText(text, textX, (textY-lineHeight));
ctx.fillText(text, textX, textY - lineHeight);
text = `${percent}%`;
textX = Math.round((width - ctx.measureText(text).width) / 2);
textY = height / 2;
@@ -305,7 +292,7 @@ export class UtilitiesService {
text = `${count} / ${total}`;
textX = Math.round((width - ctx.measureText(text).width) / 2);
textY = height / 2;
ctx.fillText(text, textX, (textY+lineHeight));
ctx.fillText(text, textX, textY + lineHeight);
ctx.save();
//console.log(width, height, fontSize);
},
@@ -321,22 +308,26 @@ export class UtilitiesService {
id: 'beforeinit'
},*/
{
beforeDatasetDraw: (chart: Chart<"doughnut", number[], unknown>) => {
const width = chart.width, height = chart.height, ctx = chart.ctx;
beforeDatasetDraw: (chart: Chart<'doughnut', number[], unknown>) => {
const width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
const fontSize = (height / 150).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.fillStyle = "#ffffff";
ctx.textBaseline = "middle";
const text = chart.data.datasets[0].data[0] + "%", textX = Math.round((width - ctx.measureText(text).width) / 2), textY = height / 2;
ctx.font = fontSize + 'em sans-serif';
ctx.fillStyle = '#ffffff';
ctx.textBaseline = 'middle';
const text = chart.data.datasets[0].data[0] + '%',
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
console.log(width, height, fontSize);
},
id: 'doughnutlabel'
}
id: 'doughnutlabel',
},
],
circleChartLegend: false
circleChartLegend: false,
};
return config;
}
@@ -350,25 +341,25 @@ export class UtilitiesService {
label: 'Nombre total de sauts',
backgroundColor: this.getSeriesColors(0.8),
borderColor: this.getSeriesColors(1), // 'rgba(255, 255, 255, 1)'
borderWidth: 2
}
borderWidth: 2,
},
],
doughnutChartOptions: {
elements: {
arc: {
borderWidth: 2,
}
},
},
plugins: {
legend: {
display: true,
position: 'left'
}
position: 'left',
},
},
responsive: true,
maintainAspectRatio: false
maintainAspectRatio: false,
},
doughnutChartLegend: false
doughnutChartLegend: false,
};
return config;
}
@@ -377,19 +368,19 @@ export class UtilitiesService {
const config: BarConfig = {
barChartData: {
labels: [''],
datasets: []
datasets: [],
},
barChartOptions: {
plugins: {
legend: {
display: true,
position: 'top'
}
position: 'top',
},
},
elements: {
bar: {
borderWidth: 1,
}
},
},
/*interaction: {
intersect: false,
@@ -400,20 +391,30 @@ export class UtilitiesService {
display: false,
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1,2], tickBorderDashOffset: 2 }
grid: {
display: true,
color: 'rgba(255,255,255,0.1)',
tickBorderDash: [1, 2],
tickBorderDashOffset: 2,
},
},
y: {
display: true,
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.2)', tickBorderDash: [1,2], tickBorderDashOffset: 2 }
}
grid: {
display: true,
color: 'rgba(255,255,255,0.2)',
tickBorderDash: [1, 2],
tickBorderDashOffset: 2,
},
},
},
responsive: true,
maintainAspectRatio: false
maintainAspectRatio: false,
},
barChartPlugins: [],
barChartLegend: true
barChartLegend: true,
};
return config;
}
@@ -422,24 +423,24 @@ export class UtilitiesService {
const config: BarConfig = {
barChartData: {
labels: [''],
datasets: []
datasets: [],
},
barChartOptions: {
indexAxis: 'y',
elements: {
bar: {
borderWidth: 1,
}
},
},
plugins: {
legend: {
display: true,
position: 'left'
position: 'left',
},
title: {
display: false,
text: 'Nombre total de sauts'
}
text: 'Nombre total de sauts',
},
},
responsive: true,
aspectRatio: 3,
@@ -447,17 +448,17 @@ export class UtilitiesService {
x: {
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1,2] }
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1, 2] },
},
y: {
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: false, color: 'rgba(255,255,255,0.2)' }
}
}
grid: { display: false, color: 'rgba(255,255,255,0.2)' },
},
},
},
barChartPlugins: [],
barChartLegend: false
barChartLegend: false,
};
return config;
}
@@ -466,14 +467,14 @@ export class UtilitiesService {
const config: LineConfig = {
lineChartData: {
labels: [],
datasets: []
datasets: [],
},
lineChartOptions: {
plugins: {
legend: {
display: true,
position: 'top'
}
position: 'top',
},
},
/*interaction: {
intersect: false,
@@ -484,64 +485,87 @@ export class UtilitiesService {
display: true,
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1,2], tickBorderDashOffset: 2 }
grid: {
display: true,
color: 'rgba(255,255,255,0.1)',
tickBorderDash: [1, 2],
tickBorderDashOffset: 2,
},
},
y: {
display: true,
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.2)', tickBorderDash: [1,2], tickBorderDashOffset: 2 }
}
grid: {
display: true,
color: 'rgba(255,255,255,0.2)',
tickBorderDash: [1, 2],
tickBorderDashOffset: 2,
},
},
},
responsive: true,
maintainAspectRatio: false
maintainAspectRatio: false,
},
lineChartLegend: true
lineChartLegend: true,
};
return config;
}
getMonthsList(): Array<string> {
return ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
return [
'Janvier',
'Février',
'Mars',
'Avril',
'Mai',
'Juin',
'Juillet',
'Août',
'Septembre',
'Octobre',
'Novembre',
'Décembre',
];
}
getStackedLineAreaChartConfig(): LineConfig {
const config: LineConfig = {
lineChartData: {
labels: [],
datasets: []
datasets: [],
},
lineChartOptions: {
plugins: {
legend: {
display: true,
position: 'top'
}
position: 'top',
},
},
interaction: {
mode: 'nearest',
axis: 'x',
intersect: false
intersect: false,
},
scales: {
x: {
display: true,
beginAtZero: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1,2] }
grid: { display: true, color: 'rgba(255,255,255,0.1)', tickBorderDash: [1, 2] },
},
y: {
display: true,
beginAtZero: true,
stacked: true,
ticks: { color: 'rgba(255,255,255,0.3)' },
grid: { display: true, color: 'rgba(255,255,255,0.2)', tickBorderDash: [1,2] }
}
grid: { display: true, color: 'rgba(255,255,255,0.2)', tickBorderDash: [1, 2] },
},
},
responsive: true,
maintainAspectRatio: false
maintainAspectRatio: false,
},
lineChartLegend: true
lineChartLegend: true,
};
return config;
}