SES-160 shop on gm and player screen #85
@ -9,7 +9,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SessionCompanion.Services.Interfaces
|
||||
{
|
||||
using SessionCompanion.Extensions.EitherType;
|
||||
using SessionCompanion.ViewModels.ApiResponses;
|
||||
|
||||
public interface IShopkeeperItemService : IServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>
|
||||
{
|
||||
Task<Either<SuccessResponse, ErrorResponse>> GetActiveShkopkeeperWithItems(int shopkeeperId, int amount, int? weaponId, int? armorId);
|
||||
}
|
||||
}
|
||||
|
@ -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<ShopkeeperItemViewModel, ShopkeeperItem>, IShopkeeperItemService
|
||||
{
|
||||
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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<ShopkeeperWithItemsDetailsViewModel>(activeShopkeeper);
|
||||
return result;
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -1,9 +1,16 @@
|
||||
@import "../../../styles.css";
|
||||
@import '../../../styles.css';
|
||||
|
||||
.toggle-class {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.character-name {
|
||||
width: 240px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<div fxShow="true" fxHide.lt-md>
|
||||
<span>Session Companion</span>
|
||||
<div fxShow="true" fxHide.lt-md class="character-name">
|
||||
<span>{{characterName}}</span>
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
</mat-toolbar>
|
||||
@ -47,7 +47,7 @@
|
||||
<a matLine>Profile</a>
|
||||
</mat-list-item>-->
|
||||
|
||||
<mat-list-item>
|
||||
<mat-list-item (click)="SwitchMiddleComponent('PlayerShopComponent')">
|
||||
<mat-icon [class.active]="selected" matListIcon>shopping_cart</mat-icon>
|
||||
<a matLine>Shop</a>
|
||||
</mat-list-item>
|
||||
|
@ -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<AppState>,
|
||||
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;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -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<WeaponViewModel>;
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
|
||||
constructor(private store: Store<AppState>, private equipmentService: EquipmentService) {}
|
||||
constructor(
|
||||
private store: Store<AppState>,
|
||||
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) => {
|
||||
|
@ -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: {},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,12 @@ 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 { 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,8 +19,12 @@ export class CharacterService {
|
||||
}
|
||||
|
||||
getLoggedCharacters(): Observable<LoggedCharactersViewModel[]> {
|
||||
return this.http.get<Either<LoggedCharactersViewModel[], ErrorResponse>>(this.baseUrl + 'loggedCharacters').pipe(
|
||||
switchMap(response => {
|
||||
return this.http
|
||||
.get<Either<LoggedCharactersViewModel[], ErrorResponse>>(
|
||||
this.baseUrl + 'loggedCharacters'
|
||||
)
|
||||
.pipe(
|
||||
switchMap((response) => {
|
||||
if (response.isLeft) {
|
||||
return of(response.left);
|
||||
} else {
|
||||
@ -30,10 +35,17 @@ export class CharacterService {
|
||||
);
|
||||
}
|
||||
|
||||
getUserCharactersList(userId: number): Observable<CharacterForLoginViewModel[]> {
|
||||
const params = new HttpParams().set('userId', userId.toString())
|
||||
return this.http.get<Either<CharacterForLoginViewModel[], ErrorResponse>>(this.baseUrl + 'userCharactersList', {params}).pipe(
|
||||
switchMap(response => {
|
||||
getUserCharactersList(
|
||||
userId: number
|
||||
): Observable<CharacterForLoginViewModel[]> {
|
||||
const params = new HttpParams().set('userId', userId.toString());
|
||||
return this.http
|
||||
.get<Either<CharacterForLoginViewModel[], ErrorResponse>>(
|
||||
this.baseUrl + 'userCharactersList',
|
||||
{ params }
|
||||
)
|
||||
.pipe(
|
||||
switchMap((response) => {
|
||||
if (response.isLeft) {
|
||||
return of(response.left);
|
||||
} else {
|
||||
@ -43,10 +55,17 @@ export class CharacterService {
|
||||
);
|
||||
}
|
||||
|
||||
getCharacterStats(characterId: number): Observable<CharacterStatsViewModel[]> {
|
||||
const params = new HttpParams().set('characterId', characterId.toString())
|
||||
return this.http.get<Either<CharacterStatsViewModel[], ErrorResponse>>( this.baseUrl + 'characterStats', {params}).pipe(
|
||||
switchMap( response => {
|
||||
getCharacterStats(
|
||||
characterId: number
|
||||
): Observable<CharacterStatsViewModel[]> {
|
||||
const params = new HttpParams().set('characterId', characterId.toString());
|
||||
return this.http
|
||||
.get<Either<CharacterStatsViewModel[], ErrorResponse>>(
|
||||
this.baseUrl + 'characterStats',
|
||||
{ params }
|
||||
)
|
||||
.pipe(
|
||||
switchMap((response) => {
|
||||
if (response.isLeft) {
|
||||
return of(response.left);
|
||||
} else {
|
||||
@ -56,4 +75,23 @@ 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);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -128,4 +128,46 @@ export class ShopkeeperService {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
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,9 @@
|
||||
export interface ShopkeeperItemsWithItemNameAndTypeForPlayerViewModel {
|
||||
shopkeeperId: number;
|
||||
armorId: number;
|
||||
weaponId: number;
|
||||
amount: number;
|
||||
amountToBuy: number;
|
||||
armor: {};
|
||||
weapon: {};
|
||||
}
|
@ -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> _sessionHub;
|
||||
|
||||
public ShopkeeperController(IShopkeeperService shopkeeperService, IHubContext<SessionHub> sessionHub)
|
||||
public ShopkeeperController(IShopkeeperService shopkeeperService, IShopkeeperItemService shopkeeperItemsService, ICharacterWeaponService characterWeaponService, ICharacterArmorService characterArmorService, IHubContext<SessionHub> 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;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user