mirror of
https://github.com/TomasiDeveloping/PlayerManagement.git
synced 2026-04-16 09:12:20 +00:00
v. 0.11.0
This commit is contained in:
parent
fa3a0ec218
commit
bfbb030cb2
37
Api/Controllers/v1/SquadTypesController.cs
Normal file
37
Api/Controllers/v1/SquadTypesController.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Application.DataTransferObjects.SquadType;
|
||||
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 SquadTypesController(ISquadTypeRepository squadTypeRepository, ILogger<SquadTypesController> logger)
|
||||
: ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<SquadTypeDto>>> GetSquadTypes(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var squadTypesResult = await squadTypeRepository.GetSquadTypesAsync(cancellationToken);
|
||||
if (squadTypesResult.IsFailure) return BadRequest(squadTypesResult.Error);
|
||||
return squadTypesResult.Value.Count > 0
|
||||
? Ok(squadTypesResult.Value)
|
||||
: NoContent();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{ErrorMessage}", e.Message);
|
||||
return Problem(
|
||||
detail: $"Failed to process {nameof(GetSquadTypes)}",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Internal server error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Api/Controllers/v1/SquadsController.cs
Normal file
106
Api/Controllers/v1/SquadsController.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using Application.DataTransferObjects.Squad;
|
||||
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 SquadsController(ISquadRepository squadRepository, ILogger<SquadsController> logger) : ControllerBase
|
||||
{
|
||||
[HttpGet("player/{playerId:guid}")]
|
||||
public async Task<ActionResult<List<SquadDto>>> GetPlayerSquads(Guid playerId, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playerSquadsResult = await squadRepository.GetPlayerSquadsAsync(playerId, cancellationToken);
|
||||
|
||||
if (playerSquadsResult.IsFailure) return BadRequest(playerSquadsResult.Error);
|
||||
|
||||
return playerSquadsResult.Value.Count > 0
|
||||
? Ok(playerSquadsResult.Value)
|
||||
: NoContent();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{ErrorMessage}", e.Message);
|
||||
return Problem(
|
||||
detail: $"Failed to process {nameof(GetPlayerSquads)}",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Internal server error");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<SquadDto>> CreateSquad(CreateSquadDto createSquadDto,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ModelState.IsValid) return UnprocessableEntity(ModelState);
|
||||
|
||||
var createSquadResult = await squadRepository.CreateSquadAsync(createSquadDto, cancellationToken);
|
||||
|
||||
return createSquadResult.IsSuccess
|
||||
? Ok(createSquadResult.Value)
|
||||
: BadRequest(createSquadResult.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{ErrorMessage}", e.Message);
|
||||
return Problem(
|
||||
detail: $"Failed to process {nameof(GetPlayerSquads)}",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Internal server error");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut("{squadId:guid}")]
|
||||
public async Task<ActionResult<SquadDto>> UpdateSquad(Guid squadId, UpdateSquadDto updateSquadDto, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ModelState.IsValid) return UnprocessableEntity(ModelState);
|
||||
|
||||
var updateSquadResult = await squadRepository.UpdateSquadAsync(updateSquadDto, cancellationToken);
|
||||
return updateSquadResult.IsSuccess
|
||||
? Ok(updateSquadResult.Value)
|
||||
: BadRequest(updateSquadResult.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{ErrorMessage}", e.Message);
|
||||
return Problem(
|
||||
detail: $"Failed to process {nameof(UpdateSquad)}",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Internal server error");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete("{squadId:guid}")]
|
||||
public async Task<ActionResult<bool>> DeleteSquad(Guid squadId, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var deleteSquadResult = await squadRepository.DeleteSquadAsync(squadId, cancellationToken);
|
||||
|
||||
return deleteSquadResult.IsSuccess
|
||||
? Ok(deleteSquadResult.Value)
|
||||
: BadRequest(deleteSquadResult.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{ErrorMessage}", e.Message);
|
||||
return Problem(
|
||||
detail: $"Failed to process {nameof(DeleteSquad)}",
|
||||
statusCode: StatusCodes.Status500InternalServerError,
|
||||
title: "Internal server error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
using Api.Helpers;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Api.Controllers.v1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
public class ValuesController : ControllerBase
|
||||
{
|
||||
[AllowApiKey]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Test([FromQuery] Guid allianceId, [FromQuery] string? key)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
AllianceId = allianceId,
|
||||
Key = key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,6 +37,8 @@ public static class ApplicationDependencyInjection
|
||||
services.AddScoped<ICustomEventCategoryRepository, CustomEventCategoryRepository>();
|
||||
services.AddScoped<ICustomEventLeaderBoardRepository, CustomEventLeaderboardRepository>();
|
||||
services.AddScoped<IStatRepository, StatRepository>();
|
||||
services.AddScoped<ISquadTypeRepository, SquadTypeRepository>();
|
||||
services.AddScoped<ISquadRepository, SquadRepository>();
|
||||
|
||||
|
||||
services.AddTransient<IJwtService, JwtService>();
|
||||
|
||||
12
Application/DataTransferObjects/Squad/CreateSquadDto.cs
Normal file
12
Application/DataTransferObjects/Squad/CreateSquadDto.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Application.DataTransferObjects.Squad;
|
||||
|
||||
public class CreateSquadDto
|
||||
{
|
||||
public Guid SquadTypeId { get; set; }
|
||||
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public decimal Power { get; set; }
|
||||
|
||||
public int Position { get; set; }
|
||||
}
|
||||
19
Application/DataTransferObjects/Squad/SquadDto.cs
Normal file
19
Application/DataTransferObjects/Squad/SquadDto.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace Application.DataTransferObjects.Squad;
|
||||
|
||||
public class SquadDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid SquadTypeId { get; set; }
|
||||
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public required string TypeName { get; set; }
|
||||
|
||||
public decimal Power { get; set; }
|
||||
|
||||
public int Position { get; set; }
|
||||
|
||||
public DateTime LastUpdateAt { get; set; }
|
||||
|
||||
}
|
||||
14
Application/DataTransferObjects/Squad/UpdateSquadDto.cs
Normal file
14
Application/DataTransferObjects/Squad/UpdateSquadDto.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Application.DataTransferObjects.Squad;
|
||||
|
||||
public class UpdateSquadDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid SquadTypeId { get; set; }
|
||||
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public decimal Power { get; set; }
|
||||
|
||||
public int Position { get; set; }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
namespace Application.DataTransferObjects.SquadType;
|
||||
|
||||
public class SquadTypeDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public required string TypeName { get; set; }
|
||||
|
||||
}
|
||||
9
Application/Errors/SquadErrors.cs
Normal file
9
Application/Errors/SquadErrors.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Application.Errors;
|
||||
|
||||
public class SquadErrors
|
||||
{
|
||||
public static readonly Error NotFound = new("Error.Squad.NotFound",
|
||||
"The quad with the specified identifier was not found");
|
||||
|
||||
public static readonly Error IdConflict = new("Error.Note.IdConflict", "There is a conflict with the id's");
|
||||
}
|
||||
15
Application/Interfaces/ISquadRepository.cs
Normal file
15
Application/Interfaces/ISquadRepository.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Application.Classes;
|
||||
using Application.DataTransferObjects.Squad;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface ISquadRepository
|
||||
{
|
||||
Task<Result<List<SquadDto>>> GetPlayerSquadsAsync(Guid playerId, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Result<SquadDto>> CreateSquadAsync(CreateSquadDto createSquadDto, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Result<SquadDto>> UpdateSquadAsync(UpdateSquadDto updateSquadDto, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Result<bool>> DeleteSquadAsync(Guid squadId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
9
Application/Interfaces/ISquadTypeRepository.cs
Normal file
9
Application/Interfaces/ISquadTypeRepository.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using Application.Classes;
|
||||
using Application.DataTransferObjects.SquadType;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface ISquadTypeRepository
|
||||
{
|
||||
Task<Result<List<SquadTypeDto>>> GetSquadTypesAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
21
Application/Profiles/SquadProfile.cs
Normal file
21
Application/Profiles/SquadProfile.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using Application.DataTransferObjects.Squad;
|
||||
using AutoMapper;
|
||||
using Database.Entities;
|
||||
|
||||
namespace Application.Profiles;
|
||||
|
||||
public class SquadProfile : Profile
|
||||
{
|
||||
public SquadProfile()
|
||||
{
|
||||
CreateMap<Squad, SquadDto>()
|
||||
.ForMember(des => des.TypeName, opt => opt.MapFrom(src => src.SquadType.TypeName));
|
||||
|
||||
CreateMap<CreateSquadDto, Squad>()
|
||||
.ForMember(dest => dest.LastUpdateAt, opt => opt.MapFrom(src => DateTime.UtcNow))
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => Guid.CreateVersion7()));
|
||||
|
||||
CreateMap<UpdateSquadDto, Squad>()
|
||||
.ForMember(des => des.LastUpdateAt, opt => opt.MapFrom(src => DateTime.UtcNow));
|
||||
}
|
||||
}
|
||||
13
Application/Profiles/SquadTypeProfile.cs
Normal file
13
Application/Profiles/SquadTypeProfile.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Application.DataTransferObjects.SquadType;
|
||||
using AutoMapper;
|
||||
using Database.Entities;
|
||||
|
||||
namespace Application.Profiles;
|
||||
|
||||
public class SquadTypeProfile : Profile
|
||||
{
|
||||
public SquadTypeProfile()
|
||||
{
|
||||
CreateMap<SquadType, SquadTypeDto>();
|
||||
}
|
||||
}
|
||||
91
Application/Repositories/SquadRepository.cs
Normal file
91
Application/Repositories/SquadRepository.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using Application.Classes;
|
||||
using Application.DataTransferObjects.Squad;
|
||||
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 SquadRepository(ApplicationContext dbContext, IMapper mapper, ILogger<SquadRepository> logger) : ISquadRepository
|
||||
{
|
||||
public async Task<Result<List<SquadDto>>> GetPlayerSquadsAsync(Guid playerId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var playerSquads = await dbContext.Squads
|
||||
.Where(squad => squad.PlayerId == playerId)
|
||||
.ProjectTo<SquadDto>(mapper.ConfigurationProvider)
|
||||
.OrderBy(squad => squad.Position)
|
||||
.AsNoTracking()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Success(playerSquads);
|
||||
}
|
||||
|
||||
public async Task<Result<SquadDto>> CreateSquadAsync(CreateSquadDto createSquadDto, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newSuad = mapper.Map<Squad>(createSquadDto);
|
||||
|
||||
await dbContext.Squads.AddAsync(newSuad, cancellationToken);
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Result.Success(mapper.Map<SquadDto>(newSuad));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{DatabaseException}", e.Message);
|
||||
return Result.Failure<SquadDto>(GeneralErrors.DatabaseError);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<SquadDto>> UpdateSquadAsync(UpdateSquadDto updateSquadDto, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var squadToUpdate = await dbContext.Squads
|
||||
.FirstOrDefaultAsync(squad => squad.Id == updateSquadDto.Id, cancellationToken);
|
||||
|
||||
if (squadToUpdate is null) return Result.Failure<SquadDto>(SquadErrors.NotFound);
|
||||
|
||||
mapper.Map(updateSquadDto, squadToUpdate);
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Result.Success(mapper.Map<SquadDto>(squadToUpdate));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{DatabaseException}", e.Message);
|
||||
return Result.Failure<SquadDto>(GeneralErrors.DatabaseError);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result<bool>> DeleteSquadAsync(Guid squadId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var squadToDelete = await dbContext.Squads
|
||||
.FirstOrDefaultAsync(squad => squad.Id == squadId, cancellationToken);
|
||||
|
||||
if (squadToDelete is null) return Result.Failure<bool>(SquadErrors.NotFound);
|
||||
|
||||
dbContext.Squads.Remove(squadToDelete);
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Result.Success(mapper.Map<bool>(true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "{DatabaseException}", e.Message);
|
||||
return Result.Failure<bool>(GeneralErrors.DatabaseError);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Application/Repositories/SquadTypeRepository.cs
Normal file
22
Application/Repositories/SquadTypeRepository.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using Application.Classes;
|
||||
using Application.DataTransferObjects.SquadType;
|
||||
using Application.Interfaces;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Application.Repositories;
|
||||
|
||||
public class SquadTypeRepository(ApplicationContext dbContext, IMapper mapper) : ISquadTypeRepository
|
||||
{
|
||||
public async Task<Result<List<SquadTypeDto>>> GetSquadTypesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var squadTypes = await dbContext.SquadTypes
|
||||
.ProjectTo<SquadTypeDto>(mapper.ConfigurationProvider)
|
||||
.AsNoTracking()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Success(squadTypes);
|
||||
}
|
||||
}
|
||||
@ -46,6 +46,10 @@ public class ApplicationContext(DbContextOptions<ApplicationContext> options) :
|
||||
|
||||
public DbSet<CustomEventCategory> CustomEventCategories { get; set; }
|
||||
|
||||
public DbSet<Squad> Squads { get; set; }
|
||||
|
||||
public DbSet<SquadType> SquadTypes { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
|
||||
28
Database/Configurations/SquadConfiguration.cs
Normal file
28
Database/Configurations/SquadConfiguration.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Database.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Database.Configurations;
|
||||
|
||||
public class SquadConfiguration : IEntityTypeConfiguration<Squad>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Squad> builder)
|
||||
{
|
||||
builder.HasKey(squad => squad.Id);
|
||||
builder.Property(squad => squad.Id).ValueGeneratedNever();
|
||||
|
||||
builder.Property(squad => squad.Power).IsRequired().HasPrecision(18,2);
|
||||
builder.Property(squad => squad.Position).IsRequired();
|
||||
builder.Property(squad => squad.LastUpdateAt).IsRequired();
|
||||
|
||||
builder.HasOne(squad => squad.SquadType)
|
||||
.WithMany(squadType => squadType.Squads)
|
||||
.HasForeignKey(squad => squad.SquadTypeId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(squatType => squatType.Player)
|
||||
.WithMany(player => player.Squads)
|
||||
.HasForeignKey(squad => squad.PlayerId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
46
Database/Configurations/SquadTypeConfiguration.cs
Normal file
46
Database/Configurations/SquadTypeConfiguration.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using Database.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Database.Configurations;
|
||||
|
||||
public class SquadTypeConfiguration : IEntityTypeConfiguration<SquadType>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SquadType> builder)
|
||||
{
|
||||
builder.HasKey(squadType => squadType.Id);
|
||||
builder.Property(squadType => squadType.Id).ValueGeneratedNever();
|
||||
|
||||
builder.Property(squadType => squadType.TypeName)
|
||||
.IsRequired()
|
||||
.HasMaxLength(150);
|
||||
|
||||
var squadTypes = new List<SquadType>()
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = Guid.CreateVersion7(),
|
||||
TypeName = "Tanks"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = Guid.CreateVersion7(),
|
||||
TypeName = "Missile"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = Guid.CreateVersion7(),
|
||||
TypeName = "Aircraft"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = Guid.CreateVersion7(),
|
||||
TypeName = "Mixed"
|
||||
}
|
||||
};
|
||||
|
||||
builder.HasData(squadTypes);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -41,4 +41,6 @@ public class Player : BaseEntity
|
||||
public ICollection<CustomEventParticipant> CustomEventParticipants { get; set; } = [];
|
||||
|
||||
public ICollection<ZombieSiegeParticipant> ZombieSiegeParticipants { get; set; } = [];
|
||||
|
||||
public ICollection<Squad> Squads { get; set; } = [];
|
||||
}
|
||||
18
Database/Entities/Squad.cs
Normal file
18
Database/Entities/Squad.cs
Normal file
@ -0,0 +1,18 @@
|
||||
namespace Database.Entities;
|
||||
|
||||
public class Squad : BaseEntity
|
||||
{
|
||||
public Guid SquadTypeId { get; set; }
|
||||
|
||||
public SquadType SquadType { get; set; } = null!;
|
||||
|
||||
public decimal Power { get; set; }
|
||||
|
||||
public int Position { get; set; }
|
||||
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public Player Player { get; set; } = null!;
|
||||
|
||||
public DateTime LastUpdateAt { get; set; }
|
||||
}
|
||||
8
Database/Entities/SquadType.cs
Normal file
8
Database/Entities/SquadType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Database.Entities;
|
||||
|
||||
public class SquadType : BaseEntity
|
||||
{
|
||||
public required string TypeName { get; set; }
|
||||
|
||||
public ICollection<Squad> Squads { get; set; } = [];
|
||||
}
|
||||
1379
Database/Migrations/20250617074428_Add_Squds.Designer.cs
generated
Normal file
1379
Database/Migrations/20250617074428_Add_Squds.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
96
Database/Migrations/20250617074428_Add_Squds.cs
Normal file
96
Database/Migrations/20250617074428_Add_Squds.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Add_Squds : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SquadType",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TypeName = table.Column<string>(type: "nvarchar(150)", maxLength: 150, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SquadType", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Squad",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
SquadTypeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Power = table.Column<long>(type: "bigint", nullable: false),
|
||||
PlayerId = table.Column<Guid>(type: "uniqueidentifier", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Squad", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Squad_Players_PlayerId",
|
||||
column: x => x.PlayerId,
|
||||
principalSchema: "dbo",
|
||||
principalTable: "Players",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_Squad_SquadType_SquadTypeId",
|
||||
column: x => x.SquadTypeId,
|
||||
principalSchema: "dbo",
|
||||
principalTable: "SquadType",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
schema: "dbo",
|
||||
table: "SquadType",
|
||||
columns: new[] { "Id", "TypeName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("01977cd8-bb62-7089-85cb-5a48223a6e92"), "Aircraft" },
|
||||
{ new Guid("01977cd8-bb62-7150-a0f9-5415e46a87e4"), "Mixed" },
|
||||
{ new Guid("01977cd8-bb62-79aa-9a71-95d57250d723"), "Missile" },
|
||||
{ new Guid("01977cd8-bb62-7d5b-823e-b77c6121c4f1"), "Tanks" }
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Squad_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
column: "PlayerId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Squad_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
column: "SquadTypeId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Squad",
|
||||
schema: "dbo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SquadType",
|
||||
schema: "dbo");
|
||||
}
|
||||
}
|
||||
}
|
||||
1382
Database/Migrations/20250617082727_Update_Squad.Designer.cs
generated
Normal file
1382
Database/Migrations/20250617082727_Update_Squad.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
224
Database/Migrations/20250617082727_Update_Squad.cs
Normal file
224
Database/Migrations/20250617082727_Update_Squad.cs
Normal file
@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Update_Squad : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Squad_Players_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squad");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Squad_SquadType_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squad");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_SquadType",
|
||||
schema: "dbo",
|
||||
table: "SquadType");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Squad",
|
||||
schema: "dbo",
|
||||
table: "Squad");
|
||||
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "SquadType",
|
||||
schema: "dbo",
|
||||
newName: "SquadTypes",
|
||||
newSchema: "dbo");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "Squad",
|
||||
schema: "dbo",
|
||||
newName: "Squads",
|
||||
newSchema: "dbo");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Squad_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
newName: "IX_Squads_SquadTypeId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Squad_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
newName: "IX_Squads_PlayerId");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Position",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_SquadTypes",
|
||||
schema: "dbo",
|
||||
table: "SquadTypes",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Squads",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
column: "Id");
|
||||
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Squads_Players_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
column: "PlayerId",
|
||||
principalSchema: "dbo",
|
||||
principalTable: "Players",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Squads_SquadTypes_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
column: "SquadTypeId",
|
||||
principalSchema: "dbo",
|
||||
principalTable: "SquadTypes",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Squads_Players_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squads");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Squads_SquadTypes_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squads");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_SquadTypes",
|
||||
schema: "dbo",
|
||||
table: "SquadTypes");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Squads",
|
||||
schema: "dbo",
|
||||
table: "Squads");
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
schema: "dbo",
|
||||
table: "SquadTypes",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("01977d00-1596-7078-b24d-f5abd8baaec1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
schema: "dbo",
|
||||
table: "SquadTypes",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("01977d00-1596-71a1-bbff-db88a4a59f32"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
schema: "dbo",
|
||||
table: "SquadTypes",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("01977d00-1596-7644-98aa-ff20f05f13bb"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
schema: "dbo",
|
||||
table: "SquadTypes",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("01977d00-1596-7c18-a665-e079870ae3cb"));
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Position",
|
||||
schema: "dbo",
|
||||
table: "Squads");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "SquadTypes",
|
||||
schema: "dbo",
|
||||
newName: "SquadType",
|
||||
newSchema: "dbo");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "Squads",
|
||||
schema: "dbo",
|
||||
newName: "Squad",
|
||||
newSchema: "dbo");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Squads_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
newName: "IX_Squad_SquadTypeId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Squads_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
newName: "IX_Squad_PlayerId");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_SquadType",
|
||||
schema: "dbo",
|
||||
table: "SquadType",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Squad",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
schema: "dbo",
|
||||
table: "SquadType",
|
||||
columns: new[] { "Id", "TypeName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("01977cd8-bb62-7089-85cb-5a48223a6e92"), "Aircraft" },
|
||||
{ new Guid("01977cd8-bb62-7150-a0f9-5415e46a87e4"), "Mixed" },
|
||||
{ new Guid("01977cd8-bb62-79aa-9a71-95d57250d723"), "Missile" },
|
||||
{ new Guid("01977cd8-bb62-7d5b-823e-b77c6121c4f1"), "Tanks" }
|
||||
});
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Squad_Players_PlayerId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
column: "PlayerId",
|
||||
principalSchema: "dbo",
|
||||
principalTable: "Players",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Squad_SquadType_SquadTypeId",
|
||||
schema: "dbo",
|
||||
table: "Squad",
|
||||
column: "SquadTypeId",
|
||||
principalSchema: "dbo",
|
||||
principalTable: "SquadType",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
}
|
||||
}
|
||||
1385
Database/Migrations/20250619052205_Add_Lastupdate_to_squad.Designer.cs
generated
Normal file
1385
Database/Migrations/20250619052205_Add_Lastupdate_to_squad.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Add_Lastupdate_to_squad : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "LastUpdateAt",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
type: "datetime2",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LastUpdateAt",
|
||||
schema: "dbo",
|
||||
table: "Squads");
|
||||
}
|
||||
}
|
||||
}
|
||||
1386
Database/Migrations/20250619075856_Change_squad_power_to_decimal.Designer.cs
generated
Normal file
1386
Database/Migrations/20250619075856_Change_squad_power_to_decimal.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Change_squad_power_to_decimal : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<decimal>(
|
||||
name: "Power",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
type: "decimal(18,2)",
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
nullable: false,
|
||||
oldClrType: typeof(long),
|
||||
oldType: "bigint");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<long>(
|
||||
name: "Power",
|
||||
schema: "dbo",
|
||||
table: "Squads",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
oldClrType: typeof(decimal),
|
||||
oldType: "decimal(18,2)",
|
||||
oldPrecision: 18,
|
||||
oldScale: 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -510,6 +510,73 @@ namespace Database.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.Squad", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("LastUpdateAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<int>("Position")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("Power")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<Guid>("SquadTypeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlayerId");
|
||||
|
||||
b.HasIndex("SquadTypeId");
|
||||
|
||||
b.ToTable("Squads", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.SquadType", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("TypeName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("nvarchar(150)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SquadTypes", "dbo");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("01978732-b32b-7af9-bf5f-a69585d89eb7"),
|
||||
TypeName = "Tanks"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("01978732-b32b-7fe8-9ee5-68b0d0df44f4"),
|
||||
TypeName = "Missile"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("01978732-b32b-780e-bef0-6bcf784ee1b4"),
|
||||
TypeName = "Aircraft"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("01978732-b32b-79c9-adaa-19ed53157f67"),
|
||||
TypeName = "Mixed"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -661,19 +728,19 @@ namespace Database.Migrations
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("01972f47-5fb5-7584-a312-e749206f0036"),
|
||||
Id = new Guid("01978732-b32e-7aa5-8e77-507b8b20977d"),
|
||||
Code = 1,
|
||||
Name = "Silver League"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("01972f47-5fb6-7dec-93aa-b62f0e167fde"),
|
||||
Id = new Guid("01978732-b32e-76d6-9beb-3fd062efe9ef"),
|
||||
Code = 2,
|
||||
Name = "Gold League"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("01972f47-5fb6-7f9a-8a2d-9f47fa1803e1"),
|
||||
Id = new Guid("01978732-b32e-7583-9522-90dde6d778b6"),
|
||||
Code = 3,
|
||||
Name = "Diamond League"
|
||||
});
|
||||
@ -1078,6 +1145,25 @@ namespace Database.Migrations
|
||||
b.Navigation("Rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.Squad", b =>
|
||||
{
|
||||
b.HasOne("Database.Entities.Player", "Player")
|
||||
.WithMany("Squads")
|
||||
.HasForeignKey("PlayerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Database.Entities.SquadType", "SquadType")
|
||||
.WithMany("Squads")
|
||||
.HasForeignKey("SquadTypeId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Player");
|
||||
|
||||
b.Navigation("SquadType");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.User", b =>
|
||||
{
|
||||
b.HasOne("Database.Entities.Alliance", "Alliance")
|
||||
@ -1260,6 +1346,8 @@ namespace Database.Migrations
|
||||
|
||||
b.Navigation("Notes");
|
||||
|
||||
b.Navigation("Squads");
|
||||
|
||||
b.Navigation("VsDuelParticipants");
|
||||
|
||||
b.Navigation("ZombieSiegeParticipants");
|
||||
@ -1270,6 +1358,11 @@ namespace Database.Migrations
|
||||
b.Navigation("Players");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.SquadType", b =>
|
||||
{
|
||||
b.Navigation("Squads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Database.Entities.VsDuel", b =>
|
||||
{
|
||||
b.Navigation("VsDuelParticipants");
|
||||
|
||||
13
README.md
13
README.md
@ -21,6 +21,19 @@ This project is currently in the **Beta Phase**.
|
||||
|
||||
---
|
||||
|
||||
### **[0.11.0]** - *2025-06-19*
|
||||
#### ✨ Added
|
||||
- **Squad Management per Player:** You can now add up to **four squads per player**, each with:
|
||||
- **Power** (in millions)
|
||||
- **Position**
|
||||
- **Type**: Tank, Aircraft, Missile, or Mixed
|
||||
- **Visual Enhancements:** Squad types are displayed with custom icons and total power is summarized at the top of the squad card.
|
||||
|
||||
🛠️ **Fixed**
|
||||
- (N/A)
|
||||
|
||||
---
|
||||
|
||||
### **[0.10.0]** - *2025-06-02*
|
||||
#### ✨ Added
|
||||
- **Team Selection for Desert Storm:** You can now assign **Team A** or **Team B** when creating a Desert Storm entry.
|
||||
|
||||
@ -66,6 +66,8 @@ import { CustomEventLeaderboardComponent } from './pages/custom-event/custom-eve
|
||||
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";
|
||||
import { PlayerSquadsComponent } from './pages/player-squads/player-squads.component';
|
||||
import { SquadEditModalComponent } from './modals/squad-edit-modal/squad-edit-modal.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -119,7 +121,9 @@ import {CountUpModule} from "ngx-countup";
|
||||
ImprintComponent,
|
||||
CustomEventCategoryComponent,
|
||||
CustomEventLeaderboardComponent,
|
||||
CustomEventEventsComponent
|
||||
CustomEventEventsComponent,
|
||||
PlayerSquadsComponent,
|
||||
SquadEditModalComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
@if (squadForm) {
|
||||
<div class="modal-header" xmlns="http://www.w3.org/1999/html">
|
||||
<h4 class="modal-title">{{ isUpdate ? 'Update Squad ' : 'Insert new Squad' }}</h4>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="activeModal.dismiss()"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="squadForm">
|
||||
|
||||
<div class="form-floating mb-3 is-invalid">
|
||||
<select [ngClass]="{
|
||||
'is-invalid': f['position'].invalid && (f['position'].dirty || !f['position'].untouched),
|
||||
'is-valid': f['position'].valid}" class="form-select" id="position" formControlName="position">
|
||||
@for (position of positions; track position) {
|
||||
<option [ngValue]="position">{{ position }}</option>
|
||||
}
|
||||
</select>
|
||||
<label for="position">Position</label>
|
||||
@if (f['position'].invalid && (f['position'].dirty || !f['position'].untouched)) {
|
||||
<div class="invalid-feedback">
|
||||
@if (f['position'].hasError('required')) {
|
||||
<p>Position is required</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-floating mb-3 is-invalid">
|
||||
<input [ngClass]="{
|
||||
'is-invalid': f['power'].invalid && (f['power'].dirty || !f['power'].untouched),
|
||||
'is-valid': f['power'].valid}"
|
||||
type="number" class="form-control" id="power" placeholder="power" formControlName="power">
|
||||
<label for="power">Power in millions</label>
|
||||
@if (f['power'].invalid && (f['power'].dirty || !f['power'].untouched)) {
|
||||
<div class="invalid-feedback">
|
||||
@if (f['power'].hasError('required')) {
|
||||
<p>Power is required</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-floating mb-3 is-invalid">
|
||||
<select [ngClass]="{
|
||||
'is-invalid': f['squadTypeId'].invalid && (f['squadTypeId'].dirty || !f['squadTypeId'].untouched),
|
||||
'is-valid': f['squadTypeId'].valid}" class="form-select" id="squadTypeId" formControlName="squadTypeId">
|
||||
@for (type of squadTypes; track type.id) {
|
||||
<option [ngValue]="type.id">{{ type.typeName }}</option>
|
||||
}
|
||||
</select>
|
||||
<label for="squadTypeId">Squad Type</label>
|
||||
@if (f['squadTypeId'].invalid && (f['squadTypeId'].dirty || !f['squadTypeId'].untouched)) {
|
||||
<div class="invalid-feedback">
|
||||
@if (f['squadTypeId'].hasError('required')) {
|
||||
<p>Squad Type is required</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning" (click)="activeModal.dismiss()">Close</button>
|
||||
<button [disabled]="squadForm.invalid" (click)="onSubmit()" type="submit"
|
||||
class=" btn btn-success">{{ isUpdate ? 'Update' : 'Insert' }} Squad
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
import {Component, inject, Input, OnInit} from '@angular/core';
|
||||
import {SquadTypeService} from "../../services/squad-type.service";
|
||||
import {SquadService} from "../../services/squad.service";
|
||||
import {SquadTypeModel} from "../../models/squadType.model";
|
||||
import {CreateSquadModel, SquadModel, UpdateSquadModel} from "../../models/squad.model";
|
||||
import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {FormControl, FormGroup, Validators} from "@angular/forms";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
||||
@Component({
|
||||
selector: 'app-squad-edit-modal',
|
||||
templateUrl: './squad-edit-modal.component.html',
|
||||
styleUrl: './squad-edit-modal.component.css'
|
||||
})
|
||||
export class SquadEditModalComponent implements OnInit {
|
||||
|
||||
public activeModal: NgbActiveModal = inject(NgbActiveModal);
|
||||
@Input({required: true}) playerId!: string;
|
||||
@Input({required: true}) isUpdate!: boolean;
|
||||
@Input({required: true}) currentSquad!: SquadModel;
|
||||
public squadTypes: SquadTypeModel[] = [];
|
||||
public positions: number[] = [1, 2, 3, 4];
|
||||
public squadForm!: FormGroup;
|
||||
private readonly _squadTypeService: SquadTypeService = inject(SquadTypeService);
|
||||
private readonly _squadService: SquadService = inject(SquadService);
|
||||
private readonly _toaster: ToastrService = inject(ToastrService);
|
||||
|
||||
get f() {
|
||||
return this.squadForm.controls;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getSquadTypes();
|
||||
this.squadForm = new FormGroup({
|
||||
id: new FormControl<string>(this.currentSquad.id),
|
||||
playerId: new FormControl<string>(this.currentSquad.playerId),
|
||||
power: new FormControl<number | null>(this.isUpdate ? this.currentSquad.power : null, [Validators.required]),
|
||||
position: new FormControl<number | null>(this.isUpdate ? this.currentSquad.position : null, [Validators.required]),
|
||||
squadTypeId: new FormControl<string>(this.currentSquad.squadTypeId, [Validators.required]),
|
||||
})
|
||||
}
|
||||
|
||||
getSquadTypes() {
|
||||
this._squadTypeService.getSquadTypes().subscribe({
|
||||
next: (response: SquadTypeModel[]) => {
|
||||
this.squadTypes = response;
|
||||
},
|
||||
error: (error: Error) => {
|
||||
console.error(error);
|
||||
this._toaster.error('Could not get squad types', 'Get squad types');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onSubmit() {
|
||||
if (this.squadForm.invalid) {
|
||||
return;
|
||||
}
|
||||
if (this.isUpdate) {
|
||||
const squad: UpdateSquadModel = this.squadForm.value as UpdateSquadModel;
|
||||
this.updateSquad(squad);
|
||||
} else {
|
||||
const squad: CreateSquadModel = this.squadForm.value as CreateSquadModel;
|
||||
this.addSquad(squad);
|
||||
}
|
||||
}
|
||||
|
||||
private updateSquad(squad: UpdateSquadModel) {
|
||||
this._squadService.updateSquad(squad.id, squad).subscribe({
|
||||
next: (_: SquadModel) => {
|
||||
this._toaster.success('Squad updated successfully', 'Squad update');
|
||||
this.activeModal.close();
|
||||
},
|
||||
error: (error: Error) => {
|
||||
console.error(error);
|
||||
this._toaster.error('Could not update squad types', 'Squad update');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private addSquad(squad: CreateSquadModel) {
|
||||
this._squadService.createSquad(squad).subscribe({
|
||||
next: (_: SquadModel) => {
|
||||
this._toaster.success('Squad created successfully', 'Squad create');
|
||||
this.activeModal.close();
|
||||
},
|
||||
error: (error: Error) => {
|
||||
console.error(error);
|
||||
this._toaster.error('Could not create squad', 'Squad create');
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
16
Ui/src/app/models/squad.model.ts
Normal file
16
Ui/src/app/models/squad.model.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export interface SquadModel extends CreateSquadModel{
|
||||
id: string;
|
||||
typeName: string;
|
||||
lastUpdateAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateSquadModel {
|
||||
squadTypeId: string;
|
||||
playerId: string;
|
||||
power: number;
|
||||
position: number;
|
||||
}
|
||||
|
||||
export interface UpdateSquadModel extends CreateSquadModel {
|
||||
id: string;
|
||||
}
|
||||
4
Ui/src/app/models/squadType.model.ts
Normal file
4
Ui/src/app/models/squadType.model.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface SquadTypeModel {
|
||||
id: string;
|
||||
typeName: string;
|
||||
}
|
||||
@ -5,9 +5,11 @@
|
||||
</div>
|
||||
@if (currentPlayer) {
|
||||
<!-- Player card-->
|
||||
<div class="card border-info mt-3">
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-6 mb-3 d-flex">
|
||||
<div class="card border-info flex-fill">
|
||||
<h5 class="card-header border-info text-center">Player Information</h5>
|
||||
<div class="card-body">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title">Name: <span class="text-primary">{{ currentPlayer.playerName }}</span></h5>
|
||||
<p class="card-text">Rank: <span class="text-primary">{{ currentPlayer.rankName }}</span></p>
|
||||
<p class="card-text">Headquarter: <span class="text-primary">{{ currentPlayer.level }}</span></p>
|
||||
@ -19,7 +21,7 @@
|
||||
class="text-primary">{{ currentPlayer.modifiedOn | date: 'dd.MM.yyyy HH:mm' }}</span></p>
|
||||
<p class="card-text">Modified by: <span class="text-primary">{{currentPlayer.modifiedBy}}</span></p>
|
||||
}
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="mt-auto d-flex justify-content-between">
|
||||
<button (click)="openPlayerNotes(currentPlayer)" type="button" class="btn btn-primary position-relative">
|
||||
Notes
|
||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
||||
@ -36,9 +38,17 @@
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3 d-flex">
|
||||
<app-player-squads [playerId]="playerId"></app-player-squads>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Accordion-->
|
||||
<div ngbAccordion #accordion="ngbAccordion" class="mt-3 pb-5">
|
||||
<!-- Marshal guard-->
|
||||
|
||||
@ -64,5 +64,4 @@ export class PlayerInformationComponent implements OnInit {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
76
Ui/src/app/pages/player-squads/player-squads.component.html
Normal file
76
Ui/src/app/pages/player-squads/player-squads.component.html
Normal file
@ -0,0 +1,76 @@
|
||||
<div class="card border-info flex-fill w-100">
|
||||
<h5 class="card-header border-info text-center">
|
||||
Squad Power
|
||||
@if (squads.length > 0) {
|
||||
<span class="text-success fw-bold">
|
||||
{{ totalPower | number:'1.2-2' }} million
|
||||
</span>
|
||||
}
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Add Squad -->
|
||||
@if (squads.length < 4) {
|
||||
<div class="d-flex justify-content-end mb-3">
|
||||
<button (click)="addSquad()" class="btn btn-sm btn-success" title="Add Squad">
|
||||
<i class="bi bi-plus-lg"></i> Add
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<!-- Squad List -->
|
||||
@for (squad of squads; track squad.id) {
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
|
||||
<!-- Title Row -->
|
||||
<h6 class="mb-2">{{ squad.position }}. Squad ({{ squad.typeName }})</h6>
|
||||
|
||||
<!-- Power | Actions | Image -->
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
|
||||
<!-- Power -->
|
||||
<div>
|
||||
<strong>Power:</strong> {{ squad.power | number:'1.2-2' }}M
|
||||
</div>
|
||||
|
||||
<!-- Edit / Delete Icons -->
|
||||
<div>
|
||||
<i
|
||||
(click)="editSquad(squad)"
|
||||
class="bi bi-pencil text-primary me-3 cursor-pointer"
|
||||
title="Edit Squad">
|
||||
</i>
|
||||
<i
|
||||
(click)="deleteSquad(squad)"
|
||||
class="bi bi-trash text-danger cursor-pointer"
|
||||
title="Delete Squad">
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<!-- Image -->
|
||||
<img
|
||||
[src]="'assets/images/icons/' + squad.typeName + '.png'"
|
||||
alt="{{ squad.typeName }}"
|
||||
style="width: 50px; height: 50px;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Last Update -->
|
||||
<div class="text-muted">
|
||||
<small>Last updated: {{ squad.lastUpdateAt | date:'dd.MM.yyyy' }}</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- No Squads -->
|
||||
@if (!squads?.length) {
|
||||
<div class="text-muted text-center">
|
||||
No squads available.
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
103
Ui/src/app/pages/player-squads/player-squads.component.ts
Normal file
103
Ui/src/app/pages/player-squads/player-squads.component.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import {Component, inject, Input, OnInit} from '@angular/core';
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {SquadEditModalComponent} from "../../modals/squad-edit-modal/squad-edit-modal.component";
|
||||
import {SquadModel} from "../../models/squad.model";
|
||||
import {SquadService} from "../../services/squad.service";
|
||||
import Swal from "sweetalert2";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
||||
@Component({
|
||||
selector: 'app-player-squads',
|
||||
templateUrl: './player-squads.component.html',
|
||||
styleUrl: './player-squads.component.css'
|
||||
})
|
||||
export class PlayerSquadsComponent implements OnInit {
|
||||
|
||||
@Input({required: true}) playerId!: string;
|
||||
public squads: SquadModel[] = [];
|
||||
private readonly _modalService: NgbModal = inject(NgbModal);
|
||||
private readonly _squadService: SquadService = inject(SquadService);
|
||||
private readonly _toaster: ToastrService = inject(ToastrService);
|
||||
|
||||
get totalPower(): number {
|
||||
return this.squads?.reduce((sum, squad) => sum + squad.power, 0) || 0;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getPlayerSquads();
|
||||
}
|
||||
|
||||
getPlayerSquads(): void {
|
||||
this._squadService.getPlayerSquads(this.playerId).subscribe({
|
||||
next: (result) => {
|
||||
if (result) {
|
||||
this.squads = result;
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.log(err);
|
||||
this._toaster.error('Error getting player squads', 'Getting player squads');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
editSquad(squad: SquadModel) {
|
||||
this.onOpenModal(this.playerId, squad, true);
|
||||
}
|
||||
|
||||
deleteSquad(squad: SquadModel) {
|
||||
Swal.fire({
|
||||
title: "Delete Squad ?",
|
||||
text: `Do you really want to delete the ${squad.typeName} squad`,
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
this._squadService.deleteSquad(squad.id).subscribe({
|
||||
next: ((response) => {
|
||||
if (response) {
|
||||
Swal.fire({
|
||||
title: "Deleted!",
|
||||
text: "Squad has been deleted",
|
||||
icon: "success"
|
||||
}).then(_ => this.getPlayerSquads());
|
||||
}
|
||||
}),
|
||||
error: (error: Error) => {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addSquad() {
|
||||
const squad: SquadModel = {
|
||||
id: '',
|
||||
playerId: this.playerId,
|
||||
squadTypeId: '',
|
||||
power: 0,
|
||||
position: 0,
|
||||
lastUpdateAt: new Date(),
|
||||
typeName: ''
|
||||
};
|
||||
this.onOpenModal(this.playerId, squad, false);
|
||||
}
|
||||
|
||||
onOpenModal(playerId: string, squad: SquadModel, isUpdate: boolean) {
|
||||
const modalRef = this._modalService.open(SquadEditModalComponent,
|
||||
{animation: true, backdrop: 'static', centered: true, size: 'lg'});
|
||||
modalRef.componentInstance.playerId = playerId;
|
||||
modalRef.componentInstance.currentSquad = squad;
|
||||
modalRef.componentInstance.isUpdate = isUpdate;
|
||||
modalRef.closed.subscribe({
|
||||
next: (() => {
|
||||
this.getPlayerSquads();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
18
Ui/src/app/services/squad-type.service.ts
Normal file
18
Ui/src/app/services/squad-type.service.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {environment} from "../../environments/environment";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs";
|
||||
import {SquadTypeModel} from "../models/squadType.model";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SquadTypeService {
|
||||
|
||||
private readonly _serviceUrl = environment.apiBaseUrl + 'SquadTypes/';
|
||||
private readonly _httpClient: HttpClient = inject(HttpClient);
|
||||
|
||||
getSquadTypes(): Observable<SquadTypeModel[]> {
|
||||
return this._httpClient.get<SquadTypeModel[]>(this._serviceUrl);
|
||||
}
|
||||
}
|
||||
30
Ui/src/app/services/squad.service.ts
Normal file
30
Ui/src/app/services/squad.service.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {environment} from "../../environments/environment";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs";
|
||||
import {CreateSquadModel, SquadModel, UpdateSquadModel} from "../models/squad.model";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SquadService {
|
||||
|
||||
private readonly _serviceUrl = environment.apiBaseUrl + 'Squads/';
|
||||
private readonly _httpClient: HttpClient = inject(HttpClient);
|
||||
|
||||
getPlayerSquads(playerId: string): Observable<SquadModel[]> {
|
||||
return this._httpClient.get<SquadModel[]>(this._serviceUrl + 'player/' + playerId)
|
||||
}
|
||||
|
||||
createSquad(createSquad: CreateSquadModel): Observable<SquadModel> {
|
||||
return this._httpClient.post<SquadModel>(this._serviceUrl, createSquad);
|
||||
}
|
||||
|
||||
updateSquad(squadId: string, updateSquad: UpdateSquadModel): Observable<SquadModel> {
|
||||
return this._httpClient.put<SquadModel>(this._serviceUrl + squadId, updateSquad);
|
||||
}
|
||||
|
||||
deleteSquad(squadId: string): Observable<boolean> {
|
||||
return this._httpClient.delete<boolean>(this._serviceUrl + squadId);
|
||||
}
|
||||
}
|
||||
BIN
Ui/src/assets/images/icons/Aircraft.png
Normal file
BIN
Ui/src/assets/images/icons/Aircraft.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
Ui/src/assets/images/icons/Missile.png
Normal file
BIN
Ui/src/assets/images/icons/Missile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
Ui/src/assets/images/icons/Mixed.png
Normal file
BIN
Ui/src/assets/images/icons/Mixed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
BIN
Ui/src/assets/images/icons/Tanks.png
Normal file
BIN
Ui/src/assets/images/icons/Tanks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Loading…
x
Reference in New Issue
Block a user