SES-160 shop on gm and player screen #85
@ -9,7 +9,11 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SessionCompanion.Services.Interfaces
|
namespace SessionCompanion.Services.Interfaces
|
||||||
{
|
{
|
||||||
|
using SessionCompanion.Extensions.EitherType;
|
||||||
|
using SessionCompanion.ViewModels.ApiResponses;
|
||||||
|
|
||||||
public interface IShopkeeperItemService : IServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>
|
public interface IShopkeeperItemService : IServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>
|
||||||
{
|
{
|
||||||
|
Task<Either<SuccessResponse, ErrorResponse>> GetActiveShkopkeeperWithItems(int shopkeeperId, int amount, int? weaponId, int? armorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,6 @@ namespace SessionCompanion.Services.Interfaces
|
|||||||
{
|
{
|
||||||
Task<Either<SuccessResponse, ErrorResponse>> CreateNewShopKeeper(ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel);
|
Task<Either<SuccessResponse, ErrorResponse>> CreateNewShopKeeper(ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel);
|
||||||
Task<Either<SuccessResponse, ErrorResponse>> ChangeShopkeeperStatus(int shopkeeperId, bool availability);
|
Task<Either<SuccessResponse, ErrorResponse>> ChangeShopkeeperStatus(int shopkeeperId, bool availability);
|
||||||
|
Task<Either<ShopkeeperWithItemsDetailsViewModel, ErrorResponse>> GetActiveShkopkeeperWithItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,17 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SessionCompanion.Services.Profiles
|
namespace SessionCompanion.Services.Profiles
|
||||||
{
|
{
|
||||||
|
using SessionCompanion.ViewModels.ShopkeeperItemViewModels;
|
||||||
|
|
||||||
public class ShopkeeperItemsProfile : Profile
|
public class ShopkeeperItemsProfile : Profile
|
||||||
{
|
{
|
||||||
public ShopkeeperItemsProfile()
|
public ShopkeeperItemsProfile()
|
||||||
{
|
{
|
||||||
CreateMap<ShopkeeperItemViewModel, ShopkeeperItem>().ReverseMap();
|
CreateMap<ShopkeeperItemViewModel, ShopkeeperItem>().ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<ShopkeeperItemDetailsViewModel, ShopkeeperItem>()
|
||||||
|
.ForMember(vm => vm.Armor, conf => conf.MapFrom(item => item.Armor))
|
||||||
|
.ForMember(vm => vm.Weapon, conf => conf.MapFrom(item => item.Weapon)).ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@ namespace SessionCompanion.Services.Profiles
|
|||||||
CreateMap<ShopkeeperViewModel, Shopkeeper>().ReverseMap();
|
CreateMap<ShopkeeperViewModel, Shopkeeper>().ReverseMap();
|
||||||
CreateMap<Shopkeeper, ShopkeeperWithItemsViewModel>()
|
CreateMap<Shopkeeper, ShopkeeperWithItemsViewModel>()
|
||||||
.ForMember(vm => vm.Items, conf => conf.MapFrom(items => items.ShopkeeperItems)).ReverseMap();
|
.ForMember(vm => vm.Items, conf => conf.MapFrom(items => items.ShopkeeperItems)).ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<Shopkeeper, ShopkeeperWithItemsDetailsViewModel>()
|
||||||
|
.ForMember(vm => vm.Items, conf => conf.MapFrom(items => items.ShopkeeperItems)).ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,56 @@ using SessionCompanion.Services.Base;
|
|||||||
using SessionCompanion.Services.Interfaces;
|
using SessionCompanion.Services.Interfaces;
|
||||||
using SessionCompanion.ViewModels.ShopkeeperItemsViewModels;
|
using SessionCompanion.ViewModels.ShopkeeperItemsViewModels;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SessionCompanion.Services.Services
|
namespace SessionCompanion.Services.Services
|
||||||
{
|
{
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using SessionCompanion.Extensions.EitherType;
|
||||||
|
using SessionCompanion.ViewModels.ApiResponses;
|
||||||
|
using SessionCompanion.ViewModels.ShopkeeperViewModels;
|
||||||
|
|
||||||
public class ShopkeeperItemService : ServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>, IShopkeeperItemService
|
public class ShopkeeperItemService : ServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>, IShopkeeperItemService
|
||||||
{
|
{
|
||||||
public ShopkeeperItemService(IMapper mapper, IRepository<ShopkeeperItem> repository) : base(mapper, repository)
|
public ShopkeeperItemService(IMapper mapper, IRepository<ShopkeeperItem> repository) : base(mapper, repository)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
public async Task<Either<SuccessResponse, ErrorResponse>> GetActiveShkopkeeperWithItems(int shopkeeperId, int amount, int? weaponId, int? armorId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var shopkeeperItem = await Repository.Get(c => c.ShopkeeperId.Equals(shopkeeperId) && c.WeaponId.Equals(weaponId) && c.ArmorId.Equals(armorId)).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (shopkeeperItem == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Shopkeeper with given id's couldn't have been found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shopkeeperItem.Amount - amount < 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Shopkeeper does not have that quantity of the item");
|
||||||
|
}
|
||||||
|
else if (shopkeeperItem.Amount - amount == 0)
|
||||||
|
{
|
||||||
|
this.Repository.Delete(shopkeeperItem);
|
||||||
|
await this.Repository.Save();
|
||||||
|
return new SuccessResponse("Items were deducted from the shopkeeper");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shopkeeperItem.Amount -= amount;
|
||||||
|
await this.Repository.Update(shopkeeperItem);
|
||||||
|
await this.Repository.Save();
|
||||||
|
return new SuccessResponse("Items were deducted from the shopkeeper");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ namespace SessionCompanion.Services.Services
|
|||||||
{
|
{
|
||||||
public ShopkeeperService(IMapper mapper, IRepository<Shopkeeper> repository) : base(mapper, repository)
|
public ShopkeeperService(IMapper mapper, IRepository<Shopkeeper> repository) : base(mapper, repository)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Funkcja zmienia status sprzedawcy
|
/// Funkcja zmienia status sprzedawcy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -41,26 +42,27 @@ namespace SessionCompanion.Services.Services
|
|||||||
await Repository.Update(shopkeeper);
|
await Repository.Update(shopkeeper);
|
||||||
}
|
}
|
||||||
await Repository.Save();
|
await Repository.Save();
|
||||||
return new SuccessResponse("Shopkeepers updated") { StatusCode = 200 };
|
return new SuccessResponse(200, "Shopkeepers updated");
|
||||||
}
|
}
|
||||||
|
|
||||||
var newActiveShopkeeper = shopkeepers.Where(c => c.Id.Equals(shopkeeperId)).Single();
|
var newActiveShopkeeper = shopkeepers.Where(c => c.Id.Equals(shopkeeperId)).Single();
|
||||||
newActiveShopkeeper.IsAvailable = false;
|
newActiveShopkeeper.IsAvailable = false;
|
||||||
await Repository.Update(newActiveShopkeeper);
|
await Repository.Update(newActiveShopkeeper);
|
||||||
await Repository.Save();
|
await Repository.Save();
|
||||||
return new SuccessResponse("Shopkeepers updated") { StatusCode = 200 };
|
return new SuccessResponse(200, "Shopkeepers updated");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Either<SuccessResponse, ErrorResponse>> CreateNewShopKeeper(ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel)
|
public async Task<Either<SuccessResponse, ErrorResponse>> CreateNewShopKeeper(ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var activeShopkeeper = await Repository.Get(c => c.IsAvailable.Equals(true)).SingleAsync();
|
var activeShopkeeper = await Repository.Get(c => c.IsAvailable.Equals(true)).FirstOrDefaultAsync();
|
||||||
if (activeShopkeeper is not null && shopkeeperWithItemsViewModel.IsAvailable)
|
if (activeShopkeeper != null && shopkeeperWithItemsViewModel.IsAvailable)
|
||||||
{
|
{
|
||||||
activeShopkeeper.IsAvailable = false;
|
activeShopkeeper.IsAvailable = false;
|
||||||
await Repository.Update(activeShopkeeper);
|
await Repository.Update(activeShopkeeper);
|
||||||
@ -75,5 +77,23 @@ namespace SessionCompanion.Services.Services
|
|||||||
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Either<ShopkeeperWithItemsDetailsViewModel, ErrorResponse>> GetActiveShkopkeeperWithItems()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var activeShopkeeper = await Repository.Get(c => c.IsAvailable.Equals(true))
|
||||||
|
.Include(t => t.ShopkeeperItems)
|
||||||
|
.ThenInclude(t => t.Armor)
|
||||||
|
.Include(t => t.ShopkeeperItems)
|
||||||
|
.ThenInclude(t => t.Weapon).FirstOrDefaultAsync();
|
||||||
|
var result = Mapper.Map<ShopkeeperWithItemsDetailsViewModel>(activeShopkeeper);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ErrorResponse() { StatusCode = 500, Message = e.Message };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SessionCompanion.ViewModels.ShopkeeperItemViewModels
|
||||||
|
{
|
||||||
|
using SessionCompanion.ViewModels.ArmorViewModels;
|
||||||
|
using SessionCompanion.ViewModels.WeaponViewModels;
|
||||||
|
|
||||||
|
public class ShopkeeperItemDetailsViewModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id Sprzedawcy
|
||||||
|
/// </summary>
|
||||||
|
public int? ShopkeeperId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id zbroi
|
||||||
|
/// </summary>
|
||||||
|
public int? ArmorId { get; set; }
|
||||||
|
|
||||||
|
public ArmorViewModel Armor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id broni
|
||||||
|
/// </summary>
|
||||||
|
public int? WeaponId { get; set; }
|
||||||
|
|
||||||
|
public WeaponViewModel Weapon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ilość przedmiotu
|
||||||
|
/// </summary>
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,20 +6,26 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SessionCompanion.ViewModels.ShopkeeperItemsViewModels
|
namespace SessionCompanion.ViewModels.ShopkeeperItemsViewModels
|
||||||
{
|
{
|
||||||
|
using SessionCompanion.ViewModels.ArmorViewModels;
|
||||||
|
using SessionCompanion.ViewModels.WeaponViewModels;
|
||||||
|
|
||||||
public class ShopkeeperItemViewModel
|
public class ShopkeeperItemViewModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id Sprzedawcy
|
/// Id Sprzedawcy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? ShopkeeperId { get; set; }
|
public int? ShopkeeperId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id zbroi
|
/// Id zbroi
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? ArmorId { get; set; }
|
public int? ArmorId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id broni
|
/// Id broni
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? WeaponId { get; set; }
|
public int? WeaponId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ilość przedmiotu
|
/// Ilość przedmiotu
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SessionCompanion.ViewModels.ShopkeeperViewModels
|
||||||
|
{
|
||||||
|
using SessionCompanion.ViewModels.ShopkeeperItemViewModels;
|
||||||
|
|
||||||
|
public class ShopkeeperWithItemsDetailsViewModel
|
||||||
|
{
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nazwa sklepikarza
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Status sklepikarza
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAvailable { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lista przedmiotów danego sklepikarza
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<ShopkeeperItemDetailsViewModel> Items { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@ import {
|
|||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
|
MatStepperModule,
|
||||||
} from '@angular/material';
|
} from '@angular/material';
|
||||||
import { UserService } from '../services/user.service';
|
import { UserService } from '../services/user.service';
|
||||||
import { StoreModule } from '@ngrx/store';
|
import { StoreModule } from '@ngrx/store';
|
||||||
@ -52,7 +53,7 @@ import { MonsterService } from '../services/monster.service';
|
|||||||
import { SpellDetailsDialogComponent } from './components/spell-details-dialog/spell-details-dialog.component';
|
import { SpellDetailsDialogComponent } from './components/spell-details-dialog/spell-details-dialog.component';
|
||||||
import { GameMasterShopkeepersTableComponent } from './components/game-master-shopkeepers-table/game-master-shopkeepers-table.component';
|
import { GameMasterShopkeepersTableComponent } from './components/game-master-shopkeepers-table/game-master-shopkeepers-table.component';
|
||||||
import { PlayerWeaponsTableComponent } from './components/player-weapons-table/player-weapons-table.component';
|
import { PlayerWeaponsTableComponent } from './components/player-weapons-table/player-weapons-table.component';
|
||||||
import {EquipmentService} from "../services/equipment.service";
|
import { EquipmentService } from '../services/equipment.service';
|
||||||
import { PlayerArmorsTableComponent } from './components/player-armors-table/player-armors-table.component';
|
import { PlayerArmorsTableComponent } from './components/player-armors-table/player-armors-table.component';
|
||||||
import { PlayerOtherEquipmentTableComponent } from './components/player-other-equipment-table/player-other-equipment-table.component';
|
import { PlayerOtherEquipmentTableComponent } from './components/player-other-equipment-table/player-other-equipment-table.component';
|
||||||
import { SendMessageActionComponent } from './components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component';
|
import { SendMessageActionComponent } from './components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component';
|
||||||
@ -64,6 +65,9 @@ import { DragDropModule } from '@angular/cdk/drag-drop';
|
|||||||
import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.component';
|
import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.component';
|
||||||
import { CreateCharacterComponent } from './components/create-character/create-character.component';
|
import { CreateCharacterComponent } from './components/create-character/create-character.component';
|
||||||
import { PersonalizeTemplateComponent } from './components/personalize-template/personalize-template.component';
|
import { PersonalizeTemplateComponent } from './components/personalize-template/personalize-template.component';
|
||||||
|
import { ShopkeeperService } from '../services/shopkeeper.service';
|
||||||
|
import { NewShopkeeperDialogComponent } from './components/game-master-shopkeepers-table/shopkeeper-dialogs/new-shopkeeper-dialog/new-shopkeeper-dialog.component';
|
||||||
|
import { PlayerShopComponent } from './components/player-shop/player-shop.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -92,6 +96,8 @@ import { PersonalizeTemplateComponent } from './components/personalize-template/
|
|||||||
MessageDialogComponent,
|
MessageDialogComponent,
|
||||||
GameMasterTurntrackerComponent,
|
GameMasterTurntrackerComponent,
|
||||||
ChooseMonsterDialogComponent,
|
ChooseMonsterDialogComponent,
|
||||||
|
NewShopkeeperDialogComponent,
|
||||||
|
PlayerShopComponent,
|
||||||
CreateCharacterComponent,
|
CreateCharacterComponent,
|
||||||
PersonalizeTemplateComponent,
|
PersonalizeTemplateComponent,
|
||||||
],
|
],
|
||||||
@ -125,6 +131,7 @@ import { PersonalizeTemplateComponent } from './components/personalize-template/
|
|||||||
DynamicModule,
|
DynamicModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
DragDropModule,
|
DragDropModule,
|
||||||
|
MatStepperModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
UserService,
|
UserService,
|
||||||
@ -135,6 +142,7 @@ import { PersonalizeTemplateComponent } from './components/personalize-template/
|
|||||||
OtherEquipmentService,
|
OtherEquipmentService,
|
||||||
MonsterService,
|
MonsterService,
|
||||||
EquipmentService,
|
EquipmentService,
|
||||||
|
ShopkeeperService,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
@ -155,6 +163,8 @@ import { PersonalizeTemplateComponent } from './components/personalize-template/
|
|||||||
MessageDialogComponent,
|
MessageDialogComponent,
|
||||||
GameMasterTurntrackerComponent,
|
GameMasterTurntrackerComponent,
|
||||||
ChooseMonsterDialogComponent,
|
ChooseMonsterDialogComponent,
|
||||||
|
NewShopkeeperDialogComponent,
|
||||||
|
PlayerShopComponent,
|
||||||
CreateCharacterComponent,
|
CreateCharacterComponent,
|
||||||
PersonalizeTemplateComponent,
|
PersonalizeTemplateComponent,
|
||||||
],
|
],
|
||||||
|
@ -17,7 +17,6 @@ export class SendMessageActionComponent implements OnInit {
|
|||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
SendMessage(message: string) {
|
SendMessage(message: string) {
|
||||||
debugger;
|
|
||||||
this.signalRService.SendMessageToPlayer(this.characterId, message);
|
this.signalRService.SendMessageToPlayer(this.characterId, message);
|
||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ export class GameMasterCharacterActionsDialogComponent implements OnInit {
|
|||||||
this.characterId = this.data.characterid;
|
this.characterId = this.data.characterid;
|
||||||
this.characterName = this.data.characterName;
|
this.characterName = this.data.characterName;
|
||||||
this.inputs = { characterId: this.characterId };
|
this.inputs = { characterId: this.characterId };
|
||||||
console.log(this.inputs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeActionComponent(componentName: string): void {
|
ChangeActionComponent(componentName: string): void {
|
||||||
|
@ -105,6 +105,7 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.signalRService.Login();
|
this.signalRService.Login();
|
||||||
|
this.UpdateCharactersList();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateSidenavStatus(sidenav: string, newValue: boolean) {
|
UpdateSidenavStatus(sidenav: string, newValue: boolean) {
|
||||||
|
@ -42,3 +42,9 @@ button {
|
|||||||
.mat-column-actions {
|
.mat-column-actions {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add-new-shopkeeper-button {
|
||||||
|
float: right;
|
||||||
|
color: whitesmoke;
|
||||||
|
border-color: whitesmoke;
|
||||||
|
}
|
||||||
|
@ -11,23 +11,19 @@
|
|||||||
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
|
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="itemsCount">
|
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Items Count </th>
|
|
||||||
<td mat-cell *matCellDef="let row"> {{row.itemsCount}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let row">
|
<td mat-cell *matCellDef="let row">
|
||||||
<button mat-flat-button
|
<button mat-flat-button
|
||||||
*ngIf="row.isAvailable"
|
*ngIf="row.isAvailable"
|
||||||
color="red">
|
color="red"
|
||||||
|
(click)="DeactivateShopkeeper(row.id)">
|
||||||
Deactivate
|
Deactivate
|
||||||
</button>
|
</button>
|
||||||
<button mat-flat-button *ngIf="!row.isAvailable" color="green">
|
<button mat-flat-button *ngIf="!isAnyAvailable" color="green" (click)="ActivateShopkeeper(row.id)">
|
||||||
Activate
|
Activate
|
||||||
</button>
|
</button>
|
||||||
<button mat-flat-button color="warn" >
|
<button mat-flat-button color="warn" (click)="RemoveShopkeeper(row.id)">
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -44,3 +40,7 @@
|
|||||||
|
|
||||||
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button mat-stroked-button class="add-new-shopkeeper-button" (click)="AddNewShopkeeper()">
|
||||||
|
Add new
|
||||||
|
</button>
|
||||||
|
@ -3,6 +3,13 @@ import { MatPaginator } from '@angular/material/paginator';
|
|||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
|
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
|
||||||
|
import { ShopkeeperViewModel } from '../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperViewModel';
|
||||||
|
import { ShopkeeperService } from '../../../services/shopkeeper.service';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { ErrorResponse } from '../../../types/ErrorResponse';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { NewShopkeeperDialogComponent } from './shopkeeper-dialogs/new-shopkeeper-dialog/new-shopkeeper-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-game-master-shopkeepers-table',
|
selector: 'app-game-master-shopkeepers-table',
|
||||||
@ -10,35 +17,120 @@ import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/M
|
|||||||
styleUrls: ['./game-master-shopkeepers-table.component.css'],
|
styleUrls: ['./game-master-shopkeepers-table.component.css'],
|
||||||
})
|
})
|
||||||
export class GameMasterShopkeepersTableComponent implements OnInit {
|
export class GameMasterShopkeepersTableComponent implements OnInit {
|
||||||
displayedColumns: string[] = ['name', 'itemsCount', 'actions'];
|
displayedColumns: string[] = ['name', 'actions'];
|
||||||
dataSource: MatTableDataSource<{
|
dataSource: MatTableDataSource<ShopkeeperViewModel>;
|
||||||
name: string;
|
isAnyAvailable: boolean = false;
|
||||||
itemsCount: number;
|
|
||||||
isAvailable: boolean;
|
|
||||||
}>; //TODO zmienić na skopkeeper view model
|
|
||||||
|
|
||||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||||
|
|
||||||
constructor() {}
|
constructor(
|
||||||
|
private shopkeeperService: ShopkeeperService,
|
||||||
|
public dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.dataSource = new MatTableDataSource<{
|
this.GetAllShopkeepers();
|
||||||
name: string;
|
}
|
||||||
itemsCount: number;
|
|
||||||
isAvailable: boolean;
|
GetAllShopkeepers() {
|
||||||
}>([
|
this.shopkeeperService
|
||||||
{
|
.GetAllShopkeepers()
|
||||||
name: 'Test',
|
.pipe(first())
|
||||||
itemsCount: 12,
|
.subscribe(
|
||||||
isAvailable: true,
|
(result) => {
|
||||||
|
this.dataSource = new MatTableDataSource(result);
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
if (result.find((e) => e.isAvailable) != null) {
|
||||||
|
this.isAnyAvailable = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
(error: ErrorResponse | HttpErrorResponse) => {
|
||||||
name: 'Test2',
|
console.error(error);
|
||||||
itemsCount: 12,
|
if (error instanceof HttpErrorResponse) {
|
||||||
isAvailable: false,
|
error = error.error as ErrorResponse;
|
||||||
|
}
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivateShopkeeper(shopkeeperId: number) {
|
||||||
|
this.shopkeeperService
|
||||||
|
.ChangeShopkeeperStatus(shopkeeperId, true)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(result) => {
|
||||||
|
this.dataSource.data.find(
|
||||||
|
(e) => e.id == shopkeeperId
|
||||||
|
).isAvailable = true;
|
||||||
|
this.isAnyAvailable = true;
|
||||||
},
|
},
|
||||||
]);
|
(error: ErrorResponse | HttpErrorResponse) => {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof HttpErrorResponse) {
|
||||||
|
error = error.error as ErrorResponse;
|
||||||
|
}
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeactivateShopkeeper(shopkeeperId: number) {
|
||||||
|
this.shopkeeperService
|
||||||
|
.ChangeShopkeeperStatus(shopkeeperId, false)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(result) => {
|
||||||
|
this.dataSource.data.find(
|
||||||
|
(e) => e.id == shopkeeperId
|
||||||
|
).isAvailable = false;
|
||||||
|
this.isAnyAvailable = false;
|
||||||
|
},
|
||||||
|
(error: ErrorResponse | HttpErrorResponse) => {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof HttpErrorResponse) {
|
||||||
|
error = error.error as ErrorResponse;
|
||||||
|
}
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveShopkeeper(shopkeeperId: number) {
|
||||||
|
let currentStatus = this.dataSource.data.find((e) => e.id == shopkeeperId)
|
||||||
|
.isAvailable;
|
||||||
|
this.shopkeeperService
|
||||||
|
.RemoveShopkeeper(shopkeeperId, currentStatus)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(result) => {
|
||||||
|
if (currentStatus == true) {
|
||||||
|
this.isAnyAvailable = false;
|
||||||
|
}
|
||||||
|
this.dataSource.data = this.dataSource.data.filter(
|
||||||
|
(e) => e.id != shopkeeperId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(error: ErrorResponse | HttpErrorResponse) => {
|
||||||
|
console.error(error);
|
||||||
|
if (error instanceof HttpErrorResponse) {
|
||||||
|
error = error.error as ErrorResponse;
|
||||||
|
}
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddNewShopkeeper() {
|
||||||
|
this.dialog
|
||||||
|
.open(NewShopkeeperDialogComponent)
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(() => {
|
||||||
|
this.GetAllShopkeepers();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilter(event: Event) {
|
applyFilter(event: Event) {
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
::ng-deep .mat-horizontal-content-container {
|
||||||
|
overflow-y: auto !important;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
background-color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-paginator {
|
||||||
|
background-color: initial;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-select-arrow {
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-select-value {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-to-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-to-right > button {
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shopkeeper-create-button {
|
||||||
|
color: #7bce7b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shopkeeper-stepper-main {
|
||||||
|
background-color: #4f5c69;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-step-label {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-step-icon-selected {
|
||||||
|
background-color: #df7c0f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-step-icon-state-edit {
|
||||||
|
background-color: #df7c0f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep mat-dialog-container {
|
||||||
|
background-color: #4f5c69 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
|
||||||
|
background-color: #df7c0f;
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
<mat-horizontal-stepper [linear]="true" #stepper class="shopkeeper-stepper-main">
|
||||||
|
<mat-step [stepControl]="nameFormGroup">
|
||||||
|
<form [formGroup]="nameFormGroup">
|
||||||
|
<ng-template matStepLabel class="stepper-header">Fill out your shop name</ng-template>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input matInput placeholder="Bob..." formControlName="name" required>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<div class="button-to-right">
|
||||||
|
<button mat-button matStepperNext>Next</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step>
|
||||||
|
<ng-template matStepLabel>Select items</ng-template>
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table [dataSource]="dataSourceWithAllitems" matSort class="w-100">
|
||||||
|
|
||||||
|
<ng-container matColumnDef="select">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Select
|
||||||
|
</th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<mat-checkbox (click)="$event.stopPropagation()"
|
||||||
|
(change)="$event ? selection.toggle(row) : null"
|
||||||
|
[checked]="selection.isSelected(row)">
|
||||||
|
</mat-checkbox>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
|
||||||
|
<td mat-cell *matCellDef="let row"> {{row.itemName}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemType">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let row"> {{row.itemType}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
|
<tr class="mat-row" *matNoDataRow>
|
||||||
|
<td class="mat-cell" colspan="4">No data found</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
||||||
|
</div>
|
||||||
|
<div class="button-to-right">
|
||||||
|
<button mat-button matStepperPrevious>Back</button>
|
||||||
|
<button mat-button (click)="ToFinalStep(stepper)" >Next</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step>
|
||||||
|
<ng-template matStepLabel>Set a quantity</ng-template>
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table [dataSource]="finalDataSource" matSort class="w-100">
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
|
||||||
|
<td mat-cell *matCellDef="let row"> {{row.itemName}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemType">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let row"> {{row.itemType}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="amount" >
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header > Amount </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<mat-form-field style="width: 60px">
|
||||||
|
<input matInput type="number" [(ngModel)]="row.amount" min="1">
|
||||||
|
</mat-form-field>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Remove </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<button mat-icon-button (click)="RemoveItem(row.weaponId, row.armorId)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumnsForFinal"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumnsForFinal;"></tr>
|
||||||
|
|
||||||
|
<tr class="mat-row" *matNoDataRow>
|
||||||
|
<td class="mat-cell" colspan="4">No data found</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
||||||
|
</div>
|
||||||
|
<div class="button-to-right">
|
||||||
|
<button mat-button matStepperPrevious>Back</button>
|
||||||
|
<button mat-button (click)="CreateShopkeeper()" class="shopkeeper-create-button">Create</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
</mat-horizontal-stepper>
|
||||||
|
|
@ -0,0 +1,170 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { WeaponService } from '../../../../../services/weapon.service';
|
||||||
|
import { ArmorService } from '../../../../../services/armor.service';
|
||||||
|
import { ShopkeeperItemsWithItemNameAndTypeViewModel } from '../../../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsWithItemNameAndTypeViewModel';
|
||||||
|
import { first, map } from 'rxjs/operators';
|
||||||
|
import { forkJoin, Observable } from 'rxjs';
|
||||||
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
|
import {
|
||||||
|
MatDialog,
|
||||||
|
MatDialogRef,
|
||||||
|
MatHorizontalStepper,
|
||||||
|
} from '@angular/material';
|
||||||
|
import { ShopkeeperService } from '../../../../../services/shopkeeper.service';
|
||||||
|
import { ShopkeeperWithItemsViewModel } from '../../../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperWithItemsViewModel';
|
||||||
|
import { ShopkeeperItemsViewModel } from '../../../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsViewModel';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-new-shopkeeper-dialog',
|
||||||
|
templateUrl: './new-shopkeeper-dialog.component.html',
|
||||||
|
styleUrls: ['./new-shopkeeper-dialog.component.css'],
|
||||||
|
})
|
||||||
|
export class NewShopkeeperDialogComponent implements OnInit {
|
||||||
|
displayedColumnsForFinal: string[] = [
|
||||||
|
'itemName',
|
||||||
|
'itemType',
|
||||||
|
'amount',
|
||||||
|
'actions',
|
||||||
|
];
|
||||||
|
displayedColumns: string[] = ['select', 'itemName', 'itemType'];
|
||||||
|
dataSourceWithAllitems: MatTableDataSource<ShopkeeperItemsWithItemNameAndTypeViewModel>;
|
||||||
|
selection = new SelectionModel<ShopkeeperItemsWithItemNameAndTypeViewModel>(
|
||||||
|
true,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
finalDataSource: MatTableDataSource<ShopkeeperItemsWithItemNameAndTypeViewModel>;
|
||||||
|
nameFormGroup: FormGroup;
|
||||||
|
|
||||||
|
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||||
|
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||||
|
@ViewChild(MatPaginator, { static: true }) paginatorForFinal: MatPaginator;
|
||||||
|
@ViewChild(MatSort, { static: true }) sortForFinal: MatSort;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private weaponService: WeaponService,
|
||||||
|
private armorService: ArmorService,
|
||||||
|
private shopkeeperService: ShopkeeperService,
|
||||||
|
public dialogRef: MatDialogRef<NewShopkeeperDialogComponent>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.GetAllWeaponsAndArmors()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
|
this.dataSourceWithAllitems = new MatTableDataSource<ShopkeeperItemsWithItemNameAndTypeViewModel>(
|
||||||
|
res
|
||||||
|
);
|
||||||
|
this.dataSourceWithAllitems.sort = this.sort;
|
||||||
|
this.dataSourceWithAllitems.paginator = this.paginator;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.finalDataSource = new MatTableDataSource<ShopkeeperItemsWithItemNameAndTypeViewModel>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
this.finalDataSource.paginator = this.paginatorForFinal;
|
||||||
|
this.finalDataSource.sort = this.sortForFinal;
|
||||||
|
|
||||||
|
this.nameFormGroup = this.formBuilder.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAllWeaponsAndArmors(): Observable<
|
||||||
|
ShopkeeperItemsWithItemNameAndTypeViewModel[]
|
||||||
|
> {
|
||||||
|
return forkJoin([
|
||||||
|
this.armorService.GetAllArmors(),
|
||||||
|
this.weaponService.GetAllWeapons(),
|
||||||
|
]).pipe(
|
||||||
|
first(),
|
||||||
|
map(([armors, weapons]) => {
|
||||||
|
let resultArray: ShopkeeperItemsWithItemNameAndTypeViewModel[];
|
||||||
|
|
||||||
|
resultArray = weapons.map<ShopkeeperItemsWithItemNameAndTypeViewModel>(
|
||||||
|
(e) => {
|
||||||
|
return {
|
||||||
|
shopkeeperId: null,
|
||||||
|
amount: 1,
|
||||||
|
armorId: null,
|
||||||
|
weaponId: e.id,
|
||||||
|
itemName: e.name,
|
||||||
|
itemType: 'Weapon',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...resultArray,
|
||||||
|
...armors.map<ShopkeeperItemsWithItemNameAndTypeViewModel>((e) => {
|
||||||
|
return {
|
||||||
|
shopkeeperId: null,
|
||||||
|
amount: 1,
|
||||||
|
armorId: null,
|
||||||
|
weaponId: e.id,
|
||||||
|
itemName: e.name,
|
||||||
|
itemType: 'Armor',
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ToFinalStep(stepper: MatHorizontalStepper) {
|
||||||
|
this.selection.selected.forEach((item) => {
|
||||||
|
if (
|
||||||
|
this.finalDataSource.data.filter(
|
||||||
|
(e) => e.armorId == item.armorId && e.weaponId == item.weaponId
|
||||||
|
).length == 0
|
||||||
|
) {
|
||||||
|
this.finalDataSource.data = [...this.finalDataSource.data, item];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.selection.clear();
|
||||||
|
|
||||||
|
stepper.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateShopkeeper() {
|
||||||
|
if (this.finalDataSource.data.length > 0) {
|
||||||
|
let filteredData = this.finalDataSource.data.filter((e) => e.amount > 0);
|
||||||
|
let shopkeeperModel: ShopkeeperWithItemsViewModel = {
|
||||||
|
id: null,
|
||||||
|
name: this.nameFormGroup.value.name,
|
||||||
|
isAvailable: false,
|
||||||
|
items: filteredData.map<ShopkeeperItemsViewModel>((item) => {
|
||||||
|
return {
|
||||||
|
shopkeeperId: null,
|
||||||
|
armorId: item.armorId,
|
||||||
|
weaponId: item.weaponId,
|
||||||
|
amount: item.amount,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
this.shopkeeperService
|
||||||
|
.CreateShopkeeper(shopkeeperModel)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((result) => {
|
||||||
|
this.dialogRef.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveItem(weaponId: number, armorId: number) {
|
||||||
|
if (weaponId != null) {
|
||||||
|
this.finalDataSource.data = this.finalDataSource.data.filter(
|
||||||
|
(e) => e.weaponId != weaponId
|
||||||
|
);
|
||||||
|
} else if (armorId != null) {
|
||||||
|
this.finalDataSource.data = this.finalDataSource.data.filter(
|
||||||
|
(e) => e.armorId != armorId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -116,7 +116,6 @@ export class GameMasterTurntrackerComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
result.forEach((ele) => {
|
result.forEach((ele) => {
|
||||||
if (monstersOnList.map((e) => e.name).includes(ele.name)) {
|
if (monstersOnList.map((e) => e.name).includes(ele.name)) {
|
||||||
debugger;
|
|
||||||
let maxCurrentId = Math.max(
|
let maxCurrentId = Math.max(
|
||||||
...monstersOnList.map((e) => e.monsterId),
|
...monstersOnList.map((e) => e.monsterId),
|
||||||
0
|
0
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
@import "../../../styles.css";
|
@import '../../../styles.css';
|
||||||
|
|
||||||
.toggle-class {
|
.toggle-class {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.character-name {
|
||||||
|
width: 240px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-spacer {
|
.menu-spacer {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
<mat-icon>menu</mat-icon>
|
<mat-icon>menu</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<span class="menu-spacer"></span>
|
<span class="menu-spacer"></span>
|
||||||
<div fxShow="true" fxHide.lt-md>
|
<div fxShow="true" fxHide.lt-md class="character-name">
|
||||||
<span>Session Companion</span>
|
<span>{{characterName}}</span>
|
||||||
</div>
|
</div>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<a matLine>Profile</a>
|
<a matLine>Profile</a>
|
||||||
</mat-list-item>-->
|
</mat-list-item>-->
|
||||||
|
|
||||||
<mat-list-item>
|
<mat-list-item (click)="SwitchMiddleComponent('PlayerShopComponent')">
|
||||||
<mat-icon [class.active]="selected" matListIcon>shopping_cart</mat-icon>
|
<mat-icon [class.active]="selected" matListIcon>shopping_cart</mat-icon>
|
||||||
<a matLine>Shop</a>
|
<a matLine>Shop</a>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
|
@ -12,6 +12,8 @@ import { Router } from '@angular/router';
|
|||||||
import { ClearCharacterId } from '../../store/actions/player.action';
|
import { ClearCharacterId } from '../../store/actions/player.action';
|
||||||
import { MatSnackBar } from '@angular/material';
|
import { MatSnackBar } from '@angular/material';
|
||||||
import { SnackbarComponent } from '../../shared/snackbar/snackbar.component';
|
import { SnackbarComponent } from '../../shared/snackbar/snackbar.component';
|
||||||
|
import { CharacterService } from '../../../services/character.service';
|
||||||
|
import { PlayerShopComponent } from '../player-shop/player-shop.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-player-dashboard',
|
selector: 'app-player-dashboard',
|
||||||
@ -22,12 +24,14 @@ export class PlayerDashboardComponent implements OnInit {
|
|||||||
middleComponent;
|
middleComponent;
|
||||||
isExpanded = false;
|
isExpanded = false;
|
||||||
selected = false;
|
selected = false;
|
||||||
|
characterName: string = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private signalRService: PlayerSignalRService,
|
private signalRService: PlayerSignalRService,
|
||||||
private store: Store<AppState>,
|
private store: Store<AppState>,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private _snackBar: MatSnackBar
|
private _snackBar: MatSnackBar,
|
||||||
|
private characterService: CharacterService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -38,6 +42,12 @@ export class PlayerDashboardComponent implements OnInit {
|
|||||||
this.SubscribeToEvents();
|
this.SubscribeToEvents();
|
||||||
this.signalRService.Login(id);
|
this.signalRService.Login(id);
|
||||||
this.SwitchMiddleComponent('AbilitiesComponent');
|
this.SwitchMiddleComponent('AbilitiesComponent');
|
||||||
|
this.characterService
|
||||||
|
.GetCharacterBasicInfo(id)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((result) => {
|
||||||
|
this.characterName = result.name;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +69,9 @@ export class PlayerDashboardComponent implements OnInit {
|
|||||||
case 'PlayerOtherEquipmentTableComponent':
|
case 'PlayerOtherEquipmentTableComponent':
|
||||||
this.middleComponent = PlayerOtherEquipmentTableComponent;
|
this.middleComponent = PlayerOtherEquipmentTableComponent;
|
||||||
break;
|
break;
|
||||||
|
case 'PlayerShopComponent':
|
||||||
|
this.middleComponent = PlayerShopComponent;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +95,12 @@ export class PlayerDashboardComponent implements OnInit {
|
|||||||
gmMessage: result.parameters.message,
|
gmMessage: result.parameters.message,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
case 'RefreshShopComponent':
|
||||||
|
this.middleComponent = '';
|
||||||
|
|
||||||
|
this.middleComponent = PlayerShopComponent;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
.no-shops-button {
|
||||||
|
color: whitesmoke !important;
|
||||||
|
background-color: #ad2424 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
background-color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-paginator {
|
||||||
|
background-color: initial;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-select-arrow {
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-select-value {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-sort-header-container {
|
||||||
|
color: whitesmoke !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-form-field {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-header-cell {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-cell {
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep td.mat-cell:first-of-type,
|
||||||
|
::ng-deep th.mat-header-cell:first-of-type {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-shop-buy-button {
|
||||||
|
background-color: #1f4416;
|
||||||
|
margin-left: 5px;
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
<div *ngIf="shopkeeper == null">
|
||||||
|
<button mat-flat-button disabled class="no-shops-button">
|
||||||
|
All stores are currently closed, please visit us later.
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="shopkeeper != null">
|
||||||
|
<p>
|
||||||
|
{{shopkeeper.name}}
|
||||||
|
</p>
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table [dataSource]="dataSource" matSort class="w-100">
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemName" >
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header > Name </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<span *ngIf="row.armor != null; else weaponNameBlock" >
|
||||||
|
{{row.armor.name}}
|
||||||
|
</span>
|
||||||
|
<ng-template #weaponNameBlock >
|
||||||
|
{{row.weapon.name}}
|
||||||
|
</ng-template>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="itemType">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<span *ngIf="row.armor != null; else weaponTypeBlock" >
|
||||||
|
Armor
|
||||||
|
</span>
|
||||||
|
<ng-template #weaponTypeBlock >
|
||||||
|
Weapon
|
||||||
|
</ng-template>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="amount">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Amount </th>
|
||||||
|
<td mat-cell *matCellDef="let row"> {{row.amount}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="amountToBuy">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> How many </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<mat-form-field style="width: 60px">
|
||||||
|
<input matInput type="number" [(ngModel)]="row.amountToBuy" min="1">
|
||||||
|
</mat-form-field>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let row">
|
||||||
|
<button class="player-shop-buy-button" mat-flat-button (click)="BuyItem(row.weaponId, row.armorId)">
|
||||||
|
Buy
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
|
<tr class="mat-row" *matNoDataRow>
|
||||||
|
<td class="mat-cell" colspan="4">No data found</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,144 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { ShopkeeperWithItemsDetailsViewModel } from '../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperWithItemsDetailsViewModel';
|
||||||
|
import { ShopkeeperService } from '../../../services/shopkeeper.service';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { PlayerSignalRService } from '../../shared/signalR-service/player-signalR.service';
|
||||||
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel } from '../../../types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '../../store/models/app-state.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-player-shop',
|
||||||
|
templateUrl: './player-shop.component.html',
|
||||||
|
styleUrls: ['./player-shop.component.css'],
|
||||||
|
})
|
||||||
|
export class PlayerShopComponent implements OnInit {
|
||||||
|
shopkeeper: ShopkeeperWithItemsDetailsViewModel;
|
||||||
|
|
||||||
|
displayedColumns: string[] = [
|
||||||
|
'itemName',
|
||||||
|
'itemType',
|
||||||
|
'amount',
|
||||||
|
'amountToBuy',
|
||||||
|
'actions',
|
||||||
|
];
|
||||||
|
dataSource: MatTableDataSource<ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel>;
|
||||||
|
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||||
|
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private shopkeeperService: ShopkeeperService,
|
||||||
|
private signalRService: PlayerSignalRService,
|
||||||
|
private store: Store<AppState>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.SubscribeToEvents();
|
||||||
|
this.GetActiveShopkeeper();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetActiveShopkeeper(): void {
|
||||||
|
this.shopkeeperService
|
||||||
|
.GetActiveShopkeeper()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((result) => {
|
||||||
|
this.shopkeeper = result;
|
||||||
|
|
||||||
|
if (this.shopkeeper != null) {
|
||||||
|
this.dataSource = new MatTableDataSource(
|
||||||
|
result.items.map<ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel>(
|
||||||
|
(item) => {
|
||||||
|
return {
|
||||||
|
shopkeeperId: item.shopkeeperId,
|
||||||
|
weaponId: item.weaponId,
|
||||||
|
armorId: item.armorId,
|
||||||
|
amount: item.amount,
|
||||||
|
amountToBuy: 1,
|
||||||
|
armor: item.armor,
|
||||||
|
weapon: item.weapon,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyItem(weaponId: number, armorId: number) {
|
||||||
|
this.store
|
||||||
|
.select((s) => s.playerStore.characterId)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((chracterId) => {
|
||||||
|
let amount = this.dataSource.data.find(
|
||||||
|
(item) => item.weaponId == weaponId && item.armorId == armorId
|
||||||
|
).amountToBuy;
|
||||||
|
|
||||||
|
this.shopkeeperService
|
||||||
|
.BuyItemFromShopkeeper(
|
||||||
|
this.shopkeeper.id,
|
||||||
|
chracterId,
|
||||||
|
weaponId,
|
||||||
|
armorId,
|
||||||
|
amount
|
||||||
|
)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(result) => {},
|
||||||
|
(error) => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshAmountOnList() {
|
||||||
|
this.shopkeeperService
|
||||||
|
.GetActiveShopkeeper()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((result) => {
|
||||||
|
this.dataSource.data.forEach((item, index, object) => {
|
||||||
|
if (item.weaponId != null) {
|
||||||
|
let lineWithSameWeapon = result.items.find(
|
||||||
|
(e) => e.weaponId == item.weaponId
|
||||||
|
);
|
||||||
|
if (lineWithSameWeapon == null) {
|
||||||
|
object.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
object[index].amount = lineWithSameWeapon.amount;
|
||||||
|
}
|
||||||
|
} else if (item.armorId != null) {
|
||||||
|
let lineWithSameArmor = result.items.find(
|
||||||
|
(e) => e.armorId == item.armorId
|
||||||
|
);
|
||||||
|
if (lineWithSameArmor == null) {
|
||||||
|
object.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
object[index].amount = lineWithSameArmor.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private SubscribeToEvents(): void {
|
||||||
|
this.signalRService.runMethod.subscribe(
|
||||||
|
(result: { methodName: string; parameters }) => {
|
||||||
|
switch (result.methodName) {
|
||||||
|
case 'RefreshShopComponent':
|
||||||
|
this.GetActiveShopkeeper();
|
||||||
|
break;
|
||||||
|
case 'RefreshShopkeeperItems':
|
||||||
|
this.RefreshAmountOnList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -33,5 +33,29 @@ export class PlayerSignalRService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
this.signalR.hubConnection.on('NewShopkeeperArrived', () => {
|
||||||
|
this.runMethod.next({
|
||||||
|
methodName: 'RefreshShopComponent',
|
||||||
|
parameters: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.signalR.hubConnection.on('ShopkeeperLeft', () => {
|
||||||
|
this.runMethod.next({
|
||||||
|
methodName: 'RefreshShopComponent',
|
||||||
|
parameters: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.signalR.hubConnection.on('ShopkeeperRemoved', () => {
|
||||||
|
this.runMethod.next({
|
||||||
|
methodName: 'RefreshShopComponent',
|
||||||
|
parameters: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.signalR.hubConnection.on('ItemFromShopkeeperWasBought', () => {
|
||||||
|
this.runMethod.next({
|
||||||
|
methodName: 'RefreshShopkeeperItems',
|
||||||
|
parameters: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import { LoggedCharactersViewModel } from '../types/viewmodels/character-viewmod
|
|||||||
import { CharacterStatsViewModel } from '../types/viewmodels/character-viewmodels/CharacterStatsViewModel';
|
import { CharacterStatsViewModel } from '../types/viewmodels/character-viewmodels/CharacterStatsViewModel';
|
||||||
import { CharacterFromTemplatesViewModel } from '../types/viewmodels/character-viewmodels/CharacterFromTemplatesViewModel';
|
import { CharacterFromTemplatesViewModel } from '../types/viewmodels/character-viewmodels/CharacterFromTemplatesViewModel';
|
||||||
import { SuccessResponse } from '../types/SuccessResponse';
|
import { SuccessResponse } from '../types/SuccessResponse';
|
||||||
|
import { CharacterBasicInfoViewModel } from '../types/viewmodels/character-viewmodels/CharacterBasicInfoViewModel';
|
||||||
|
|
||||||
Injectable({
|
Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@ -117,4 +118,24 @@ export class CharacterService {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetCharacterBasicInfo(
|
||||||
|
characterId: number
|
||||||
|
): Observable<CharacterBasicInfoViewModel> {
|
||||||
|
const params = new HttpParams().set('characterId', characterId.toString());
|
||||||
|
return this.http
|
||||||
|
.get<Either<CharacterBasicInfoViewModel, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'characterBasicInfo',
|
||||||
|
{ params }
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,167 @@
|
|||||||
|
import { Inject, Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable, of, throwError } from 'rxjs';
|
||||||
|
import { ShopkeeperViewModel } from '../types/viewmodels/shopkeeper-viewmodels/ShopkeeperViewModel';
|
||||||
|
import { Either } from '../types/Either';
|
||||||
|
import { ErrorResponse } from '../types/ErrorResponse';
|
||||||
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { SuccessResponse } from '../types/SuccessResponse';
|
||||||
|
import { ShopkeeperWithItemsDetailsViewModel } from '../types/viewmodels/shopkeeper-viewmodels/ShopkeeperWithItemsDetailsViewModel';
|
||||||
|
import { ShopkeeperWithItemsViewModel } from '../types/viewmodels/shopkeeper-viewmodels/ShopkeeperWithItemsViewModel';
|
||||||
|
|
||||||
|
Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
});
|
||||||
|
export class ShopkeeperService {
|
||||||
|
private baseUrl = 'api/shopkeeper/';
|
||||||
|
constructor(private http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
|
||||||
|
this.baseUrl = baseUrl + this.baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAllShopkeepers(): Observable<ShopkeeperViewModel[]> {
|
||||||
|
return this.http
|
||||||
|
.get<Either<ShopkeeperViewModel[], ErrorResponse>>(
|
||||||
|
this.baseUrl + 'getShopkeepers'
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetActiveShopkeeper(): Observable<ShopkeeperWithItemsDetailsViewModel> {
|
||||||
|
return this.http
|
||||||
|
.get<Either<ShopkeeperWithItemsDetailsViewModel, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'getActiveShopkeeper'
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateShopkeeper(
|
||||||
|
shopkeeperModel: ShopkeeperWithItemsViewModel
|
||||||
|
): Observable<SuccessResponse> {
|
||||||
|
const httpOptions = {
|
||||||
|
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<Either<SuccessResponse, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'createNewShopkeeper',
|
||||||
|
shopkeeperModel,
|
||||||
|
httpOptions
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeShopkeeperStatus(
|
||||||
|
shopkeeperId: number,
|
||||||
|
newStatus: boolean
|
||||||
|
): Observable<SuccessResponse> {
|
||||||
|
const params = new HttpParams()
|
||||||
|
.set('shopkeeperId', shopkeeperId.toString())
|
||||||
|
.set('availability', newStatus.toString());
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.put<Either<SuccessResponse, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'changeShopkeeperStatus',
|
||||||
|
null,
|
||||||
|
{ params }
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveShopkeeper(
|
||||||
|
shopkeeperId: number,
|
||||||
|
currentStatus: boolean
|
||||||
|
): Observable<SuccessResponse> {
|
||||||
|
const params = new HttpParams()
|
||||||
|
.set('shopkeeperId', shopkeeperId.toString())
|
||||||
|
.set('wasAvailable', currentStatus.toString());
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.delete<Either<SuccessResponse, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'removeShopkeeper',
|
||||||
|
{ params }
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyItemFromShopkeeper(
|
||||||
|
shopkeeperId: number,
|
||||||
|
characterId: number,
|
||||||
|
weaponId: number,
|
||||||
|
armorId: number,
|
||||||
|
amount: number
|
||||||
|
): Observable<SuccessResponse> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
|
||||||
|
if (armorId != null) {
|
||||||
|
params = new HttpParams()
|
||||||
|
.set('shopkeeperId', shopkeeperId.toString())
|
||||||
|
.set('characterId', characterId.toString())
|
||||||
|
.set('amount', amount.toString())
|
||||||
|
.set('armorId', armorId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weaponId != null) {
|
||||||
|
params = new HttpParams()
|
||||||
|
.set('shopkeeperId', shopkeeperId.toString())
|
||||||
|
.set('characterId', characterId.toString())
|
||||||
|
.set('amount', amount.toString())
|
||||||
|
.set('weaponId', weaponId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.put<Either<SuccessResponse, ErrorResponse>>(
|
||||||
|
this.baseUrl + 'buyItem',
|
||||||
|
null,
|
||||||
|
{ params }
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
switchMap((response) => {
|
||||||
|
if (response.isLeft) {
|
||||||
|
return of(response.left);
|
||||||
|
} else {
|
||||||
|
return throwError(response.right);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
export interface CharacterBasicInfoViewModel {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
level: number;
|
||||||
|
currentHealthPoints: number;
|
||||||
|
maxHealthPoints: number;
|
||||||
|
class: string;
|
||||||
|
race: string;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
export interface ShopkeeperItemsViewModel {
|
||||||
|
shopkeeperId: number;
|
||||||
|
armorId: number;
|
||||||
|
weaponId: number;
|
||||||
|
amount: number;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
export interface ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel {
|
||||||
|
shopkeeperId: number;
|
||||||
|
armorId: number;
|
||||||
|
weaponId: number;
|
||||||
|
amount: number;
|
||||||
|
amountToBuy: number;
|
||||||
|
armor: {};
|
||||||
|
weapon: {};
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
export interface ShopkeeperItemsWithItemNameAndTypeViewModel {
|
||||||
|
shopkeeperId: number;
|
||||||
|
armorId: number;
|
||||||
|
weaponId: number;
|
||||||
|
amount: number;
|
||||||
|
itemName: string;
|
||||||
|
itemType: string;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface ShopkeeperViewModel {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
isAvailable: boolean;
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
export interface ShopkeeperWithItemsDetailsViewModel {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
isAvailable: boolean;
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
shopkeeperId: number;
|
||||||
|
armorId: number;
|
||||||
|
armor: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
category: string;
|
||||||
|
armorClassBase: string;
|
||||||
|
haveDexterityBonus: true;
|
||||||
|
minimumStrength: number;
|
||||||
|
haveStealthDisadvantage: boolean;
|
||||||
|
weight: number;
|
||||||
|
cost: number;
|
||||||
|
currencyType: number;
|
||||||
|
};
|
||||||
|
weaponId: number;
|
||||||
|
weapon: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
cost: number;
|
||||||
|
weight: number;
|
||||||
|
currencyType: number;
|
||||||
|
diceCount: number;
|
||||||
|
diceValue: number;
|
||||||
|
twoHandDiceCount: number;
|
||||||
|
twoHandDiceValue: number;
|
||||||
|
twoHandDamageType: string;
|
||||||
|
description: string;
|
||||||
|
weaponType: string;
|
||||||
|
rangeMeele: number;
|
||||||
|
rangeThrowNormal: number;
|
||||||
|
rangeThrowLong: number;
|
||||||
|
rangeLong: number;
|
||||||
|
};
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { ShopkeeperItemsViewModel } from './ShopkeeperItemsViewModel';
|
||||||
|
|
||||||
|
export interface ShopkeeperWithItemsViewModel {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
isAvailable: boolean;
|
||||||
|
items: ShopkeeperItemsViewModel[];
|
||||||
|
}
|
@ -11,26 +11,54 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SessionCompanion.Controllers
|
namespace SessionCompanion.Controllers
|
||||||
{
|
{
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
using SessionCompanion.Hubs;
|
||||||
|
using SessionCompanion.ViewModels.CharacterArmorViewModels;
|
||||||
|
using SessionCompanion.ViewModels.CharacterWeaponViewModels;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/shopkeeper")]
|
[Route("api/shopkeeper")]
|
||||||
public class ShopkeeperController : Controller
|
public class ShopkeeperController : Controller
|
||||||
{
|
{
|
||||||
private IShopkeeperService _service;
|
private IShopkeeperService _service;
|
||||||
public ShopkeeperController(IShopkeeperService shopkeeperService)
|
|
||||||
|
private IShopkeeperItemService _shopkeeperItemsService;
|
||||||
|
|
||||||
|
private ICharacterArmorService _characterArmorService;
|
||||||
|
|
||||||
|
private ICharacterWeaponService _characterWeaponService;
|
||||||
|
private IHubContext<SessionHub> _sessionHub;
|
||||||
|
|
||||||
|
public ShopkeeperController(IShopkeeperService shopkeeperService, IShopkeeperItemService shopkeeperItemsService, ICharacterWeaponService characterWeaponService, ICharacterArmorService characterArmorService, IHubContext<SessionHub> sessionHub)
|
||||||
{
|
{
|
||||||
_service = shopkeeperService;
|
this._service = shopkeeperService;
|
||||||
|
this._shopkeeperItemsService = shopkeeperItemsService;
|
||||||
|
this._characterArmorService = characterArmorService;
|
||||||
|
this._characterWeaponService = characterWeaponService;
|
||||||
|
this._sessionHub = sessionHub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Endpoint zwracający liste sklepikarzy
|
/// Endpoint zwracający liste sklepikarzy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Lista sklepikarzy</returns>
|
/// <returns>Lista sklepikarzy</returns>
|
||||||
[HttpGet("getShopkeepers")]
|
[HttpGet("getShopkeepers")]
|
||||||
public async Task<List<ShopkeeperViewModel>> GetShopkeepers()
|
public async Task<Either<List<ShopkeeperViewModel>, ErrorResponse>> GetShopkeepers()
|
||||||
{
|
{
|
||||||
return _service.Get().ToList();
|
return _service.Get().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Endpoint zwracający aktywnego sklepikarza
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Lista sklepikarzy</returns>
|
||||||
|
[HttpGet("getActiveShopkeeper")]
|
||||||
|
public async Task<Either<ShopkeeperWithItemsDetailsViewModel, ErrorResponse>> GetActiveShopkeepers()
|
||||||
|
{
|
||||||
|
return await _service.GetActiveShkopkeeperWithItems();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Endpoint służacy do zmiany statusu sklepikarza
|
/// Endpoint służacy do zmiany statusu sklepikarza
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -38,9 +66,118 @@ namespace SessionCompanion.Controllers
|
|||||||
/// <param name="availability"></param>
|
/// <param name="availability"></param>
|
||||||
/// <returns>SuccesResponse/ErrorResponse</returns>
|
/// <returns>SuccesResponse/ErrorResponse</returns>
|
||||||
[HttpPut("changeShopkeeperStatus")]
|
[HttpPut("changeShopkeeperStatus")]
|
||||||
public async Task<Either<SuccessResponse, ErrorResponse>> ChangeShopkeeperStatus([Required] int shopkeeperId, [Required] bool availability)
|
public async Task<Either<SuccessResponse, ErrorResponse>> ChangeShopkeeperStatus([FromQuery][Required] int shopkeeperId, [FromQuery][Required] bool availability)
|
||||||
{
|
{
|
||||||
return await _service.ChangeShopkeeperStatus(shopkeeperId, availability);
|
var result = await _service.ChangeShopkeeperStatus(shopkeeperId, availability);
|
||||||
|
if (result.IsLeft && availability)
|
||||||
|
{
|
||||||
|
await this._sessionHub.Clients.Group("Players").SendAsync("NewShopkeeperArrived");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await this._sessionHub.Clients.Group("Players").SendAsync("ShopkeeperLeft");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Metoda kupna przedmiotu od Shopkeepera
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="shopkeeperId">id sprzedawcy</param>
|
||||||
|
/// <param name="characterId">id postaci</param>
|
||||||
|
/// <param name="weaponId">id broni</param>
|
||||||
|
/// <param name="armorId">id pancerza</param>
|
||||||
|
/// <param name="amount">ilosc przedmiotu do kupienia</param>
|
||||||
|
/// <returns>Sukces bądź błąd</returns>
|
||||||
|
[HttpPut("buyItem")]
|
||||||
|
public async Task<Either<SuccessResponse, ErrorResponse>> BuyItemFromShopkeeper([Required] int shopkeeperId, [Required] int characterId, int? weaponId, int? armorId, [Required] int amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
{
|
||||||
|
return new ErrorResponse("Given amount is 0 or less");
|
||||||
|
}
|
||||||
|
if (shopkeeperId <= 0)
|
||||||
|
{
|
||||||
|
return new ErrorResponse("Wrong Shopkeeper Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterId <= 0)
|
||||||
|
{
|
||||||
|
return new ErrorResponse("Wrong Character Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
var substrackResult = await this._shopkeeperItemsService.GetActiveShkopkeeperWithItems(shopkeeperId, amount, weaponId, armorId);
|
||||||
|
|
||||||
|
if (substrackResult.IsLeft)
|
||||||
|
{
|
||||||
|
await this._sessionHub.Clients.Groups("Players").SendAsync("ItemFromShopkeeperWasBought");
|
||||||
|
|
||||||
|
if (weaponId.HasValue)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
await this._characterWeaponService.Create(
|
||||||
|
new CharacterWeaponViewModel()
|
||||||
|
{
|
||||||
|
CharacterId = characterId,
|
||||||
|
HoldInLeftHand = false,
|
||||||
|
HoldInRightHand = false,
|
||||||
|
InUse = false,
|
||||||
|
WeaponId = weaponId.Value
|
||||||
|
});
|
||||||
|
await this._characterWeaponService.SaveAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (armorId.HasValue)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
await this._characterArmorService.Create(
|
||||||
|
new CharacterArmorViewModel()
|
||||||
|
{
|
||||||
|
ArmorId = armorId.Value,
|
||||||
|
CharacterId = characterId,
|
||||||
|
InUse = false
|
||||||
|
});
|
||||||
|
await this._characterArmorService.SaveAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SuccessResponse("Ttems have been purchased");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return substrackResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost("createNewShopkeeper")]
|
||||||
|
public async Task<Either<SuccessResponse, ErrorResponse>> CreateNewShopKeeper([Required] ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return new ErrorResponse() { StatusCode = 500, Message = "Model is invalid" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _service.CreateNewShopKeeper(shopkeeperWithItemsViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("removeShopkeeper")]
|
||||||
|
public async Task<Either<SuccessResponse, ErrorResponse>> RemoveShopkeeper([Required] int shopkeeperId, bool wasAvailable)
|
||||||
|
{
|
||||||
|
await this._service.Delete(shopkeeperId);
|
||||||
|
await this._service.SaveAsync();
|
||||||
|
|
||||||
|
if (wasAvailable)
|
||||||
|
{
|
||||||
|
await this._sessionHub.Clients.Group("Players").SendAsync("ShopkeeperRemoved");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SuccessResponse("Delete completed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user