-
-
-
-
-
-
-
-
- folder
- Link 1
-
-
- folder
- Link 2
-
-
- folder
- Link 3
-
-
-
-
-
- SessionCompanion
-
-
-
-
-
-
-
-
-
-
- folder
- Link 1
-
-
- folder
- Link 2
-
-
- folder
- Link 3
-
-
-
-
+
+
+
+
+
+
+
+
+
+ folder
+ Link 1
+
+
+ folder
+ Link 2
+
+
+ folder
+ Link 3
+
+
+
+
+
+ SessionCompanion
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ loggedCharacter.name.length > 12
+ ? (loggedCharacter.name | slice: 0:12) + '..'
+ : loggedCharacter.name
+ }}
+
+
+
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts
index 1b303b8..d93a20e 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts
@@ -1,20 +1,37 @@
-import {Component, OnInit} from '@angular/core';
-import {animateText, onSideNavChange} from '../../shared/animations/sidenav-animations';
-import {GMSignalRService} from '../../shared/signalR-service/gm-signalR.service';
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import {
+ animateText,
+ onSideNavChange,
+} from '../../shared/animations/sidenav-animations';
+import { GMSignalRService } from '../../shared/signalR-service/gm-signalR.service';
+import { CharacterService } from '../../../services/character.service';
+import { Subscription } from 'rxjs';
+import { ErrorResponse } from '../../../types/ErrorResponse';
+import { HttpErrorResponse } from '@angular/common/http';
+import { LoggedCharactersViewModel } from '../../../types/viewmodels/character-viewmodels/LoggedCharactersViewModel';
+import { first } from 'rxjs/operators';
@Component({
selector: 'app-game-master-dashboard',
templateUrl: './game-master-dashboard.component.html',
styleUrls: ['./game-master-dashboard.component.css'],
- animations: [onSideNavChange, animateText]
+ animations: [onSideNavChange, animateText],
})
-export class GameMasterDashboardComponent implements OnInit {
+export class GameMasterDashboardComponent implements OnInit, OnDestroy {
+ allSubscriptions = new Subscription();
leftSidenavExpanded = false;
leftSidenavTextExpanded = false;
rightSidenavExpanded = false;
rightSidenavTextExpanded = false;
- constructor(private signalRService: GMSignalRService) {}
+ loggedCharacters: LoggedCharactersViewModel[];
+
+ constructor(
+ private signalRService: GMSignalRService,
+ private characterService: CharacterService
+ ) {
+ this.SubscribeToEvents();
+ }
ngOnInit() {
this.signalRService.Login();
@@ -36,4 +53,36 @@ export class GameMasterDashboardComponent implements OnInit {
break;
}
}
+
+ UpdateCharactersList(): void {
+ this.characterService
+ .getLoggedCharacters()
+ .pipe(first())
+ .subscribe(
+ (success) => {
+ this.loggedCharacters = success;
+ },
+ (error: ErrorResponse | HttpErrorResponse) => {
+ if (error instanceof HttpErrorResponse) {
+ error = error.error as ErrorResponse;
+ }
+ console.error(error.message);
+ }
+ );
+ }
+
+ private SubscribeToEvents(): void {
+ this.signalRService.message.subscribe((message: string) => {
+ if (
+ message === 'New player connected' ||
+ message === 'Player disconnected'
+ ) {
+ this.UpdateCharactersList();
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ this.allSubscriptions.unsubscribe();
+ }
}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.html
index c9837d9..9f07043 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.html
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.html
@@ -1,6 +1,6 @@
-
arrow_back
+
arrow_back
@@ -11,7 +11,7 @@
type="text"
required
name="username">
-
+
Username is required
person
@@ -26,7 +26,7 @@
type="password"
name="password"/>
lock
-
+
Password is required
@@ -40,10 +40,10 @@
type="password"
name="confirmPassword"/>
lock
-
+
Confirm your password
-
+
Please make sure your passwords match
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.ts
index 5532c93..f3ebc93 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/registration/registration.component.ts
@@ -6,7 +6,6 @@ import {Subscription} from 'rxjs';
import {ErrorResponse} from '../../../types/ErrorResponse';
import {UserRegisterViewModel} from '../../../types/viewmodels/user-viewmodels/UserRegisterViewModel';
import {HttpErrorResponse} from '@angular/common/http';
-import {type} from 'os';
@Component({
selector: 'app-registration',
@@ -36,27 +35,33 @@ export class RegistrationComponent implements OnDestroy {
}
Register() {
- const userRegisterModel = new class implements UserRegisterViewModel {
- password: string;
- username: string;
- };
+ if (this.signUpFormGroup.valid) {
+ const userRegisterModel = new class implements UserRegisterViewModel {
+ password: string;
+ username: string;
+ };
- userRegisterModel.username = this.signUpFormGroup.get('newAccount').value['username'];
- userRegisterModel.password = this.signUpFormGroup.get('newAccount').value['password'];
+ userRegisterModel.username = this.signUpFormGroup.get('newAccount').value['username'];
+ userRegisterModel.password = this.signUpFormGroup.get('newAccount').value['password'];
- this.allSubscriptions.add(
- this.userService.registerUser(userRegisterModel).subscribe(
- () => {
- this.router.navigate(['login']);
- },
- (error: ErrorResponse | HttpErrorResponse) => {
- if (error instanceof HttpErrorResponse) {
- error = error.error as ErrorResponse;
+ this.allSubscriptions.add(
+ this.userService.registerUser(userRegisterModel).subscribe(
+ () => {
+ this.router.navigate(['login']);
+ },
+ (error: ErrorResponse | HttpErrorResponse) => {
+ if (error instanceof HttpErrorResponse) {
+ error = error.error as ErrorResponse;
+ }
+ this.apiError = true;
+ this.apiErrorMessage = error.message;
}
- this.apiError = true;
- this.apiErrorMessage = error.message;
- }
- ));
+ ));
+ } else {
+ this.signUpFormGroup.get('newAccount').get('username').markAsTouched();
+ this.signUpFormGroup.get('newAccount').get('password').markAsTouched();
+ this.signUpFormGroup.get('newAccount').get('confirmPassword').markAsTouched();
+ }
}
ngOnDestroy() {
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.css
index ccf116c..41aa481 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.css
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.css
@@ -47,10 +47,6 @@ input {
font-size: 20px;
}
-.align-to-right {
- text-align: right;
-}
-
@media (max-width: 400px) {
.container {
margin-left: 0%;
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.html
index 178319d..5eae2cc 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.html
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.html
@@ -1,21 +1,15 @@
-
arrow_back
+
arrow_back
-
+
- Oweja
- arrow_forward
+
+ account_circle
+ {{character.name}}
+ arrow_forward
+ {{character.className}} level: {{character.level}}
+
-
- James
- arrow_forward
-
-
- Legolas
- arrow_forward
-
-
-
-
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.ts
index 2409f57..bb796df 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-character/select-character.component.ts
@@ -1,30 +1,49 @@
-import { Component } from '@angular/core';
+import {Component, OnInit} from '@angular/core';
import { Router } from '@angular/router';
+import {first} from 'rxjs/operators';
+import {ClearUserId} from '../../store/actions/app.actions';
+import {ErrorResponse} from '../../../types/ErrorResponse';
+import {HttpErrorResponse} from '@angular/common/http';
+import {Store} from '@ngrx/store';
+import {AppState} from '../../store/models/app-state.model';
+import {CharacterService} from '../../../services/character.service';
+import {CharacterForLoginViewModel} from '../../../types/viewmodels/character-viewmodels/CharacterForLoginViewModel';
+import {AddCharacterId} from '../../store/actions/player.action';
@Component({
selector: 'app-select-character',
templateUrl: './select-character.component.html',
styleUrls: ['./select-character.component.css']
})
-export class SelectCharacterComponent {
- isExpanded = false;
+export class SelectCharacterComponent implements OnInit {
+ charactersList: CharacterForLoginViewModel[];
- collapse() {
- this.isExpanded = false;
+ constructor(private router: Router, private store: Store, private characterService: CharacterService) {}
+
+ ngOnInit() {
+ this.getUserCharactersList();
}
- toggle() {
- this.isExpanded = !this.isExpanded;
+ getUserCharactersList() {
+ this.store.select(s => s.appStore.userId).pipe(first()).subscribe((userId) => {
+ this.characterService.getUserCharactersList(userId).pipe(first()).subscribe((charactersList) => {
+ this.charactersList = charactersList;
+ }, (error: ErrorResponse | HttpErrorResponse) => {
+ if (error instanceof HttpErrorResponse) {
+ error = error.error as ErrorResponse;
+ }
+ console.error(error.message);
+ } );
+ });
}
- constructor(private router: Router) {}
-
- onCharacterClick(){
- this.router.navigate(['player'])
+ onCharacterClick(characterId: number) {
+ this.store.dispatch(new AddCharacterId({characterId}));
+ this.router.navigate(['player']);
}
- onArrowBackClick(){
- this.router.navigate(['login'])
+ onArrowBackClick() {
+ this.store.dispatch(new ClearUserId());
+ this.router.navigate(['login']);
}
}
-
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-role/select-role.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-role/select-role.component.ts
index 12bb627..1565301 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-role/select-role.component.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/select-role/select-role.component.ts
@@ -12,7 +12,8 @@ import {AddRole} from '../../store/actions/app.actions';
export class SelectRoleComponent {
isExpanded = false;
- constructor(private router: Router, private store: Store<{ role: string }>) {}
+ constructor(private router: Router, private store: Store<{ role: string }>) {
+ }
collapse() {
this.isExpanded = false;
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.html
index 5b673af..6eede7b 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.html
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.html
@@ -1,6 +1,6 @@
-
arrow_back
+
arrow_back
@@ -12,7 +12,7 @@
type="text"
required
name="username">
-
+
Username is required
person
@@ -28,7 +28,7 @@
type="password"
name="password"/>
lock
-
+
Password is required
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.ts
index 16ac96e..1bf5263 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/sign-in/sign-in.component.ts
@@ -6,9 +6,10 @@ import {ErrorResponse} from '../../../types/ErrorResponse';
import {Observable, Subscription} from 'rxjs';
import {HttpErrorResponse} from '@angular/common/http';
import {AppStoreModel} from '../../store/models/app-store.model';
-import { Store } from '@ngrx/store';
+import {select, Store} from '@ngrx/store';
import {AddUserId} from '../../store/actions/app.actions';
-import { AppState } from 'src/app/store/models/app-state.model';
+import {AppState} from 'src/app/store/models/app-state.model';
+import {first} from "rxjs/operators";
@Component({
selector: 'app-sign-in',
@@ -38,12 +39,12 @@ export class SignInComponent implements OnDestroy, OnInit {
});
ngOnInit() {
- this.role$ = this.store.select(s => s.appState);
+ this.role$ = this.store.select(s => s.appStore);
}
onLoginButtonClick() {
let role = '';
- this.store.select(s => s.appState.role).subscribe((v)=>{
+ this.store.select(s => s.appStore.role).pipe(first()).subscribe((v) => {
role = v;
});
this.allSubscriptions.add(
@@ -52,7 +53,6 @@ export class SignInComponent implements OnDestroy, OnInit {
this.signInFormGroup.get('signIn').value['password']).subscribe(
(success) => {
this.store.dispatch(new AddUserId({userId: success}));
- //TODO zmienić na jedna linie
if (role === 'player') {
this.router.navigate(['select-character']);
} else {
@@ -69,13 +69,12 @@ export class SignInComponent implements OnDestroy, OnInit {
));
}
- onRegisterButtonClick(){
- this.router.navigate(['register'])
- //TODO connect with backend
+ onRegisterButtonClick() {
+ this.router.navigate(['register']);
}
- onArrowBackClick(){
- this.router.navigate([''])
+ onArrowBackClick() {
+ this.router.navigate(['']);
}
collapse() {
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/reducers/index.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/reducers/index.ts
deleted file mode 100644
index 4f57bb0..0000000
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/reducers/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import {
- ActionReducer,
- ActionReducerMap,
- createFeatureSelector,
- createSelector,
- MetaReducer
-} from '@ngrx/store';
-import { environment } from '../../environments/environment';
-
-export interface State {
-
-}
-
-export const reducers: ActionReducerMap
= {
-
-};
-
-
-export const metaReducers: MetaReducer[] = !environment.production ? [] : [];
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/how-to.RMD b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/how-to.RMD
new file mode 100644
index 0000000..b0d9081
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/how-to.RMD
@@ -0,0 +1,4 @@
+Moduł został już dodany i wstrzyknięty do roota apki.
+
+Aby dodać nową ikonkę, plik svg wstawiamy do folderu assets/icons/svg-icons.
+Oraz dodajym kolejnego enuma w pliku sc-icon.model.ts
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/session-companion-icons-registry.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/session-companion-icons-registry.service.ts
new file mode 100644
index 0000000..6d48cad
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/sc-icons/session-companion-icons-registry.service.ts
@@ -0,0 +1,22 @@
+import {Injectable} from '@angular/core';
+import {scIcon} from '../../../assets/icons/sc-icon.model';
+import {MatIconRegistry} from '@angular/material';
+import {DomSanitizer} from '@angular/platform-browser';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SessionCompanionIconsRegistry {
+ constructor(private registry: MatIconRegistry, private sanitizer: DomSanitizer) {
+ }
+
+ public registerIcons(): void {
+ this.loadIcons(Object.values(scIcon), '../assets/icons/svg-icons');
+ }
+
+ private loadIcons(iconKeys: string[], iconUrl: string): void {
+ iconKeys.forEach((icon: string) => {
+ this.registry.addSvgIcon(icon, this.sanitizer.bypassSecurityTrustResourceUrl(`${iconUrl}/${icon}.svg`));
+ });
+ }
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts
index 4ca94db..08cf425 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts
@@ -1,12 +1,15 @@
import { Inject, Injectable } from '@angular/core';
import { SignalRService } from './base/signalR.service';
+import {Subject} from 'rxjs';
@Injectable({ providedIn: 'root' })
export class GMSignalRService {
signalR: SignalRService;
+ message: Subject;
constructor(@Inject('BASE_URL') baseUrl: string) {
this.signalR = new SignalRService(baseUrl);
+ this.message = new Subject();
this.registerOnServerEvents();
}
@@ -17,10 +20,15 @@ export class GMSignalRService {
if (this.signalR.connectionEstablished$.getValue() === true) {
this.signalR.hubConnection.send('GameMasterLogin');
}
- });
+ }).unsubscribe();
}
private registerOnServerEvents(): void {
-
+ this.signalR.hubConnection.on('Welcome', (message: string) => {
+ this.message.next('New player connected');
+ });
+ this.signalR.hubConnection.on('GoodBye', (message: string) => {
+ this.message.next('Player disconnected');
+ });
}
}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/app.actions.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/app.actions.ts
index 4b2b34b..362b983 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/app.actions.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/app.actions.ts
@@ -1,9 +1,9 @@
-import {AppStoreModel} from '../models/app-store.model';
-import { Action } from '@ngrx/store';
+import {Action} from '@ngrx/store';
export enum AppActionTypes {
ADD_USER_ID = '[APP] Add user id',
- ADD_ROLE = '[APP] Add role'
+ ADD_ROLE = '[APP] Add role',
+ CLEAR_USER_ID = '[APP] Clear user id'
}
export class AddUserId implements Action {
@@ -20,4 +20,13 @@ export class AddRole implements Action {
}
}
-export type AppAction = AddUserId | AddRole;
+export class ClearUserId implements Action {
+ readonly type = AppActionTypes.CLEAR_USER_ID;
+
+ constructor() {
+ }
+}
+
+
+
+export type AppAction = AddUserId | AddRole | ClearUserId;
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/player.action.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/player.action.ts
new file mode 100644
index 0000000..45c74d8
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/actions/player.action.ts
@@ -0,0 +1,15 @@
+import {Action} from "@ngrx/store";
+
+export enum PlayerActionTypes {
+ ADD_CHARACTER_ID= '[PLAYER] Add character id'
+}
+
+export class AddCharacterId implements Action {
+ readonly type = PlayerActionTypes.ADD_CHARACTER_ID;
+
+ constructor(public payload: {characterId: number}) {
+
+ }
+}
+
+export type PlayerAction = AddCharacterId;
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/app-state.model.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/app-state.model.ts
index 30226ba..fe999ff 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/app-state.model.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/app-state.model.ts
@@ -1,5 +1,15 @@
import {AppStoreModel} from './app-store.model';
+import {ActionReducerMap} from '@ngrx/store';
+import {AppReducer} from '../reducers/app.reducer';
+import {PlayerStoreModel} from './player-store.model';
+import {PlayerReducer} from '../reducers/player.reducer';
export interface AppState {
- appState: AppStoreModel;
+ appStore: AppStoreModel;
+ playerStore: PlayerStoreModel;
}
+
+export const reducers: ActionReducerMap = {
+ appStore: AppReducer,
+ playerStore: PlayerReducer,
+};
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/player-store.model.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/player-store.model.ts
new file mode 100644
index 0000000..8cc606f
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/models/player-store.model.ts
@@ -0,0 +1,3 @@
+export interface PlayerStoreModel {
+ characterId: number;
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/app.reducer.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/app.reducer.ts
index 777c63a..d86c636 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/app.reducer.ts
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/app.reducer.ts
@@ -12,6 +12,8 @@ export function AppReducer(state: AppStoreModel = initialState, action: AppActio
return {...state, userId: action.payload.userId};
case AppActionTypes.ADD_ROLE:
return {...state, role: action.payload.role};
+ case AppActionTypes.CLEAR_USER_ID:
+ return {...state, userId: null};
default:
return state;
}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/player.reducer.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/player.reducer.ts
new file mode 100644
index 0000000..3077834
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/store/reducers/player.reducer.ts
@@ -0,0 +1,15 @@
+import {PlayerStoreModel} from '../models/player-store.model';
+import {PlayerAction, PlayerActionTypes} from '../actions/player.action';
+
+const initialState: PlayerStoreModel = {
+ characterId: null
+};
+
+export function PlayerReducer(state: PlayerStoreModel = initialState, action: PlayerAction) {
+ switch (action.type) {
+ case PlayerActionTypes.ADD_CHARACTER_ID:
+ return {...state, characterId: action.payload.characterId};
+ default:
+ return state;
+ }
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/sc-icon.model.ts b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/sc-icon.model.ts
new file mode 100644
index 0000000..e3537d1
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/sc-icon.model.ts
@@ -0,0 +1,14 @@
+export enum scIcon {
+ Barbarian = 'barbarian',
+ Bard = 'bard',
+ Cleric = 'cleric',
+ Druid = 'druid',
+ Fighter = 'fighter',
+ Monk = 'monk',
+ Paladin = 'paladin',
+ Ranger = 'ranger',
+ rogue = 'rogue',
+ Sorcerer = 'sorcerer',
+ Warlock = 'warlock',
+ Wizard = 'wizard'
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/barbarian.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/barbarian.svg
new file mode 100644
index 0000000..ea18fd3
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/barbarian.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/bard.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/bard.svg
new file mode 100644
index 0000000..1e139d8
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/bard.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/cleric.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/cleric.svg
new file mode 100644
index 0000000..f7a6586
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/cleric.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/druid.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/druid.svg
new file mode 100644
index 0000000..8290333b
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/druid.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/fighter.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/fighter.svg
new file mode 100644
index 0000000..0f55a43
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/fighter.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/monk.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/monk.svg
new file mode 100644
index 0000000..dccf6ac
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/monk.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/paladin.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/paladin.svg
new file mode 100644
index 0000000..615bc8f
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/paladin.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/ranger.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/ranger.svg
new file mode 100644
index 0000000..8defce6
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/ranger.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/rogue.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/rogue.svg
new file mode 100644
index 0000000..a5ebf42
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/rogue.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/sorcerer.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/sorcerer.svg
new file mode 100644
index 0000000..6fa42fb
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/sorcerer.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/warlock.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/warlock.svg
new file mode 100644
index 0000000..d84762e
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/warlock.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/wizard.svg b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/wizard.svg
new file mode 100644
index 0000000..1df2853
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/assets/icons/svg-icons/wizard.svg
@@ -0,0 +1 @@
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts
new file mode 100644
index 0000000..c390a44
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/services/character.service.ts
@@ -0,0 +1,44 @@
+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';
+
+Injectable({
+ providedIn: 'root'
+})
+export class CharacterService {
+ private baseUrl = 'api/character/';
+ constructor(private http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
+ this.baseUrl = baseUrl + this.baseUrl;
+ }
+
+ 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)
+ );
+ }
+
+ 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);
+ }
+ })
+ );
+ }
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/styles.css b/SessionCompanion/SessionCompanion/ClientApp/src/styles.css
index bd973fd..311e04a 100644
--- a/SessionCompanion/SessionCompanion/ClientApp/src/styles.css
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/styles.css
@@ -73,6 +73,10 @@ mat-divider {
border-top-color: #e9cca7 !important;
}
+.arrow-select {
+ cursor: pointer;
+}
+
html,
body {
height: 100%;
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterForLoginViewModel.ts b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterForLoginViewModel.ts
new file mode 100644
index 0000000..fa9c0d8
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/CharacterForLoginViewModel.ts
@@ -0,0 +1,7 @@
+export interface CharacterForLoginViewModel {
+ id: number;
+ userId: number;
+ name: string;
+ className: string;
+ level: number;
+}
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/LoggedCharactersViewModel.ts b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/LoggedCharactersViewModel.ts
new file mode 100644
index 0000000..36ea974
--- /dev/null
+++ b/SessionCompanion/SessionCompanion/ClientApp/src/types/viewmodels/character-viewmodels/LoggedCharactersViewModel.ts
@@ -0,0 +1,7 @@
+export interface LoggedCharactersViewModel {
+ id: number;
+ name: string;
+ level: number;
+ currentHealthPoints: number;
+ class: string;
+}