use counter

This commit is contained in:
Tomasi - Developing 2025-05-12 09:25:14 +02:00
parent 52f9e85eb5
commit 1b57b8babe
13 changed files with 155 additions and 5 deletions

View File

@ -0,0 +1,35 @@
using Application.DataTransferObjects.Stat;
using Application.Interfaces;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
namespace Api.Controllers.v1
{
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[ApiVersion("1.0")]
public class StatsController(IStatRepository statRepository, ILogger<StatsController> logger) : ControllerBase
{
[HttpGet("useCount")]
public async Task<ActionResult<AllianceUseToolCount>> GetUseCount(CancellationToken cancellationToken)
{
try
{
var useCountResult = await statRepository.GetAllianceUseToolCountAsync(cancellationToken);
return useCountResult.IsFailure
? BadRequest(useCountResult.Error)
: Ok(useCountResult.Value);
}
catch (Exception e)
{
logger.LogError(e, "{ErrorMessage}", e.Message);
return Problem(
detail: $"Failed to process {nameof(GetUseCount)}",
statusCode: StatusCodes.Status500InternalServerError,
title: "Internal server error");
}
}
}
}

View File

@ -36,6 +36,7 @@ public static class ApplicationDependencyInjection
services.AddScoped<IApiKeyRepository, ApiKeyRepository>();
services.AddScoped<ICustomEventCategoryRepository, CustomEventCategoryRepository>();
services.AddScoped<ICustomEventLeaderBoardRepository, CustomEventLeaderboardRepository>();
services.AddScoped<IStatRepository, StatRepository>();
services.AddTransient<IJwtService, JwtService>();

View File

@ -0,0 +1,6 @@
namespace Application.DataTransferObjects.Stat;
public class AllianceUseToolCount
{
public int Amount { get; set; }
}

View File

@ -0,0 +1,9 @@
using Application.Classes;
using Application.DataTransferObjects.Stat;
namespace Application.Interfaces;
public interface IStatRepository
{
Task<Result<AllianceUseToolCount>> GetAllianceUseToolCountAsync(CancellationToken cancellationToken);
}

View File

@ -0,0 +1,20 @@
using Application.Classes;
using Application.DataTransferObjects.Stat;
using Application.Interfaces;
using Database;
using Microsoft.EntityFrameworkCore;
namespace Application.Repositories;
public class StatRepository(ApplicationContext dbContext) : IStatRepository
{
public async Task<Result<AllianceUseToolCount>> GetAllianceUseToolCountAsync(CancellationToken cancellationToken)
{
var allianceCount = await dbContext.Alliances.CountAsync(cancellationToken);
return Result.Success(new AllianceUseToolCount
{
Amount = allianceCount
});
}
}

19
Ui/package-lock.json generated
View File

@ -26,6 +26,7 @@
"bootswatch": "^5.3.3",
"jest-editor-support": "*",
"moment": "^2.30.1",
"ngx-countup": "^13.2.0",
"ngx-mask": "^19.0.6",
"ngx-pagination": "^6.0.3",
"ngx-spinner": "^17.0.0",
@ -6536,6 +6537,11 @@
"node": ">= 0.10"
}
},
"node_modules/countup.js": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.8.2.tgz",
"integrity": "sha512-UtRoPH6udaru/MOhhZhI/GZHJKAyAxuKItD2Tr7AbrqrOPBX/uejWBBJt8q86169AMqKkE9h9/24kFWbUk/Bag=="
},
"node_modules/critters": {
"version": "0.0.24",
"resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz",
@ -10841,6 +10847,19 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node_modules/ngx-countup": {
"version": "13.2.0",
"resolved": "https://registry.npmjs.org/ngx-countup/-/ngx-countup-13.2.0.tgz",
"integrity": "sha512-8HpLinaRAg9qta8P/1BjP7IzVY8USNbn9981StlvYPNshLwZcmSmxKJIuHzE9zTL+y7ILWih2L4SDyJDfsIyVw==",
"dependencies": {
"countup.js": "^2.3.2",
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": ">=13.0.0",
"@angular/core": ">=13.0.0"
}
},
"node_modules/ngx-mask": {
"version": "19.0.6",
"resolved": "https://registry.npmjs.org/ngx-mask/-/ngx-mask-19.0.6.tgz",

View File

@ -28,6 +28,7 @@
"bootswatch": "^5.3.3",
"jest-editor-support": "*",
"moment": "^2.30.1",
"ngx-countup": "^13.2.0",
"ngx-mask": "^19.0.6",
"ngx-pagination": "^6.0.3",
"ngx-spinner": "^17.0.0",

View File

@ -138,6 +138,18 @@
color: #ff3860;
}
.alliance-counter {
margin-top: 20px;
font-size: 1rem;
font-weight: 500;
text-align: center;
color: #ffffffcc;
}
.count {
color: #4fc3f7;
font-weight: bold;
margin: 0 6px;
}
/* Footer */
/*.footer {*/
/* display: flex;*/

View File

@ -80,6 +80,13 @@
</div>
</form>
</div>
<div class="alliance-counter" *ngIf="allianceCount !== null">
<span>Currently </span>
<span class="count">
<span [countUp]="allianceCount"></span>
</span>
<span> alliances use the tool</span>
</div>
</div>
<footer class="footer d-flex flex-wrap justify-content-center justify-content-md-between align-items-center px-3 py-3 mt-auto shadow-sm gap-2 small text-center">

View File

@ -1,4 +1,4 @@
import {Component, inject} from '@angular/core';
import {Component, inject, OnInit} from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {AuthenticationService} from "../../services/authentication.service";
import {Router} from "@angular/router";
@ -6,16 +6,15 @@ import {ToastrService} from "ngx-toastr";
import {LoginRequestModel} from "../../models/login.model";
import {environment} from "../../../environments/environment";
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
import {PlayerEditModalComponent} from "../../modals/player-edit-modal/player-edit-modal.component";
import {PlayerModel} from "../../models/player.model";
import {ForgotPasswordComponent} from "../forgot-password/forgot-password.component";
import {StatService} from "../../services/stat.service";
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent {
export class LoginComponent implements OnInit {
public isPasswordType: boolean = true;
public currentYear: number = new Date().getFullYear();
@ -27,9 +26,11 @@ export class LoginComponent {
});
private readonly _authenticationService: AuthenticationService = inject(AuthenticationService);
private readonly _statService: StatService = inject(StatService);
private readonly _router: Router = inject(Router);
private readonly _toastr: ToastrService = inject(ToastrService);
private readonly _modalService : NgbModal = inject(NgbModal);
allianceCount: number | null = null;
get email() {
return this.loginForm.get('email');
@ -39,6 +40,18 @@ export class LoginComponent {
return this.loginForm.get('password');
}
ngOnInit() {
this.fetchAllianceCount();
}
fetchAllianceCount() {
this._statService.getAllianceUseCount().subscribe({
next: ((response => {
this.allianceCount = response;
}))
})
}
onLogin(): void {
if (this.loginForm.invalid) {
return;

View File

@ -65,6 +65,7 @@ import { CustomEventCategoryComponent } from './pages/custom-event/custom-event-
import { CustomEventLeaderboardComponent } from './pages/custom-event/custom-event-leaderboard/custom-event-leaderboard.component';
import { CustomEventEventsComponent } from './pages/custom-event/custom-event-events/custom-event-events.component';
import {NgxMaskDirective, NgxMaskPipe, provideNgxMask} from "ngx-mask";
import {CountUpModule} from "ngx-countup";
@NgModule({
declarations: [
@ -140,7 +141,8 @@ import {NgxMaskDirective, NgxMaskPipe, provideNgxMask} from "ngx-mask";
}),
AgCharts,
NgxMaskDirective,
NgxMaskPipe
NgxMaskPipe,
CountUpModule
],
providers: [
provideNgxMask(),

View File

@ -6,6 +6,10 @@ import {finalize} from "rxjs";
export const spinnerInterceptor: HttpInterceptorFn = (req, next) => {
const spinnerService: SpinnerService = inject(SpinnerService);
if(req.url.includes('Stats/useCount')) {
return next(req);
}
spinnerService.busy();
return next(req).pipe(

View File

@ -0,0 +1,21 @@
import {inject, Injectable} from '@angular/core';
import {environment} from "../../environments/environment";
import {HttpClient} from "@angular/common/http";
import {map, Observable} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class StatService {
private readonly _serviceUrl = environment.apiBaseUrl + 'Stats/';
private readonly _httpClient: HttpClient = inject(HttpClient);
getAllianceUseCount() : Observable<number> {
return this._httpClient.get<{amount: number}>(this._serviceUrl + 'useCount')
.pipe(
map(res => res.amount)
)
}
}