Merge pull request 'SES-135 abilities card' (#63) from SES-135 into dev

Reviewed-on: #63
This commit is contained in:
Łukasz Góreczny 2021-01-10 16:02:19 +01:00
commit eefd121157
12 changed files with 186 additions and 42 deletions

View File

@ -36,7 +36,7 @@ const routes: Routes = [
path: 'select-character',
component: SelectCharacterComponent,
pathMatch: 'full'
}
},
];
export const appRoutingModule = RouterModule.forRoot(routes);

View File

@ -35,6 +35,7 @@ import { CharacterService } from '../services/character.service';
import { AbilityCardComponent } from './components/ability-card/ability-card.component';
import { GameMasterSpellsTableComponent } from './components/game-master-spells-table/game-master-spells-table.component';
import { GameMasterArmorsTableComponent } from './components/game-master-armors-table/game-master-armors-table.component';
import { AbilitiesComponent } from './components/abilities/abilities.component';
@NgModule({
declarations: [
@ -48,6 +49,7 @@ import { GameMasterArmorsTableComponent } from './components/game-master-armors-
AbilityCardComponent,
GameMasterSpellsTableComponent,
GameMasterArmorsTableComponent,
AbilitiesComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
@ -79,6 +81,7 @@ import { GameMasterArmorsTableComponent } from './components/game-master-armors-
entryComponents: [
GameMasterSpellsTableComponent,
GameMasterArmorsTableComponent,
AbilitiesComponent,
],
})
export class AppModule {}

View File

@ -0,0 +1,6 @@
<div *ngFor="let ability of characterStats">
<app-ability-card [ability]="ability"
[headStyle]="{bgColor: '#e9cca7', textColor: '#102028'}"
[contentStyle]="{bgColor: '#102028', textColor: 'white'}">
</app-ability-card>
</div>

View File

@ -0,0 +1,38 @@
import { Component, OnInit } from '@angular/core';
import {CharacterStatsViewModel} from "../../../types/viewmodels/character-viewmodels/CharacterStatsViewModel";
import {Store} from "@ngrx/store";
import {AppState} from "../../store/models/app-state.model";
import {CharacterService} from "../../../services/character.service";
import {first} from "rxjs/operators";
import {ErrorResponse} from "../../../types/ErrorResponse";
import {HttpErrorResponse} from "@angular/common/http";
@Component({
selector: 'app-abilities',
templateUrl: './abilities.component.html',
styleUrls: ['./abilities.component.css']
})
export class AbilitiesComponent implements OnInit {
characterStats: CharacterStatsViewModel[];
constructor(private store: Store<AppState>, private characterService: CharacterService) {}
ngOnInit() {
this.getCharacterStats();
}
getCharacterStats() {
this.store.select( s => s.playerStore.characterId).pipe(first()).subscribe((characterId) => {
this.characterService.getCharacterStats(characterId).pipe(first()).subscribe((characterStats) => {
console.log(characterStats)
this.characterStats = characterStats;
}, (error: ErrorResponse | HttpErrorResponse) => {
if (error instanceof HttpErrorResponse) {
error = error.error as ErrorResponse;
}
console.error(error.message);
});
})
}
}

View File

@ -1,30 +1,84 @@
#ability-value:hover{
opacity: 0.5;
cursor: pointer;
}
#ability-saving-throws:hover{
opacity: 0.5;
cursor: pointer;
}
.cardContainerClass {
border: 2px solid;
border-radius: 10px;
box-shadow: 0 0 8px;
}
#main{
width: 480px;
height: 480px;
padding-bottom: 15px;
}
@media (max-width: 468px) {
#main {
width: 340px;
}
}
@media (min-width: 468px) and (max-width: 768px) {
#main {
width: 420px;
}
}
@media (min-width: 768px) {
#main {
width: 480px;
}
}
#main>.mat-card{
padding: 0;
}
.diagonal-line{
width:50px;
background:linear-gradient(45deg,rgb(16 32 40 / 0%) 49%,black,#ffffff00 51%);
background:linear-gradient(45deg,rgb(16 32 40 / 0%) 49%,white,#ffffff00 51%);
}
#ability-card-header {
font-weight: 600;
border-radius: 10px 10px 0 0;
}
@media (max-width: 468px) {
#ability-card-header {
font-size: 11px;
}
}
#ability-card-content{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 0 0 10px 10px;
}
#skill-btn{
border-color: black;
border: 2px solid #9e814d;
flex: 1 0 auto;
margin-bottom: 10px;
margin-left: 10px;
margin-right: 10px;
border-radius: 5px;
}
#skill-btn:hover{
opacity: 0.5;
}
#skill-btn-divider{
border-left: black 1px solid;
border-left: #9e814d 2px solid;
padding-right: 10px;
padding-top: 10px;
padding-bottom: 10px;

View File

@ -1,22 +1,22 @@
<div *ngIf="ability" id="main">
<mat-card>
<mat-card [style.border-color]="headStyle.bgColor" [style.color]="headStyle.bgColor" class="cardContainerClass">
<mat-card-header id="ability-card-header" [style.background]="headStyle.bgColor" [style.color]="headStyle.textColor">
{{ability.value}}
<div id="ability-value">{{ability.value}}</div>
<div class="diagonal-line"></div>
Mod: {{ability.modification > 0? '+' + ability.modification : '-' + ability.modification}}
<div class="diagonal-line"></div>
{{ability.name}}
<div *ngIf="ability.canSaveThrows" class="diagonal-line" style="margin-left: auto"></div>
<div *ngIf="ability.canSaveThrows" style="margin-right: 10px">
ST: {{ability.savingThrows > 0? '+' + ability.savingThrows : '-' + ability.savingThrows}}
<div id="ability-saving-throws">ST: {{ability.savingThrows > 0? '+' + ability.savingThrows : '-' + ability.savingThrows}}</div>
</div>
</mat-card-header>
<mat-divider [style.border-top-color]="'black'"></mat-divider>
<mat-card-content id="ability-card-content" [style.background]="contentStyle.bgColor" [style.color]="contentStyle.textColor">
<a mat-stroked-button *ngFor="let skill of ability.skills" id="skill-btn">
<a [style.border-color]="headStyle.bgColor" mat-stroked-button *ngFor="let skill of ability.skills" id="skill-btn">
{{skill.name}}
&nbsp; &nbsp;
<span id="skill-btn-divider"></span>
<span [style.border-left-color]="headStyle.bgColor" id="skill-btn-divider"></span>
{{skill.value > 0? '+' + skill.value : '-' + skill.value}}
</a>
</mat-card-content>

View File

@ -1,5 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { AbilityViewModel } from '../../../types/viewmodels/ability-viewmodels/AbilityViewModel';
import {CharacterStatsViewModel} from "../../../types/viewmodels/character-viewmodels/CharacterStatsViewModel";
@Component({
selector: 'app-ability-card',
@ -7,7 +8,7 @@ import { AbilityViewModel } from '../../../types/viewmodels/ability-viewmodels/A
styleUrls: ['./ability-card.component.css'],
})
export class AbilityCardComponent implements OnInit {
@Input() ability: AbilityViewModel;
@Input() ability: CharacterStatsViewModel;
@Input() headStyle: { bgColor: string; textColor: string };
@Input() contentStyle: { bgColor: string; textColor: string };
@ -15,5 +16,29 @@ export class AbilityCardComponent implements OnInit {
ngOnInit() {
this.ability.skills.sort((a, b) => (a.name > b.name ? 1 : -1));
this.changeColors();
}
changeColors(){
switch(this.ability.name){
case 'Charisma':
this.headStyle.bgColor = '#FFEB85';
break;
case 'Dexterity':
this.headStyle.bgColor = '#4BBE9C';
break;
case 'Constitution':
this.headStyle.bgColor = 'red';
break;
case 'Intelligence':
this.headStyle.bgColor = '#5AA9E6';
break;
case 'Strength':
this.headStyle.bgColor = '#C41E3D';
break;
case 'Wisdom':
this.headStyle.bgColor = '#9F4BBE';
break;
}
}
}

View File

@ -15,37 +15,32 @@
<mat-sidenav #sidenav class="sidenav">
<mat-nav-list>
<mat-list-item [routerLink]="['/player']" [routerLinkActive]="['active']">
<mat-icon [class.active]="selected" matListIcon>home</mat-icon>
<a matLine>Home</a>
</mat-list-item>
<mat-list-item [routerLink]="['/player/statistic']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>query_stats</mat-icon>
<a matLine>Statistic and throws</a>
<a matLine>Statistic and throws</a>
</mat-list-item>
<mat-list-item [routerLink]="['/player/equipment']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>local_mall</mat-icon>
<a matLine>Equipment</a>
</mat-list-item>
<mat-list-item [routerLink]="['/player/spells']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>brightness_4</mat-icon>
<a matLine>Spells</a>
</mat-list-item>
<mat-list-item [routerLink]="['/player/profile']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>account_circle</mat-icon>
<a matLine>Profile</a>
</mat-list-item>
<mat-list-item [routerLink]="['/player/shop']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>shopping_cart</mat-icon>
<a matLine>Shop</a>
</mat-list-item>
<mat-list-item [routerLink]="['/']" [routerLinkActive]="['active']">
<mat-list-item>
<mat-icon [class.active]="selected" matListIcon>exit_to_app</mat-icon>
<a matLine>Log out</a>
</mat-list-item>
@ -53,7 +48,9 @@
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content class="content">
<app-ability-card class="ability_card_container" [ability]="ability" [contentStyle]="{bgColor: 'red', textColor: 'white'}" [headStyle]="{bgColor: 'red', textColor: 'white'}"></app-ability-card>
<div class="ability_card_container">
<ng-container *ngComponentOutlet="middleComponent"></ng-container>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
</div>

View File

@ -1,9 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { AbilityViewModel } from "../../../types/viewmodels/ability-viewmodels/AbilityViewModel";
import { PlayerSignalRService } from "../../shared/signalR-service/player-signalR.service";
import { first } from "rxjs/operators";
import { Store } from '@ngrx/store';
import { AppState } from 'src/app/store/models/app-state.model';
import { AbilitiesComponent } from '../abilities/abilities.component';
@Component({
selector: 'app-player-dashboard',
@ -11,6 +11,7 @@ import { AppState } from 'src/app/store/models/app-state.model';
styleUrls: ['./player-dashboard.component.css'],
})
export class PlayerDashboardComponent implements OnInit {
middleComponent;
isExpanded = false;
selected = false;
@ -20,25 +21,17 @@ export class PlayerDashboardComponent implements OnInit {
this.store.select(s => s.playerStore.characterId).pipe(first()).subscribe((id) => {
this.signalRService.Login(id);
});
}
ability: AbilityViewModel = {
id: 1,
name: 'Strength',
value: 18,
modification: 2,
canSaveThrows: true,
savingThrows: 1,
skills: [
{
name: 'Throw',
value: 1,
can: false
}
]
this.SwitchMiddleComponent('AbilitiesComponent');
}
toggle() {
this.isExpanded = !this.isExpanded;
this.isExpanded = !this.isExpanded;
}
SwitchMiddleComponent(componentName: string) {
switch(componentName){
case 'AbilitiesComponent':
this.middleComponent = AbilitiesComponent;
}
}
}

View File

@ -6,6 +6,7 @@ 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";
Injectable({
providedIn: 'root'
@ -41,4 +42,18 @@ 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 => {
if (response.isLeft) {
return of(response.left);
} else {
return throwError(response.right);
}
})
);
}
}

View File

@ -0,0 +1,13 @@
export interface CharacterStatsViewModel {
id: number;
name: string;
value: number;
modification: number;
savingThrows: number;
canSaveThrows: boolean;
skills: [{
name: string;
value: number;
can: boolean;
}];
}