fix/little-updates #1

Merged
sandre merged 16 commits from fix/little-updates into master 2026-01-12 14:25:51 +00:00
25 changed files with 3745 additions and 3230 deletions

View File

@@ -10,7 +10,7 @@
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path. // If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/skydiveLogs-api/bin/Debug/net6.0/skydiveLogs-api.dll", "program": "${workspaceFolder}/skydiveLogs-api/bin/Debug/net8.0/skydiveLogs-api.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/skydiveLogs-api", "cwd": "${workspaceFolder}/skydiveLogs-api",
"stopAtEntry": false, "stopAtEntry": false,

View File

@@ -17,6 +17,7 @@ namespace skydiveLogs_api.Domain
ForLastMonthByJumpType = new List<Statistic>(); ForLastMonthByJumpType = new List<Statistic>();
ForLastYearByDz = new List<Statistic>(); ForLastYearByDz = new List<Statistic>();
ForLastYearByJumpType = new List<Statistic>(); ForLastYearByJumpType = new List<Statistic>();
ByYearByJumpType = new List<Statistic>();
} }
#endregion Public Constructors #endregion Public Constructors
@@ -32,6 +33,7 @@ namespace skydiveLogs_api.Domain
public IEnumerable<Statistic> ForLastMonthByJumpType { get; set; } public IEnumerable<Statistic> ForLastMonthByJumpType { get; set; }
public IEnumerable<Statistic> ForLastYearByDz { get; set; } public IEnumerable<Statistic> ForLastYearByDz { get; set; }
public IEnumerable<Statistic> ForLastYearByJumpType { get; set; } public IEnumerable<Statistic> ForLastYearByJumpType { get; set; }
public IEnumerable<Statistic> ByYearByJumpType { get; set; }
public int Id { get; set; } public int Id { get; set; }
public User User { get; set; } public User User { get; set; }

View File

@@ -26,6 +26,9 @@ namespace skydiveLogs_api.DomainBusiness.Interfaces
IEnumerable<Statistic> GetStatsForLastYearByDz(); IEnumerable<Statistic> GetStatsForLastYearByDz();
IEnumerable<Statistic> GetStatsForLastYearByJumpType(); IEnumerable<Statistic> GetStatsForLastYearByJumpType();
IEnumerable<Statistic> GetStatsByYearByJumpType();
void Reset(); void Reset();
#endregion Public Methods #endregion Public Methods

View File

@@ -304,6 +304,34 @@ namespace skydiveLogs_api.DomainBusiness
return allStats.ForLastYearByJumpType; return allStats.ForLastYearByJumpType;
} }
public IEnumerable<Statistic> GetStatsByYearByJumpType()
{
var allStats = GetAllStats();
if (!allStats.ByYearByJumpType.Any())
{
var allJumps = _jumpService.GetAllJumps();
var results = new List<Statistic>();
if (allJumps.Any())
{
results = allJumps.GroupBy(j => new { j.JumpType.Name, j.JumpDate.Year },
j => j,
(groupby, jumps) => new Statistic
{
Label = groupby.Year.ToString(),
Label2 = groupby.Name.ToString(),
Nb = jumps.Count()
})
.ToList();
}
allStats.ByYearByJumpType = results;
_userStatsRepository.Update(allStats);
}
return allStats.ByYearByJumpType;
}
public void Reset() public void Reset()
{ {
var resetStats = new UserStats(); var resetStats = new UserStats();

View File

@@ -10,7 +10,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Runtime.Caching" Version="7.0.0" /> <PackageReference Include="System.Runtime.Caching" Version="9.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -10,7 +10,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="LiteDB" Version="5.0.19" /> <PackageReference Include="LiteDB" Version="5.0.21" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -10,8 +10,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -95,6 +95,15 @@ namespace skydiveLogs_api.Controllers
return result; return result;
} }
[HttpGet("ByYearByJumpType")]
[EnableCors]
public IEnumerable<StatisticForChartResp> ByYearByJumpType()
{
var result = _statsService.GetStatsByYearByJumpType();
return _mapper.Map<IEnumerable<StatisticForChartResp>>(result);
}
[HttpGet("Reset")] [HttpGet("Reset")]
[EnableCors] [EnableCors]
public void Reset() public void Reset()

View File

@@ -18,10 +18,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" /> <PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.16" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.9" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,3 +0,0 @@
toto/1totoTOTO2
tata/1tataTATA2
titi/1titiTITI2

View File

@@ -1,31 +1,44 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:7.0.14-bookworm-slim-amd64 AS base # Use the official Microsoft ASP.NET Core image to build the backend
EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-backend
WORKDIR "/src/backend"
RUN apt-get -y update COPY Back/ .
RUN apt-get -y install nginx RUN dotnet restore "skydiveLogs-api/skydiveLogs-api.csproj"
RUN dotnet publish "skydiveLogs-api/skydiveLogs-api.csproj" -c Release -o /app/publish
RUN mkdir -p /app/Front /app/API
# Use the official node image to build the Angular app
COPY Front/skydivelogs-app/dist /app/Front FROM node:20-alpine AS build-frontend
COPY Back/dist /app/API WORKDIR /app
COPY ["Front/skydivelogs-app/package.json", "Front/skydivelogs-app/package-lock.json*", "./"]
RUN rm -f /app/startup.sh RUN npm install
COPY startup.sh /app COPY --exclude=Front/skydivelogs-app/node_modules/* Front/skydivelogs-app/ .
RUN chmod 755 /app/startup.sh RUN npm run build
RUN update-rc.d nginx defaults # Use a .NET runtime image to serve both the backend and frontend
COPY nginx.conf /etc/nginx/sites-available/default FROM mcr.microsoft.com/dotnet/aspnet:8.0.16-bookworm-slim-amd64 AS final
# CMD ["service" "nginx" "start;"] WORKDIR /app
# RUN service nginx restart
# Install nginx
VOLUME /app/API/Data RUN apt-get update && apt-get install -y nginx curl && rm -rf /var/lib/apt/lists/*
VOLUME /app/Front/config
# Copy custom nginx configuration
ENV ASPNETCORE_URLS http://+:5001 COPY nginx.conf /etc/nginx/sites-available/default
RUN rm -rf /usr/share/nginx/html/*
# WORKDIR /app/API
# ENTRYPOINT ["dotnet", "skydiveLogs-api.dll"] # Copy frontend dist folder to nginx html directory
ENTRYPOINT ["sh", "/app/startup.sh"] COPY --from=build-frontend /app/dist /usr/share/nginx/html
# CMD ["sh", "/app/startup.sh"]
# Copy backend from the correct build stage
COPY --from=build-backend /app/publish /app
# Expose port 80 for the application
EXPOSE 80
ENV ASPNETCORE_URLS http://+:5001
VOLUME /app/Data
VOLUME /usr/share/nginx/html/config
# Start nginx and the .NET Core app
CMD ["sh", "-c", "dotnet /app/skydiveLogs-api.dll & nginx -g 'daemon off;'"]

File diff suppressed because it is too large Load Diff

View File

@@ -9,8 +9,8 @@
<div> <div>
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="infos"> <ng-container matColumnDef="infos">
<th mat-header-cell *matHeaderCellDef style="min-width: 80px;"></th> <th mat-header-cell *matHeaderCellDef style="min-width: 80px;text-wrap: nowrap;"></th>
<td mat-cell *matCellDef="let element" style="text-align: left;"> <td mat-cell *matCellDef="let element" style="text-align: left;text-wrap: nowrap;">
<mat-icon aria-hidden="false" aria-label="Additional informations of the jump" <mat-icon aria-hidden="false" aria-label="Additional informations of the jump"
style="cursor: pointer;" (click)='openDialog(element, false)'>info</mat-icon> style="cursor: pointer;" (click)='openDialog(element, false)'>info</mat-icon>
<mat-icon aria-hidden="false" aria-label="Special jump" <mat-icon aria-hidden="false" aria-label="Special jump"
@@ -36,9 +36,9 @@
</ng-container> </ng-container>
<ng-container matColumnDef="jumpType"> <ng-container matColumnDef="jumpType">
<th mat-header-cell *matHeaderCellDef style="min-width: 100px;">{{ 'List_Jump_Header_JumpType' | <th mat-header-cell *matHeaderCellDef style="min-width: 100px;text-wrap: nowrap;">{{ 'List_Jump_Header_JumpType' |
translate }}</th> translate }}</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element" style="text-wrap: nowrap;">
<span class="smallSpanWithBreakWord" [innerHTML]="element.jumpType.name"></span> <span class="smallSpanWithBreakWord" [innerHTML]="element.jumpType.name"></span>
</td> </td>
</ng-container> </ng-container>
@@ -64,8 +64,8 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef style="min-width: 80px;"></th> <th mat-header-cell *matHeaderCellDef style="min-width: 80px;text-wrap: nowrap;"></th>
<td mat-cell *matCellDef="let element" style="text-align: left;"> <td mat-cell *matCellDef="let element" style="text-align: left;text-wrap: nowrap;">
<mat-icon aria-hidden="false" aria-label="Delete this jump" style="cursor: pointer;" <mat-icon aria-hidden="false" aria-label="Delete this jump" style="cursor: pointer;"
(click)='delete(element)'>delete</mat-icon> (click)='delete(element)'>delete</mat-icon>
<mat-icon aria-hidden="false" aria-label="Update some informations of the jump" <mat-icon aria-hidden="false" aria-label="Update some informations of the jump"

View File

@@ -1,18 +1,24 @@
.formListTunnelFlight { .formListTunnelFlight {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 150px; min-width: 150px;
max-width: 500px; max-width: 500px;
width: 100%; width: 100%;
} }
.content { .content {
min-height: 90vh; min-height: 90vh;
display: flex; display: flex;
justify-content: left; justify-content: left;
flex-direction: column; flex-direction: column;
align-items: initial; align-items: initial;
padding-top: 25px; padding-top: 25px;
} }
.chart-container {
position: relative;
margin: auto;
height: 80vh;
width: 80vw;
}

View File

@@ -1,89 +1,136 @@
<div class="content"> <div class="content">
<div> <div>
<button mat-raised-button color="accent" [routerLink]="['/newTunnelFlight']" [routerLinkActive]="['active']" <button
skipLocationChange>{{ 'ListTunnelFlight_Add' | translate }}</button> mat-raised-button
</div> color="accent"
[routerLink]="['/newTunnelFlight']"
[routerLinkActive]="['active']"
skipLocationChange
>
{{ "ListTunnelFlight_Add" | translate }}
</button>
</div>
<mat-progress-bar [mode]="'indeterminate'" *ngIf="isLoading"></mat-progress-bar> <mat-progress-bar
[mode]="'indeterminate'"
*ngIf="isLoading"
></mat-progress-bar>
<mat-radio-group [(ngModel)]="selectedPeriod" (ngModelChange)="onPeriodChange()"> <mat-radio-group
<mat-radio-button value="currentYear">{{ 'ListTunnelFlight_CurrentYear' | translate }}</mat-radio-button> [(ngModel)]="selectedPeriod"
<mat-radio-button value="12Months">{{ 'ListTunnelFlight_12Months' | translate }}</mat-radio-button> (ngModelChange)="onPeriodChange()"
<mat-radio-button value="all">{{ 'ListTunnelFlight_AllFlights' | translate }}</mat-radio-button> >
</mat-radio-group> <mat-radio-button value="currentYear">{{
"ListTunnelFlight_CurrentYear" | translate
}}</mat-radio-button>
<mat-radio-button value="12Months">{{
"ListTunnelFlight_12Months" | translate
}}</mat-radio-button>
<mat-radio-button value="all">{{
"ListTunnelFlight_AllFlights" | translate
}}</mat-radio-button>
</mat-radio-group>
<mat-nav-list> <mat-nav-list>
<mat-list-item matListItemLine *ngFor="let stat of stats"> <mat-list-item matListItemLine *ngFor="let stat of stats">
<label>{{stat.id}} : {{stat.values}}</label> <label>{{ stat.id }} : {{ stat.values }}</label>
</mat-list-item> </mat-list-item>
</mat-nav-list> </mat-nav-list>
<div style="display: inline-block; position: relative; width: 100%;"> <div class="chart-container">
<canvas baseChart <canvas
[data]="barChartData" baseChart
[options]="barChartOptions" [data]="barChartData"
[plugins]="barChartPlugins" [options]="barChartOptions"
[legend]="barChartLegend" [plugins]="barChartPlugins"
[type]="barChartType"> [legend]="barChartLegend"
</canvas> [type]="barChartType"
</div> >
</canvas>
</div>
<div> <div>
<button mat-raised-button color="accent" (click)="onLoadTable()" >{{ 'ListTunnelFlight_LoadTable' | translate }}</button> <button mat-raised-button color="accent" (click)="onLoadTable()">
{{ "ListTunnelFlight_LoadTable" | translate }}
</button>
<table mat-table [dataSource]="dataSourceTable" *ngIf="dataSourceTable?.data.length"> <table
<ng-container matColumnDef="id"> mat-table
<th mat-header-cell *matHeaderCellDef>ID</th> [dataSource]="dataSourceTable"
<td mat-cell *matCellDef="let element"> *ngIf="dataSourceTable?.data.length"
<span class="smallSpanWithBreakWord" [innerHTML]="element.id"></span> >
</td> <ng-container matColumnDef="id">
</ng-container> <th mat-header-cell *matHeaderCellDef>ID</th>
<td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.id"></span>
</td>
</ng-container>
<ng-container matColumnDef="tunnel"> <ng-container matColumnDef="tunnel">
<th mat-header-cell *matHeaderCellDef>Tunnel</th> <th mat-header-cell *matHeaderCellDef>Tunnel</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.tunnel.name"></span> <span
</td> class="smallSpanWithBreakWord"
</ng-container> [innerHTML]="element.tunnel.name"
></span>
</td>
</ng-container>
<ng-container matColumnDef="jumpType"> <ng-container matColumnDef="jumpType">
<th mat-header-cell *matHeaderCellDef>Jump Type</th> <th mat-header-cell *matHeaderCellDef>Jump Type</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.jumpType.name"></span> <span
</td> class="smallSpanWithBreakWord"
</ng-container> [innerHTML]="element.jumpType.name"
></span>
</td>
</ng-container>
<ng-container matColumnDef="nbMinutes"> <ng-container matColumnDef="nbMinutes">
<th mat-header-cell *matHeaderCellDef>Minutes</th> <th mat-header-cell *matHeaderCellDef>Minutes</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.nbMinutes"></span> <span
</td> class="smallSpanWithBreakWord"
</ng-container> [innerHTML]="element.nbMinutes"
></span>
</td>
</ng-container>
<ng-container matColumnDef="notes"> <ng-container matColumnDef="notes">
<th mat-header-cell *matHeaderCellDef>Notes</th> <th mat-header-cell *matHeaderCellDef>Notes</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.notes"></span> <span
</td> class="smallSpanWithBreakWord"
</ng-container> [innerHTML]="element.notes"
></span>
</td>
</ng-container>
<ng-container matColumnDef="flightDate"> <ng-container matColumnDef="flightDate">
<th mat-header-cell *matHeaderCellDef>Date</th> <th mat-header-cell *matHeaderCellDef>Date</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.flightDate | date: 'yyyy-MM-dd'"></span> <span
</td> class="smallSpanWithBreakWord"
</ng-container> [innerHTML]="element.flightDate | date : 'yyyy-MM-dd'"
></span>
</td>
</ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef style="min-width: 80px;"></th> <th mat-header-cell *matHeaderCellDef style="min-width: 80px"></th>
<td mat-cell *matCellDef="let element" style="text-align: left;"> <td mat-cell *matCellDef="let element" style="text-align: left">
<mat-icon aria-hidden="false" aria-label="Delete this jump" style="cursor: pointer;" <mat-icon
(click)='delete(element)'>delete</mat-icon> aria-hidden="false"
</td> aria-label="Delete this jump"
</ng-container> style="cursor: pointer"
(click)="delete(element)"
>delete</mat-icon
>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</div> </div>
</div> </div>

View File

@@ -39,4 +39,11 @@
} }
.contentFlex { .contentFlex {
flex: 45%; flex: 45%;
} }
.chart-container {
position: relative;
margin: auto;
height: 80vh;
width: 80vw;
}

View File

@@ -1,52 +1,61 @@
<div class="content"> <div class="content">
<div class="paragraph"> <div class="paragraph">
<label class="left160">{{ 'Summary_TotalJumps' | translate }}</label> <label class="left160">{{ "Summary_TotalJumps" | translate }}</label>
<span>: {{ totalJumps }}</span> <span>: {{ totalJumps }}</span>
</div> </div>
<div class="paragraph"> <div class="paragraph">
<label class="left160">{{ 'Summary_TotalCutaways' | translate }}</label> <label class="left160">{{ "Summary_TotalCutaways" | translate }}</label>
<span>: {{ totalCutaways }}</span> <span>: {{ totalCutaways }}</span>
</div> </div>
<div class="paragraph"> <div class="paragraph">
<label class="left160">{{ 'Summary_LastJump' | translate }}</label> <label class="left160">{{ "Summary_LastJump" | translate }}</label>
<span>: {{ lastJump }}</span> <span>: {{ lastJump }}</span>
</div> </div>
<div class="paragraph" style="margin-top: 20px;"> <div class="paragraph" style="margin-top: 20px">
<label class="left160">{{ 'Summary_Refresh' | translate }}</label> <label class="left160">{{ "Summary_Refresh" | translate }}</label>
<mat-icon aria-hidden="false" aria-label="Force the refresh of the stats" style="cursor: pointer;" <mat-icon
(click)='refreshStats()'>cached</mat-icon> aria-hidden="false"
aria-label="Force the refresh of the stats"
style="cursor: pointer"
(click)="refreshStats()"
>cached</mat-icon
>
</div> </div>
<mat-tab-group mat-align-tabs="left" animationDuration="0ms" <mat-tab-group
(selectedIndex)="0" (selectedTabChange)="onTabChanged($event);"> mat-align-tabs="left"
animationDuration="0ms"
(selectedIndex)="(0)"
(selectedTabChange)="onTabChanged($event)"
>
<mat-tab label="{{ 'Summary_LastMonth_Title' | translate }}"> <mat-tab label="{{ 'Summary_LastMonth_Title' | translate }}">
<ng-template matTabContent> <ng-template matTabContent>
<div class="containerFlex"> <div class="containerFlex">
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ 'Summary_LastMonth_ByDz' | translate }}</legend> <legend>{{ "Summary_LastMonth_ByDz" | translate }}</legend>
<table mat-table [dataSource]="dsJumpForLastMonthByDz"> <table mat-table [dataSource]="dsJumpForLastMonthByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</fieldset> </fieldset>
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ 'Summary_LastMonth_ByJumpType' | translate }}</legend> <legend>{{ "Summary_LastMonth_ByJumpType" | translate }}</legend>
<table mat-table [dataSource]="dsJumpForLastMonthByJumpType"> <table mat-table [dataSource]="dsJumpForLastMonthByJumpType">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</fieldset> </fieldset>
</div> </div>
@@ -57,27 +66,27 @@
<ng-template matTabContent> <ng-template matTabContent>
<div class="containerFlex"> <div class="containerFlex">
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ 'Summary_LastYear_ByDz' | translate }}</legend> <legend>{{ "Summary_LastYear_ByDz" | translate }}</legend>
<table mat-table [dataSource]="dsJumpForLastYearByDz"> <table mat-table [dataSource]="dsJumpForLastYearByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</fieldset> </fieldset>
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ 'Summary_LastYear_ByJumpType' | translate }}</legend> <legend>{{ "Summary_LastYear_ByJumpType" | translate }}</legend>
<table mat-table [dataSource]="dsJumpForLastYearByJumpType"> <table mat-table [dataSource]="dsJumpForLastYearByJumpType">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</fieldset> </fieldset>
</div> </div>
@@ -88,12 +97,12 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByDz"> <table mat-table [dataSource]="dsNbJumpByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -102,12 +111,12 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByAircraft"> <table mat-table [dataSource]="dsNbJumpByAircraft">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -116,12 +125,12 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByGear"> <table mat-table [dataSource]="dsNbJumpByGear">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -130,12 +139,12 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByType"> <table mat-table [dataSource]="dsNbJumpByType">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -144,14 +153,30 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByYear"> <table mat-table [dataSource]="dsNbJumpByYear">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{element.label}}</td> <td mat-cell *matCellDef="let element">{{ element.label }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{element.nb}}</td> <td mat-cell *matCellDef="let element">{{ element.nb }}</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'Summary_ByYearByJumpType_Title' | translate }}">
<ng-template matTabContent>
<div class="chart-container">
<canvas
baseChart
[data]="barChartData"
[options]="barChartOptions"
[plugins]="barChartPlugins"
[legend]="barChartLegend"
[type]="barChartType"
>
</canvas>
</div>
</ng-template>
</mat-tab>
</mat-tab-group> </mat-tab-group>
</div> </div>

View File

@@ -1,21 +1,26 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from "@angular/core";
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from "@angular/material/table";
import { MatTabChangeEvent, MatTabGroup } from '@angular/material/tabs'; import { MatTabChangeEvent, MatTabGroup } from "@angular/material/tabs";
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from "@ngx-translate/core";
import { DatePipe } from '@angular/common'; import { DatePipe } from "@angular/common";
import { ChartConfiguration, ChartData, ChartType, Colors } from "chart.js";
import { ServiceComm } from '../../services/service-comm.service'; import { ServiceComm } from "../../services/service-comm.service";
import { StatsService } from '../../services/stats.service'; import { StatsService } from "../../services/stats.service";
import { StatsByDzResp, StatsByAircraftResp, StatsByGearResp, import {
StatsByJumpTypeResp, StatsByYearResp } from '../../models/stats'; StatsByDzResp,
StatsByAircraftResp,
StatsByGearResp,
StatsByJumpTypeResp,
StatsByYearResp,
} from "../../models/stats";
@Component({ @Component({
selector: 'app-summary', selector: "app-summary",
templateUrl: './summary.component.html', templateUrl: "./summary.component.html",
styleUrls: ['./summary.component.css'], styleUrls: ["./summary.component.css"],
standalone: false standalone: false,
}) })
export class SummaryComponent implements OnInit { export class SummaryComponent implements OnInit {
public dsNbJumpByDz: MatTableDataSource<StatsByDzResp>; public dsNbJumpByDz: MatTableDataSource<StatsByDzResp>;
public dsNbJumpByAircraft: MatTableDataSource<StatsByAircraftResp>; public dsNbJumpByAircraft: MatTableDataSource<StatsByAircraftResp>;
@@ -26,43 +31,61 @@ export class SummaryComponent implements OnInit {
public dsJumpForLastYearByJumpType: MatTableDataSource<StatsByJumpTypeResp>; public dsJumpForLastYearByJumpType: MatTableDataSource<StatsByJumpTypeResp>;
public dsJumpForLastMonthByDz: MatTableDataSource<StatsByDzResp>; public dsJumpForLastMonthByDz: MatTableDataSource<StatsByDzResp>;
public dsJumpForLastMonthByJumpType: MatTableDataSource<StatsByJumpTypeResp>; public dsJumpForLastMonthByJumpType: MatTableDataSource<StatsByJumpTypeResp>;
public displayedColumns: Array<string> = ["label", "nb"];
public displayedColumnsByYearByJumpType: Array<string> = [
"label",
"label2",
"nb",
];
public displayedColumns: Array<string> = ['label', 'nb']; public barChartLegend = true;
public barChartPlugins = [];
public barChartData: ChartData<"line">;
public barChartOptions: ChartConfiguration["options"];
public barChartType: ChartType;
private jumpTypeToColor: Map<string, string>;
public totalJumps: number; public totalJumps: number;
public totalCutaways: number; public totalCutaways: number;
public lastJump: string; public lastJump: string;
@ViewChild(MatTabGroup) tabGroup: MatTabGroup; @ViewChild(MatTabGroup) tabGroup: MatTabGroup;
constructor(private serviceApi: StatsService, constructor(
private serviceComm: ServiceComm, private serviceApi: StatsService,
private translateService: TranslateService) { } private serviceComm: ServiceComm,
private translateService: TranslateService
) {}
ngOnInit() { ngOnInit() {
this.serviceComm.forceTranslateTitle.subscribe((data)=> { this.serviceComm.forceTranslateTitle.subscribe((data) => {
if (data === true){ if (data === true) {
this.updateTitle(); this.updateTitle();
} }
}); });
this.updateTitle(); this.updateTitle();
this.serviceApi.getSimpleSummary() this.serviceApi.getSimpleSummary().subscribe((data) => {
.subscribe(data => { this.totalJumps = data.totalJumps;
this.totalJumps = data.totalJumps; this.totalCutaways = data.totalCutaways;
this.totalCutaways = data.totalCutaways;
const datepipe: DatePipe = new DatePipe('en-US') const datepipe: DatePipe = new DatePipe("en-US");
let formattedDate = datepipe.transform(data.lastJump.jumpDate, 'EEEE dd MMMM YYYY') let formattedDate = datepipe.transform(
this.lastJump = formattedDate + ' (' + data.lastJump.dropZone.name + ')'; data.lastJump.jumpDate,
}); "EEEE dd MMMM YYYY"
);
this.lastJump = formattedDate + " (" + data.lastJump.dropZone.name + ")";
});
this.serviceApi.getStatsOfLastMonth() this.serviceApi.getStatsOfLastMonth().subscribe((data) => {
.subscribe(data => { data.byDz.sort((a, b) => b.nb - a.nb);
data.byDz.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastMonthByDz = new MatTableDataSource(data.byDz);
this.dsJumpForLastMonthByDz = new MatTableDataSource(data.byDz); data.byJumpType.sort((a, b) => b.nb - a.nb);
data.byJumpType.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastMonthByJumpType = new MatTableDataSource(
this.dsJumpForLastMonthByJumpType = new MatTableDataSource(data.byJumpType); data.byJumpType
}); );
});
this.chartConfig();
} }
public refreshStats() { public refreshStats() {
@@ -73,64 +96,160 @@ export class SummaryComponent implements OnInit {
public onTabChanged(event: MatTabChangeEvent) { public onTabChanged(event: MatTabChangeEvent) {
switch (event.index) { switch (event.index) {
case 0: case 0:
this.serviceApi.getStatsOfLastMonth() this.serviceApi.getStatsOfLastMonth().subscribe((data) => {
.subscribe(data => { data.byDz.sort((a, b) => b.nb - a.nb);
data.byDz.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastMonthByDz = new MatTableDataSource(data.byDz);
this.dsJumpForLastMonthByDz = new MatTableDataSource(data.byDz); data.byJumpType.sort((a, b) => b.nb - a.nb);
data.byJumpType.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastMonthByJumpType = new MatTableDataSource(
this.dsJumpForLastMonthByJumpType = new MatTableDataSource(data.byJumpType); data.byJumpType
}); );
});
break; break;
case 1: case 1:
this.serviceApi.getStatsOfLastYear() this.serviceApi.getStatsOfLastYear().subscribe((data) => {
.subscribe(data => { data.byDz.sort((a, b) => b.nb - a.nb);
data.byDz.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastYearByDz = new MatTableDataSource(data.byDz);
this.dsJumpForLastYearByDz = new MatTableDataSource(data.byDz); data.byJumpType.sort((a, b) => b.nb - a.nb);
data.byJumpType.sort((a, b) => b.nb - a.nb ); this.dsJumpForLastYearByJumpType = new MatTableDataSource(
this.dsJumpForLastYearByJumpType = new MatTableDataSource(data.byJumpType); data.byJumpType
}); );
});
break; break;
case 2: case 2:
this.serviceApi.getStatsByDz() this.serviceApi.getStatsByDz().subscribe((data) => {
.subscribe(data => { data.sort((a, b) => b.nb - a.nb);
data.sort((a, b) => b.nb - a.nb); this.dsNbJumpByDz = new MatTableDataSource(data);
this.dsNbJumpByDz = new MatTableDataSource(data); });
});
break; break;
case 3: case 3:
this.serviceApi.getStatsByAircraft() this.serviceApi.getStatsByAircraft().subscribe((data) => {
.subscribe(data => { data.sort((a, b) => b.nb - a.nb);
data.sort((a, b) => b.nb - a.nb); this.dsNbJumpByAircraft = new MatTableDataSource(data);
this.dsNbJumpByAircraft = new MatTableDataSource(data); });
});
break; break;
case 4: case 4:
this.serviceApi.getStatsByGear() this.serviceApi.getStatsByGear().subscribe((data) => {
.subscribe(data => { data.sort((a, b) => b.nb - a.nb);
data.sort((a, b) => b.nb - a.nb); this.dsNbJumpByGear = new MatTableDataSource(data);
this.dsNbJumpByGear = new MatTableDataSource(data); });
});
break; break;
case 5: case 5:
this.serviceApi.getStatsByJumpType() this.serviceApi.getStatsByJumpType().subscribe((data) => {
.subscribe(data => { data.sort((a, b) => b.nb - a.nb);
data.sort((a, b) => b.nb - a.nb); this.dsNbJumpByType = new MatTableDataSource(data);
this.dsNbJumpByType = new MatTableDataSource(data); });
});
break; break;
case 6: case 6:
this.serviceApi.getStatsByYear() this.serviceApi.getStatsByYear().subscribe((data) => {
.subscribe(data => { data.sort((a, b) => b.label.localeCompare(a.label));
data.sort((a, b) => b.label.localeCompare(a.label)); this.dsNbJumpByYear = new MatTableDataSource(data);
this.dsNbJumpByYear = new MatTableDataSource(data); });
}); break;
case 7:
this.serviceApi.getStatsByYearByJumpType().subscribe((data) => {
data.sort((a, b) => a.label.localeCompare(b.label));
let firstYear: number = Number(data[0].label);
const now = new Date();
const currentYear = now.getFullYear();
const nbYears = currentYear - firstYear;
let listOfYears = new Array(nbYears)
.fill(null)
.map(() => firstYear++);
// Prepare the list of jump type with am empty array
let tmpResults = new Map<string, number[]>();
const listOfJumpType = [...new Set(data.map((obj) => obj.label2))];
listOfJumpType.forEach((type) => {
tmpResults.set(type, new Array(nbYears).fill(NaN));
});
for (let i = 0; i < listOfYears.length; i++) {
const year = listOfYears[i].toString();
let filteredStats = data.filter((d) => d.label == year);
if (filteredStats.length > 0) {
filteredStats.forEach((fs) => {
tmpResults.get(fs.label2)[i] = fs.nb;
});
}
}
const results = [];
tmpResults.forEach((value, key) => {
const color = this.jumpTypeToColor.get(key);
let tmp = {
label: key,
data: value,
backgroundColor: color,
borderColor: color,
pointBackgroundColor: color,
fill: false,
pointRadius: 6,
};
results.push(tmp);
});
this.barChartData = {
labels: listOfYears,
datasets: results,
};
});
break; break;
} }
} }
private updateTitle() { private updateTitle() {
this.translateService.get("Summary_Title").subscribe( this.translateService.get("Summary_Title").subscribe((data) => {
data => { this.serviceComm.updatedComponentTitle(data); } this.serviceComm.updatedComponentTitle(data);
); });
}
private chartConfig() {
this.barChartType = "line";
this.barChartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
},
colors: {
forceOverride: true,
},
},
interaction: {
intersect: false,
mode: "nearest",
axis: "x",
},
scales: {
x: {
stacked: false,
},
y: {
stacked: false,
beginAtZero: true,
},
},
};
this.jumpTypeToColor = new Map<string, string>([
["PAC", "#FFD700"],
["Solo", "#FFA500"],
["RW 3", "#40E0D0"],
["RW 4", "#008080"],
["RW 8", "#7FFFD4"],
["RW X", "#114556"],
["FreeFly", "#FFC0CB"],
["FreeStyle", "#FF91A4"],
["Track/Trace", "#87CEEB"],
["Canopy", "#228B22"],
["Landing accuracy", "#FF6347"],
["Wingsuit 1", "#E6E6FA"],
["Wingsuit 2", "#E0B0FF"],
["Wingsuit 3", "#9400D3"],
]);
} }
} }

View File

@@ -1,133 +1,134 @@
{ {
"Login_Title" : "Login to the Skydive log", "Login_Title": "Login to the Skydive log",
"Login_Tab_CreateUser" : "Create and login a user", "Login_Tab_CreateUser": "Create and login a user",
"Login_Tab_WithUser" : "Login with a user", "Login_Tab_WithUser": "Login with a user",
"LoginUser_BtnLogin" : "Login", "LoginUser_BtnLogin": "Login",
"LoginUser_PasswordPattern" : "The pattern of the password ([A-Za-z0-9_-] {{ '{' }}8,15{{ '}' }})", "LoginUser_PasswordPattern": "The pattern of the password ([A-Za-z0-9_-] {{ '{' }}8,15{{ '}' }})",
"LoginUser_PasswordRequired" : "Password is required", "LoginUser_PasswordRequired": "Password is required",
"LoginUser_Password" : "Password", "LoginUser_Password": "Password",
"LoginUser_Username" : "Username", "LoginUser_Username": "Username",
"LoginUser_UsernamePattern" : "Username must have min 3 characters", "LoginUser_UsernamePattern": "Username must have min 3 characters",
"LoginUser_UsernameRequired" : "Username is required", "LoginUser_UsernameRequired": "Username is required",
"LoginCreateUser_Firstname" : "Firstname", "LoginCreateUser_Firstname": "Firstname",
"LoginCreateUser_FirstnameRequired" : "Firstname is required", "LoginCreateUser_FirstnameRequired": "Firstname is required",
"LoginCreateUser_FirstnamePattern" : "Firstname must have min 3 characters", "LoginCreateUser_FirstnamePattern": "Firstname must have min 3 characters",
"LoginCreateUser_Lastname" : "Lastname", "LoginCreateUser_Lastname": "Lastname",
"LoginCreateUser_LastnameRequired" : "Lastname is required", "LoginCreateUser_LastnameRequired": "Lastname is required",
"LoginCreateUser_LastnamePattern" : "Lastname must have min 3 characters", "LoginCreateUser_LastnamePattern": "Lastname must have min 3 characters",
"LoginCreateUser_Email" : "E-mail", "LoginCreateUser_Email": "E-mail",
"LoginCreateUser_EmailRequired" : "E-mail is required", "LoginCreateUser_EmailRequired": "E-mail is required",
"LoginCreateUser_EmailPattern" : "It's not a e-mail", "LoginCreateUser_EmailPattern": "It's not a e-mail",
"LoginCreateUser_Username" : "Username", "LoginCreateUser_Username": "Username",
"LoginCreateUser_UsernameRequired" : "Username is required", "LoginCreateUser_UsernameRequired": "Username is required",
"LoginCreateUser_UsernamePattern" : "Username must have min 3 characters", "LoginCreateUser_UsernamePattern": "Username must have min 3 characters",
"LoginCreateUser_Password" : "Password", "LoginCreateUser_Password": "Password",
"LoginCreateUser_PasswordRequired" : "Password is required", "LoginCreateUser_PasswordRequired": "Password is required",
"LoginCreateUser_PasswordPattern" : "The pattern of the password ([A-Za-z0-9_-|/]{{ '{' }}8,15{{ '}' }})", "LoginCreateUser_PasswordPattern": "The pattern of the password ([A-Za-z0-9_-|/]{{ '{' }}8,15{{ '}' }})",
"LoginCreateUser_BtnLogin" : "Create user and login", "LoginCreateUser_BtnLogin": "Create user and login",
"Default_Title" : "Home", "Default_Title": "Home",
"ListDz_Title" : "List of DZs", "ListDz_Title": "List of DZs",
"Summary_Title" : "Summary", "Summary_Title": "Summary",
"NewJump_Title" : "New jumps", "NewJump_Title": "New jumps",
"ListJumps_Title" : "List of jumps", "ListJumps_Title": "List of jumps",
"ListJumpTypes_Title" : "List of jump types", "ListJumpTypes_Title": "List of jump types",
"ListGears_Title" : "List of gears", "ListGears_Title": "List of gears",
"ListAircrafts_Title" : "List of aircrafts", "ListAircrafts_Title": "List of aircrafts",
"NewTunnelFlight_Title" : "New tunnel flights", "NewTunnelFlight_Title": "New tunnel flights",
"ListTunnelFlight_Title" : "List of hours of tunnel", "ListTunnelFlight_Title": "List of hours of tunnel",
"App_Footer" : "Web software to log your skydive jumps - v", "App_Footer": "Web software to log your skydive jumps - v",
"App_Nav_Summary" : "Summary", "App_Nav_Summary": "Summary",
"App_Nav_Jumps" : "List of jumps", "App_Nav_Jumps": "List of jumps",
"App_Nav_NewJump" : "Add a new jump", "App_Nav_NewJump": "Add a new jump",
"App_Nav_Dzs" : "List of DZs", "App_Nav_Dzs": "List of DZs",
"App_Nav_Aircrafts" : "List of aircrafts", "App_Nav_Aircrafts": "List of aircrafts",
"App_Nav_JumpTypes" : "List of jump types", "App_Nav_JumpTypes": "List of jump types",
"App_Nav_Gears" : "List of gears", "App_Nav_Gears": "List of gears",
"App_Nav_Logout" : "Logout", "App_Nav_Logout": "Logout",
"App_Nav_NewTunnelFlight" : "Add tunnel time", "App_Nav_NewTunnelFlight": "Add tunnel time",
"App_Nav_TunnelFlights": "The tunnel flights", "App_Nav_TunnelFlights": "The tunnel flights",
"List_Aircrafts_Add" : "Add a aircraft", "List_Aircrafts_Add": "Add a aircraft",
"List_Aircrafts_Header_Id" : "ID", "List_Aircrafts_Header_Id": "ID",
"List_Aircrafts_Header_Name" : "Name", "List_Aircrafts_Header_Name": "Name",
"List_Aircrafts_Header_Image" : "Image", "List_Aircrafts_Header_Image": "Image",
"List_Gears_Add" : "Add a gear", "List_Gears_Add": "Add a gear",
"List_Gears_Header_Id" : "ID", "List_Gears_Header_Id": "ID",
"List_Gears_Header_Name" : "Name", "List_Gears_Header_Name": "Name",
"List_Gears_Header_Manufacturer" : "Manufacturer", "List_Gears_Header_Manufacturer": "Manufacturer",
"List_Gears_Header_CanopySize" : "Canopy size", "List_Gears_Header_CanopySize": "Canopy size",
"List_Gears_Header_Aad" : "AAD system", "List_Gears_Header_Aad": "AAD system",
"List_Gears_Header_Main" : "Main canopy", "List_Gears_Header_Main": "Main canopy",
"List_Gears_Header_Reserve" : "Reserve canopy", "List_Gears_Header_Reserve": "Reserve canopy",
"List_JumpType_Add" : "Add a jump type", "List_JumpType_Add": "Add a jump type",
"List_JumpType_Header_Id" : "ID", "List_JumpType_Header_Id": "ID",
"List_JumpType_Header_Name" : "Name", "List_JumpType_Header_Name": "Name",
"List_Jump_Add" : "Add jumps", "List_Jump_Add": "Add jumps",
"List_Jump_Header_Num" : "Num", "List_Jump_Header_Num": "Num",
"List_Jump_Header_Date" : "Date", "List_Jump_Header_Date": "Date",
"List_Jump_Header_JumpType" : "Jump Type", "List_Jump_Header_JumpType": "Jump Type",
"List_Jump_Header_Aircraft" : "Aircraft", "List_Jump_Header_Aircraft": "Aircraft",
"List_Jump_Header_Dz" : "Drop Zone", "List_Jump_Header_Dz": "Drop Zone",
"List_Jump_Header_Gear" : "Gear", "List_Jump_Header_Gear": "Gear",
"List_Dz_Add" : "Add a drop zone", "List_Dz_Add": "Add a drop zone",
"List_Dz_Header_ID" : "ID", "List_Dz_Header_ID": "ID",
"List_Dz_Header_Name" : "Name", "List_Dz_Header_Name": "Name",
"List_Dz_Header_Address" : "Address", "List_Dz_Header_Address": "Address",
"List_Dz_Header_Type" : "Type", "List_Dz_Header_Type": "Type",
"List_Dz_Filter" : "Filter", "List_Dz_Filter": "Filter",
"List_Dz_Filter_PlaceHolder" : "Filter on the name or address of center", "List_Dz_Filter_PlaceHolder": "Filter on the name or address of center",
"Summary_TotalJumps" : "Total jumps", "Summary_TotalJumps": "Total jumps",
"Summary_TotalCutaways" : "Total cutaways", "Summary_TotalCutaways": "Total cutaways",
"Summary_LastJump" : "Last jump", "Summary_LastJump": "Last jump",
"Summary_Refresh" : "Refresh", "Summary_Refresh": "Refresh",
"Summary_LastMonth_Title" : "Jumps in the last month", "Summary_LastMonth_Title": "Jumps in the last month",
"Summary_LastMonth_ByDz" : "By DZ", "Summary_LastMonth_ByDz": "By DZ",
"Summary_LastMonth_ByJumpType" : "By jump type", "Summary_LastMonth_ByJumpType": "By jump type",
"Summary_LastYear_Title" : "Jumps in the last year", "Summary_LastYear_Title": "Jumps in the last year",
"Summary_LastYear_ByDz" : "By DZ", "Summary_LastYear_ByDz": "By DZ",
"Summary_LastYear_ByJumpType" : "By jump type", "Summary_LastYear_ByJumpType": "By jump type",
"Summary_ByDz_Title" : "By DZ", "Summary_ByDz_Title": "By DZ",
"Summary_ByAircraft_Title" : "By aircraft", "Summary_ByAircraft_Title": "By aircraft",
"Summary_ByGear_Title" : "By gear", "Summary_ByGear_Title": "By gear",
"Summary_ByJumpType_Title" : "By jump type", "Summary_ByJumpType_Title": "By jump type",
"Summary_ByYear_Title" : "By year", "Summary_ByYear_Title": "By year",
"Summary_ByYearByJumpType_Title": "By year and by type",
"NewJump_GoToJump" : "View the jumps", "NewJump_GoToJump": "View the jumps",
"NewJump_ResetForm" : "Reset form after adding", "NewJump_ResetForm": "Reset form after adding",
"NewJump_ChooseJumpType" : "Choose the jump type", "NewJump_ChooseJumpType": "Choose the jump type",
"NewJump_ChooseAircraft" : "Choose the aircraft", "NewJump_ChooseAircraft": "Choose the aircraft",
"NewJump_ChooseDz" : "Choose the DZ", "NewJump_ChooseDz": "Choose the DZ",
"NewJump_ChooseGear" : "Choose the used gear", "NewJump_ChooseGear": "Choose the used gear",
"NewJump_Cutaway" : "With a cutaway ?", "NewJump_Cutaway": "With a cutaway ?",
"NewJump_Special" : "Is a special jump ?", "NewJump_Special": "Is a special jump ?",
"NewJump_ExitAlt" : "Exit altitude", "NewJump_ExitAlt": "Exit altitude",
"NewJump_DeployAlt" : "Deploy altitude", "NewJump_DeployAlt": "Deploy altitude",
"NewJump_Count" : "Count of jumps", "NewJump_Count": "Count of jumps",
"NewJump_Comments" : "Comments", "NewJump_Comments": "Comments",
"NewJump_Submit" : "Submit", "NewJump_Submit": "Submit",
"NewTunnelFlight_ChooseTunnel": "Choose the tunnel", "NewTunnelFlight_ChooseTunnel": "Choose the tunnel",
"NewTunnelFlight_Minutes": "Minutes of the flight", "NewTunnelFlight_Minutes": "Minutes of the flight",
"NewTunnelFlight_Comments": "Comments", "NewTunnelFlight_Comments": "Comments",
"NewTunnelFlight_Submit": "Submit", "NewTunnelFlight_Submit": "Submit",
"NewTunnelFlight_Comments_Lbl": "Comments", "NewTunnelFlight_Comments_Lbl": "Comments",
"NewTunnelFlight_Minutes_Lbl": "Time of flight (minutes)", "NewTunnelFlight_Minutes_Lbl": "Time of flight (minutes)",
"NewTunnelFlight_Date_Lbl": "Date of flight", "NewTunnelFlight_Date_Lbl": "Date of flight",
"NewTunnelFlight_GoToJump": "View the tunnel flights", "NewTunnelFlight_GoToJump": "View the tunnel flights",
"NewTunnelFlight_ChooseJumpType": "Choose the jump type", "NewTunnelFlight_ChooseJumpType": "Choose the jump type",
"ListTunnelFlight_CurrentYear": "On the current year", "ListTunnelFlight_CurrentYear": "On the current year",
"ListTunnelFlight_12Months": "On 12 last months", "ListTunnelFlight_12Months": "On 12 last months",
"ListTunnelFlight_Add" : "Add tunnel flights", "ListTunnelFlight_Add": "Add tunnel flights",
"ListTunnelFlight_LoadTable" : "Load the tunnel flights", "ListTunnelFlight_LoadTable": "Load the tunnel flights",
"ListTunnelFlight_AllFlights" : "All" "ListTunnelFlight_AllFlights": "All"
} }

View File

@@ -1,133 +1,134 @@
{ {
"Login_Title" : "Connexion à Skydive log", "Login_Title": "Connexion à Skydive log",
"Login_Tab_CreateUser" : "Créer et se connecter", "Login_Tab_CreateUser": "Créer et se connecter",
"Login_Tab_WithUser" : "Se connecter", "Login_Tab_WithUser": "Se connecter",
"LoginUser_BtnLogin" : "Connecter", "LoginUser_BtnLogin": "Connecter",
"LoginUser_PasswordPattern" : "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.", "LoginUser_PasswordPattern": "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.",
"LoginUser_PasswordRequired" : "Le mot de passe est obligatoire", "LoginUser_PasswordRequired": "Le mot de passe est obligatoire",
"LoginUser_Password" : "Mot de passe", "LoginUser_Password": "Mot de passe",
"LoginUser_Username" : "Identifiant", "LoginUser_Username": "Identifiant",
"LoginUser_UsernamePattern" : "L'identifiant doit être minimum de 3 caractères", "LoginUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères",
"LoginUser_UsernameRequired" : "L'identifiant est obligatoire", "LoginUser_UsernameRequired": "L'identifiant est obligatoire",
"LoginCreateUser_Firstname" : "Prénom", "LoginCreateUser_Firstname": "Prénom",
"LoginCreateUser_FirstnameRequired" : "Le prénom est obligatoire", "LoginCreateUser_FirstnameRequired": "Le prénom est obligatoire",
"LoginCreateUser_FirstnamePattern" : "Le prénom doit être minimum de 3 caractères", "LoginCreateUser_FirstnamePattern": "Le prénom doit être minimum de 3 caractères",
"LoginCreateUser_Lastname" : "Nom", "LoginCreateUser_Lastname": "Nom",
"LoginCreateUser_LastnameRequired" : "Le nom est obligatoire", "LoginCreateUser_LastnameRequired": "Le nom est obligatoire",
"LoginCreateUser_LastnamePattern" : "Le nom doit être minimum de 3 caractères", "LoginCreateUser_LastnamePattern": "Le nom doit être minimum de 3 caractères",
"LoginCreateUser_Email" : "E-mail", "LoginCreateUser_Email": "E-mail",
"LoginCreateUser_EmailRequired" : "E-mail est obligatoire", "LoginCreateUser_EmailRequired": "E-mail est obligatoire",
"LoginCreateUser_EmailPattern" : "Ceci n'est pas un adresse mail", "LoginCreateUser_EmailPattern": "Ceci n'est pas un adresse mail",
"LoginCreateUser_Username" : "Identifiant", "LoginCreateUser_Username": "Identifiant",
"LoginCreateUser_UsernameRequired" : "L'identifiant est obligatoire", "LoginCreateUser_UsernameRequired": "L'identifiant est obligatoire",
"LoginCreateUser_UsernamePattern" : "L'identifiant doit être minimum de 3 caractères", "LoginCreateUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères",
"LoginCreateUser_Password" : "Mot de passe", "LoginCreateUser_Password": "Mot de passe",
"LoginCreateUser_PasswordRequired" : "Le mot de passe est obligatoire", "LoginCreateUser_PasswordRequired": "Le mot de passe est obligatoire",
"LoginCreateUser_PasswordPattern" : "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.", "LoginCreateUser_PasswordPattern": "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.",
"LoginCreateUser_BtnLogin" : "Créer et se connecter", "LoginCreateUser_BtnLogin": "Créer et se connecter",
"Default_Title" : "Accueil", "Default_Title": "Accueil",
"ListDz_Title" : "Liste des centres de parachutisme", "ListDz_Title": "Liste des centres de parachutisme",
"Summary_Title" : "Récapitulatif", "Summary_Title": "Récapitulatif",
"NewJump_Title" : "Nouveaux sauts", "NewJump_Title": "Nouveaux sauts",
"ListJumps_Title" : "Liste des sauts", "ListJumps_Title": "Liste des sauts",
"ListJumpTypes_Title" : "Liste des types de saut", "ListJumpTypes_Title": "Liste des types de saut",
"ListGears_Title" : "Liste des pièges", "ListGears_Title": "Liste des pièges",
"ListAircrafts_Title" : "Liste des avions", "ListAircrafts_Title": "Liste des avions",
"NewTunnelFlight_Title" : "Nouveaux créneaux de soufflerie", "NewTunnelFlight_Title": "Nouveaux créneaux de soufflerie",
"ListTunnelFlight_Title" : "Heures de tunnel", "ListTunnelFlight_Title": "Heures de tunnel",
"App_Footer" : "Application pour enregistrer ses sauts de parachutisme - v", "App_Footer": "Application pour enregistrer ses sauts de parachutisme - v",
"App_Nav_Summary" : "Récapitulatif", "App_Nav_Summary": "Récapitulatif",
"App_Nav_Jumps" : "Les sauts", "App_Nav_Jumps": "Les sauts",
"App_Nav_NewJump" : "Ajouter un saut", "App_Nav_NewJump": "Ajouter un saut",
"App_Nav_Dzs" : "Centre de parachutisme", "App_Nav_Dzs": "Centre de parachutisme",
"App_Nav_Aircrafts" : "Avions", "App_Nav_Aircrafts": "Avions",
"App_Nav_JumpTypes" : "Type de saut", "App_Nav_JumpTypes": "Type de saut",
"App_Nav_Gears" : "Pièges", "App_Nav_Gears": "Pièges",
"App_Nav_Logout" : "Se déconnecter", "App_Nav_Logout": "Se déconnecter",
"App_Nav_NewTunnelFlight" : "Ajouter du temps en tunnel", "App_Nav_NewTunnelFlight": "Ajouter du temps en tunnel",
"App_Nav_TunnelFlights": "Les vols en soufflerie", "App_Nav_TunnelFlights": "Les vols en soufflerie",
"List_Aircrafts_Add" : "Ajouter un avion", "List_Aircrafts_Add": "Ajouter un avion",
"List_Aircrafts_Header_Id" : "ID", "List_Aircrafts_Header_Id": "ID",
"List_Aircrafts_Header_Name" : "Nom", "List_Aircrafts_Header_Name": "Nom",
"List_Aircrafts_Header_Image" : "Image", "List_Aircrafts_Header_Image": "Image",
"List_Gears_Add" : "Ajouter un piège", "List_Gears_Add": "Ajouter un piège",
"List_Gears_Header_Id" : "ID", "List_Gears_Header_Id": "ID",
"List_Gears_Header_Name" : "Nom", "List_Gears_Header_Name": "Nom",
"List_Gears_Header_Manufacturer" : "Fabriquant", "List_Gears_Header_Manufacturer": "Fabriquant",
"List_Gears_Header_CanopySize" : "Taille de voile", "List_Gears_Header_CanopySize": "Taille de voile",
"List_Gears_Header_Aad" : "Système de sécurité", "List_Gears_Header_Aad": "Système de sécurité",
"List_Gears_Header_Main" : "Principale", "List_Gears_Header_Main": "Principale",
"List_Gears_Header_Reserve" : "Réserve", "List_Gears_Header_Reserve": "Réserve",
"List_JumpType_Add" : "Ajouter un type de saut", "List_JumpType_Add": "Ajouter un type de saut",
"List_JumpType_Header_Id" : "ID", "List_JumpType_Header_Id": "ID",
"List_JumpType_Header_Name" : "Nom", "List_JumpType_Header_Name": "Nom",
"List_Jump_Add" : "Ajouter des sauts", "List_Jump_Add": "Ajouter des sauts",
"List_Jump_Header_Num" : "Numéro", "List_Jump_Header_Num": "Numéro",
"List_Jump_Header_Date" : "Date", "List_Jump_Header_Date": "Date",
"List_Jump_Header_JumpType" : "Type de saut", "List_Jump_Header_JumpType": "Type de saut",
"List_Jump_Header_Aircraft" : "Avion", "List_Jump_Header_Aircraft": "Avion",
"List_Jump_Header_Dz" : "Centre", "List_Jump_Header_Dz": "Centre",
"List_Jump_Header_Gear" : "Piège", "List_Jump_Header_Gear": "Piège",
"List_Dz_Add" : "Ajouter un centre de parachutisme", "List_Dz_Add": "Ajouter un centre de parachutisme",
"List_Dz_Header_ID" : "ID", "List_Dz_Header_ID": "ID",
"List_Dz_Header_Name" : "Nom", "List_Dz_Header_Name": "Nom",
"List_Dz_Header_Address" : "Adresse", "List_Dz_Header_Address": "Adresse",
"List_Dz_Header_Type" : "Type", "List_Dz_Header_Type": "Type",
"List_Dz_Filter" : "Filtrer", "List_Dz_Filter": "Filtrer",
"List_Dz_Filter_PlaceHolder" : "Filtrer sur le nom ou l'adresse du centre", "List_Dz_Filter_PlaceHolder": "Filtrer sur le nom ou l'adresse du centre",
"Summary_TotalJumps" : "Nombre de sauts", "Summary_TotalJumps": "Nombre de sauts",
"Summary_TotalCutaways" : "Nombre de libération", "Summary_TotalCutaways": "Nombre de libération",
"Summary_LastJump" : "Le dernier saut", "Summary_LastJump": "Le dernier saut",
"Summary_Refresh" : "Refresh", "Summary_Refresh": "Refresh",
"Summary_LastMonth_Title" : "Les sauts du dernier mois", "Summary_LastMonth_Title": "Les sauts du dernier mois",
"Summary_LastMonth_ByDz" : "Par centre", "Summary_LastMonth_ByDz": "Par centre",
"Summary_LastMonth_ByJumpType" : "Par type de saut", "Summary_LastMonth_ByJumpType": "Par type de saut",
"Summary_LastYear_Title" : "Les sauts de la dernière année", "Summary_LastYear_Title": "Les sauts de la dernière année",
"Summary_LastYear_ByDz" : "Par centre", "Summary_LastYear_ByDz": "Par centre",
"Summary_LastYear_ByJumpType" : "Par type de saut", "Summary_LastYear_ByJumpType": "Par type de saut",
"Summary_ByDz_Title" : "Par centre", "Summary_ByDz_Title": "Par centre",
"Summary_ByAircraft_Title" : "Par avion", "Summary_ByAircraft_Title": "Par avion",
"Summary_ByGear_Title" : "Par piège", "Summary_ByGear_Title": "Par piège",
"Summary_ByJumpType_Title" : "Par type de saut", "Summary_ByJumpType_Title": "Par type de saut",
"Summary_ByYear_Title" : "Par an", "Summary_ByYear_Title": "Par an",
"Summary_ByYear_Title": "Par an et par type",
"NewJump_GoToJump" : "Voir les sauts", "NewJump_GoToJump": "Voir les sauts",
"NewJump_ResetForm" : "Reset du formulaire après l'ajout", "NewJump_ResetForm": "Reset du formulaire après l'ajout",
"NewJump_ChooseJumpType" : "Choisir le type de saut", "NewJump_ChooseJumpType": "Choisir le type de saut",
"NewJump_ChooseAircraft" : "Choisir l'avion largueur", "NewJump_ChooseAircraft": "Choisir l'avion largueur",
"NewJump_ChooseDz" : "Choisir le centre", "NewJump_ChooseDz": "Choisir le centre",
"NewJump_ChooseGear" : "Choisir le piège", "NewJump_ChooseGear": "Choisir le piège",
"NewJump_Cutaway" : "Libération ?", "NewJump_Cutaway": "Libération ?",
"NewJump_Special" : "Saut spécial ?", "NewJump_Special": "Saut spécial ?",
"NewJump_ExitAlt" : "Altitude de sortie", "NewJump_ExitAlt": "Altitude de sortie",
"NewJump_DeployAlt" : "Altitude d'ouverture", "NewJump_DeployAlt": "Altitude d'ouverture",
"NewJump_Count" : "Nombre de sauts", "NewJump_Count": "Nombre de sauts",
"NewJump_Comments" : "Commentaires", "NewJump_Comments": "Commentaires",
"NewJump_Submit" : "Ajouter", "NewJump_Submit": "Ajouter",
"NewTunnelFlight_ChooseTunnel": "Choisir le tunnel", "NewTunnelFlight_ChooseTunnel": "Choisir le tunnel",
"NewTunnelFlight_Minutes": "Temps de vol(minutes)", "NewTunnelFlight_Minutes": "Temps de vol(minutes)",
"NewTunnelFlight_Comments": "Commentaires", "NewTunnelFlight_Comments": "Commentaires",
"NewTunnelFlight_Submit": "Ajouter", "NewTunnelFlight_Submit": "Ajouter",
"NewTunnelFlight_Comments_Lbl": "Commentaires", "NewTunnelFlight_Comments_Lbl": "Commentaires",
"NewTunnelFlight_Minutes_Lbl": "Temps de vol(minutes)", "NewTunnelFlight_Minutes_Lbl": "Temps de vol(minutes)",
"NewTunnelFlight_Date_Lbl": "Date des vols", "NewTunnelFlight_Date_Lbl": "Date des vols",
"NewTunnelFlight_GoToJump": "Voir les temps de vol en soufflerie", "NewTunnelFlight_GoToJump": "Voir les temps de vol en soufflerie",
"NewTunnelFlight_ChooseJumpType": "Choisir le type de saut", "NewTunnelFlight_ChooseJumpType": "Choisir le type de saut",
"ListTunnelFlight_CurrentYear": "Dans l'année en cours", "ListTunnelFlight_CurrentYear": "Dans l'année en cours",
"ListTunnelFlight_12Months": "Sur 12 derniers mois", "ListTunnelFlight_12Months": "Sur 12 derniers mois",
"ListTunnelFlight_Add" : "Ajouter du temps en soufflerie", "ListTunnelFlight_Add": "Ajouter du temps en soufflerie",
"ListTunnelFlight_LoadTable" : "Charger les vols en tunnel", "ListTunnelFlight_LoadTable": "Charger les vols en tunnel",
"ListTunnelFlight_AllFlights" : "Tous les vols" "ListTunnelFlight_AllFlights": "Tous les vols"
} }

View File

@@ -12,5 +12,6 @@ export enum CacheApiKey {
StatsOfLastYear, StatsOfLastYear,
StatsOfLastMonth, StatsOfLastMonth,
StatsByYear, StatsByYear,
Tunnel Tunnel,
StatsByYearByJumpType,
} }

View File

@@ -1,15 +1,14 @@
import { Observable } from 'rxjs'; import { Observable } from "rxjs";
import { Jump, JumpResp } from './jump'; import { Jump, JumpResp } from "./jump";
export class StatsResp { export class StatsResp {
public simpleSummary: Observable<SimpleSummary>; public simpleSummary: Observable<SimpleSummary>;
public statsByDz: Observable<Array<StatsByDzResp>>; public statsByDz: Observable<Array<StatsByDzResp>>;
public statsByAircraft: Observable<Array<StatsByAircraftResp>>; public statsByAircraft: Observable<Array<StatsByAircraftResp>>;
public statsByGear: Observable<Array<StatsByGearResp>>; public statsByGear: Observable<Array<StatsByGearResp>>;
public statsByJumpType: Observable<Array<StatsByJumpTypeResp>>; public statsByJumpType: Observable<Array<StatsByJumpTypeResp>>;
public statsByYear: Observable<Array<StatsByYearResp>>; public statsByYear: Observable<Array<StatsByYearResp>>;
public statsByYearByJumpType: Observable<Array<StatsByYearByJumpTypeResp>>;
public statsForLastYear: Observable<StatsForLastYearResp>; public statsForLastYear: Observable<StatsForLastYearResp>;
public statsForLastMonth: Observable<StatsForLastMonthResp>; public statsForLastMonth: Observable<StatsForLastMonthResp>;
} }
@@ -81,9 +80,21 @@ export class StatsByYearResp {
public nb: number; public nb: number;
} }
export class StatsByYearByJumpTypeResp {
constructor(data: any) {
Object.assign(this, data);
}
public label: string;
public label2: string;
public nb: number;
}
export class StatsForLastYearResp { export class StatsForLastYearResp {
constructor(dataByDz: Array<StatsByDzResp>, constructor(
dataByJumpType: Array<StatsByJumpTypeResp>) { dataByDz: Array<StatsByDzResp>,
dataByJumpType: Array<StatsByJumpTypeResp>
) {
this.byDz = new Array<StatsByDzResp>(); this.byDz = new Array<StatsByDzResp>();
this.byJumpType = new Array<StatsByJumpTypeResp>(); this.byJumpType = new Array<StatsByJumpTypeResp>();
@@ -96,8 +107,10 @@ export class StatsForLastYearResp {
} }
export class StatsForLastMonthResp { export class StatsForLastMonthResp {
constructor(dataByDz: Array<StatsByDzResp>, constructor(
dataByJumpType: Array<StatsByJumpTypeResp>) { dataByDz: Array<StatsByDzResp>,
dataByJumpType: Array<StatsByJumpTypeResp>
) {
this.byDz = new Array<StatsByDzResp>(); this.byDz = new Array<StatsByDzResp>();
this.byJumpType = new Array<StatsByJumpTypeResp>(); this.byJumpType = new Array<StatsByJumpTypeResp>();

View File

@@ -1,28 +1,38 @@
import { Injectable } from '@angular/core'; import { Injectable } from "@angular/core";
import { HttpClient } from '@angular/common/http'; import { HttpClient } from "@angular/common/http";
import { Observable } from 'rxjs'; import { Observable } from "rxjs";
import { map } from 'rxjs/operators'; import { map } from "rxjs/operators";
import { StatsByDzResp, StatsByAircraftResp, StatsByJumpTypeResp, import {
StatsByGearResp, StatsByYearResp, StatsForLastMonthResp, StatsByDzResp,
StatsForLastYearResp, SimpleSummary, SimpleSummaryResp } from '../models/stats'; StatsByAircraftResp,
StatsByJumpTypeResp,
StatsByGearResp,
StatsByYearResp,
StatsByYearByJumpTypeResp,
StatsForLastMonthResp,
StatsForLastYearResp,
SimpleSummary,
SimpleSummaryResp,
} from "../models/stats";
import { BaseService } from './base.service'; import { BaseService } from "./base.service";
import { DropzoneService } from "./dropzone.service"; import { DropzoneService } from "./dropzone.service";
import { AircraftService } from "./aircraft.service"; import { AircraftService } from "./aircraft.service";
import { JumpTypeService } from "./jump-type.service"; import { JumpTypeService } from "./jump-type.service";
import { GearService } from "./gear.service"; import { GearService } from "./gear.service";
import { CacheApiKey } from '../models/cache-api-key.enum'; import { CacheApiKey } from "../models/cache-api-key.enum";
import { Jump } from '../models/jump'; import { Jump } from "../models/jump";
@Injectable() @Injectable()
export class StatsService extends BaseService { export class StatsService extends BaseService {
constructor(private http: HttpClient, constructor(
private dropzoneService: DropzoneService, private http: HttpClient,
private aircraftService: AircraftService, private dropzoneService: DropzoneService,
private jumpTypeService: JumpTypeService, private aircraftService: AircraftService,
private gearService: GearService) { private jumpTypeService: JumpTypeService,
private gearService: GearService
) {
super(); super();
} }
@@ -35,119 +45,208 @@ export class StatsService extends BaseService {
this.serviceCacheApi.delete(CacheApiKey.StatsByYear); this.serviceCacheApi.delete(CacheApiKey.StatsByYear);
this.serviceCacheApi.delete(CacheApiKey.StatsOfLastYear); this.serviceCacheApi.delete(CacheApiKey.StatsOfLastYear);
this.serviceCacheApi.delete(CacheApiKey.StatsOfLastMonth); this.serviceCacheApi.delete(CacheApiKey.StatsOfLastMonth);
this.serviceCacheApi.delete(CacheApiKey.StatsByYearByJumpType);
} }
public resetStats() { public resetStats() {
this.http.get(`${this.apiUrl}/Stats/Reset`, { headers: this.headers }).subscribe(); this.http
.get(`${this.apiUrl}/Stats/Reset`, { headers: this.headers })
.subscribe();
} }
public getSimpleSummary(): Observable<SimpleSummary> { public getSimpleSummary(): Observable<SimpleSummary> {
let callToApi = this.http.get<SimpleSummaryResp>(`${this.apiUrl}/Stats/Simple`, { headers: this.headers }) let callToApi = this.http
.pipe(map(response => { .get<SimpleSummaryResp>(`${this.apiUrl}/Stats/Simple`, {
let tmp = new Jump(response.lastJump); headers: this.headers,
this.dropzoneService.getById(response.lastJump.dropZoneId).subscribe((d)=> tmp.dropZone = d ); })
this.aircraftService.getById(response.lastJump.aircraftId).subscribe((d)=> tmp.aircraft = d ); .pipe(
this.jumpTypeService.getById(response.lastJump.jumpTypeId).subscribe((d)=> tmp.jumpType = d ); map((response) => {
this.gearService.getById(response.lastJump.gearId).subscribe((d)=> tmp.gear = d ); let tmp = new Jump(response.lastJump);
this.dropzoneService
.getById(response.lastJump.dropZoneId)
.subscribe((d) => (tmp.dropZone = d));
this.aircraftService
.getById(response.lastJump.aircraftId)
.subscribe((d) => (tmp.aircraft = d));
this.jumpTypeService
.getById(response.lastJump.jumpTypeId)
.subscribe((d) => (tmp.jumpType = d));
this.gearService
.getById(response.lastJump.gearId)
.subscribe((d) => (tmp.gear = d));
let stats = new SimpleSummary(response); let stats = new SimpleSummary(response);
stats.lastJump = tmp; stats.lastJump = tmp;
return stats; return stats;
}) })
); );
return this.serviceCacheApi.get<SimpleSummary>(CacheApiKey.SimpleSummary, callToApi); return this.serviceCacheApi.get<SimpleSummary>(
CacheApiKey.SimpleSummary,
callToApi
);
} }
public getStatsByDz(): Observable<Array<StatsByDzResp>> { public getStatsByDz(): Observable<Array<StatsByDzResp>> {
let callToApi = this.http.get<Array<StatsByDzResp>>(`${this.apiUrl}/Stats/ByDz`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<Array<StatsByDzResp>>(`${this.apiUrl}/Stats/ByDz`, {
map(response => { headers: this.headers,
const stats = response.map(data => new StatsByDzResp(data)); })
return stats; .pipe(
}) map((response) => {
); const stats = response.map((data) => new StatsByDzResp(data));
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByDzResp>>(CacheApiKey.StatsByDz, callToApi); return this.serviceCacheApi.get<Array<StatsByDzResp>>(
CacheApiKey.StatsByDz,
callToApi
);
} }
public getStatsByAircraft(): Observable<Array<StatsByAircraftResp>> { public getStatsByAircraft(): Observable<Array<StatsByAircraftResp>> {
let callToApi = this.http.get<Array<StatsByAircraftResp>>(`${this.apiUrl}/Stats/ByAircraft`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<Array<StatsByAircraftResp>>(`${this.apiUrl}/Stats/ByAircraft`, {
map(response => { headers: this.headers,
const stats = response.map(data => new StatsByAircraftResp(data)); })
return stats; .pipe(
}) map((response) => {
); const stats = response.map((data) => new StatsByAircraftResp(data));
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByAircraftResp>>(CacheApiKey.StatsByAircraft, callToApi); return this.serviceCacheApi.get<Array<StatsByAircraftResp>>(
CacheApiKey.StatsByAircraft,
callToApi
);
} }
public getStatsByJumpType(): Observable<Array<StatsByJumpTypeResp>> { public getStatsByJumpType(): Observable<Array<StatsByJumpTypeResp>> {
let callToApi = this.http.get<Array<StatsByJumpTypeResp>>(`${this.apiUrl}/Stats/ByJumpType`,{ headers: this.headers }) let callToApi = this.http
.pipe( .get<Array<StatsByJumpTypeResp>>(`${this.apiUrl}/Stats/ByJumpType`, {
map(response => { headers: this.headers,
const stats = response.map(data => new StatsByJumpTypeResp(data)); })
return stats; .pipe(
}) map((response) => {
); const stats = response.map((data) => new StatsByJumpTypeResp(data));
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByJumpTypeResp>>(CacheApiKey.StatsByJumpType, callToApi); return this.serviceCacheApi.get<Array<StatsByJumpTypeResp>>(
CacheApiKey.StatsByJumpType,
callToApi
);
} }
public getStatsByGear(): Observable<Array<StatsByGearResp>> { public getStatsByGear(): Observable<Array<StatsByGearResp>> {
let callToApi = this.http.get<Array<StatsByGearResp>>(`${this.apiUrl}/Stats/ByGear`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<Array<StatsByGearResp>>(`${this.apiUrl}/Stats/ByGear`, {
map(response => { headers: this.headers,
const stats = response.map(data => new StatsByGearResp(data)); })
return stats; .pipe(
}) map((response) => {
); const stats = response.map((data) => new StatsByGearResp(data));
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByGearResp>>(CacheApiKey.StatsByGear, callToApi); return this.serviceCacheApi.get<Array<StatsByGearResp>>(
CacheApiKey.StatsByGear,
callToApi
);
} }
public getStatsByYear(): Observable<Array<StatsByYearResp>> { public getStatsByYear(): Observable<Array<StatsByYearResp>> {
let callToApi = this.http.get<Array<StatsByYearResp>>(`${this.apiUrl}/Stats/ByYear`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<Array<StatsByYearResp>>(`${this.apiUrl}/Stats/ByYear`, {
map(response => { headers: this.headers,
const stats = response.map(data => new StatsByYearResp(data)); })
return stats; .pipe(
}) map((response) => {
); const stats = response.map((data) => new StatsByYearResp(data));
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByYearResp>>(CacheApiKey.StatsByYear, callToApi); return this.serviceCacheApi.get<Array<StatsByYearResp>>(
CacheApiKey.StatsByYear,
callToApi
);
} }
public getStatsOfLastYear(): Observable<StatsForLastYearResp> { public getStatsOfLastYear(): Observable<StatsForLastYearResp> {
let callToApi = this.http.get<StatsForLastYearResp>(`${this.apiUrl}/Stats/ForLastYear`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<StatsForLastYearResp>(`${this.apiUrl}/Stats/ForLastYear`, {
map(response => { headers: this.headers,
const statsByDz = response.byDz.map(data => new StatsByDzResp(data)); })
const statsByJumpType = response.byJumpType.map( .pipe(
data => new StatsByDzResp(data) map((response) => {
); const statsByDz = response.byDz.map(
(data) => new StatsByDzResp(data)
);
const statsByJumpType = response.byJumpType.map(
(data) => new StatsByDzResp(data)
);
return new StatsForLastYearResp(statsByDz, statsByJumpType); return new StatsForLastYearResp(statsByDz, statsByJumpType);
}) })
); );
return this.serviceCacheApi.get<StatsForLastYearResp>(CacheApiKey.StatsOfLastYear, callToApi); return this.serviceCacheApi.get<StatsForLastYearResp>(
CacheApiKey.StatsOfLastYear,
callToApi
);
} }
public getStatsOfLastMonth(): Observable<StatsForLastMonthResp> { public getStatsOfLastMonth(): Observable<StatsForLastMonthResp> {
let callToApi = this.http.get<StatsForLastYearResp>(`${this.apiUrl}/Stats/ForLastMonth`, { headers: this.headers }) let callToApi = this.http
.pipe( .get<StatsForLastYearResp>(`${this.apiUrl}/Stats/ForLastMonth`, {
map(response => { headers: this.headers,
const statsByDz = response.byDz.map(data => new StatsByDzResp(data)); })
const statsByJumpType = response.byJumpType.map( .pipe(
data => new StatsByDzResp(data) map((response) => {
); const statsByDz = response.byDz.map(
(data) => new StatsByDzResp(data)
);
const statsByJumpType = response.byJumpType.map(
(data) => new StatsByDzResp(data)
);
return new StatsForLastMonthResp(statsByDz, statsByJumpType); return new StatsForLastMonthResp(statsByDz, statsByJumpType);
}) })
); );
return this.serviceCacheApi.get<StatsForLastMonthResp>(CacheApiKey.StatsOfLastMonth, callToApi); return this.serviceCacheApi.get<StatsForLastMonthResp>(
CacheApiKey.StatsOfLastMonth,
callToApi
);
}
public getStatsByYearByJumpType(): Observable<
Array<StatsByYearByJumpTypeResp>
> {
let callToApi = this.http
.get<Array<StatsByYearByJumpTypeResp>>(
`${this.apiUrl}/Stats/ByYearByJumpType`,
{
headers: this.headers,
}
)
.pipe(
map((response) => {
const stats = response.map(
(data) => new StatsByYearByJumpTypeResp(data)
);
return stats;
})
);
return this.serviceCacheApi.get<Array<StatsByYearByJumpTypeResp>>(
CacheApiKey.StatsByYearByJumpType,
callToApi
);
} }
} }

11
TODO.md
View File

@@ -1,11 +0,0 @@
BACK :
- JumpType :
- ajouter l'indication que le type de saut est faisable en tunnel
FRONT :
- JumpType :
- ajouter dans la page un check-box pour indiquer que le type est faisable en tunnel
- permettre de mettre à jour le type sur l'info "en tunnel"
- Tunnel Flight
- la liste de type de vol filter pour ceux concernant par le tunnel
- avec juste 1 date

View File

@@ -4,7 +4,8 @@ server {
server_name _; server_name _;
root /app/Front; #root /app/Front;
root /usr/share/nginx/html;
index index.html; index index.html;
location /api { location /api {