mirror of
https://github.com/TomasiDeveloping/PlayerManagement.git
synced 2026-04-16 17:22:21 +00:00
Implement custom event
This commit is contained in:
parent
4ac162e8dc
commit
bb735a68aa
112
Api/Controllers/v1/CustomEventParticipantsController.cs
Normal file
112
Api/Controllers/v1/CustomEventParticipantsController.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
using Application.DataTransferObjects.CustomEventParticipant;
|
||||||
|
using Application.Interfaces;
|
||||||
|
using Asp.Versioning;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Api.Controllers.v1
|
||||||
|
{
|
||||||
|
[Route("api/v{version:apiVersion}/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[Authorize]
|
||||||
|
public class CustomEventParticipantsController(ICustomEventParticipantRepository customEventParticipantRepository, ILogger<CustomEventParticipantsController> logger) : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
[HttpGet("{customEventParticipantId:guid}")]
|
||||||
|
public async Task<ActionResult<CustomEventParticipantDto>> GetCustomEventParticipant(
|
||||||
|
Guid customEventParticipantId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var customEventParticipantResult =
|
||||||
|
await customEventParticipantRepository.GetCustomEventParticipantAsync(customEventParticipantId,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return customEventParticipantResult.IsFailure
|
||||||
|
? BadRequest(customEventParticipantResult.Error)
|
||||||
|
: Ok(customEventParticipantResult.Value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("Player/{playerId:guid}")]
|
||||||
|
public async Task<ActionResult<List<CreateCustomEventParticipantDto>>> GetPlayerCustomEventParticipants(
|
||||||
|
Guid playerId, [FromQuery] int last,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var customEventPlayerParticipatedResult =
|
||||||
|
await customEventParticipantRepository.GetPlayerCustomEventParticipantsAsync(playerId, last,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (customEventPlayerParticipatedResult.IsFailure)
|
||||||
|
return BadRequest(customEventPlayerParticipatedResult.Error);
|
||||||
|
|
||||||
|
return customEventPlayerParticipatedResult.Value.Count > 0
|
||||||
|
? Ok(customEventPlayerParticipatedResult.Value)
|
||||||
|
: NoContent();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> InsertCustomEventParticipant(
|
||||||
|
List<CreateCustomEventParticipantDto> createCustomEventParticipants, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid) return UnprocessableEntity(ModelState);
|
||||||
|
|
||||||
|
var createResult =
|
||||||
|
await customEventParticipantRepository.InsertCustomEventParticipantAsync(
|
||||||
|
createCustomEventParticipants, cancellationToken);
|
||||||
|
|
||||||
|
return createResult.IsFailure
|
||||||
|
? BadRequest(createResult.Error)
|
||||||
|
: StatusCode(StatusCodes.Status201Created);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{customEventParticipantId:guid}")]
|
||||||
|
public async Task<ActionResult<CustomEventParticipantDto>> UpdateCustomEventParticipant(
|
||||||
|
Guid customEventParticipantId,
|
||||||
|
UpdateCustomEventParticipantDto updateEventParticipantDto, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid) return UnprocessableEntity(ModelState);
|
||||||
|
|
||||||
|
if (customEventParticipantId != updateEventParticipantDto.Id)
|
||||||
|
return Conflict(new Error("", ""));
|
||||||
|
|
||||||
|
var updateResult =
|
||||||
|
await customEventParticipantRepository.UpdateCustomEventParticipantAsync(
|
||||||
|
updateEventParticipantDto, cancellationToken);
|
||||||
|
|
||||||
|
return updateResult.IsFailure
|
||||||
|
? BadRequest(updateResult.Error)
|
||||||
|
: Ok(updateResult.Value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,6 @@
|
|||||||
<Folder Include="DataTransferObjects\Alliance\" />
|
<Folder Include="DataTransferObjects\Alliance\" />
|
||||||
<Folder Include="Classes\" />
|
<Folder Include="Classes\" />
|
||||||
<Folder Include="DataTransferObjects\MarshalGuardParticipant\" />
|
<Folder Include="DataTransferObjects\MarshalGuardParticipant\" />
|
||||||
<Folder Include="DataTransferObjects\CustomEventParticipant\" />
|
|
||||||
<Folder Include="DataTransferObjects\ZombieSiegeParticipant\" />
|
<Folder Include="DataTransferObjects\ZombieSiegeParticipant\" />
|
||||||
<Folder Include="DataTransferObjects\Rank\" />
|
<Folder Include="DataTransferObjects\Rank\" />
|
||||||
<Folder Include="DataTransferObjects\Note\" />
|
<Folder Include="DataTransferObjects\Note\" />
|
||||||
|
|||||||
@ -24,6 +24,7 @@ public static class ApplicationDependencyInjection
|
|||||||
services.AddScoped<IAuthenticationRepository, AuthenticationRepository>();
|
services.AddScoped<IAuthenticationRepository, AuthenticationRepository>();
|
||||||
services.AddScoped<IRankRepository, RankRepository>();
|
services.AddScoped<IRankRepository, RankRepository>();
|
||||||
services.AddScoped<ICustomEventRepository, CustomEventRepository>();
|
services.AddScoped<ICustomEventRepository, CustomEventRepository>();
|
||||||
|
services.AddScoped<ICustomEventParticipantRepository, CustomEventParticipantRepository>();
|
||||||
services.AddScoped<IMarshalGuardParticipantRepository, MarshalGuardParticipantRepository>();
|
services.AddScoped<IMarshalGuardParticipantRepository, MarshalGuardParticipantRepository>();
|
||||||
services.AddScoped<IVsDuelParticipantRepository, VsDuelParticipantRepository>();
|
services.AddScoped<IVsDuelParticipantRepository, VsDuelParticipantRepository>();
|
||||||
services.AddScoped<IUserRepository, UserRepository>();
|
services.AddScoped<IUserRepository, UserRepository>();
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class CreateCustomEventDto
|
|||||||
public Guid AllianceId { get; set; }
|
public Guid AllianceId { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public required string EventDateString { get; set; }
|
public required string EventDate { get; set; }
|
||||||
|
|
||||||
public bool IsInProgress { get; set; }
|
public bool IsInProgress { get; set; }
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ public class UpdateCustomEventDto
|
|||||||
public required string Description { get; set; }
|
public required string Description { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public required string EventDateString { get; set; }
|
public required string EventDate { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public bool IsInProgress { get; set; }
|
public bool IsInProgress { get; set; }
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Application.DataTransferObjects.CustomEventParticipant;
|
||||||
|
|
||||||
|
public class CreateCustomEventParticipantDto
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public Guid CustomEventId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public Guid PlayerId { get; set; }
|
||||||
|
|
||||||
|
public bool? Participated { get; set; }
|
||||||
|
|
||||||
|
public long? AchievedPoints { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Application.DataTransferObjects.CustomEventParticipant;
|
||||||
|
|
||||||
|
public class UpdateCustomEventParticipantDto
|
||||||
|
{
|
||||||
|
[Required] public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public Guid CustomEventId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public Guid PlayerId { get; set; }
|
||||||
|
|
||||||
|
public bool? Participated { get; set; }
|
||||||
|
|
||||||
|
public long? AchievedPoints { get; set; }
|
||||||
|
}
|
||||||
17
Application/Interfaces/ICustomEventParticipantRepository.cs
Normal file
17
Application/Interfaces/ICustomEventParticipantRepository.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Application.Classes;
|
||||||
|
using Application.DataTransferObjects.CustomEventParticipant;
|
||||||
|
|
||||||
|
namespace Application.Interfaces;
|
||||||
|
|
||||||
|
public interface ICustomEventParticipantRepository
|
||||||
|
{
|
||||||
|
Task<Result<CustomEventParticipantDto>> GetCustomEventParticipantAsync(Guid customEventParticipantId,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
Task<Result<bool>> InsertCustomEventParticipantAsync(
|
||||||
|
List<CreateCustomEventParticipantDto> createCustomEventParticipants, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<Result<List<CustomEventParticipantDto>>> GetPlayerCustomEventParticipantsAsync(Guid playerId, int last, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<Result<CustomEventParticipantDto>> UpdateCustomEventParticipantAsync(
|
||||||
|
UpdateCustomEventParticipantDto updateCustomEventParticipant, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -9,7 +9,11 @@ public class CustomEventParticipantProfile : Profile
|
|||||||
public CustomEventParticipantProfile()
|
public CustomEventParticipantProfile()
|
||||||
{
|
{
|
||||||
CreateMap<CustomEventParticipant, CustomEventParticipantDto>()
|
CreateMap<CustomEventParticipant, CustomEventParticipantDto>()
|
||||||
.ForMember(des => des.Id, opt => opt.MapFrom(src => Guid.CreateVersion7()))
|
|
||||||
.ForMember(des => des.PlayerName, opt => opt.MapFrom(src => src.Player.PlayerName));
|
.ForMember(des => des.PlayerName, opt => opt.MapFrom(src => src.Player.PlayerName));
|
||||||
|
|
||||||
|
CreateMap<CreateCustomEventParticipantDto, CustomEventParticipant>()
|
||||||
|
.ForMember(des => des.Id, opt => opt.MapFrom(src => Guid.CreateVersion7()));
|
||||||
|
|
||||||
|
CreateMap<UpdateCustomEventParticipantDto, CustomEventParticipant>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,12 +10,15 @@ public class CustomEventProfile : Profile
|
|||||||
{
|
{
|
||||||
CreateMap<CustomEvent, CustomEventDto>();
|
CreateMap<CustomEvent, CustomEventDto>();
|
||||||
|
|
||||||
|
CreateMap<CustomEvent, CustomEventDetailDto>()
|
||||||
|
.ForMember(des => des.CustomEventParticipants, opt => opt.MapFrom(src => src.CustomEventParticipants));
|
||||||
|
|
||||||
CreateMap<CreateCustomEventDto, CustomEvent>()
|
CreateMap<CreateCustomEventDto, CustomEvent>()
|
||||||
.ForMember(des => des.Id, opt => opt.MapFrom(src => Guid.CreateVersion7()))
|
.ForMember(des => des.Id, opt => opt.MapFrom(src => Guid.CreateVersion7()))
|
||||||
.ForMember(des => des.EventDate, opt => opt.MapFrom(src => DateTime.Parse(src.EventDateString)));
|
.ForMember(des => des.EventDate, opt => opt.MapFrom(src => DateTime.Parse(src.EventDate)));
|
||||||
|
|
||||||
CreateMap<UpdateCustomEventDto, CustomEvent>()
|
CreateMap<UpdateCustomEventDto, CustomEvent>()
|
||||||
.ForMember(des => des.ModifiedOn, opt => opt.MapFrom(src => DateTime.Now))
|
.ForMember(des => des.ModifiedOn, opt => opt.MapFrom(src => DateTime.Now))
|
||||||
.ForMember(des => des.EventDate, opt => opt.MapFrom(src => DateTime.Parse(src.EventDateString)));
|
.ForMember(des => des.EventDate, opt => opt.MapFrom(src => DateTime.Parse(src.EventDate)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
83
Application/Repositories/CustomEventParticipantRepository.cs
Normal file
83
Application/Repositories/CustomEventParticipantRepository.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using Application.Classes;
|
||||||
|
using Application.DataTransferObjects.CustomEventParticipant;
|
||||||
|
using Application.Errors;
|
||||||
|
using Application.Interfaces;
|
||||||
|
using AutoMapper;
|
||||||
|
using AutoMapper.QueryableExtensions;
|
||||||
|
using Database;
|
||||||
|
using Database.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Application.Repositories;
|
||||||
|
|
||||||
|
public class CustomEventParticipantRepository(ApplicationContext context, IMapper mapper, ILogger<CustomEventParticipantRepository> logger) : ICustomEventParticipantRepository
|
||||||
|
{
|
||||||
|
public async Task<Result<CustomEventParticipantDto>> GetCustomEventParticipantAsync(Guid customEventParticipantId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var customEventParticipantById = await context.CustomEventParticipants
|
||||||
|
.ProjectTo<CustomEventParticipantDto>(mapper.ConfigurationProvider)
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(customEventParticipant => customEventParticipant.Id == customEventParticipantId,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return customEventParticipantById is null
|
||||||
|
? Result.Failure<CustomEventParticipantDto>(new Error("", ""))
|
||||||
|
: Result.Success(customEventParticipantById);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<bool>> InsertCustomEventParticipantAsync(List<CreateCustomEventParticipantDto> createCustomEventParticipants, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var customEventParticipants = mapper.Map<List<CustomEventParticipant>>(createCustomEventParticipants);
|
||||||
|
|
||||||
|
await context.CustomEventParticipants.AddRangeAsync(customEventParticipants, cancellationToken);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
return Result.Success(true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return Result.Failure<bool>(GeneralErrors.DatabaseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<List<CustomEventParticipantDto>>> GetPlayerCustomEventParticipantsAsync(Guid playerId, int last, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var customEventPlayerParticipated = await context.CustomEventParticipants
|
||||||
|
.Where(customEventParticipant => customEventParticipant.PlayerId == playerId)
|
||||||
|
.OrderByDescending(customEventParticipant => customEventParticipant.CustomEvent.EventDate)
|
||||||
|
.Take(last)
|
||||||
|
.ProjectTo<CustomEventParticipantDto>(mapper.ConfigurationProvider)
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Result.Success(customEventPlayerParticipated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<CustomEventParticipantDto>> UpdateCustomEventParticipantAsync(UpdateCustomEventParticipantDto updateCustomEventParticipant,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var customEventParticipantToUpdate = await context.CustomEventParticipants
|
||||||
|
.FirstOrDefaultAsync(
|
||||||
|
customEventParticipant => customEventParticipant.Id == updateCustomEventParticipant.Id,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (customEventParticipantToUpdate is null) return Result.Failure<CustomEventParticipantDto>(new Error("", ""));
|
||||||
|
|
||||||
|
mapper.Map(updateCustomEventParticipant, customEventParticipantToUpdate);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
return Result.Success(mapper.Map<CustomEventParticipantDto>(customEventParticipantToUpdate));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, e.Message);
|
||||||
|
return Result.Failure<CustomEventParticipantDto>(GeneralErrors.DatabaseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,6 +21,7 @@ import {ResetPasswordComponent} from "./Authentication/reset-password/reset-pass
|
|||||||
import {CustomEventComponent} from "./pages/custom-event/custom-event.component";
|
import {CustomEventComponent} from "./pages/custom-event/custom-event.component";
|
||||||
import {ZombieSiegeComponent} from "./pages/zombie-siege/zombie-siege.component";
|
import {ZombieSiegeComponent} from "./pages/zombie-siege/zombie-siege.component";
|
||||||
import {ZombieSiegeDetailComponent} from "./pages/zombie-siege/zombie-siege-detail/zombie-siege-detail.component";
|
import {ZombieSiegeDetailComponent} from "./pages/zombie-siege/zombie-siege-detail/zombie-siege-detail.component";
|
||||||
|
import {CustomEventDetailComponent} from "./pages/custom-event/custom-event-detail/custom-event-detail.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: 'players', component: PlayerComponent, canActivate: [authGuard]},
|
{path: 'players', component: PlayerComponent, canActivate: [authGuard]},
|
||||||
@ -36,6 +37,7 @@ const routes: Routes = [
|
|||||||
{path: 'account', component: AccountComponent, canActivate: [authGuard]},
|
{path: 'account', component: AccountComponent, canActivate: [authGuard]},
|
||||||
{path: 'change-password', component: ChangePasswordComponent, canActivate: [authGuard]},
|
{path: 'change-password', component: ChangePasswordComponent, canActivate: [authGuard]},
|
||||||
{path: 'custom-event', component: CustomEventComponent, canActivate: [authGuard]},
|
{path: 'custom-event', component: CustomEventComponent, canActivate: [authGuard]},
|
||||||
|
{path: 'custom-event-detail/:id', component: CustomEventDetailComponent, canActivate: [authGuard]},
|
||||||
{path: 'zombie-siege', component: ZombieSiegeComponent, canActivate: [authGuard]},
|
{path: 'zombie-siege', component: ZombieSiegeComponent, canActivate: [authGuard]},
|
||||||
{path: 'zombie-siege-detail/:id', component: ZombieSiegeDetailComponent, canActivate: [authGuard]},
|
{path: 'zombie-siege-detail/:id', component: ZombieSiegeDetailComponent, canActivate: [authGuard]},
|
||||||
{path: 'login', component: LoginComponent},
|
{path: 'login', component: LoginComponent},
|
||||||
|
|||||||
@ -50,6 +50,8 @@ import { UnderDevelopmentComponent } from './helpers/under-development/under-dev
|
|||||||
import { ZombieSiegeComponent } from './pages/zombie-siege/zombie-siege.component';
|
import { ZombieSiegeComponent } from './pages/zombie-siege/zombie-siege.component';
|
||||||
import { ZombieSiegeParticipantsModalComponent } from './modals/zombie-siege-participants-modal/zombie-siege-participants-modal.component';
|
import { ZombieSiegeParticipantsModalComponent } from './modals/zombie-siege-participants-modal/zombie-siege-participants-modal.component';
|
||||||
import { ZombieSiegeDetailComponent } from './pages/zombie-siege/zombie-siege-detail/zombie-siege-detail.component';
|
import { ZombieSiegeDetailComponent } from './pages/zombie-siege/zombie-siege-detail/zombie-siege-detail.component';
|
||||||
|
import { CustomEventParticipantsModelComponent } from './modals/custom-event-participants-model/custom-event-participants-model.component';
|
||||||
|
import { CustomEventDetailComponent } from './pages/custom-event/custom-event-detail/custom-event-detail.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -90,7 +92,9 @@ import { ZombieSiegeDetailComponent } from './pages/zombie-siege/zombie-siege-de
|
|||||||
UnderDevelopmentComponent,
|
UnderDevelopmentComponent,
|
||||||
ZombieSiegeComponent,
|
ZombieSiegeComponent,
|
||||||
ZombieSiegeParticipantsModalComponent,
|
ZombieSiegeParticipantsModalComponent,
|
||||||
ZombieSiegeDetailComponent
|
ZombieSiegeDetailComponent,
|
||||||
|
CustomEventParticipantsModelComponent,
|
||||||
|
CustomEventDetailComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
.check-box-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-color {
|
||||||
|
color: #43c315;
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
<div class="modal-header flex-column" xmlns="http://www.w3.org/1999/html">
|
||||||
|
<div class="d-flex justify-content-between align-items-center w-100">
|
||||||
|
<h4 class="modal-title">Select Player for Custom event</h4>
|
||||||
|
<button (click)="activeModal.dismiss()" aria-label="Close" class="btn-close" type="button"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
@if (!isParticipationEvent && !isPointEvent) {
|
||||||
|
<p class="text-danger">Please choose an event type like points, participation or both</p>
|
||||||
|
} @else {
|
||||||
|
@if (participantsForm) {
|
||||||
|
<form [formGroup]="participantsForm" class="row g-3">
|
||||||
|
<ng-container formArrayName="customEventParticipants">
|
||||||
|
@for (participant of customEventParticipants.controls; track participant; let i=$index) {
|
||||||
|
<ng-container [formGroupName]="i">
|
||||||
|
<div class="col-12 col-md-6 mb-4">
|
||||||
|
<div class="d-flex flex-column border p-3">
|
||||||
|
<h6 class="mb-2 text-color">{{participant.get('playerName')?.value}}</h6>
|
||||||
|
@if (isPointEvent) {
|
||||||
|
<div class="col mb-2">
|
||||||
|
<label for="point{{i}}">Achieved Points</label>
|
||||||
|
<input [ngClass]="{
|
||||||
|
'is-valid': participant.get('achievedPoints')?.valid,
|
||||||
|
'is-invalid': participant.get('achievedPoints')?.invalid && (participant.get('achievedPoints')?.touched || participant.get('achievedPoints')?.dirty)
|
||||||
|
}" type="number" min="0" class="form-control form-control-sm" id="point{{i}}" formControlName="achievedPoints">
|
||||||
|
@if (participant.get('achievedPoints')?.invalid && (participant.get('achievedPoints')?.touched || participant.get('achievedPoints')?.dirty)) {
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@if (participant.get('achievedPoints')?.hasError('required')){
|
||||||
|
<p>points is required</p>
|
||||||
|
}
|
||||||
|
@if (participant.get('achievedPoints')?.hasError('pattern')){
|
||||||
|
<p>points must not be less than 0</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isParticipationEvent) {
|
||||||
|
<div class="col">
|
||||||
|
<input class="form-check-input" id="participated{{i}}" formControlName="participated" type="checkbox">
|
||||||
|
<label class="form-check-label ps-2" for="participated{{i}}"> Participated</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
</ng-container>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@if (participantsForm) {
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button (click)="activeModal.dismiss()" class="btn btn-warning" type="button">Close</button>
|
||||||
|
<button (click)="onSubmit()" [disabled]="!isPointEvent && !isParticipationEvent || participantsForm.invalid"
|
||||||
|
class=" btn btn-success" type="submit">{{isUpdate ? 'Update Participants' : 'Add to event'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
import {Component, inject, Input, OnInit} from '@angular/core';
|
||||||
|
import {PlayerService} from "../../services/player.service";
|
||||||
|
import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";
|
||||||
|
import {PlayerModel} from "../../models/player.model";
|
||||||
|
import {FormArray, FormControl, FormGroup, Validators} from "@angular/forms";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-custom-event-participants-model',
|
||||||
|
templateUrl: './custom-event-participants-model.component.html',
|
||||||
|
styleUrl: './custom-event-participants-model.component.css'
|
||||||
|
})
|
||||||
|
export class CustomEventParticipantsModelComponent implements OnInit {
|
||||||
|
|
||||||
|
private readonly _playerService: PlayerService = inject(PlayerService);
|
||||||
|
|
||||||
|
public activeModal: NgbActiveModal = inject(NgbActiveModal);
|
||||||
|
|
||||||
|
public playerParticipated: {playerId: string, playerName: string, participated: boolean, achievedPoints: number}[] = [];
|
||||||
|
public participantsForm!: FormGroup;
|
||||||
|
public isUpdate: boolean = false;
|
||||||
|
|
||||||
|
@Input({required: true}) allianceId!: string;
|
||||||
|
@Input({required: true}) isPointEvent!: boolean;
|
||||||
|
@Input({required: true}) isParticipationEvent!: boolean;
|
||||||
|
@Input() players: {playerId: string, playerName: string, participated: boolean, achievedPoints: number}[] | undefined;
|
||||||
|
|
||||||
|
get customEventParticipants(): FormArray {
|
||||||
|
return this.participantsForm.get('customEventParticipants') as FormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.players) {
|
||||||
|
this.isUpdate = true;
|
||||||
|
this.playerParticipated = [...this.players];
|
||||||
|
this.createParticipantForm();
|
||||||
|
} else {
|
||||||
|
this.getPlayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlayers() {
|
||||||
|
this._playerService.getAlliancePlayer(this.allianceId).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
response.forEach((player: PlayerModel) => {
|
||||||
|
this.playerParticipated.push({playerId: player.id, playerName: player.playerName, participated: false, achievedPoints: 0});
|
||||||
|
});
|
||||||
|
this.playerParticipated.sort((a, b) => a.playerName.localeCompare(b.playerName));
|
||||||
|
}
|
||||||
|
this.createParticipantForm();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createParticipantForm() {
|
||||||
|
this.participantsForm = new FormGroup({
|
||||||
|
customEventParticipants: new FormArray([])
|
||||||
|
});
|
||||||
|
this.playerParticipated.forEach(player => {
|
||||||
|
this.customEventParticipants.push(new FormGroup({
|
||||||
|
id: new FormControl<string>(''),
|
||||||
|
playerId: new FormControl(player.playerId),
|
||||||
|
playerName: new FormControl<string>(player.playerName),
|
||||||
|
participated: new FormControl<boolean>(player.participated),
|
||||||
|
achievedPoints: new FormControl<number>(player.achievedPoints, [Validators.required, Validators.pattern('(0|[1-9]\\d*)')])
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
const participants = this.participantsForm.value.customEventParticipants;
|
||||||
|
this.activeModal.close(participants);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,12 +5,25 @@ export interface CustomEventModel {
|
|||||||
allianceId: string;
|
allianceId: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
isPointsEvent?: boolean;
|
isPointsEvent: boolean;
|
||||||
isParticipationEvent?: boolean;
|
isParticipationEvent: boolean;
|
||||||
eventDate: Date;
|
eventDate: Date;
|
||||||
isInProgress: boolean;
|
isInProgress: boolean;
|
||||||
|
createdBy: string;
|
||||||
|
modifiedBy?: string;
|
||||||
|
modifiedOn?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CustomEventDetailModel extends CustomEventModel {
|
export interface CustomEventDetailModel extends CustomEventModel {
|
||||||
customEventParticipants: CustomEventParticipantModel[];
|
customEventParticipants: CustomEventParticipantModel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateCustomEventModel {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
isPointsEvent: boolean;
|
||||||
|
isParticipationEvent: boolean;
|
||||||
|
eventDate: string;
|
||||||
|
allianceId: string;
|
||||||
|
isInProgress: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ export interface CustomEventParticipantModel {
|
|||||||
id: string;
|
id: string;
|
||||||
playerId: string;
|
playerId: string;
|
||||||
customEventId: string;
|
customEventId: string;
|
||||||
participated?: boolean;
|
participated: boolean;
|
||||||
achievedPoints?: number;
|
achievedPoints: number;
|
||||||
playerName: string;
|
playerName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
<div class="container mt-3 pb-5">
|
||||||
|
<!-- Back button-->
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto">
|
||||||
|
<button routerLink="/custom-event" class="btn btn-primary" type="button"><i class="bi bi-arrow-left"></i> Back</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (customEventDetail) {
|
||||||
|
<div class="card mt-5">
|
||||||
|
<h5 class="card-header text-center">
|
||||||
|
<div>{{customEventDetail.eventDate | date: 'dd.MM.yyyy'}}</div>
|
||||||
|
</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Name: <span class="text-primary">{{customEventDetail.name}}</span></h5>
|
||||||
|
<p class="card-text">Description: <span class="text-primary">{{customEventDetail.description}}</span></p>
|
||||||
|
<p class="card-text">Point event:
|
||||||
|
<i class="bi " [ngClass]="customEventDetail.isPointsEvent ? 'bi-check-lg text-success' : 'bi-x-lg text-danger'"></i>
|
||||||
|
</p>
|
||||||
|
<p class="card-text">Participation event:
|
||||||
|
<i class="bi " [ngClass]="customEventDetail.isParticipationEvent ? 'bi-check-lg text-success' : 'bi-x-lg text-danger'"></i>
|
||||||
|
</p>
|
||||||
|
@if (customEventDetail.isParticipationEvent) {
|
||||||
|
<p class="card-text">Participation rate: <ngb-progressbar class="mb-3" type="success" [value]="participatedPlayers" [max]="customEventDetail.customEventParticipants.length" [showValue]="true" /></p>
|
||||||
|
|
||||||
|
}
|
||||||
|
<p class="card-text">Status:
|
||||||
|
@if (customEventDetail.isInProgress) {
|
||||||
|
<span class="text-primary"> In Progress</span>
|
||||||
|
} @else {
|
||||||
|
<span class="text-primary"> Done</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<p class="card-text">Creator: <span class="text-primary">{{customEventDetail.createdBy}}</span></p>
|
||||||
|
@if (customEventDetail.modifiedOn) {
|
||||||
|
<p class="card-text">Modified: <span class="text-primary">{{customEventDetail.modifiedOn | date: 'dd.MM.yyyy HH:mm'}}</span>
|
||||||
|
by <span class="text-primary">{{customEventDetail.modifiedBy}}</span></p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<p class="card-text text-center">Participants</p>
|
||||||
|
<div ngbScrollSpy class="bg-light p-3 rounded-2 mb-3" style="height: 200px">
|
||||||
|
<div class="row">
|
||||||
|
@for (player of customEventDetail.customEventParticipants; track player.id) {
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6 mb-4">
|
||||||
|
<div class="d-flex flex-column border p-3">
|
||||||
|
<h6 class="mb-1 text-success">{{player.playerName}}</h6>
|
||||||
|
@if (customEventDetail.isPointsEvent) {
|
||||||
|
<div class="col mb-1">
|
||||||
|
Achieved Points: <span class="text-primary">{{player.achievedPoints}}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (customEventDetail.isParticipationEvent) {
|
||||||
|
<div class="col">
|
||||||
|
Participated: <i class="bi " [ngClass]="player.participated ? 'bi-check-lg text-success' : 'bi-x-lg text-danger'"></i>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import {Component, inject, OnInit} from '@angular/core';
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
import {CustomEventService} from "../../../services/custom-event.service";
|
||||||
|
import {CustomEventDetailModel} from "../../../models/customEvent.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-custom-event-detail',
|
||||||
|
templateUrl: './custom-event-detail.component.html',
|
||||||
|
styleUrl: './custom-event-detail.component.css'
|
||||||
|
})
|
||||||
|
export class CustomEventDetailComponent implements OnInit {
|
||||||
|
|
||||||
|
private readonly _activatedRote: ActivatedRoute = inject(ActivatedRoute);
|
||||||
|
private readonly _customEventService: CustomEventService = inject(CustomEventService);
|
||||||
|
|
||||||
|
private customEventId!: string;
|
||||||
|
|
||||||
|
public customEventDetail: CustomEventDetailModel | undefined;
|
||||||
|
public participatedPlayers: number = 0;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.customEventId = this._activatedRote.snapshot.params['id'];
|
||||||
|
|
||||||
|
if (!this.customEventId) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
this.getCustomEventDetail(this.customEventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomEventDetail(customEventId: string) {
|
||||||
|
this._customEventService.getCustomEventDetail(customEventId).subscribe({
|
||||||
|
next: ((response: CustomEventDetailModel) => {
|
||||||
|
if (response) {
|
||||||
|
this.participatedPlayers = 0;
|
||||||
|
this.customEventDetail = response;
|
||||||
|
if (this.customEventDetail.isParticipationEvent) {
|
||||||
|
this.customEventDetail.customEventParticipants.forEach((player) => {
|
||||||
|
if (player.participated) {
|
||||||
|
this.participatedPlayers++;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,155 @@
|
|||||||
<div class="container mt-3 pb-5">
|
<div class="container mt-3 pb-5">
|
||||||
<h2 class="text-center">Custom Event</h2>
|
<h2 class="text-center">Custom Event</h2>
|
||||||
|
|
||||||
<app-under-development></app-under-development>
|
@if (!isCreateCustomEvent) {
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto">
|
||||||
|
<button (click)="onCreateEvent()" class="btn btn-primary" type="button">Create new Event</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (isCreateCustomEvent) {
|
||||||
|
<form [formGroup]="customEventForm">
|
||||||
|
<!-- Event date-->
|
||||||
|
<div class="form-floating mb-3 is-invalid">
|
||||||
|
<input [ngClass]="{
|
||||||
|
'is-invalid': f['eventDate'].invalid && (f['eventDate'].dirty || f['eventDate'].touched),
|
||||||
|
'is-valid': f['eventDate'].valid}"
|
||||||
|
type="date" class="form-control" id="eventDate" placeholder="eventDate" formControlName="eventDate">
|
||||||
|
<label for="eventDate">Event date</label>
|
||||||
|
@if (f['eventDate'].invalid && (f['eventDate'].dirty || f['eventDate'].touched)) {
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@if (f['eventDate'].hasError('required')) {
|
||||||
|
<p>eventDate is required</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<!-- Event name-->
|
||||||
|
<div class="form-floating mb-3 is-invalid">
|
||||||
|
<input [ngClass]="{
|
||||||
|
'is-invalid': f['name'].invalid && (f['name'].dirty || f['name'].touched),
|
||||||
|
'is-valid': f['name'].valid}"
|
||||||
|
type="text" class="form-control" maxlength="151" id="name" placeholder="name" formControlName="name">
|
||||||
|
<label for="name">Event name</label>
|
||||||
|
@if (f['name'].invalid && (f['name'].dirty || f['name'].touched)) {
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@if (f['name'].hasError('required')) {
|
||||||
|
<p>Name is required</p>
|
||||||
|
}
|
||||||
|
@if (f['name'].hasError('maxlength')) {
|
||||||
|
<p>Maximum 150 characters allowed</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<!-- Description-->
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea [ngClass]="{
|
||||||
|
'is-valid': f['description'].valid,
|
||||||
|
'is-invalid': f['description'].invalid && (f['description'].touched || f['description'].dirty)
|
||||||
|
}" class="form-control" maxlength="501" formControlName="description" placeholder="description" id="description" style="height: 100px"></textarea>
|
||||||
|
<label for="description">description</label>
|
||||||
|
@if (f['description'].invalid && (f['description'].touched || f['description'].dirty)) {
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@if (f['description'].hasError('required')) {
|
||||||
|
<p>Description is required</p>
|
||||||
|
}
|
||||||
|
@if (f['description'].hasError('maxlength')) {
|
||||||
|
<p>Maximum 500 characters allowed</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<!-- In progress-->
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" formControlName="isInProgress" id="isInProgress">
|
||||||
|
<label class="form-check-label" for="isInProgress">
|
||||||
|
In Progress
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- Is point event-->
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" formControlName="isPointsEvent" id="isPointsEvent">
|
||||||
|
<label class="form-check-label" for="isPointsEvent">
|
||||||
|
Points Event
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- Is participation event-->
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" formControlName="isParticipationEvent" id="isParticipationEvent">
|
||||||
|
<label class="form-check-label" for="isParticipationEvent">
|
||||||
|
Participation Event
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@if (!playerSelected) {
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<p class="text-warning">Please add participants</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto">
|
||||||
|
<button (click)="onAddParticipants()" class="btn btn-primary" type="button">{{isUpdate ? 'Update Participants' : 'Add Participants'}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<button (click)="onCancel()" type="button" class="btn btn-warning">Cancel</button>
|
||||||
|
<button [disabled]="customEventForm.invalid || playerParticipated.length <= 0" (click)="onSubmit()" type="submit" class="btn btn-success">{{isUpdate ? 'Update': 'Create'}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (!isCreateCustomEvent) {
|
||||||
|
@if (customEvents.length > 0) {
|
||||||
|
<div class="table-responsive mt-5">
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Event Date</th>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Point event</th>
|
||||||
|
<th scope="col">Participation event</th>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<th scope="col">Creator</th>
|
||||||
|
<th scope="col">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (customEvent of customEvents; track customEvent.id) {
|
||||||
|
<tr>
|
||||||
|
<td>{{customEvent.eventDate | date: 'dd.MM.yyyy'}}</td>
|
||||||
|
<td>{{customEvent.name}}</td>
|
||||||
|
<td>
|
||||||
|
<i class="bi " [ngClass]="customEvent.isPointsEvent ? 'bi-check-lg text-success' : 'bi-x-lg text-danger'"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<i class="bi " [ngClass]="customEvent.isParticipationEvent ? 'bi-check-lg text-success' : 'bi-x-lg text-danger'"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if (customEvent.isInProgress) {
|
||||||
|
<i class="bi bi-hourglass-split"></i> In Progress
|
||||||
|
} @else {
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>{{customEvent.createdBy}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex gap-3 justify-content-around">
|
||||||
|
<i (click)="onGoToCustomEventDetail(customEvent)" class="bi custom-info-icon bi-info-circle-fill"></i>
|
||||||
|
<i (click)="onEditCustomEvent(customEvent)" class="bi custom-edit-icon bi-pencil-fill"></i>
|
||||||
|
<i (click)="onDeleteCustomEvent(customEvent)" class="bi custom-delete-icon bi-trash3"></i>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<div class="alert alert-secondary text-center mt-5" role="alert">
|
||||||
|
No saved custom events
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,10 +1,257 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, inject, OnInit} from '@angular/core';
|
||||||
|
import {FormControl, FormGroup, Validators} from "@angular/forms";
|
||||||
|
import {JwtTokenService} from "../../services/jwt-token.service";
|
||||||
|
import {CreateCustomEventModel, CustomEventDetailModel, CustomEventModel} from "../../models/customEvent.model";
|
||||||
|
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||||
|
import {
|
||||||
|
CustomEventParticipantsModelComponent
|
||||||
|
} from "../../modals/custom-event-participants-model/custom-event-participants-model.component";
|
||||||
|
import {CustomEventService} from "../../services/custom-event.service";
|
||||||
|
import {CustomEventParticipantModel} from "../../models/customEventParticipant.model";
|
||||||
|
import {CustomEventParticipantService} from "../../services/custom-event-participant.service";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
import {forkJoin, Observable} from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-custom-event',
|
selector: 'app-custom-event',
|
||||||
templateUrl: './custom-event.component.html',
|
templateUrl: './custom-event.component.html',
|
||||||
styleUrl: './custom-event.component.css'
|
styleUrl: './custom-event.component.css'
|
||||||
})
|
})
|
||||||
export class CustomEventComponent {
|
export class CustomEventComponent implements OnInit {
|
||||||
|
|
||||||
|
customEvents: CustomEventModel[] = [];
|
||||||
|
customEventDetail!: CustomEventDetailModel;
|
||||||
|
isCreateCustomEvent: boolean = false;
|
||||||
|
customEventForm!: FormGroup;
|
||||||
|
playerSelected: boolean = false;
|
||||||
|
playerParticipated: { playerId: string, playerName: string, participated: boolean, achievedPoints: number }[] = [];
|
||||||
|
customEventParticipants: CustomEventParticipantModel[] = [];
|
||||||
|
isUpdate: boolean = false;
|
||||||
|
private readonly _tokenService: JwtTokenService = inject(JwtTokenService);
|
||||||
|
private readonly _modalService: NgbModal = inject(NgbModal);
|
||||||
|
private readonly _customEventService: CustomEventService = inject(CustomEventService);
|
||||||
|
private readonly _customEventParticipantService: CustomEventParticipantService = inject(CustomEventParticipantService);
|
||||||
|
private readonly _router: Router = inject(Router);
|
||||||
|
private readonly _toastr: ToastrService = inject(ToastrService);
|
||||||
|
private allianceId: string = this._tokenService.getAllianceId()!;
|
||||||
|
|
||||||
|
get f() {
|
||||||
|
return this.customEventForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.getCustomEvents(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomEvents(take: number) {
|
||||||
|
this.customEvents = [];
|
||||||
|
this._customEventService.getAllianceCustomEvents(this.allianceId, take).subscribe({
|
||||||
|
next: ((response: CustomEventModel[]) => {
|
||||||
|
if (response) {
|
||||||
|
this.customEvents = response;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
error: (error) => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onCreateEvent() {
|
||||||
|
this.createCustomEventForm(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createCustomEventForm(isUpdate: boolean, customEventDetail: CustomEventDetailModel | null = null) {
|
||||||
|
if (isUpdate) {
|
||||||
|
this.playerSelected = true;
|
||||||
|
this.playerParticipated = [...customEventDetail!.customEventParticipants];
|
||||||
|
} else {
|
||||||
|
this.playerSelected = false;
|
||||||
|
}
|
||||||
|
const d = isUpdate ? new Date(customEventDetail!.eventDate) : new Date();
|
||||||
|
this.customEventForm = new FormGroup({
|
||||||
|
id: new FormControl<string>(isUpdate ? customEventDetail!.id : ''),
|
||||||
|
allianceId: new FormControl<string>(this.allianceId),
|
||||||
|
name: new FormControl<string>(isUpdate ? customEventDetail!.name : '', [Validators.required, Validators.maxLength(150)]),
|
||||||
|
description: new FormControl<string>(isUpdate ? customEventDetail!.description : '', [Validators.required, Validators.maxLength(500)]),
|
||||||
|
isPointsEvent: new FormControl<boolean>(isUpdate ? customEventDetail!.isPointsEvent : false),
|
||||||
|
isParticipationEvent: new FormControl(isUpdate ? customEventDetail!.isParticipationEvent : false),
|
||||||
|
eventDate: new FormControl<string>(new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())).toISOString().substring(0, 10)),
|
||||||
|
isInProgress: new FormControl<boolean>(isUpdate ? customEventDetail!.isInProgress : true)
|
||||||
|
});
|
||||||
|
this.isCreateCustomEvent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddParticipants() {
|
||||||
|
const modalRef = this._modalService.open(CustomEventParticipantsModelComponent,
|
||||||
|
{animation: true, backdrop: 'static', centered: true, size: 'lg', scrollable: true});
|
||||||
|
if (this.playerSelected) {
|
||||||
|
this.playerParticipated.sort((a, b) => a.playerName.localeCompare(b.playerName));
|
||||||
|
modalRef.componentInstance.players = [...this.playerParticipated];
|
||||||
|
}
|
||||||
|
modalRef.componentInstance.allianceId = this.allianceId;
|
||||||
|
modalRef.componentInstance.isParticipationEvent = this.customEventForm.controls['isParticipationEvent'].value;
|
||||||
|
modalRef.componentInstance.isPointEvent = this.customEventForm.controls['isPointsEvent'].value;
|
||||||
|
modalRef.closed.subscribe({
|
||||||
|
next: ((response: any[]) => {
|
||||||
|
if (response) {
|
||||||
|
this.playerSelected = true;
|
||||||
|
this.playerParticipated = [...response];
|
||||||
|
this.playerParticipated.sort((a, b) => a.playerName.localeCompare(b.playerName));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {
|
||||||
|
this.isUpdate = false;
|
||||||
|
this.isCreateCustomEvent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
if (this.customEventForm.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isUpdate) {
|
||||||
|
this.updateCustomEvent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const customEvent: CreateCustomEventModel = this.customEventForm.value as CreateCustomEventModel;
|
||||||
|
this._customEventService.createCustomEvent(customEvent).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
this.insertCustomEventParticipants(response.id);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
error: ((error: any) => {
|
||||||
|
console.error(error);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
insertCustomEventParticipants(customEventId: string) {
|
||||||
|
const customEventParticipants: CustomEventParticipantModel[] = [];
|
||||||
|
this.playerParticipated.forEach((player) => {
|
||||||
|
const participant: CustomEventParticipantModel = {
|
||||||
|
id: '',
|
||||||
|
customEventId: customEventId,
|
||||||
|
participated: player.participated,
|
||||||
|
playerId: player.playerId,
|
||||||
|
achievedPoints: player.achievedPoints,
|
||||||
|
playerName: player.playerName
|
||||||
|
};
|
||||||
|
customEventParticipants.push(participant);
|
||||||
|
});
|
||||||
|
this._customEventParticipantService.insertCustomEventParticipants(customEventParticipants).subscribe({
|
||||||
|
next: (() => {
|
||||||
|
this.playerParticipated = [];
|
||||||
|
this.onCancel();
|
||||||
|
this.getCustomEvents(10);
|
||||||
|
}),
|
||||||
|
error: (error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onGoToCustomEventDetail(customEvent: CustomEventModel) {
|
||||||
|
this._router.navigate(['custom-event-detail', customEvent.id]).then();
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditCustomEvent(customEvent: CustomEventModel) {
|
||||||
|
this._customEventService.getCustomEventDetail(customEvent.id).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
this.customEventParticipants = structuredClone(response.customEventParticipants);
|
||||||
|
this.isUpdate = true;
|
||||||
|
this.createCustomEventForm(true, response);
|
||||||
|
|
||||||
|
this.customEventDetail = response;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteCustomEvent(customEvent: CustomEventModel) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Delete Custom event ?",
|
||||||
|
text: `Do you really want to delete the custom event`,
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: "#3085d6",
|
||||||
|
cancelButtonColor: "#d33",
|
||||||
|
confirmButtonText: "Yes, delete it!"
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
this._customEventService.deleteCustomEvent(customEvent.id).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Deleted!",
|
||||||
|
text: "Custom event has been deleted",
|
||||||
|
icon: "success"
|
||||||
|
}).then(_ => this.getCustomEvents(10));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
error: (error: Error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateCustomEvent() {
|
||||||
|
const participantsToUpdate: any[] = [];
|
||||||
|
const customEvent: CustomEventModel = this.customEventForm.value as CustomEventModel;
|
||||||
|
this.customEventParticipants.forEach((participant) => {
|
||||||
|
const player = this.playerParticipated.find(p => p.playerId === participant.playerId);
|
||||||
|
if (player!.participated !== participant.participated || player!.achievedPoints !== participant.achievedPoints) {
|
||||||
|
const playerToUpdate: CustomEventParticipantModel = {
|
||||||
|
playerId: player!.playerId,
|
||||||
|
achievedPoints: player!.achievedPoints,
|
||||||
|
playerName: player!.playerName,
|
||||||
|
participated: player!.participated,
|
||||||
|
id: participant.id,
|
||||||
|
customEventId: participant.customEventId,
|
||||||
|
}
|
||||||
|
participantsToUpdate.push(playerToUpdate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._customEventService.updateCustomEvent(customEvent.id, customEvent).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
this.updateCustomEventParticipants(participantsToUpdate);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateCustomEventParticipants(participantsToUpdate: any[]) {
|
||||||
|
if (participantsToUpdate.length <= 0) {
|
||||||
|
this._toastr.success('Successfully updated!', 'Successfully');
|
||||||
|
this.onCancel();
|
||||||
|
this.getCustomEvents(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requests: Observable<CustomEventParticipantModel>[] = [];
|
||||||
|
participantsToUpdate.forEach(participant => {
|
||||||
|
const request = this._customEventParticipantService.updateCustomEventParticipant(participant.id, participant);
|
||||||
|
requests.push(request);
|
||||||
|
})
|
||||||
|
forkJoin(requests).subscribe({
|
||||||
|
next: ((response) => {
|
||||||
|
if (response) {
|
||||||
|
this._toastr.success('Successfully updated!', 'Successfully');
|
||||||
|
this.onCancel();
|
||||||
|
this.getCustomEvents(10);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
Ui/src/app/services/custom-event-participant.service.ts
Normal file
23
Ui/src/app/services/custom-event-participant.service.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {inject, Injectable} from '@angular/core';
|
||||||
|
import {environment} from "../../environments/environment";
|
||||||
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {CustomEventParticipantModel} from "../models/customEventParticipant.model";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CustomEventParticipantService {
|
||||||
|
|
||||||
|
private readonly _serviceUrl = environment.apiBaseUrl + 'customEventParticipants/';
|
||||||
|
private readonly _httpClient: HttpClient = inject(HttpClient);
|
||||||
|
|
||||||
|
insertCustomEventParticipants(customEventParticipants: CustomEventParticipantModel[]): Observable<void> {
|
||||||
|
return this._httpClient.post<void>(this._serviceUrl, customEventParticipants);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCustomEventParticipant(customEventParticipantId: string, customEventParticipantModel: CustomEventParticipantModel): Observable<CustomEventParticipantModel> {
|
||||||
|
return this._httpClient.put<CustomEventParticipantModel>(this._serviceUrl + customEventParticipantId, customEventParticipantModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
38
Ui/src/app/services/custom-event.service.ts
Normal file
38
Ui/src/app/services/custom-event.service.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {inject, Injectable} from '@angular/core';
|
||||||
|
import {environment} from "../../environments/environment";
|
||||||
|
import {HttpClient, HttpParams} from "@angular/common/http";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {CreateCustomEventModel, CustomEventDetailModel, CustomEventModel} from "../models/customEvent.model";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CustomEventService {
|
||||||
|
|
||||||
|
private readonly _serviceUrl = environment.apiBaseUrl + 'customEvents/';
|
||||||
|
private readonly _httpClient: HttpClient = inject(HttpClient);
|
||||||
|
|
||||||
|
|
||||||
|
getAllianceCustomEvents(allianceId: string, take: number): Observable<CustomEventModel[]> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
params = params.append('take', take);
|
||||||
|
return this._httpClient.get<CustomEventModel[]>(this._serviceUrl + 'Alliance/' + allianceId, {params: params});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomEventDetail(customEventId: string): Observable<CustomEventDetailModel> {
|
||||||
|
return this._httpClient.get<CustomEventDetailModel>(this._serviceUrl + 'GetCustomEventDetail/' + customEventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
createCustomEvent(customEvent: CreateCustomEventModel): Observable<CustomEventModel> {
|
||||||
|
return this._httpClient.post<CustomEventModel>(this._serviceUrl, customEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCustomEvent(customEventId: string, customEvent: CustomEventModel): Observable<CustomEventModel> {
|
||||||
|
return this._httpClient.put<CustomEventModel>(this._serviceUrl + customEventId, customEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCustomEvent(customEventId: string): Observable<boolean> {
|
||||||
|
return this._httpClient.delete<boolean>(this._serviceUrl + customEventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user