diff --git a/src/app/core/navigation-bar/navigation-bar.component.html b/src/app/core/navigation-bar/navigation-bar.component.html
index 684f59804..a23536cda 100644
--- a/src/app/core/navigation-bar/navigation-bar.component.html
+++ b/src/app/core/navigation-bar/navigation-bar.component.html
@@ -9,6 +9,10 @@
games
+
+ players
+
+
servers
diff --git a/src/app/players/models/player.ts b/src/app/players/models/player.ts
index 74b6f2499..f913fc6e3 100644
--- a/src/app/players/models/player.ts
+++ b/src/app/players/models/player.ts
@@ -6,6 +6,7 @@ export interface Player {
joinedAt: Date;
steamId: string;
avatarUrl: string;
+ gameCount: number;
role?: PlayerRole;
etf2lProfileId?: number;
skill?: { [gameClass: string]: number };
diff --git a/src/app/players/player-list/player-list.component.html b/src/app/players/player-list/player-list.component.html
new file mode 100644
index 000000000..27e57721e
--- /dev/null
+++ b/src/app/players/player-list/player-list.component.html
@@ -0,0 +1,7 @@
+
diff --git a/src/app/players/player-list/player-list.component.scss b/src/app/players/player-list/player-list.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/players/player-list/player-list.component.spec.ts b/src/app/players/player-list/player-list.component.spec.ts
new file mode 100644
index 000000000..c0c8abc08
--- /dev/null
+++ b/src/app/players/player-list/player-list.component.spec.ts
@@ -0,0 +1,37 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { PlayerListComponent } from './player-list.component';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { AppState } from '@app/app.state';
+import { RouterTestingModule } from '@angular/router/testing';
+import { Store } from '@ngrx/store';
+import { allPlayers } from '../players.selectors';
+
+describe('PlayerListComponent', () => {
+ let component: PlayerListComponent;
+ let fixture: ComponentFixture;
+ let store: MockStore;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PlayerListComponent ],
+ imports: [ RouterTestingModule ],
+ providers: [
+ provideMockStore(),
+ ],
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ store = TestBed.get(Store);
+ store.overrideSelector(allPlayers, []);
+
+ fixture = TestBed.createComponent(PlayerListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/players/player-list/player-list.component.ts b/src/app/players/player-list/player-list.component.ts
new file mode 100644
index 000000000..edf9b71a2
--- /dev/null
+++ b/src/app/players/player-list/player-list.component.ts
@@ -0,0 +1,27 @@
+import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { Store } from '@ngrx/store';
+import { AppState } from '@app/app.state';
+import { allPlayers } from '../players.selectors';
+import { Player } from '../models/player';
+import { loadPlayers } from '../players.actions';
+
+@Component({
+ selector: 'app-player-list',
+ templateUrl: './player-list.component.html',
+ styleUrls: ['./player-list.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PlayerListComponent implements OnInit {
+
+ players: Observable = this.store.select(allPlayers);
+
+ constructor(
+ private store: Store,
+ ) { }
+
+ ngOnInit() {
+ this.store.dispatch(loadPlayers());
+ }
+
+}
diff --git a/src/app/players/players-routing.module.ts b/src/app/players/players-routing.module.ts
index 658241b53..bbd08f06a 100644
--- a/src/app/players/players-routing.module.ts
+++ b/src/app/players/players-routing.module.ts
@@ -2,8 +2,10 @@ import { Routes, RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { PlayerDetailsComponent } from './player-details/player-details.component';
import { PlayerEditComponent } from './player-edit/player-edit.component';
+import { PlayerListComponent } from './player-list/player-list.component';
const routes: Routes = [
+ { path: 'players', component: PlayerListComponent },
{ path: 'player/:id', component: PlayerDetailsComponent },
{ path: 'player/:id/edit', component: PlayerEditComponent },
];
diff --git a/src/app/players/players.actions.ts b/src/app/players/players.actions.ts
index 225612bc6..ec237292f 100644
--- a/src/app/players/players.actions.ts
+++ b/src/app/players/players.actions.ts
@@ -37,3 +37,10 @@ export const playerSkillLoaded = createAction(
'[API] Player skill loaded',
props<{ playerSkill: PlayerSkill }>(),
);
+
+export const loadPlayers = createAction('[Player list] Load all players');
+
+export const playersLoaded = createAction(
+ '[API] All players loaded',
+ props<{ players: Player[] }>(),
+);
diff --git a/src/app/players/players.effects.ts b/src/app/players/players.effects.ts
index 6c552c70e..85fec37c1 100644
--- a/src/app/players/players.effects.ts
+++ b/src/app/players/players.effects.ts
@@ -2,7 +2,8 @@ import { Injectable } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';
import { PlayersService } from './players.service';
import { map, mergeMap } from 'rxjs/operators';
-import { loadPlayer, playerLoaded, playerEdited, editPlayer, playerSkillLoaded, loadPlayerSkill } from './players.actions';
+import { loadPlayer, playerLoaded, playerEdited, editPlayer, playerSkillLoaded, loadPlayerSkill, loadPlayers,
+ playersLoaded } from './players.actions';
@Injectable()
export class PlayerEffects {
@@ -33,6 +34,15 @@ export class PlayerEffects {
)
);
+ loadAllPlayers = createEffect(() =>
+ this.actions.pipe(
+ ofType(loadPlayers),
+ mergeMap(() => this.playersService.fetchAllPlayers().pipe(
+ map(players => playersLoaded({ players })),
+ )),
+ )
+ );
+
constructor(
private actions: Actions,
private playersService: PlayersService,
diff --git a/src/app/players/players.module.ts b/src/app/players/players.module.ts
index 9a4bc3f3b..faaf876dd 100644
--- a/src/app/players/players.module.ts
+++ b/src/app/players/players.module.ts
@@ -12,6 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { PlayerEditComponent } from './player-edit/player-edit.component';
import { PlayerEditSkillComponent } from './player-edit-skill/player-edit-skill.component';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
+import { PlayerListComponent } from './player-list/player-list.component';
@NgModule({
declarations: [
@@ -20,6 +21,7 @@ import { TooltipModule } from 'ngx-bootstrap/tooltip';
PlayerDetailsComponent,
PlayerEditComponent,
PlayerEditSkillComponent,
+ PlayerListComponent,
],
imports: [
CommonModule,
diff --git a/src/app/players/players.reducer.ts b/src/app/players/players.reducer.ts
index c35fd6131..9419d3d52 100644
--- a/src/app/players/players.reducer.ts
+++ b/src/app/players/players.reducer.ts
@@ -2,7 +2,7 @@ import { EntityState } from '@ngrx/entity';
import { Player } from './models/player';
import { adapter } from './players.adapter';
import { createReducer, Action, on } from '@ngrx/store';
-import { playerLoaded, editPlayer, playerUpdated, playerEdited, playerSkillLoaded } from './players.actions';
+import { playerLoaded, editPlayer, playerUpdated, playerEdited, playerSkillLoaded, playersLoaded } from './players.actions';
export interface State extends EntityState {
locked: boolean; // is player editing enabled or not
@@ -24,6 +24,7 @@ const playerReducer = createReducer(
skill: playerSkill.skill,
}
}, state)),
+ on(playersLoaded, (state, { players }) => adapter.upsertMany(players, state)),
);
export function reducer(state: State | undefined, action: Action) {
diff --git a/src/app/players/players.selectors.ts b/src/app/players/players.selectors.ts
index 803e189d6..48f029cec 100644
--- a/src/app/players/players.selectors.ts
+++ b/src/app/players/players.selectors.ts
@@ -6,7 +6,8 @@ import { adapter } from './players.adapter';
const playersFeature = createFeatureSelector('players');
export const playersLocked = createSelector(playersFeature, feature => feature.locked);
-const { selectEntities } = adapter.getSelectors();
+const { selectEntities, selectAll } = adapter.getSelectors();
const playerEntities = createSelector(playersFeature, selectEntities);
+export const allPlayers = createSelector(playersFeature, selectAll);
export const playerById = (playerId: string) => createSelector(playerEntities, entites => entites[playerId]);
diff --git a/src/app/players/players.service.spec.ts b/src/app/players/players.service.spec.ts
index ffa2e227b..cfeb1f6c4 100644
--- a/src/app/players/players.service.spec.ts
+++ b/src/app/players/players.service.spec.ts
@@ -45,7 +45,7 @@ describe('PlayersService', () => {
describe('#savePlayer()', () => {
it('should call the endpoint', inject([PlayersService], (service: PlayersService) => {
const player: Player = { id: 'FAKE_ID', name: 'FAKE_NAME', joinedAt: new Date(), steamId: 'FAKE_STEAM_ID',
- avatarUrl: 'FAKE_AVATAR_URL', skill: { } };
+ avatarUrl: 'FAKE_AVATAR_URL', skill: { }, gameCount: 0 };
service.savePlayer(player).subscribe();
const req = httpContoller.expectOne('FAKE_URL/players/FAKE_ID');
expect(req.request.method).toBe('PUT');
diff --git a/src/app/players/players.service.ts b/src/app/players/players.service.ts
index df60359b3..788d400a3 100644
--- a/src/app/players/players.service.ts
+++ b/src/app/players/players.service.ts
@@ -36,4 +36,8 @@ export class PlayersService {
return this.http.put(`${this.apiUrl}/players/${playerSkill.player}/skill`, playerSkill);
}
+ fetchAllPlayers(): Observable {
+ return this.http.get(`${this.apiUrl}/players`);
+ }
+
}