diff --git a/SessionCompanion/SessionCompanion.Services/Interfaces/IShopkeeperItemService.cs b/SessionCompanion/SessionCompanion.Services/Interfaces/IShopkeeperItemService.cs index 6f6bb45..197522e 100644 --- a/SessionCompanion/SessionCompanion.Services/Interfaces/IShopkeeperItemService.cs +++ b/SessionCompanion/SessionCompanion.Services/Interfaces/IShopkeeperItemService.cs @@ -9,7 +9,11 @@ using System.Threading.Tasks; namespace SessionCompanion.Services.Interfaces { + using SessionCompanion.Extensions.EitherType; + using SessionCompanion.ViewModels.ApiResponses; + public interface IShopkeeperItemService : IServiceBase { + Task> GetActiveShkopkeeperWithItems(int shopkeeperId, int amount, int? weaponId, int? armorId); } } diff --git a/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperItemService.cs b/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperItemService.cs index 271e927..1778f59 100644 --- a/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperItemService.cs +++ b/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperItemService.cs @@ -5,16 +5,56 @@ using SessionCompanion.Services.Base; using SessionCompanion.Services.Interfaces; using SessionCompanion.ViewModels.ShopkeeperItemsViewModels; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; 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, IShopkeeperItemService { public ShopkeeperItemService(IMapper mapper, IRepository repository) : base(mapper, repository) { } + + public async Task> 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 }; + } + } } } diff --git a/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperService.cs b/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperService.cs index 73ec699..d859da0 100644 --- a/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperService.cs +++ b/SessionCompanion/SessionCompanion.Services/Services/ShopkeeperService.cs @@ -86,7 +86,7 @@ namespace SessionCompanion.Services.Services .Include(t => t.ShopkeeperItems) .ThenInclude(t => t.Armor) .Include(t => t.ShopkeeperItems) - .ThenInclude(t => t.Weapon).SingleAsync(); + .ThenInclude(t => t.Weapon).FirstOrDefaultAsync(); var result = Mapper.Map(activeShopkeeper); return result; } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts index 1b290e7..a26051f 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts @@ -65,6 +65,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.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({ declarations: [ @@ -94,6 +95,7 @@ import { NewShopkeeperDialogComponent } from './components/game-master-shopkeepe GameMasterTurntrackerComponent, ChooseMonsterDialogComponent, NewShopkeeperDialogComponent, + PlayerShopComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), @@ -158,6 +160,7 @@ import { NewShopkeeperDialogComponent } from './components/game-master-shopkeepe GameMasterTurntrackerComponent, ChooseMonsterDialogComponent, NewShopkeeperDialogComponent, + PlayerShopComponent, ], }) export class AppModule {} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.css index 95aaff4..9e7e493 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.css +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.css @@ -1,9 +1,16 @@ -@import "../../../styles.css"; +@import '../../../styles.css'; -.toggle-class{ +.toggle-class { margin: 5px; } +.character-name { + width: 240px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .menu-spacer { flex: 1 1 auto; } @@ -36,7 +43,7 @@ background-color: #102028; } -.mat-list-item.active{ +.mat-list-item.active { color: #e9cca7; } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.html index 9920974..797b0dd 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.html +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.html @@ -5,8 +5,8 @@ menu -
- Session Companion +
+ {{characterName}}
@@ -47,7 +47,7 @@ Profile --> - + shopping_cart Shop diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts index 2041330..02ef477 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts @@ -12,6 +12,8 @@ import { Router } from '@angular/router'; import { ClearCharacterId } from '../../store/actions/player.action'; import { MatSnackBar } from '@angular/material'; import { SnackbarComponent } from '../../shared/snackbar/snackbar.component'; +import { CharacterService } from '../../../services/character.service'; +import { PlayerShopComponent } from '../player-shop/player-shop.component'; @Component({ selector: 'app-player-dashboard', @@ -22,12 +24,14 @@ export class PlayerDashboardComponent implements OnInit { middleComponent; isExpanded = false; selected = false; + characterName: string = ''; constructor( private signalRService: PlayerSignalRService, private store: Store, private router: Router, - private _snackBar: MatSnackBar + private _snackBar: MatSnackBar, + private characterService: CharacterService ) {} ngOnInit() { @@ -38,6 +42,13 @@ export class PlayerDashboardComponent implements OnInit { this.SubscribeToEvents(); this.signalRService.Login(id); this.SwitchMiddleComponent('AbilitiesComponent'); + this.characterService + .GetCharacterBasicInfo(id) + .pipe(first()) + .subscribe((result) => { + console.log(result); + this.characterName = result.name; + }); }); } @@ -59,6 +70,9 @@ export class PlayerDashboardComponent implements OnInit { case 'PlayerOtherEquipmentTableComponent': this.middleComponent = PlayerOtherEquipmentTableComponent; break; + case 'PlayerShopComponent': + this.middleComponent = PlayerShopComponent; + break; } } @@ -82,6 +96,12 @@ export class PlayerDashboardComponent implements OnInit { gmMessage: result.parameters.message, }, }); + break; + case 'RefreshShopComponent': + this.middleComponent = ''; + + this.middleComponent = PlayerShopComponent; + break; } } ); diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.css new file mode 100644 index 0000000..eb0329a --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.css @@ -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; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.html new file mode 100644 index 0000000..5f81186 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.html @@ -0,0 +1,70 @@ +
+ +
+
+

+ {{shopkeeper.name}} +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name + + {{row.armor.name}} + + + {{row.weapon.name}} + + Type + + Armor + + + Weapon + + Amount {{row.amount}} How many + + + + Actions + +
No data found
+ + +
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.ts new file mode 100644 index 0000000..f6b76a0 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-shop/player-shop.component.ts @@ -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; + @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; + @ViewChild(MatSort, { static: true }) sort: MatSort; + + constructor( + private shopkeeperService: ShopkeeperService, + private signalRService: PlayerSignalRService, + private store: Store + ) {} + + 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( + (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; + } + } + ); + } +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-weapons-table/player-weapons-table.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-weapons-table/player-weapons-table.component.ts index 89d454a..b9db9f7 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-weapons-table/player-weapons-table.component.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-weapons-table/player-weapons-table.component.ts @@ -13,22 +13,20 @@ import { AppState } from '../../store/models/app-state.model'; @Component({ selector: 'app-player-weapons-table', templateUrl: './player-weapons-table.component.html', - styleUrls: ['./player-weapons-table.component.css'] + styleUrls: ['./player-weapons-table.component.css'], }) export class PlayerWeaponsTableComponent implements OnInit { weapons: WeaponViewModel[]; - displayedColumns: string[] = [ - 'name', - 'weaponType', - 'weight', - 'cost', - ]; + displayedColumns: string[] = ['name', 'weaponType', 'weight', 'cost']; dataSource: MatTableDataSource; @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @ViewChild(MatSort, { static: true }) sort: MatSort; - constructor(private store: Store, private equipmentService: EquipmentService) {} + constructor( + private store: Store, + private equipmentService: EquipmentService + ) {} ngOnInit() { this.getCharacterWeapons(); @@ -40,7 +38,7 @@ export class PlayerWeaponsTableComponent implements OnInit { .pipe(first()) .subscribe((characterId) => { this.equipmentService - .getCharacterWeapons(1) + .getCharacterWeapons(characterId) .pipe(first()) .subscribe( (result) => { diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts index 4216e7f..c085d1e 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts @@ -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: {}, + }); + }); } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts index db70675..59ddd7f 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts @@ -1,16 +1,17 @@ -import {Inject, Injectable} from '@angular/core'; -import {HttpClient, HttpParams} from '@angular/common/http'; -import {Observable, of, throwError} from 'rxjs'; -import {ErrorResponse} from '../types/ErrorResponse'; -import {Either} from '../types/Either'; -import {CharacterForLoginViewModel} from '../types/viewmodels/character-viewmodels/CharacterForLoginViewModel'; -import {switchMap, retry} from 'rxjs/operators'; -import {LoggedCharactersViewModel} from '../types/viewmodels/character-viewmodels/LoggedCharactersViewModel'; -import {CharacterStatsViewModel} from "../types/viewmodels/character-viewmodels/CharacterStatsViewModel"; +import { Inject, Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, of, throwError } from 'rxjs'; +import { ErrorResponse } from '../types/ErrorResponse'; +import { Either } from '../types/Either'; +import { CharacterForLoginViewModel } from '../types/viewmodels/character-viewmodels/CharacterForLoginViewModel'; +import { switchMap, retry } from 'rxjs/operators'; +import { LoggedCharactersViewModel } from '../types/viewmodels/character-viewmodels/LoggedCharactersViewModel'; +import { CharacterStatsViewModel } from '../types/viewmodels/character-viewmodels/CharacterStatsViewModel'; +import { CharacterBasicInfoViewModel } from '../types/viewmodels/character-viewmodels/CharacterBasicInfoViewModel'; Injectable({ - providedIn: 'root' -}) + providedIn: 'root', +}); export class CharacterService { private baseUrl = 'api/character/'; constructor(private http: HttpClient, @Inject('BASE_URL') baseUrl: string) { @@ -18,42 +19,79 @@ export class CharacterService { } getLoggedCharacters(): Observable { - return this.http.get>(this.baseUrl + 'loggedCharacters').pipe( - switchMap(response => { - if (response.isLeft) { - return of(response.left); - } else { - return throwError(response.right); - } - }), - retry(3) - ); + return this.http + .get>( + this.baseUrl + 'loggedCharacters' + ) + .pipe( + switchMap((response) => { + if (response.isLeft) { + return of(response.left); + } else { + return throwError(response.right); + } + }), + retry(3) + ); } - getUserCharactersList(userId: number): Observable { - const params = new HttpParams().set('userId', userId.toString()) - return this.http.get>(this.baseUrl + 'userCharactersList', {params}).pipe( - switchMap(response => { - if (response.isLeft) { - return of(response.left); - } else { - return throwError(response.right); - } - }) - ); + getUserCharactersList( + userId: number + ): Observable { + const params = new HttpParams().set('userId', userId.toString()); + return this.http + .get>( + this.baseUrl + 'userCharactersList', + { params } + ) + .pipe( + switchMap((response) => { + if (response.isLeft) { + return of(response.left); + } else { + return throwError(response.right); + } + }) + ); } - getCharacterStats(characterId: number): Observable { - const params = new HttpParams().set('characterId', characterId.toString()) - return this.http.get>( this.baseUrl + 'characterStats', {params}).pipe( - switchMap( response => { - if (response.isLeft) { - return of(response.left); - } else { - return throwError(response.right); - } - }) - ); + getCharacterStats( + characterId: number + ): Observable { + const params = new HttpParams().set('characterId', characterId.toString()); + return this.http + .get>( + this.baseUrl + 'characterStats', + { params } + ) + .pipe( + switchMap((response) => { + if (response.isLeft) { + return of(response.left); + } else { + return throwError(response.right); + } + }) + ); } + GetCharacterBasicInfo( + characterId: number + ): Observable { + const params = new HttpParams().set('characterId', characterId.toString()); + return this.http + .get>( + this.baseUrl + 'characterBasicInfo', + { params } + ) + .pipe( + switchMap((response) => { + if (response.isLeft) { + return of(response.left); + } else { + return throwError(response.right); + } + }) + ); + } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/services/shopkeeper.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/services/shopkeeper.service.ts index f29a9d0..ad66d52 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/services/shopkeeper.service.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/services/shopkeeper.service.ts @@ -128,4 +128,46 @@ export class ShopkeeperService { }) ); } + + BuyItemFromShopkeeper( + shopkeeperId: number, + characterId: number, + weaponId: number, + armorId: number, + amount: number + ): Observable { + 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>( + this.baseUrl + 'buyItem', + null, + { params } + ) + .pipe( + switchMap((response) => { + if (response.isLeft) { + return of(response.left); + } else { + return throwError(response.right); + } + }) + ); + } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterBasicInfoViewModel.ts b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterBasicInfoViewModel.ts new file mode 100644 index 0000000..c2d6347 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterBasicInfoViewModel.ts @@ -0,0 +1,9 @@ +export interface CharacterBasicInfoViewModel { + id: number; + name: string; + level: number; + currentHealthPoints: number; + maxHealthPoints: number; + class: string; + race: string; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel.ts b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel.ts new file mode 100644 index 0000000..377004d --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/shopkeeper-viewmodels/ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel.ts @@ -0,0 +1,9 @@ +export interface ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel { + shopkeeperId: number; + armorId: number; + weaponId: number; + amount: number; + amountToBuy: number; + armor: {}; + weapon: {}; +} diff --git a/SessionCompanion/SessionCompanion/Controllers/ShopkeeperController.cs b/SessionCompanion/SessionCompanion/Controllers/ShopkeeperController.cs index dfcc2b0..674d264 100644 --- a/SessionCompanion/SessionCompanion/Controllers/ShopkeeperController.cs +++ b/SessionCompanion/SessionCompanion/Controllers/ShopkeeperController.cs @@ -14,17 +14,28 @@ namespace SessionCompanion.Controllers using Microsoft.AspNetCore.SignalR; using SessionCompanion.Hubs; + using SessionCompanion.ViewModels.CharacterArmorViewModels; + using SessionCompanion.ViewModels.CharacterWeaponViewModels; [ApiController] [Route("api/shopkeeper")] public class ShopkeeperController : Controller { private IShopkeeperService _service; + + private IShopkeeperItemService _shopkeeperItemsService; + + private ICharacterArmorService _characterArmorService; + + private ICharacterWeaponService _characterWeaponService; private IHubContext _sessionHub; - public ShopkeeperController(IShopkeeperService shopkeeperService, IHubContext sessionHub) + public ShopkeeperController(IShopkeeperService shopkeeperService, IShopkeeperItemService shopkeeperItemsService, ICharacterWeaponService characterWeaponService, ICharacterArmorService characterArmorService, IHubContext sessionHub) { this._service = shopkeeperService; + this._shopkeeperItemsService = shopkeeperItemsService; + this._characterArmorService = characterArmorService; + this._characterWeaponService = characterWeaponService; this._sessionHub = sessionHub; } @@ -70,6 +81,80 @@ namespace SessionCompanion.Controllers return result; } + /// + /// Metoda kupna przedmiotu od Shopkeepera + /// + /// id sprzedawcy + /// id postaci + /// id broni + /// id pancerza + /// ilosc przedmiotu do kupienia + /// Sukces bądź błąd + [HttpPut("buyItem")] + public async Task> 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> CreateNewShopKeeper([Required] ShopkeeperWithItemsViewModel shopkeeperWithItemsViewModel) {