diff --git a/angular.json b/angular.json
index 433ccef..72fb5bd 100644
--- a/angular.json
+++ b/angular.json
@@ -35,6 +35,7 @@
],
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
+ "node_modules/bootstrap-icons/font/bootstrap-icons.min.css",
"src/styles.less"
],
"scripts": [],
diff --git a/package-lock.json b/package-lock.json
index 659f07e..757a74c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"@ng-bootstrap/ng-bootstrap": "^18.0.0",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.3",
+ "bootstrap-icons": "^1.13.1",
"express": "^4.18.2",
"rxjs": "~7.8.0",
"sonarqube-scanner": "^4.3.0",
@@ -6249,6 +6250,22 @@
"@popperjs/core": "^2.11.8"
}
},
+ "node_modules/bootstrap-icons": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.13.1.tgz",
+ "integrity": "sha512-ijombt4v6bv5CLeXvRWKy7CuM3TRTuPEuGaGKvTV5cz65rQSY8RQ2JcHt6b90cBBAC7s8fsf2EkQDldzCoXUjw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/twbs"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
diff --git a/package.json b/package.json
index 18cf17b..c7b133f 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"@ng-bootstrap/ng-bootstrap": "^18.0.0",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.3",
+ "bootstrap-icons": "^1.13.1",
"express": "^4.18.2",
"rxjs": "~7.8.0",
"sonarqube-scanner": "^4.3.0",
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 15b378d..f56c0d5 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,59 +1,10 @@
-
-
Please select the number of teams:
-
-
-
-
-
- 0">Removed: {{ duplicateNames }}
-
-
- | Size |
- Names |
-
-
-
- @for (team of teamsArray; track $index) {
-
- | {{ team.length | number }} |
- {{ team }} |
-
- }
-
-
-
-
+
-
-
+
\ No newline at end of file
diff --git a/src/app/app.component.less b/src/app/app.component.less
index b6c917b..4217717 100644
--- a/src/app/app.component.less
+++ b/src/app/app.component.less
@@ -15,4 +15,24 @@ tr{
.wrap-cell{
word-break: break-all;
white-space: normal;
+}
+.main{
+ margin-bottom: 5rem;
+ padding: 1rem;
+ overflow-y: auto;
+}
+.custom-navbar{
+ height: 3rem;
+ width: 100vw;
+ position: fixed;
+ bottom: 0;
+ display: flex;
+ justify-content: space-around; /* Distribute items evenly */
+ z-index: 1000;
+}
+.custom-navitem{
+ text-align: center; /* Center the content of each item */
+ flex: 1;
+}
+.nav-link.active{
}
\ No newline at end of file
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 292df5e..5d2164f 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,77 +1,40 @@
-import { Component, OnInit} from '@angular/core';
+import { Component, inject, OnInit} from '@angular/core';
import { FormsModule } from '@angular/forms';
-import { RouterOutlet, ActivatedRoute } from '@angular/router';
+import { RouterOutlet, ActivatedRoute, RouterLink } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { CommonModule } from '@angular/common';
import { filter, take } from 'rxjs';
+import { ScreenBasicComponent } from "./screen-basic/screen-basic.component";
+import { ScreenRotationsComponent } from './screen-rotations/screen-rotations.component';
+import { Player } from './model';
+import { ScreenEditComponent } from './screen-edit/screen-edit.component';
+import { DataService } from './data.service';
@Component({
selector: 'app-root',
- imports: [NgbModule, RouterOutlet, CommonModule, FormsModule],
+ imports: [NgbModule, RouterOutlet, CommonModule, FormsModule, ScreenBasicComponent, ScreenRotationsComponent, ScreenEditComponent, RouterLink],
templateUrl: './app.component.html',
styleUrl: './app.component.less'
})
export class AppComponent implements OnInit {
title = 'vb';
- playerNamesValue = "";
- numTeamsSelectorValue = "2";
- numTeamsSelected = 2;
- nTeamsValue = "4";
- teamsArray: string[][] = [];
- duplicateNames: string[] = [];
+ data = inject(DataService);
- constructor(private activatedRoute: ActivatedRoute){}
+ constructor(public route: ActivatedRoute){}
ngOnInit(): void {
- this.activatedRoute.queryParams.pipe(
+ this.route.queryParams.pipe(
filter(params => Object.keys(params).length > 0), // Only proceed if params are not empty
take(1)
).subscribe(params => {
- const names = params['names']?.replaceAll(',', '\n');
- if (names) {
- this.playerNamesValue = names;
+ if (params['names']){
+ this.data.setPlayers(
+ params['names'].split(',').map((name: string) => new Player(name))
+ );
}
});
}
- onButtonGenerate(textinput: string): void{
- if(this.numTeamsSelectorValue === 'n'){
- this.numTeamsSelected = Number(this.nTeamsValue);
- }
- else{
- this.numTeamsSelected = Number(this.numTeamsSelectorValue);
- }
- let nameslist = this.playerNamesValue
- .split('\n')
- .map(function(str){return str.trim();})
- .filter(function(str){return str}); // boolean interpretation is same as non-empty
- // remove duplicates by using a Set
- let namesset = new Set(nameslist);
- let names = [...namesset];
-
-
- let teams = Array.from({ length: this.numTeamsSelected }, () => []);
- let playersPerTeam = Math.floor(names.length / this.numTeamsSelected);
-
- let nameslen = names.length;
- function* iter(list: any[]){
- let index = 0;
- while(true){
- yield list[index % list.length];
- index++;
- }
- }
- let iterator = iter(teams);
- for(let i =0; i < nameslen; i++){
- let index = Math.floor(Math.random()* names.length);
- let n = names[index];
- names.splice(index,1);
- let team = iterator.next().value;
- team.push(n);
-
- }
- this.teamsArray = teams;
- }
}
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index dc39edb..482d17e 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -1,3 +1,17 @@
import { Routes } from '@angular/router';
+import { ScreenBasicComponent } from './screen-basic/screen-basic.component';
+import { ScreenEditComponent } from './screen-edit/screen-edit.component';
+import { ScreenRotationsComponent } from './screen-rotations/screen-rotations.component';
+import { AppComponent } from './app.component';
-export const routes: Routes = [];
+export const routes: Routes = [
+ {
+ path: '',
+ children: [
+ { path: '', redirectTo: 'edit', pathMatch: 'full' },
+ { path: 'edit', component: ScreenEditComponent },
+ { path: 'basic', component: ScreenBasicComponent },
+ { path: 'rotations', component: ScreenRotationsComponent }
+ ]
+ }
+];
diff --git a/src/app/data.service.spec.ts b/src/app/data.service.spec.ts
new file mode 100644
index 0000000..38e8d9e
--- /dev/null
+++ b/src/app/data.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { DataService } from './data.service';
+
+describe('DataService', () => {
+ let service: DataService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(DataService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/app/data.service.ts b/src/app/data.service.ts
new file mode 100644
index 0000000..122aa63
--- /dev/null
+++ b/src/app/data.service.ts
@@ -0,0 +1,33 @@
+import { Injectable } from '@angular/core';
+import { Player } from './model';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DataService {
+ private players: Player[] = [];
+
+ setPlayers(players: Player[]){
+ for (let player of players){
+ this.addPlayer(player);
+ }
+ }
+
+ addPlayer(player: Player): boolean{
+ if (player.name.trim() && Player.isNew(player, this.players)){
+ this.players.push(player);
+ return true
+ }
+ return false
+ }
+ removePlayer(player: Player){
+ const index = this.players.indexOf(player);
+ if (index !== -1) {
+ this.players.splice(index, 1);
+ }
+ }
+ getPlayers(): Player[] {
+ let clone =Object.assign([],this.players);
+ return clone
+ }
+}
diff --git a/src/app/modal-rotations/modal-rotations.component.html b/src/app/modal-rotations/modal-rotations.component.html
new file mode 100644
index 0000000..9f32e34
--- /dev/null
+++ b/src/app/modal-rotations/modal-rotations.component.html
@@ -0,0 +1,73 @@
+
+
+
+
diff --git a/src/app/modal-rotations/modal-rotations.component.less b/src/app/modal-rotations/modal-rotations.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/modal-rotations/modal-rotations.component.spec.ts b/src/app/modal-rotations/modal-rotations.component.spec.ts
new file mode 100644
index 0000000..111191d
--- /dev/null
+++ b/src/app/modal-rotations/modal-rotations.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ModalRotationsComponent } from './modal-rotations.component';
+
+describe('ModalRotationsComponent', () => {
+ let component: ModalRotationsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ModalRotationsComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ModalRotationsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/modal-rotations/modal-rotations.component.ts b/src/app/modal-rotations/modal-rotations.component.ts
new file mode 100644
index 0000000..1530d7a
--- /dev/null
+++ b/src/app/modal-rotations/modal-rotations.component.ts
@@ -0,0 +1,21 @@
+import { Component, Input } from '@angular/core';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { Player} from '../model';
+import { FormsModule } from '@angular/forms';
+
+@Component({
+ selector: 'app-modal-rotations',
+ imports: [FormsModule],
+ templateUrl: './modal-rotations.component.html',
+ styleUrl: './modal-rotations.component.less'
+})
+export class ModalRotationsComponent {
+ @Input() player!: Player;
+
+ constructor(public activeModal: NgbActiveModal) {}
+
+ savePlayer() {
+ // You can emit an event or handle the save logic here
+ this.activeModal.close(this.player);
+ }
+}
diff --git a/src/app/model.ts b/src/app/model.ts
new file mode 100644
index 0000000..2608e7f
--- /dev/null
+++ b/src/app/model.ts
@@ -0,0 +1,42 @@
+export class Player{
+ name: string;
+ outside: boolean;
+ middle: boolean;
+ opposite: boolean; // dia
+ setter: boolean;
+ libero: boolean;
+
+ constructor(
+ name:string,
+ outside: boolean = false,
+ middle: boolean = false,
+ opposite: boolean = false, // dia
+ setter: boolean = false,
+ libero: boolean = false,
+ ){
+ this.name = name;
+ this.outside = outside;
+ this.middle = middle;
+ this.opposite = opposite;
+ this.setter = setter;
+ this.libero = libero;
+ }
+ serialize(): string[] {
+ const values = 'OOOO'
+ return [this.name, values];
+ }
+
+ valueOf(): string{
+ return this.name;
+ }
+ static deSerialize(name: string, values: string): Player{
+ return new Player(name);
+ }
+ static isNew(newplayer:Player, players: Player[]): boolean {
+ const seen = new Set(players.map(p => p.name));
+ if (seen.has(newplayer.name)){
+ return false
+ }
+ return true
+}
+}
diff --git a/src/app/screen-basic/screen-basic.component.html b/src/app/screen-basic/screen-basic.component.html
new file mode 100644
index 0000000..9809c52
--- /dev/null
+++ b/src/app/screen-basic/screen-basic.component.html
@@ -0,0 +1,42 @@
+
+
+
Random Teams
+
+
+
+
+
+
+ | Size |
+ Names |
+
+
+
+ @for (team of teamsArray; track $index) {
+
+ | {{ team.length | number }} |
+ {{ team }} |
+
+ }
+
+
+
+
diff --git a/src/app/screen-basic/screen-basic.component.less b/src/app/screen-basic/screen-basic.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/screen-basic/screen-basic.component.spec.ts b/src/app/screen-basic/screen-basic.component.spec.ts
new file mode 100644
index 0000000..68482f0
--- /dev/null
+++ b/src/app/screen-basic/screen-basic.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ScreenBasicComponent } from './screen-basic.component';
+
+describe('ScreenBasicComponent', () => {
+ let component: ScreenBasicComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ScreenBasicComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ScreenBasicComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/screen-basic/screen-basic.component.ts b/src/app/screen-basic/screen-basic.component.ts
new file mode 100644
index 0000000..dbb0ea3
--- /dev/null
+++ b/src/app/screen-basic/screen-basic.component.ts
@@ -0,0 +1,49 @@
+// Original Team Generation Screen for arbitrary size and number of teams
+import { Component, inject} from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { RouterOutlet, ActivatedRoute } from '@angular/router';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { CommonModule } from '@angular/common';
+import { Player } from '../model';
+import { iter } from '../util';
+import { DataService } from '../data.service';
+
+@Component({
+ selector: 'app-screen-basic',
+ imports: [NgbModule, RouterOutlet, CommonModule, FormsModule],
+ templateUrl: './screen-basic.component.html',
+ styleUrl: './screen-basic.component.less'
+})
+export class ScreenBasicComponent {
+ data = inject(DataService);
+ numTeamsSelectorValue = "2";
+ numTeamsSelected = 2;
+ nTeamsValue = "4";
+ teamsArray: string[][] = [];
+
+ onButtonGenerate(): void{
+ if(this.numTeamsSelectorValue === 'n'){
+ this.numTeamsSelected = Number(this.nTeamsValue);
+ }
+ else{
+ this.numTeamsSelected = Number(this.numTeamsSelectorValue);
+ }
+
+ let teams = Array.from({ length: this.numTeamsSelected }, () => []);
+ // clone array here
+ let localPlayers: Player[] = this.data.getPlayers();
+
+ let nameslen = localPlayers.length;
+ let iterator = iter(teams);
+ for(let i =0; i < nameslen; i++){
+ let index = Math.floor(Math.random()* localPlayers.length);
+ let n = localPlayers[index];
+ localPlayers.splice(index,1);
+ let team = iterator.next().value;
+ team.push(n.name);
+
+ }
+ this.teamsArray = teams;
+ }
+
+}
\ No newline at end of file
diff --git a/src/app/screen-edit/screen-edit.component.html b/src/app/screen-edit/screen-edit.component.html
new file mode 100644
index 0000000..625549e
--- /dev/null
+++ b/src/app/screen-edit/screen-edit.component.html
@@ -0,0 +1,33 @@
+
+
Players: {{ data.getPlayers().length }}
+
+
+
+
+ @if (alertMessage) {
+
{{ alertMessage }}
+ }
+
+
+ @for (player of data.getPlayers(); track $index) {
+ -
+ {{ player.name }}
+
+
+ }
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/screen-edit/screen-edit.component.less b/src/app/screen-edit/screen-edit.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/screen-edit/screen-edit.component.spec.ts b/src/app/screen-edit/screen-edit.component.spec.ts
new file mode 100644
index 0000000..bf13f40
--- /dev/null
+++ b/src/app/screen-edit/screen-edit.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ScreenEditComponent } from './screen-edit.component';
+
+describe('ScreenEditComponent', () => {
+ let component: ScreenEditComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ScreenEditComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ScreenEditComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/screen-edit/screen-edit.component.ts b/src/app/screen-edit/screen-edit.component.ts
new file mode 100644
index 0000000..d9a6697
--- /dev/null
+++ b/src/app/screen-edit/screen-edit.component.ts
@@ -0,0 +1,67 @@
+import { Component, inject, Input, ViewChild } from '@angular/core';
+import { NgbAlert, NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { Player } from '../model';
+import { ModalRotationsComponent } from '../modal-rotations/modal-rotations.component';
+import { FormsModule } from '@angular/forms';
+import { Subject } from 'rxjs/internal/Subject';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { debounceTime, tap } from 'rxjs/operators';
+import { DataService } from '../data.service';
+
+@Component({
+ selector: 'app-screen-edit',
+ imports: [FormsModule, NgbAlert],
+ templateUrl: './screen-edit.component.html',
+ styleUrl: './screen-edit.component.less'
+})
+export class ScreenEditComponent {
+ data = inject(DataService);
+ @ViewChild('selfClosingAlert', { static: false })selfClosingAlert!: NgbAlert;
+ private _message$ = new Subject();
+ newItem: string = "";
+ alertMessage = '';
+
+ constructor(private modalService: NgbModal) {
+ this._message$
+ .pipe(
+ takeUntilDestroyed(),
+ tap((message) => (this.alertMessage = message)),
+ debounceTime(5000),
+ )
+ .subscribe(() => this.selfClosingAlert?.close());
+ }
+
+ addItem() {
+ const name = this.newItem.trim()
+ if (name) {
+ let newPlayer = new Player(name);
+ if(this.data.addPlayer(newPlayer)){
+ this.newItem = '';
+ return
+ }
+ else{
+ this.setAlertMessage(newPlayer.name);
+ }
+ }
+ }
+ removeItem(player: Player){
+ this.data.removePlayer(player);
+ }
+
+ openPlayerModal(player: Player){
+ const modalRef = this.modalService.open(ModalRotationsComponent);
+ modalRef.componentInstance.player = player;
+ /*
+ modalRef.result.then((updatedPlayer) => {
+ // Handle the updated player data if needed
+ console.log('Player updated:', updatedPlayer);
+ }).catch((error) => {
+ console.log('Modal dismissed');
+ });
+ */
+ }
+ public setAlertMessage(s: string) {
+ this._message$.next(`"${s}" already exists. Please choose a unique name.`);
+ }
+
+}
diff --git a/src/app/screen-rotations/screen-rotations.component.html b/src/app/screen-rotations/screen-rotations.component.html
new file mode 100644
index 0000000..3f74f69
--- /dev/null
+++ b/src/app/screen-rotations/screen-rotations.component.html
@@ -0,0 +1,75 @@
+
+
Rotations
+
+
+
+
+
+
+
+
+ @for (player of LiberoPlayers; track $index) {
+ {{ player.name }}
+ }
+
+
+
+
+
+
+
+
+
+
+
+ @for (player of SetterPlayers; track $index) {
+ {{ player.name }}
+ }
+
+
+
+
+
+
+
+
+
+
+
+ @for (player of OppositePlayers; track $index) {
+ {{ player.name }}
+ }
+
+
+
+
+
+
+
+
+
+
+
+ @for (player of MiddlePlayers; track $index) {
+ {{ player.name }}
+ }
+
+
+
+
+
+
+
+
+
+
+
+ @for (player of OutsidePlayers; track $index) {
+ {{ player.name }}
+ }
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/screen-rotations/screen-rotations.component.less b/src/app/screen-rotations/screen-rotations.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/screen-rotations/screen-rotations.component.spec.ts b/src/app/screen-rotations/screen-rotations.component.spec.ts
new file mode 100644
index 0000000..0998926
--- /dev/null
+++ b/src/app/screen-rotations/screen-rotations.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ScreenRotationsComponent } from './screen-rotations.component';
+
+describe('ScreenRotationsComponent', () => {
+ let component: ScreenRotationsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ScreenRotationsComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ScreenRotationsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/screen-rotations/screen-rotations.component.ts b/src/app/screen-rotations/screen-rotations.component.ts
new file mode 100644
index 0000000..f7c5485
--- /dev/null
+++ b/src/app/screen-rotations/screen-rotations.component.ts
@@ -0,0 +1,32 @@
+// Team Generation Screen respecting volleyball roles as defined by `../model/Player`
+import { Component, inject, Input } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { Player } from '../model';
+import { NgbAccordionBody, NgbAccordionCollapse, NgbAccordionHeader, NgbAccordionItem, NgbAccordionButton, NgbAccordionDirective, NgbAccordionToggle } from '@ng-bootstrap/ng-bootstrap';
+import { DataService } from '../data.service';
+
+@Component({
+ selector: 'app-screen-rotations',
+ imports: [FormsModule, NgbAccordionButton, NgbAccordionDirective, NgbAccordionItem, NgbAccordionHeader, NgbAccordionToggle, NgbAccordionBody, NgbAccordionCollapse,],
+ templateUrl: './screen-rotations.component.html',
+ styleUrl: './screen-rotations.component.less'
+})
+export class ScreenRotationsComponent {
+ data = inject(DataService);
+
+ get OutsidePlayers(): Player[] {
+ return this.data.getPlayers().filter(player => player.outside);
+ }
+ get MiddlePlayers(): Player[] {
+ return this.data.getPlayers().filter(player => player.middle);
+ }
+ get OppositePlayers(): Player[] {
+ return this.data.getPlayers().filter(player => player.opposite);
+ }
+ get SetterPlayers(): Player[] {
+ return this.data.getPlayers().filter(player => player.setter);
+ }
+ get LiberoPlayers(): Player[] {
+ return this.data.getPlayers().filter(player => player.libero);
+ }
+}
\ No newline at end of file
diff --git a/src/app/util.ts b/src/app/util.ts
new file mode 100644
index 0000000..22bd05b
--- /dev/null
+++ b/src/app/util.ts
@@ -0,0 +1,7 @@
+export function* iter(list: any[]){
+ let index = 0;
+ while(true){
+ yield list[index % list.length];
+ index++;
+ }
+}
\ No newline at end of file