davidcr01 / WordlePlus

Repository to store all the documentation, files and structure of my Final Degree Project (TFG in Spanish). The main goal is to develop, as full-stack web developer, a remodel of the Wordle game, including more features and functionalities using Ionic, Django REST Api and PostgreSQL.
1 stars 0 forks source link

Tournaments view (S5) #37

Closed davidcr01 closed 1 year ago

davidcr01 commented 1 year ago

Description

Is necessary to implement the view of the tournaments where all the tournaments will be displayed.

Tasks

With the implementation of the ion-toolbar to select the type of the tournament, the HU12 is already implemented.

davidcr01 commented 1 year ago

Update Report

Mockup

image

HTML (UI)

The HTML code is divided into two parts: the ion-toolbar to select the length of the word, so the tournaments are filer; and the cards containing the tournaments' information.

<ion-toolbar>
    <ion-segment [scrollable]="true" [(ngModel)]="wordLength" (ionChange)="loadTournaments()">
      <ion-segment-button value="">
        <ion-label>All</ion-label>
      </ion-segment-button>
      <ion-segment-button value="4">
        <ion-label>4 Lett.</ion-label>
      </ion-segment-button>
      <ion-segment-button value="5">
        <ion-label>5 Lett.</ion-label>
      </ion-segment-button>
      <ion-segment-button value="6">
        <ion-label>6 Lett.</ion-label>
      </ion-segment-button>
      <ion-segment-button value="7">
        <ion-label>7 Lett.</ion-label>
      </ion-segment-button>
      <ion-segment-button value="8">
        <ion-label>8 Lett.</ion-label>
      </ion-segment-button>
    </ion-segment>
  </ion-toolbar>

Notice that everytime the ion-segment has changed, the loadTournaments function is executed.

<ion-content>
  <ion-card *ngFor="let tournament of tournaments">
    <ion-card-header class="tournament-header">
      <ion-icon name="trophy" class="left-icon"></ion-icon>
      <ion-card-title>{{ tournament.name }}</ion-card-title>
      <ion-icon name="trophy" class="right-icon"></ion-icon>
    </ion-card-header>
    <ion-card-content>
      <ion-list>
        <ion-item *ngIf="tournament.description">
          <ion-label class="label">Description:</ion-label>
          <ion-label class="value">{{ tournament.description }}</ion-label>
        </ion-item>
        <ion-item>
          <ion-label class="label">Max players:</ion-label>
          <ion-label class="value">{{ tournament.max_players }}</ion-label>
        </ion-item>
        <ion-item>
          <ion-label class="label">Word Length:</ion-label>
          <ion-label class="value">{{ tournament.word_length }}</ion-label>
        </ion-item>
        <ion-item>
          <ion-label class="label">Status:</ion-label>
          <ion-icon [name]="tournament.is_closed ? 'lock-closed' : 'lock-open'"></ion-icon>
        </ion-item>
      </ion-list>
    </ion-card-content>
    <ion-button expand="block" class="join-button" [disabled]="tournament.is_closed">Join</ion-button>
  </ion-card>

Notice that the status field is controlled with the is_closed variable. If is true, it shows a lock closed icon, in other cases it shows a lock opened icon.

TS logic (controller)

The strategy is to load the tournaments filtered by the length of the word depending on the ion-segment selected. Every time the ion-segment is selected, the loadTournaments function is executed. This function retreives the tournaments filtered by the wordLength variable, controlled in the ion-segment tag.

export class Tab2Page implements OnInit {
  wordLength: number;
  tournaments: any[] = [];

  constructor(private apiService: ApiService) {}

  ngOnInit() {
    this.loadTournaments();
  }

  async loadTournaments() {
    (await this.apiService.getTournaments(this.wordLength))
      .subscribe(
        (data: any) => {
          console.log(data);
          this.tournaments = data.results;
        },
        (error) => {
          console.error('Error loading tournaments:', error);
        }
      );
  }
}

Notice that a new apiService method has been added. This method is:

async getTournaments(wordLength?: number): Promise<Observable<any>> {
        let url = `${this.baseURL}/api/tournaments/`;
        if (wordLength) {
            url += `?word_length=${wordLength}`;
          }

        const accessToken = this.storageService.getAccessToken();
        if (!accessToken) {
            return throwError('Access token not found');
        }
        const decryptedToken = this.encryptionService.decryptData(await accessToken);
        const headers = new HttpHeaders({
            Authorization: `Token ${decryptedToken}`,
            'Content-Type': 'application/json'
        });

        return this.http.get(url, { headers });
      }

Which uses the view defined in #34.

davidcr01 commented 1 year ago

Update Report

Result

The result is the following: image

Notice how the join button is disabled as the tournament is closed.

The following video shows how the view changes when the filter is selected:

https://github.com/davidcr01/WordlePlus/assets/72193239/4342f791-6546-4142-9934-465948ff889a