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 + + 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 @@ +
+ + {{ player.name }} + +
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`); + } + }