Skip to content

Commit

Permalink
feat(multi): Adding tournament support and increasing max tables (#10)
Browse files Browse the repository at this point in the history
* tournament loading working

* initial challonge working

* tournament dashboard updates

* swap tables added

* players have fargo observable ids

* adding tournaments

* handling returned errors
  • Loading branch information
codephobia authored Jan 27, 2024
1 parent 5d128d0 commit c96f02c
Show file tree
Hide file tree
Showing 77 changed files with 2,923 additions and 156 deletions.
2 changes: 2 additions & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=pool
POSTGRES_PORT=5432
CHALLONGE_API_KEY=secret
CHALLONGE_USERNAME=username
11 changes: 6 additions & 5 deletions apps/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Use nxgo/cli as the base image to do the build
FROM nxgo/cli as builder
# FROM nxgo/cli as builder
FROM golang:1.20-alpine as builder

# Create app directory
WORKDIR /workspace

# Build argument for fontawesome npm token
ARG FONTAWESOME_NPM_AUTH_TOKEN
# ARG FONTAWESOME_NPM_AUTH_TOKEN

# Copy package.json and the lock file
COPY package.json package-lock.json .npmrc ./
# COPY package.json package-lock.json .npmrc ./

# Install app dependencies
RUN npm ci
# RUN npm ci

# Copy go mod files
COPY go.mod go.sum ./
Expand All @@ -29,7 +30,7 @@ COPY apps/seed apps/seed
COPY libs/go libs/go

# Copy Nx files
COPY nx.json workspace.json tsconfig.base.json ./
# COPY nx.json workspace.json tsconfig.base.json ./

# Build api app
# RUN nx build api
Expand Down
9 changes: 8 additions & 1 deletion apps/api/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/codephobia/pool-overlay/libs/go/api"
"github.com/codephobia/pool-overlay/libs/go/challonge"
overlayPkg "github.com/codephobia/pool-overlay/libs/go/overlay"
"github.com/codephobia/pool-overlay/libs/go/state"
"github.com/codephobia/pool-overlay/libs/go/telestrator"
Expand All @@ -19,6 +20,7 @@ type Core struct {
overlay *overlayPkg.Overlay
telestrator *telestrator.Telestrator
tables map[int]*state.State
challonge *challonge.Challonge
}

// NewCore returns a new Core.
Expand Down Expand Up @@ -47,6 +49,10 @@ func NewCore() (*Core, error) {
tables := map[int]*state.State{}
tables[1] = state.NewState(db, 1)
tables[2] = state.NewState(db, 2)
tables[3] = state.NewState(db, 3)

// Initialize Challonge.
challonge := challonge.NewChallonge(os.Getenv("CHALLONGE_API_KEY"), os.Getenv("CHALLONGE_USERNAME"), db, overlay, tables)

// Initialize API Server.
apiConfig := &api.Config{
Expand All @@ -58,14 +64,15 @@ func NewCore() (*Core, error) {
Previous: "1",
},
}
server := api.NewServer(apiConfig, db, overlay, telestrator, tables)
server := api.NewServer(apiConfig, db, overlay, telestrator, tables, challonge)

return &Core{
db: db,
server: server,
overlay: overlay,
telestrator: telestrator,
tables: tables,
challonge: challonge,
}, nil
}

Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';

import { overlayRoute } from './overlay/overlay.route';
import { tournamentsRoute } from './tournament/tournaments.route';
import { playersRoute } from './players/players.route';
import { gamesRoute } from './games/games.route';
import { drawingRoute } from './drawing/drawing.route';

const routes: Routes = [
overlayRoute,
tournamentsRoute,
playersRoute,
gamesRoute,
drawingRoute,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { faDesktop, faUser, faPool8Ball, faPencil } from '@fortawesome/pro-regular-svg-icons';
import { faDesktop, faUser, faPool8Ball, faPencil, faTrophyStar } from '@fortawesome/pro-regular-svg-icons';

@Component({
selector: 'pool-overlay-side-nav',
Expand All @@ -10,6 +10,10 @@ export class SideNavComponent {
icon: faDesktop,
title: 'Overlay',
link: 'overlay',
}, {
icon: faTrophyStar,
title: 'Tournaments',
link: 'tournaments',
}, {
icon: faUser,
title: 'Players',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export class ControllerStore extends ComponentStore<ControllerState> {
showFlags: false,
showFargo: true,
showScore: true,
waitingForPlayers: false,
waitingForTournamentStart: false,
tableNoLongerInUse: false,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { faPlus } from '@fortawesome/pro-regular-svg-icons';
})
export class HomePageComponent {
public faPlus = faPlus;
public tables: number[] = [1, 2];
public tables: number[] = [1, 2, 3];
public currentTable = 1;

public setTable(table: number): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ <h1 class="text-gray-50 uppercase text-4xl">{{ isCreating ? 'Create' : 'Update'
/>
</div>
</div>
<div class="flex flex-wrap -mx-3 mb-6">
<div class="w-full px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-100 text-xs font-bold mb-2" for="fargo_id">Fargo Observable ID</label>
<input
class="appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"
id="fargo_observable_id"
type="number"
min="0"
placeholder="Fargo Observable ID"
formControlName="fargo_observable_id"
/>
</div>
</div>
<div class="flex flex-wrap -mx-3 mb-6">
<div class="w-full px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-100 text-xs font-bold mb-2" for="fargo_id">Fargo ID</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class PlayerFormComponent {
this.form.addControl('id', this._fb.control(this._player.id, Validators.required));
this.form.controls.name.patchValue(this._player.name);
this.form.controls.flag_id.patchValue(this._player.flag_id);
this.form.controls.fargo_observable_id.patchValue(this._player.fargo_observable_id);
this.form.controls.fargo_id.patchValue(this._player.fargo_id);
this.form.controls.fargo_rating.patchValue(this._player.fargo_rating);
}
Expand All @@ -42,6 +43,7 @@ export class PlayerFormComponent {
this.form = this._fb.group({
name: ['', Validators.required],
flag_id: [1, Validators.required],
fargo_observable_id: [0, Validators.required],
fargo_id: [0, Validators.required],
fargo_rating: [0, Validators.required],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
<div class="w-1/12 flex flex-col justify-center items-start px-10">
<p class="text-white uppercase text-xs">Flag</p>
</div>
<div class="w-5/12 flex flex-col justify-center items-start px-10">
<div class="w-3/12 flex flex-col justify-center items-start px-10">
<p class="text-white uppercase text-xs">Name</p>
</div>
<div class="w-2/12 flex flex-col justify-center items-start px-10">
<p class="text-white uppercase text-xs whitespace-nowrap">Fargo Observable ID</p>
</div>
<div class="w-2/12 flex flex-col justify-center items-start px-10">
<p class="text-white uppercase text-xs whitespace-nowrap">Fargo ID</p>
</div>
Expand All @@ -19,9 +22,12 @@
<div class="w-1/12 flex flex-col justify-center items-start px-10">
<img *ngIf="player?.flag" class="w-5 h-auto" src="./assets/flags/{{ player?.flag?.image_path }}" [alt]="player?.flag?.country" />
</div>
<div class="w-5/12 flex flex-col justify-center px-10">
<div class="w-3/12 flex flex-col justify-center px-10">
<p class="text-white uppercase text-xs whitespace-nowrap">{{ player?.name }}</p>
</div>
<div class="w-2/12 flex flex-col justify-center px-10">
<p class="text-white uppercase text-xs">{{ player?.fargo_observable_id }}</p>
</div>
<div class="w-2/12 flex flex-col justify-center px-10">
<p class="text-white uppercase text-xs">{{ player?.fargo_id }}</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div class="flex flex-col flex-grow" *ngIf="vm$ | async as vm">
<div *ngIf="vm.hasTournaments" class="flex flex-row h-66px bg-sad-input border-sad-active border-b">
<div class="w-9/12 flex flex-col justify-center items-start px-10">
<p class="text-white uppercase text-xs">Name</p>
</div>
<div class="w-3/12 flex flex-col px-10"></div>
</div>
<ng-container *ngIf="vm.isLoaded; else loading">
<div class="flex flex-row h-66px" *ngFor="let tournament of vm.tournaments; even as isEven; odd as isOdd" [ngClass]="{ 'bg-sad-table-even': isEven, 'bg-sad-table-odd': isOdd }">
<div class="w-9/12 flex flex-col justify-center px-10">
<p class="text-white uppercase text-xs whitespace-nowrap">{{ tournament?.name }}</p>
</div>
<div class="w-3/12 flex flex-col justify-center items-end px-10">
<div class="flex flex-row gap-5 whitespace-nowrap">
<a href="https://challonge.com/{{ tournament.url }}" target="_blank" class="text-white bg-sad-challonge rounded py-2.5 px-5 uppercase text-xs mr-2.5">View on Challonge</a>
<a class="text-white bg-sad-success rounded py-2.5 px-5 uppercase text-xs" routerLink="./{{ tournament?.id }}">Select</a>
</div>
</div>
</div>
<ng-container *ngIf="!vm.hasTournaments">
<p class="p-4 text-white bg-sad-input border-sad-active border-t">Please create a new tournament on Challonge to continue.</p>
</ng-container>
</ng-container>
<ng-template #loading>
<div class="relative flex flex-row h-66px" *ngFor="let tournament of [1, 2, 3, 4, 5]; even as isEven; odd as isOdd" [ngClass]="{ 'bg-sad-table-even': isEven, 'bg-sad-table-odd': isOdd }">
<div class="shimmer-overlay"></div>
</div>
</ng-template>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Tournament } from '@pool-overlay/models';
import { TournamentListStore } from './tournament-list.store';

@Component({
selector: 'pool-overlay-tournament-list',
templateUrl: 'tournament-list.component.html',
providers: [TournamentListStore],
})
export class TournamentListComponent implements OnInit {
readonly vm$ = this.store.vm$;

@Output()
public selected = new EventEmitter<{ tournamentId: number }>();

constructor(private store: TournamentListStore) { }

public ngOnInit(): void {
this.store.getTournaments();
}

public selectTournament(tournamentId: number): void {
this.selected.emit({ tournamentId });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Injectable } from '@angular/core';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { Tournament } from '@pool-overlay/models';
import { switchMap, tap } from 'rxjs';
import { TournamentsService } from '../../services/tournament.service';

export enum LoadingState {
INIT,
LOADING,
LOADED,
}

interface TournamentListState {
callState: LoadingState;
tournaments: Tournament[];
}

export const initialState: TournamentListState = {
callState: LoadingState.INIT,
tournaments: [],
}

@Injectable()
export class TournamentListStore extends ComponentStore<TournamentListState> {
constructor(
private tournamentsService: TournamentsService,
) {
super(initialState);
}

// updaters
private updateCallState = this.updater<LoadingState>((state, callState) => ({
...state,
callState,
}));

private updateTournaments = this.updater<Tournament[]>((state, tournaments) => ({
...state,
tournaments,
callState: LoadingState.LOADED,
}));

// selectors
private isLoaded$ = this.select((state) => state.callState === LoadingState.LOADED);
private tournaments$ = this.select((state) => state.tournaments);
private hasTournaments$ = this.select(
this.isLoaded$,
this.tournaments$,
(loaded, tournaments) => loaded && !!tournaments.length
);
readonly vm$ = this.select(
this.isLoaded$,
this.tournaments$,
this.hasTournaments$,
(isLoaded, tournaments, hasTournaments) => ({
isLoaded,
tournaments,
hasTournaments,
})
);

// effects
readonly getTournaments = this.effect((trigger$) => trigger$.pipe(
tap(() => this.updateCallState(LoadingState.LOADING)),
switchMap(() => this.tournamentsService.getList().pipe(
tapResponse(
(tournaments) => this.updateTournaments(tournaments),
(err) => {
console.log(err);
}
)
)),
));
}
Loading

0 comments on commit c96f02c

Please sign in to comment.