Ajout de composants Hero Wars
This commit is contained in:
@@ -1 +1 @@
|
||||
<app-full-layout></app-full-layout>
|
||||
<app-full-layout [class]="appClass"></app-full-layout>
|
||||
@@ -0,0 +1,8 @@
|
||||
.grayscale {
|
||||
filter: grayscale(1);
|
||||
transition: all 2s ease;
|
||||
}
|
||||
.colored {
|
||||
filter: grayscale(0);
|
||||
transition: all 5s ease;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, AfterContentInit } from '@angular/core';
|
||||
import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, provideNativeDateAdapter } from '@angular/material/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@@ -31,8 +31,9 @@ export const MY_FORMATS = {
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss'
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
export class AppComponent implements OnInit, AfterContentInit {
|
||||
public title = 'Ad Astra';
|
||||
public appClass = 'grayscale';
|
||||
|
||||
constructor(private userService: UserService, private titleService: Title) { }
|
||||
|
||||
@@ -40,4 +41,8 @@ export class AppComponent implements OnInit {
|
||||
this.userService.populate();
|
||||
this.titleService.setTitle(this.title);
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.appClass = 'colored';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<div @flyInOut>
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<span class="fs-5 text-primary">{{ now | date: 'dd/MM/yyyy' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
<div class="d-flex">
|
||||
<p class="fs-3">{{description}}</p>
|
||||
</div>
|
||||
<mat-divider class="mt-2 mb-3"></mat-divider>
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="d-flex rounded-top bg-navy-light text-bg-navy-light py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="table-responsive p-0">
|
||||
<mat-stepper headerPosition="top" #stepper>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 1</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 1</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">Power limit: 320k</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 2</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 2</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">Power limit: 500k</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 3</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 3</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">No power limit</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="search">
|
||||
<ng-template matStepLabel>Statistics</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Statistics</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">variation ≥ {{ minVarPct }}%</h4>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Variation</mat-label>
|
||||
<input matInput [(ngModel)]="minVarPct" type="number" min="{{ minValue }}">
|
||||
<mat-icon matSuffix>percent</mat-icon>
|
||||
<mat-hint>excess power in %</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button (click)="stepper.reset()">Reset</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<ng-template matStepperIcon="timeline">
|
||||
<mat-icon>timeline</mat-icon>
|
||||
</ng-template>
|
||||
<ng-template matStepperIcon="search">
|
||||
<mat-icon>manage_search</mat-icon>
|
||||
</ng-template>
|
||||
</mat-stepper>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HerowarsGuildraidComponent } from './herowars-guildraid.component';
|
||||
|
||||
describe('HerowarsGuildraidComponent', () => {
|
||||
let component: HerowarsGuildraidComponent;
|
||||
let fixture: ComponentFixture<HerowarsGuildraidComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HerowarsGuildraidComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HerowarsGuildraidComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { trigger, state, style, animate, transition } from '@angular/animations';
|
||||
import { Component, DestroyRef, Injectable, inject, OnInit } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatStepperIntl, MatStepperModule } from '@angular/material/stepper';
|
||||
|
||||
import { ListErrorsComponent } from 'src/app/components/shared';
|
||||
import { Errors } from 'src/app/core/models';
|
||||
import { HWGuildRaid, HWGuildRaidAttacker, HWGuildRaidAttackers, HWGuildRaidStage, HWMember } from 'src/app/core/models/herowars';
|
||||
|
||||
import guildRaids from 'src/files-data/hw-guild-raids.json'; // page Asgard -> Guild Raid -> Log
|
||||
|
||||
@Injectable()
|
||||
export class GuildRaidStepperIntl extends MatStepperIntl {
|
||||
// the default optional label text, if unspecified is "Optional"
|
||||
override optionalLabel = 'Optional Label';
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-herowars-guildraid',
|
||||
standalone: true,
|
||||
providers: [
|
||||
{
|
||||
provide: STEPPER_GLOBAL_OPTIONS,
|
||||
useValue: { displayDefaultIndicatorType: false },
|
||||
},
|
||||
],
|
||||
imports: [
|
||||
DatePipe, FormsModule, ListErrorsComponent,
|
||||
MatButtonModule, MatCardModule, MatDividerModule, MatFormFieldModule,
|
||||
MatIconModule, MatInputModule, MatStepperModule
|
||||
],
|
||||
templateUrl: './herowars-guildraid.component.html',
|
||||
styleUrl: './herowars-guildraid.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateY(0)' })),
|
||||
transition('void => *', [
|
||||
style({ transform: 'translateY(-100%)' }),
|
||||
animate(200)
|
||||
]),
|
||||
transition('* => void', [
|
||||
style({ transform: 'translateY(100%)' }),
|
||||
animate(200)
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class HerowarsGuildraidComponent implements OnInit {
|
||||
public title = 'Guild Raids';
|
||||
public subtitle = 'Log';
|
||||
public description = 'Tools in working progress.';
|
||||
public errors: Errors = { errors: {} };
|
||||
public destroyRef = inject(DestroyRef);
|
||||
public minVarPct = 3;
|
||||
public minValue = 0;
|
||||
public now = new Date();
|
||||
private _guildMembers: HWMember[] = [];
|
||||
private _matStepperIntl = inject(MatStepperIntl);
|
||||
private _guildRaids: HWGuildRaid[] = [];
|
||||
private _raidStages: HWGuildRaidStage[] = [
|
||||
{ num: 1, name: 'Stage 1', maxPower: 320000, duration: 8, startTime: 0, endTime: 0 },
|
||||
{ num: 2, name: 'Stage 2', maxPower: 500000, duration: 8, startTime: 0, endTime: 0 },
|
||||
{ num: 3, name: 'Stage 3', maxPower: 0, duration: 0, startTime: 0, endTime: 0 }
|
||||
];
|
||||
|
||||
constructor(
|
||||
private _titleService: Title
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this._titleService.setTitle(this.title);
|
||||
this._guildMembers.map((data) => {
|
||||
data.raids = [];
|
||||
data.raidsInfo = {
|
||||
variationAvg: 0,
|
||||
variationSum: 0
|
||||
};
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
getMembers(): HWMember[] {
|
||||
return this._guildMembers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<div @flyInOut>
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<span class="fs-5 text-primary">{{ now | date: 'dd/MM/yyyy' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
<div class="d-flex">
|
||||
<p class="fs-3">{{description}}</p>
|
||||
</div>
|
||||
<mat-divider class="mt-2 mb-3"></mat-divider>
|
||||
|
||||
<mat-tab-group [selectedIndex]="0" color="warn">
|
||||
<mat-tab label="Clan">
|
||||
<div class="row g-0">
|
||||
<div class="col-12 pe-md-2 border-1 border-top">
|
||||
<!--<app-guildwar-attack [members]="getMembers()"></app-guildwar-attack>-->
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2>
|
||||
@if (clanLoaded) {
|
||||
<span class="border-1 border-bottom">{{ getClan().title }} <span class="fs-4"> – Server {{ getClan().serverId }}</span></span>
|
||||
}
|
||||
</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<span class="fs-4">Members: {{ getClan().membersCount }}/30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-0 my-3">
|
||||
<div class="col-2">
|
||||
<div class="d-flex align-items-start flex-column me-1" role="group" aria-label="Vertical button group">
|
||||
@if (clanLoaded) {
|
||||
<button mat-stroked-button color="warn" (click)="syncClan()" class="mb-1">Sync clan</button>
|
||||
}
|
||||
@else {
|
||||
<button mat-stroked-button color="megna" (click)="loadClan()" class="mb-1">Load clan</button>
|
||||
}
|
||||
@if (membersLoaded) {
|
||||
<button mat-stroked-button color="warn" (click)="syncMembers()" class="mb-1">Sync members</button>
|
||||
}
|
||||
@else {
|
||||
<button mat-stroked-button color="megna" (click)="loadMembers()" [disabled]="!clanLoaded" class="mb-1">Load members</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<dl class="dl-horizontal m-0">
|
||||
<dt>country</dt>
|
||||
<dd>{{ getClan().country }}</dd>
|
||||
<dt>serverId</dt>
|
||||
<dd>{{ getClan().serverId }}</dd>
|
||||
<dt>description</dt>
|
||||
<dd>{{ getClan().description }}</dd>
|
||||
<dt>level</dt>
|
||||
<dd>{{ getClan().level }}</dd>
|
||||
<dt>minLevel</dt>
|
||||
<dd>{{ getClan().minLevel }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<dl class="dl-horizontal m-0">
|
||||
<dt>topActivity</dt>
|
||||
<dd>{{ getClan().topActivity | number : '1.0' }}</dd>
|
||||
<dt>topDungeon</dt>
|
||||
<dd>{{ getClan().topDungeon | number : '1.0' }}</dd>
|
||||
<dt>disbanding</dt>
|
||||
<dd>{{ getClan().disbanding }}</dd>
|
||||
<dt>frameId</dt>
|
||||
<dd>{{ getClan().frameId }}</dd>
|
||||
<dt>ownerId</dt>
|
||||
<dd>{{ getClan().ownerId }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive p-0">
|
||||
<table class="table table-striped table-condensed border-top border-light">
|
||||
<thead>
|
||||
<tr role="row" class="text-bg-raspberry bg-opacity-60">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
ID
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Name
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Clan
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Server
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Last Login
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Level
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Heroes
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Titans
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (member of getMembers(); track member; let index = $index) {
|
||||
<tr role="row" class="align-middle">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span class="me-3">{{ member.id }}</span>
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
{{ member.name }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
{{ member.clanTitle }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
{{ member.serverId }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span class="me-3">{{ member.lastLoginTime + '000' | date: 'dd/MM HH:mm' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
{{ member.level }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ member.heroes.power | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
{{ member.titans.power | number : '1.0' }}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Attack">
|
||||
<div class="row g-0">
|
||||
<div class="col col-md-6 pe-md-2">
|
||||
<!--<app-guildwar-defence [members]="getMembers()" type="heroes"></app-guildwar-defence>-->
|
||||
</div>
|
||||
<div class="col col-md-6 ps-md-2">
|
||||
<!--<app-guildwar-defence [members]="getMembers()" type="titans"></app-guildwar-defence>-->
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Defense">
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="d-flex rounded-top text-bg-raspberry py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="table-responsive p-0">
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Info">
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
.btn-group-vertical {
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
button {
|
||||
margin: 2px 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HerowarsGuildwarComponent } from './herowars-guildwar.component';
|
||||
|
||||
describe('HerowarsGuildwarComponent', () => {
|
||||
let component: HerowarsGuildwarComponent;
|
||||
let fixture: ComponentFixture<HerowarsGuildwarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HerowarsGuildwarComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HerowarsGuildwarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,207 @@
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { trigger, state, style, animate, transition } from '@angular/animations';
|
||||
import { Component, DestroyRef, inject, OnInit } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import { ListErrorsComponent, GuildwarAttackComponent, GuildwarDefenceComponent } from 'src/app/components/shared';
|
||||
import { Errors, HWActivityStat, HWGuildClan, HWMember, HWMemberStat, HWWeekStat } from 'src/app/core/models';
|
||||
import { UtilitiesService } from 'src/app/core/services';
|
||||
|
||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
||||
import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
||||
|
||||
@Component({
|
||||
selector: 'app-herowars-guildwar',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe, DecimalPipe, FormsModule, ListErrorsComponent,
|
||||
MatButtonModule, MatCardModule, MatDividerModule, MatFormFieldModule,
|
||||
MatIconModule, MatInputModule, MatTabsModule,
|
||||
GuildwarAttackComponent, GuildwarDefenceComponent
|
||||
],
|
||||
templateUrl: './herowars-guildwar.component.html',
|
||||
styleUrl: './herowars-guildwar.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateY(0)' })),
|
||||
transition('void => *', [
|
||||
style({ transform: 'translateY(-100%)' }),
|
||||
animate(200)
|
||||
]),
|
||||
transition('* => void', [
|
||||
style({ transform: 'translateY(100%)' }),
|
||||
animate(200)
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class HerowarsGuildwarComponent implements OnInit {
|
||||
public title = 'Guild War';
|
||||
public subtitle = 'Log';
|
||||
public description = 'Tools in working progress.';
|
||||
public errors: Errors = { errors: {} };
|
||||
public destroyRef = inject(DestroyRef);
|
||||
public now = new Date();
|
||||
public daysToWarn = 1;
|
||||
public clanLoaded = false;
|
||||
public membersLoaded = false;
|
||||
private _guildClan: HWGuildClan = {} as HWGuildClan;
|
||||
private _guildMembers: HWMember[] = [];
|
||||
private _guildInfo: HWActivityStat = {} as HWActivityStat;
|
||||
|
||||
constructor(
|
||||
private _titleService: Title,
|
||||
private _utilitiesService: UtilitiesService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this._titleService.setTitle(this.title);
|
||||
}
|
||||
|
||||
private _resetActivity(): HWActivityStat {
|
||||
const activity: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
|
||||
return activity;
|
||||
}
|
||||
|
||||
private _importMembers() {
|
||||
try {
|
||||
const oneDayInSec = (24 * 60 * 60);
|
||||
const daysToKick = parseInt(guildData.clan.daysToKick);
|
||||
this.daysToWarn = (parseInt(guildData.clan.daysToKick) / 2);
|
||||
for (const data of Object.entries(guildData.clan.members)) {
|
||||
const member: HWMember = {} as HWMember;
|
||||
Object.assign(member, data[1]);
|
||||
if (guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1) {
|
||||
member.champion = true;
|
||||
} else {
|
||||
member.champion = false;
|
||||
}
|
||||
member.heroes = { power: 0, teams: []};
|
||||
member.titans = { power: 0, teams: []};
|
||||
this._guildMembers.push(member);
|
||||
}
|
||||
this._guildMembers.map((data) => {
|
||||
const last = new Date((parseInt(data.lastLoginTime) * 1000));
|
||||
const exp = new Date(last.getTime() + ((daysToKick * oneDayInSec) * 1000));
|
||||
const diff = Math.floor(((exp.getTime() - this.now.getTime()) / 1000));
|
||||
const daysLeft = Math.floor((diff / oneDayInSec));
|
||||
let timeLeft = diff;
|
||||
if (daysLeft >= 1) {
|
||||
timeLeft = (diff - (daysLeft * oneDayInSec));
|
||||
}
|
||||
data.inactivity = {
|
||||
daysLeft: daysLeft,
|
||||
timeLeft: timeLeft,
|
||||
dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
|
||||
dropDate: Math.floor((exp.getTime() / 1000))
|
||||
};
|
||||
data.raids = [];
|
||||
data.raidsInfo = {
|
||||
variationAvg: 0,
|
||||
variationSum: 0
|
||||
};
|
||||
data.stat = {} as HWMemberStat;
|
||||
let index = guildData.membersStat.findIndex(stat => stat.userId === data.id);
|
||||
if (index !== -1) {
|
||||
delete (guildData.membersStat[index] as {userId?: string}).userId;
|
||||
Object.assign(data.stat, guildData.membersStat[index]);
|
||||
//data.stat = guildData.membersStat[index];
|
||||
}
|
||||
index = guildStatistics.stat.findIndex(stat => stat.id === data.id);
|
||||
if (index !== -1) {
|
||||
delete (guildStatistics.stat[index] as {id?: string}).id;
|
||||
const stat: HWWeekStat = {} as HWWeekStat;
|
||||
Object.assign(stat, guildStatistics.stat[index]);
|
||||
data.weekStat = stat;
|
||||
data.adventureSum = guildStatistics.stat[index].adventureStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
this._guildClan.sumTotal.adventure += data.adventureSum;
|
||||
this._guildClan.sumTotal.gifts += data.clanGiftsSum;
|
||||
this._guildClan.sumTotal.war += data.clanWarSum;
|
||||
}
|
||||
|
||||
data.score = (data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum);
|
||||
data.warGifts = (((this._guildClan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20);
|
||||
|
||||
this._guildClan.todayTotal.activity += data.stat.todayActivity;
|
||||
this._guildClan.todayTotal.prestige += data.stat.todayPrestige;
|
||||
this._guildClan.todayTotal.titanite += data.stat.todayDungeonActivity;
|
||||
this._guildClan.todayTotal.score += (data.stat.todayDungeonActivity + data.stat.todayActivity + data.stat.todayPrestige);
|
||||
this._guildClan.sumTotal.activity += data.stat.activitySum;
|
||||
this._guildClan.sumTotal.prestige += data.stat.prestigeSum;
|
||||
this._guildClan.sumTotal.titanite += data.stat.dungeonActivitySum;
|
||||
this._guildClan.sumTotal.score += data.score;
|
||||
this._guildClan.sumTotal.warGifts += data.warGifts;
|
||||
|
||||
data.scoreGifts = 0;
|
||||
data.rewards = 0;
|
||||
return data;
|
||||
});
|
||||
this._guildClan.sumTotal.scoreGifts = (this._guildClan.giftsCount - Math.floor(this._guildClan.sumTotal.warGifts));
|
||||
this._guildClan.todayAverages.activity = (this._guildClan.todayTotal.activity / this._guildMembers.length);
|
||||
this._guildClan.todayAverages.prestige = (this._guildClan.todayTotal.prestige / this._guildMembers.length);
|
||||
this._guildClan.todayAverages.titanite = (this._guildClan.todayTotal.titanite / this._guildMembers.length);
|
||||
this._guildClan.todayAverages.score = (this._guildClan.todayTotal.score / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.activity = (this._guildClan.sumTotal.activity / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.prestige = (this._guildClan.sumTotal.prestige / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.titanite = (this._guildClan.sumTotal.titanite / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.war = (this._guildClan.sumTotal.war / 20);
|
||||
this._guildClan.sumAverages.adventure = (this._guildClan.sumTotal.adventure / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.gifts = (this._guildClan.sumTotal.gifts / this._guildMembers.length);
|
||||
this._guildClan.sumAverages.score = (this._guildClan.sumTotal.score / this._guildMembers.length);
|
||||
|
||||
this._guildMembers.map((data) => {
|
||||
data.scoreGifts = ((data.score / this._guildClan.sumTotal.score) * this._guildClan.sumTotal.scoreGifts);
|
||||
data.rewards = Math.floor((data.scoreGifts + data.warGifts));
|
||||
this._guildClan.sumTotal.rewards += data.rewards;
|
||||
return data;
|
||||
});
|
||||
this._guildClan.sumAverages.rewards = (this._guildClan.sumTotal.rewards / this._guildMembers.length);
|
||||
|
||||
console.log(this._guildClan);
|
||||
console.log(this._guildMembers);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
getClan(): HWGuildClan {
|
||||
return this._guildClan;
|
||||
}
|
||||
|
||||
loadClan(): void {
|
||||
Object.assign(this._guildClan, guildData.clan);
|
||||
this._guildClan.sumAverages = this._resetActivity();
|
||||
this._guildClan.sumTotal = this._resetActivity();
|
||||
this._guildClan.todayAverages = this._resetActivity();
|
||||
this._guildClan.todayTotal = this._resetActivity();
|
||||
this.clanLoaded = true;
|
||||
}
|
||||
|
||||
loadMembers(): void {
|
||||
this._importMembers();
|
||||
this.membersLoaded = true;
|
||||
}
|
||||
|
||||
getMembers(): HWMember[] {
|
||||
return this._guildMembers;
|
||||
}
|
||||
|
||||
syncClan(): void {
|
||||
console.log(this._guildClan);
|
||||
}
|
||||
|
||||
syncMembers(): void {
|
||||
console.log(this._guildMembers);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<div @flyInOut>
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h1 class="mb-1">{{title}}</h1>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<span class="fs-5 text-primary">{{ now | date: 'dd/MM/yyyy' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-list-errors [errors]="errors"></app-list-errors>
|
||||
<div class="d-flex">
|
||||
<p class="fs-3">{{description}}</p>
|
||||
</div>
|
||||
<mat-divider class="mt-2 mb-3"></mat-divider>
|
||||
<mat-tab-group [selectedIndex]="3">
|
||||
<mat-tab label="Guild War">
|
||||
<div class="row g-0">
|
||||
<div class="col col-md-6 pe-md-2">
|
||||
<app-guildwar-defence [members]="getMembers()" type="heroes"></app-guildwar-defence>
|
||||
</div>
|
||||
<div class="col col-md-6 ps-md-2">
|
||||
<app-guildwar-defence [members]="getMembers()" type="titans"></app-guildwar-defence>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-0">
|
||||
<div class="col-12 pe-md-2">
|
||||
<!--<app-guildwar-attack [members]="getMembers()"></app-guildwar-attack>-->
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Champions">
|
||||
<div class="row g-0">
|
||||
<div class="col col-md-6 pe-md-2">
|
||||
<div class="row">
|
||||
<div class="col col-md-6 pe-md-2">
|
||||
<app-guildwar-champions [members]="getMembers()" type="heroes"></app-guildwar-champions>
|
||||
</div>
|
||||
<div class="col col-md-6 ps-md-2">
|
||||
<app-guildwar-champions [members]="getMembers()" type="titans"></app-guildwar-champions>
|
||||
</div>
|
||||
</div>
|
||||
<app-guild-card></app-guild-card>
|
||||
</div>
|
||||
<div class="col col-md-6 ps-md-2">
|
||||
<app-guildwar-teams [members]="getMembers()"></app-guildwar-teams>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Members">
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<app-members-statistics [members]="getMembers()"></app-members-statistics>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Raids">
|
||||
<div class="row g-0">
|
||||
<div class="col">
|
||||
<app-guildraids-log [members]="getMembers()"></app-guildraids-log>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
/* herowars */
|
||||
//@use 'variable' as var;
|
||||
.icon-xxsmall {
|
||||
transform: scale(0.25);
|
||||
}
|
||||
.icon-xsmall {
|
||||
font-size: 16px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
.icon-small {
|
||||
font-size: 18px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
.icon-medium {
|
||||
font-size: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
.hstack .value {
|
||||
min-width: 56px;
|
||||
}
|
||||
|
||||
/*
|
||||
#FF41F8
|
||||
#F0060B
|
||||
#F0070C
|
||||
#CC26D5
|
||||
#7702FF
|
||||
|
||||
#35A2EB
|
||||
#B7DDD0
|
||||
#B0D9CB
|
||||
#D9CAAE
|
||||
#9788C7
|
||||
*/
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HerowarsComponent } from './herowars.component';
|
||||
|
||||
describe('HerowarsComponent', () => {
|
||||
let component: HerowarsComponent;
|
||||
let fixture: ComponentFixture<HerowarsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HerowarsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HerowarsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { trigger, state, style, animate, transition } from '@angular/animations';
|
||||
//import { Component, DestroyRef, inject, OnInit, computed, signal, Signal } from '@angular/core';
|
||||
import { Component, DestroyRef, inject, OnInit } from '@angular/core';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import {
|
||||
ListErrorsComponent,
|
||||
GuildCardComponent, GuildraidsLogComponent, GuildwarChampionsComponent,
|
||||
GuildwarAttackComponent, GuildwarDefenceComponent, GuildwarTeamsComponent, MembersStatisticsComponent
|
||||
} from 'src/app/components/shared';
|
||||
import { Errors, HWMember } from 'src/app/core/models';
|
||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
||||
//import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
||||
//import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
||||
//import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
||||
|
||||
@Component({
|
||||
selector: 'app-herowars',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule, MatTabsModule,
|
||||
ListErrorsComponent,
|
||||
GuildCardComponent, GuildraidsLogComponent, GuildwarChampionsComponent,
|
||||
GuildwarAttackComponent, GuildwarDefenceComponent, GuildwarTeamsComponent, MembersStatisticsComponent
|
||||
],
|
||||
templateUrl: './herowars.component.html',
|
||||
styleUrl: './herowars.component.scss',
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateY(0)' })),
|
||||
transition('void => *', [
|
||||
style({ transform: 'translateY(-100%)' }),
|
||||
animate(200)
|
||||
]),
|
||||
transition('* => void', [
|
||||
style({ transform: 'translateY(100%)' }),
|
||||
animate(200)
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class HerowarsComponent implements OnInit {
|
||||
public title = 'HeroWars GM Tools';
|
||||
public description = 'Tools in working progress.';
|
||||
public errors: Errors = { errors: {} };
|
||||
public destroyRef = inject(DestroyRef);
|
||||
public now = new Date();
|
||||
private _guildMembers: HWMember[] = [];
|
||||
|
||||
constructor(
|
||||
private _titleService: Title
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
try {
|
||||
this._titleService.setTitle(this.title);
|
||||
for (const data of Object.entries(guildData.clan.members)) {
|
||||
const member: HWMember = {} as HWMember;
|
||||
Object.assign(member, data[1]);
|
||||
if (guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1) {
|
||||
member.champion = true;
|
||||
} else {
|
||||
member.champion = false;
|
||||
}
|
||||
member.heroes = { power: 0, teams: []};
|
||||
member.titans = { power: 0, teams: []};
|
||||
this._guildMembers.push(member);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
getMembers(): HWMember[] {
|
||||
return this._guildMembers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export * from './dashboard/dashboard.component';
|
||||
export * from './demo/demo.component';
|
||||
export * from './dropzones/dropzones.component';
|
||||
export * from './herowars/herowars.component';
|
||||
export * from './herowars-guildwar/herowars-guildwar.component';
|
||||
export * from './herowars-guildraid/herowars-guildraid.component';
|
||||
export * from './home/home.component';
|
||||
export * from './jump/jump.component';
|
||||
export * from './jumps/jumps.component';
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<mat-card-subtitle>
|
||||
<span class="border-bottom border-navy text-navy fw-normal fs-5">{{ data.name }}</span>
|
||||
<small class="font-monospace text-navy float-end">[ {{ data.count | number : '1.0' }} ]</small>
|
||||
</mat-card-subtitle>
|
||||
<ul class="list-unstyled mt-2">
|
||||
@for (champion of data.teams; track champion; let index = $index) {
|
||||
<li [class]="(champion.id !== data.positions[data.slots[(index)]].toString()) ? 'text-red' : ''">
|
||||
<span class="slot">slot {{data.slots[(index)]}}</span>
|
||||
@if (champion.id !== data.positions[data.slots[(index)]].toString()) {
|
||||
<span class="text-decoration-line-through">{{ getMemberNameById(data.positions[data.slots[(index)]].toString()) }}</span>
|
||||
<mat-icon fontIcon="swap_horiz" class="mx-3 align-middle icon-xsmall"></mat-icon>
|
||||
}
|
||||
<span>{{ champion.name }}</span>
|
||||
<span class="font-monospace float-end">
|
||||
@switch (teamType) {
|
||||
@case ('heroes') {
|
||||
@if (champion.id !== data.positions[data.slots[(index)]].toString()) {
|
||||
<span class="text-decoration-line-through">{{ getMemberHeroesPowerById(data.positions[data.slots[(index)]].toString()) | number : '1.0' }}</span>
|
||||
<mat-icon fontIcon="swap_horiz" class="mx-3 align-middle icon-xsmall"></mat-icon>
|
||||
}
|
||||
{{ champion.heroes.power | number : '1.0' }}
|
||||
}
|
||||
@case ('titans') {
|
||||
@if (champion.id !== data.positions[data.slots[(index)]].toString()) {
|
||||
<span class="text-decoration-line-through">{{ getMemberTitansPowerById(data.positions[data.slots[(index)]].toString()) | number : '1.0' }}</span>
|
||||
<mat-icon fontIcon="swap_horiz" class="mx-3 align-middle icon-xsmall"></mat-icon>
|
||||
}
|
||||
{{ champion.titans.power | number : '1.0' }}
|
||||
}
|
||||
@default {
|
||||
0
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.slot {
|
||||
min-width: 60px;
|
||||
display: inline-block;
|
||||
}
|
||||
.mat-mdc-standard-chip {
|
||||
--mdc-chip-container-height: 28px;
|
||||
--mdc-chip-container-shape-radius: 8px 8px 8px 8px;
|
||||
--mdc-chip-label-text-color: inherit;
|
||||
--mdc-chip-label-text-line-height: 20px;
|
||||
--mdc-chip-label-text-size: 13px;
|
||||
--mdc-chip-label-text-weight: 400;
|
||||
--mdc-chip-with-avatar-avatar-shape-radius: 6px 6px 6px 6px;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
//import { Errors } from 'src/app/core/models';
|
||||
//import { HWMember, HWGuildWarFortification, HWGuildWarHeroTeam, HWGuildWarTitanTeam } from 'src/app/core/models';
|
||||
import { HWGuildWarFortification, HWMember } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-fortification-card-content',
|
||||
templateUrl: './fortification-card-content.component.html',
|
||||
styleUrl: './fortification-card-content.component.scss',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DecimalPipe,
|
||||
MatCardModule, MatChipsModule, MatIconModule
|
||||
]
|
||||
})
|
||||
export class FortificationCardContentComponent {
|
||||
public data: HWGuildWarFortification = {} as HWGuildWarFortification;
|
||||
public teamType: string = '';
|
||||
public guildMembers: HWMember[] = [];
|
||||
//public errorList: string[] = [];
|
||||
|
||||
@Input() set fortification(data: HWGuildWarFortification) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Input() set type(value: string) {
|
||||
this.teamType = value;
|
||||
}
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
getMemberNameById(id: string): string {
|
||||
let name = '';
|
||||
this.guildMembers.some((item) => {
|
||||
if (item.id === id) {
|
||||
name = item.name;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return name;
|
||||
}
|
||||
|
||||
getMemberHeroesPowerById(id: string): number {
|
||||
let power = 0;
|
||||
this.guildMembers.some((item) => {
|
||||
if (item.id === id) {
|
||||
power = item.heroes.power;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return power;
|
||||
}
|
||||
|
||||
getMemberTitansPowerById(id: string): number {
|
||||
let power = 0;
|
||||
this.guildMembers.some((item) => {
|
||||
if (item.id === id) {
|
||||
power = item.titans.power;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return power;
|
||||
}
|
||||
/*
|
||||
@Input() set errors(errorList: Errors | null) {
|
||||
this.errorList = errorList
|
||||
? Object.keys(errorList.errors || {}).map(
|
||||
(key) => `${key} ${errorList.errors[key]}`,
|
||||
)
|
||||
: [];
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<mat-card class="mb-3">
|
||||
<mat-card-header class="bg-raspberry text-bg-primary d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ guildData.clan.title }} <span class="ms-2 me-2 fw-light opacity-75">|</span><small class="fs-5 fw-light opacity-75">server {{ guildData.clan.serverId }}</small>
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ guildData.clan.membersCount }}/30</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="row mt-2">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<span class="border-bottom border-raspberry text-raspberry fs-5">Server/Season Dates</span>
|
||||
<dl class="dl-horizontal dl-large mt-3 mb-0">
|
||||
<dt>Server Reset Time</dt>
|
||||
<dd class="font-monospace">{{ (guildData.serverResetTime*1000) | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
<dt>War End Season Time</dt>
|
||||
<dd class="font-monospace">{{ (guildData.clanWarEndSeasonTime*1000) | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
<dt>Free Clan Change Start</dt>
|
||||
<dd class="font-monospace">{{ (guildData.freeClanChangeInterval.start * 1000) | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
<dt>Free Clan Change End</dt>
|
||||
<dd class="font-monospace">{{ (guildData.freeClanChangeInterval.end * 1000) | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<span class="border-bottom border-raspberry text-raspberry fs-5">Guild Overview</span>
|
||||
<dl class="dl-horizontal dl-large mt-3 mb-0">
|
||||
<dt>Members</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.clan.membersCount }}/30</dd>
|
||||
<dt>Champions</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.clan.warriors.length }}/20</dd>
|
||||
<dt>Top Activity</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.clan.topActivity | number : '1.0' }}</dd>
|
||||
<dt>Top Dungeon</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.clan.topDungeon | number : '1.0' }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="my-2"></mat-divider>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<span class="border-bottom border-raspberry text-raspberry fs-5">Guild Settings</span>
|
||||
<dl class="dl-horizontal dl-large mt-2 mb-0">
|
||||
<dt>Guild Min. Level</dt>
|
||||
<dd class="font-monospace">{{ guildData.clan.minLevel }}</dd>
|
||||
<dt>Dismissal Delay</dt>
|
||||
<dd class="font-monospace">{{ guildData.clan.daysToKick }} days</dd>
|
||||
<dt>Guild Master Gifts</dt>
|
||||
<dd class="font-monospace">{{ guildData.clan.giftsCount }}</dd>
|
||||
<dt>Adventure Stat</dt>
|
||||
<dd class="font-monospace">{{ guildData.stat.adventureStat }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<span class="border-bottom border-raspberry text-raspberry fs-5">Solide Overview</span>
|
||||
<dl class="dl-horizontal dl-large mt-2 mb-0">
|
||||
<dt>Today Activity</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.stat.todayActivity }}</dd>
|
||||
<dt>Today Titanite</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.stat.todayDungeonActivity }}</dd>
|
||||
<dt>Activity Sum</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.stat.activitySum }}</dd>
|
||||
<dt>Titanite Sum</dt>
|
||||
<dd class="font-monospace text-end">{{ guildData.stat.dungeonActivitySum }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildCardComponent } from './guild-card.component';
|
||||
|
||||
describe('GuildCardComponent', () => {
|
||||
let component: GuildCardComponent;
|
||||
let fixture: ComponentFixture<GuildCardComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildCardComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildCardComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { HWGuildData, HWGuildClan, HWGuildStat } from 'src/app/core/models';
|
||||
|
||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
||||
|
||||
@Component({
|
||||
selector: 'app-guild-card',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe, DecimalPipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule
|
||||
],
|
||||
templateUrl: './guild-card.component.html',
|
||||
styleUrl: './guild-card.component.scss'
|
||||
})
|
||||
export class GuildCardComponent implements OnInit {
|
||||
public guildData: HWGuildData = {} as HWGuildData;
|
||||
private _guildClan: HWGuildClan = {} as HWGuildClan;
|
||||
private _guildStat: HWGuildStat = {} as HWGuildStat;
|
||||
|
||||
ngOnInit() {
|
||||
Object.assign(this._guildClan, guildData.clan);
|
||||
this.guildData.clan = this._guildClan;
|
||||
Object.assign(this._guildStat, guildData.stat);
|
||||
this.guildData.stat = this._guildStat;
|
||||
this.guildData.serverResetTime = guildData.serverResetTime;
|
||||
this.guildData.clanWarEndSeasonTime = guildData.clanWarEndSeasonTime;
|
||||
this.guildData.freeClanChangeInterval = guildData.freeClanChangeInterval;
|
||||
this.guildData.giftUids = guildData.giftUids;
|
||||
}
|
||||
}
|
||||
+436
@@ -0,0 +1,436 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="d-flex rounded-top bg-navy-light text-bg-navy-light py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="table-responsive p-0">
|
||||
<form class="d-flex" [formGroup]="raidsForm" (ngSubmit)="submitForm()">
|
||||
<mat-form-field appearance="outline" class="mt-2 me-3" color="warn">
|
||||
<mat-label>Choisissez une date</mat-label>
|
||||
<input matInput [matDatepicker]="datepicker" formControlName="startTime" (dateChange)="onDateChange()" required
|
||||
cdkFocusInitial />
|
||||
<mat-hint>MM/DD/YYYY</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="datepicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #datepicker>
|
||||
<mat-datepicker-actions>
|
||||
<button mat-button matDatepickerCancel>Annuler</button>
|
||||
<button mat-raised-button color="warn" matDatepickerApply>Appliquer</button>
|
||||
</mat-datepicker-actions>
|
||||
</mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="mt-2 me-2" color="warn">
|
||||
<mat-label>Duration</mat-label>
|
||||
<input matInput formControlName="duration" required />
|
||||
<mat-hint>Stage duration in hour</mat-hint>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
<mat-stepper headerPosition="top" #stepper>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 1</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 1</h2>
|
||||
<h4 class="mb-1">
|
||||
From {{ getStagesTime(0).startTime | date: 'dd/MM HH:mm' }}
|
||||
to {{ getStagesTime(0).endTime | date: 'dd/MM HH:mm' }}
|
||||
</h4>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">Power limit: 320k</h4>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr role="row" class="bg-gray-500 text-bg-primary">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Date
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Member
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Level
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Damage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Stage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Power
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Variation
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (raid of getRaidsLog(1); track raid; let index = $index) {
|
||||
<tr role="row" class="align-middle text-{{ raid.variation.color }}">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span class="me-3">{{ raid.startTime + '000' | date: 'dd/MM HH:mm:ss' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.userName }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
{{ raid.level | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
@if (raid.damage["2"] > 0) {
|
||||
<mat-icon fontIcon="arrow_upward" color="purple" class="me-2 icon-xxsmall" matTooltip="{{ raid.damage['1'] | number : '1.0' }} + {{ raid.damage['2'] | number : '1.0' }}"></mat-icon>
|
||||
}
|
||||
{{ (raid.damage["1"] + raid.damage["2"]) | number : '1.0' }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.stage.name }}: {{ (raid.stage.maxPower / 1000) | number : '1.0' }}k
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.power | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
<span class="ms-3" [matTooltip]="raid.tooltip">
|
||||
{{ raid.variation.percent | number : '1.0-2' }}%
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 2</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 2</h2>
|
||||
<h4 class="mb-1">
|
||||
From {{ getStagesTime(1).startTime | date: 'dd/MM HH:mm' }}
|
||||
to {{ getStagesTime(1).endTime | date: 'dd/MM HH:mm' }}
|
||||
</h4>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">Power limit: 500k</h4>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr role="row" class="bg-gray-500 text-bg-primary">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Date
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Member
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Level
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Damage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Stage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Power
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Variation
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (raid of getRaidsLog(2); track raid; let index = $index) {
|
||||
<tr role="row" class="align-middle text-{{ raid.variation.color }}">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span class="me-3">{{ raid.startTime + '000' | date: 'dd/MM HH:mm:ss' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.userName }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
{{ raid.level | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
@if (raid.damage["2"] > 0) {
|
||||
<mat-icon fontIcon="arrow_upward" color="purple" class="me-2 icon-xxsmall" matTooltip="{{ raid.damage['1'] | number : '1.0' }} + {{ raid.damage['2'] | number : '1.0' }}"></mat-icon>
|
||||
}
|
||||
{{ (raid.damage["1"] + raid.damage["2"]) | number : '1.0' }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.stage.name }}: {{ (raid.stage.maxPower / 1000) | number : '1.0' }}k
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.power | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
<span class="ms-3" [matTooltip]="raid.tooltip">
|
||||
{{ raid.variation.percent | number : '1.0-2' }}%
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="timeline">
|
||||
<ng-template matStepLabel>Stage 3</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Stage 3</h2>
|
||||
<h4 class="mb-1">
|
||||
From {{ getStagesTime(2).startTime | date: 'dd/MM HH:mm' }}
|
||||
to {{ getStagesTime(2).endTime | date: 'dd/MM HH:mm' }}
|
||||
</h4>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">No power limit</h4>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr role="row" class="bg-gray-500 text-bg-primary">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Date
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Member
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Level
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Damage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Stage
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Power
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Variation
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (raid of getRaidsLog(3); track raid; let index = $index) {
|
||||
<tr role="row" class="align-middle text-{{ raid.variation.color }}">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span class="me-3">{{ raid.startTime + '000' | date: 'dd/MM HH:mm:ss' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.userName }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
{{ raid.level | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end {{ raid.damage['2'] > 0 ? 'text-purple' : '' }}">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
@if (raid.damage["2"] > 0) {
|
||||
<mat-icon fontIcon="arrow_upward" color="purple" class="me-2 icon-xxsmall" matTooltip="{{ raid.damage['1'] | number : '1.0' }} + {{ raid.damage['2'] | number : '1.0' }}"></mat-icon>
|
||||
}
|
||||
{{ (raid.damage["1"] + raid.damage["2"]) | number : '1.0' }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.stage.name }}: {{ (raid.stage.maxPower / 1000) | number : '1.0' }}k
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ raid.power | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
<span class="ms-3" [matTooltip]="raid.tooltip">
|
||||
{{ raid.variation.percent | number : '1.0-2' }}%
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step state="search">
|
||||
<ng-template matStepLabel>Statistics</ng-template>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="flex-fill">
|
||||
<h2 class="mb-1">Statistics</h2>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center me-2 text-end">
|
||||
<h4 class="mb-1">variation ≥ {{ minVarPct }}%</h4>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Variation</mat-label>
|
||||
<input matInput [(ngModel)]="minVarPct" type="number" min="0">
|
||||
<mat-icon matSuffix>percent</mat-icon>
|
||||
<mat-hint>excess power in %</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr role="row" class="bg-gray-500 text-bg-primary">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Name
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Fights
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Variation moyenne
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-start ps-2">
|
||||
[]
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (member of getMembers(); track member; let index = $index) {
|
||||
<tr role="row" class="align-middle">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ member.name }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ member.raids.length }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ member.raidsInfo.variationAvg | number : '1.0-2' }}%
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="d-flex justify-content-start">
|
||||
@for (raid of member.raids; track raid) {
|
||||
<div class="px-2 text-{{ raid.variation.color }}">
|
||||
{{ raid.variation.percent | number : '1.2-2' }}%
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="border-top border-light pt-2">
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button (click)="stepper.reset()">Reset</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
<ng-template matStepperIcon="timeline">
|
||||
<mat-icon>timeline</mat-icon>
|
||||
</ng-template>
|
||||
<ng-template matStepperIcon="search">
|
||||
<mat-icon>manage_search</mat-icon>
|
||||
</ng-template>
|
||||
</mat-stepper>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
+1
@@ -0,0 +1 @@
|
||||
/* guildraids-log */
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildraidsLogComponent } from './guildraids-log.component';
|
||||
|
||||
describe('GuildraidsLogComponent', () => {
|
||||
let component: GuildraidsLogComponent;
|
||||
let fixture: ComponentFixture<GuildraidsLogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildraidsLogComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildraidsLogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
import { Component, Injectable, inject, Input, OnInit } from '@angular/core';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatStepperIntl, MatStepperModule } from '@angular/material/stepper';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
import { HWGuildRaid, HWGuildRaidAttacker, HWGuildRaidAttackers, HWGuildRaidStage, HWMember } from 'src/app/core/models';
|
||||
|
||||
import guildRaids from 'src/files-data/hw-guild-raids.json'; // page Asgard -> Guild Raid -> Log
|
||||
|
||||
@Injectable()
|
||||
export class StepperIntl extends MatStepperIntl {
|
||||
// the default optional label text, if unspecified is "Optional"
|
||||
override optionalLabel = 'Optional Label';
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-guildraids-log',
|
||||
standalone: true,
|
||||
providers: [
|
||||
{
|
||||
provide: STEPPER_GLOBAL_OPTIONS,
|
||||
useValue: {displayDefaultIndicatorType: false},
|
||||
},
|
||||
],
|
||||
imports: [
|
||||
DatePipe, DecimalPipe, FormsModule, ReactiveFormsModule,
|
||||
MatButtonModule, MatCardModule, MatDatepickerModule, MatDividerModule,
|
||||
MatFormFieldModule, MatIconModule, MatInputModule, MatTooltipModule,
|
||||
MatStepperModule
|
||||
],
|
||||
templateUrl: './guildraids-log.component.html',
|
||||
styleUrl: './guildraids-log.component.scss'
|
||||
})
|
||||
export class GuildraidsLogComponent implements OnInit {
|
||||
public now: Date;
|
||||
public raidsForm: FormGroup;
|
||||
public guildMembers: HWMember[] = [];
|
||||
public title = 'Guild Raids';
|
||||
public subtitle = 'Log';
|
||||
public minVarPct = 3;
|
||||
private _matStepperIntl = inject(MatStepperIntl);
|
||||
private _guildRaids: HWGuildRaid[] = [];
|
||||
private _raidStages: HWGuildRaidStage[] = [
|
||||
{num: 1, name: 'Stage 1', maxPower: 350000, duration: 8, startTime: 0, endTime: 0},
|
||||
{num: 2, name: 'Stage 2', maxPower: 550000, duration: 8, startTime: 0, endTime: 0},
|
||||
{num: 3, name: 'Stage 3', maxPower: 0, duration: 0, startTime: 0, endTime: 0}
|
||||
];
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder
|
||||
) {
|
||||
this.now = new Date();
|
||||
const raidsDate = new Date();
|
||||
const startHour = 4;
|
||||
raidsDate.setHours(startHour, 0, 0, 0);
|
||||
const controlsConfig = {
|
||||
num: 1,
|
||||
name: 'Stage 1',
|
||||
maxPower: 350,
|
||||
duration: 8,
|
||||
startTime: [raidsDate.getTime(), Validators.required],
|
||||
endTime: 0
|
||||
};
|
||||
this.raidsForm = this.fb.group(controlsConfig);
|
||||
}
|
||||
|
||||
_setStagesTime(startTime: number): void {
|
||||
const raidsDate = new Date(startTime);
|
||||
const startHour = 4;
|
||||
raidsDate.setHours(startHour, 0, 0, 0);
|
||||
this._raidStages[0].startTime = raidsDate.getTime();
|
||||
|
||||
raidsDate.setHours((startHour + this._raidStages[0].duration), 0, 0, 0);
|
||||
this._raidStages[0].endTime = raidsDate.getTime();
|
||||
this._raidStages[1].startTime = raidsDate.getTime();
|
||||
|
||||
raidsDate.setHours((startHour + this._raidStages[0].duration + this._raidStages[1].duration), 0, 0, 0);
|
||||
this._raidStages[1].endTime = raidsDate.getTime();
|
||||
this._raidStages[2].startTime = raidsDate.getTime();
|
||||
|
||||
raidsDate.setHours(startHour, 0, 0, 0);
|
||||
raidsDate.setDate(raidsDate.getDate() + 4);
|
||||
this._raidStages[2].endTime = raidsDate.getTime();
|
||||
this._matStepperIntl.optionalLabel = this._raidStages[1].duration.toString() + 'h';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.guildMembers.map((data) => {
|
||||
data.raids = [];
|
||||
data.raidsInfo = {
|
||||
variationAvg: 0,
|
||||
variationSum: 0
|
||||
};
|
||||
return data;
|
||||
});
|
||||
|
||||
for (const member of Object.entries(guildRaids)) {
|
||||
const index = this.guildMembers.findIndex(item => item.id === member[0]);
|
||||
const memberRaids: HWGuildRaid[] = [];
|
||||
if (index !== -1) {
|
||||
for (const data of Object.entries(member[1])) {
|
||||
const raid: HWGuildRaid = {} as HWGuildRaid;
|
||||
Object.assign(raid, data[1]);
|
||||
const startTime: number = (parseInt(raid.startTime) * 1000);
|
||||
if (this._guildRaids.length === 0) {
|
||||
this._setStagesTime(startTime);
|
||||
}
|
||||
const raidsDate = new Date(startTime);
|
||||
if (raidsDate.getTime() > this._raidStages[1].endTime) {
|
||||
raid.stage = this._raidStages[2];
|
||||
} else if (raidsDate.getTime() > this._raidStages[0].endTime) {
|
||||
raid.stage = this._raidStages[1];
|
||||
} else {
|
||||
raid.stage = this._raidStages[0];
|
||||
}
|
||||
|
||||
raid.damage = data[1].result.damage;
|
||||
raid.level = data[1].result.level;
|
||||
raid.userName = this.guildMembers[index].name;
|
||||
|
||||
const attackers: HWGuildRaidAttackers = {} as HWGuildRaidAttackers;
|
||||
Object.assign(attackers, data[1].attackers);
|
||||
//Object.assign(raid.attackers, data[1].attackers);
|
||||
raid.attackers = [];
|
||||
raid.power = 0;
|
||||
for (const item of Object.entries(attackers)) {
|
||||
const attacker: HWGuildRaidAttacker = {
|
||||
id: item[1].id,
|
||||
power: item[1].power,
|
||||
type: item[1].type
|
||||
} as HWGuildRaidAttacker;
|
||||
raid.power += attacker.power;
|
||||
raid.attackers.push(attacker);
|
||||
}
|
||||
let percent = 0;
|
||||
if (raid.stage.maxPower > 0) {
|
||||
percent = (((raid.power / raid.stage.maxPower) - 1) * 100);
|
||||
}
|
||||
let color = 'default';
|
||||
let value = 0;
|
||||
if (raid.stage.maxPower > 0) {
|
||||
if (percent > 15) {
|
||||
color = 'raspberry';
|
||||
} else if (percent > 10) {
|
||||
color = 'red';
|
||||
} else if (percent > 5) {
|
||||
color = 'orange';
|
||||
}
|
||||
value = (raid.power - raid.stage.maxPower)
|
||||
}
|
||||
raid.variation = {
|
||||
value: value,
|
||||
percent: percent,
|
||||
color: color
|
||||
};
|
||||
raid.tooltip = Math.floor(raid.variation.value / 1000) + 'k';
|
||||
//console.log(raid.attackers);
|
||||
|
||||
memberRaids.push(raid);
|
||||
this._guildRaids.push(raid);
|
||||
}
|
||||
this.guildMembers[index].raids = memberRaids;
|
||||
const varSum = memberRaids.reduce((accumulator, currentValue) => accumulator + currentValue.variation.percent, 0);
|
||||
this.guildMembers[index].raidsInfo = {
|
||||
variationAvg: (varSum / memberRaids.length),
|
||||
variationSum: varSum
|
||||
};
|
||||
}
|
||||
}
|
||||
this._guildRaids.sort((a, b) => (a.startTime < b.startTime ? -1 : 1)).map((data) => {
|
||||
return data;
|
||||
});
|
||||
this.guildMembers.sort((a, b) => (a.raidsInfo.variationAvg > b.raidsInfo.variationAvg ? -1 : 1));/*.map((data) => {
|
||||
console.log(data.name, data.raidsInfo.variationAvg, data.raids.length);
|
||||
return data;
|
||||
});*/
|
||||
}
|
||||
|
||||
public getMembers(): HWMember[] {
|
||||
//return this.guildMembers;
|
||||
return this.minVarPct ? this.guildMembers.filter(member => (member.raidsInfo.variationAvg >= this.minVarPct) === true) : this.guildMembers;
|
||||
}
|
||||
|
||||
public getRaidsLog(stageNum: number): HWGuildRaid[] {
|
||||
return this._guildRaids.filter(raid => (raid.stage.num === stageNum) === true);
|
||||
}
|
||||
|
||||
public getStagesTime(stageNum: number): HWGuildRaidStage {
|
||||
return this._raidStages[stageNum];
|
||||
}
|
||||
|
||||
public onDateChange(): void {
|
||||
const timestamp: number = Date.parse(this.raidsForm.controls['startTime'].value);
|
||||
if (isNaN(timestamp) == false) {
|
||||
this._setStagesTime(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
submitForm(): void {
|
||||
}
|
||||
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="text-bg-warn d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
Guild War Day {{ warInfo.day }} VS {{ warInfo.clanEnemyName }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light"> {{ warInfo.endTime | date: 'dd/MM/yyyy HH:mm:ss' }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<mat-divider class="mb-3"></mat-divider>
|
||||
<div class="d-flex align-items-center ps-2 mb-3">
|
||||
<dl class="dl-horizontal dl-large mt-3 mb-0">
|
||||
<dt>Server End Time</dt>
|
||||
<dd class="font-monospace">{{ warInfo.endTime | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
<dt>Next War Time</dt>
|
||||
<dd class="font-monospace">{{ warInfo.nextWarTime| date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
<dt>Next Lock Time</dt>
|
||||
<dd class="font-monospace">{{ warInfo.nextLockTime | date: 'dd/MM/yyyy HH:mm:ss' }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="text-bg-danger d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ warInfo.clanEnemyName }} Members
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }} {{ warInfo.endTime | date: 'dd/MM/yyyy HH:mm:ss' }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="p-0">
|
||||
<table class="table table-striped table-condensed border-top border-light">
|
||||
<thead>
|
||||
<tr role="row" class="text-bg-danger bg-opacity-50">
|
||||
<th class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center text-start">
|
||||
Name
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Last Login
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Heroes
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Titans
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (enemy of getEnemies(); track enemy; let index = $index) {
|
||||
<tr role="row" class="align-middle{{ enemy.champion ? '' : ' text-muted' }}">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
<div class="d-flex{{ enemy.champion ? ' text-green' : '' }}">
|
||||
<mat-icon [fontIcon]="enemy.champion ? 'gpp_good' : 'gpp_bad'" class="me-2 icon-small"></mat-icon>
|
||||
{{ enemy.name }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span class="me-3">{{ enemy.lastLoginTime + '000' | date: 'dd/MM HH:mm' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ enemy.heroes.power | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ enemy.titans.power | number : '1.0' }}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<div class="row g-0">
|
||||
<div class="col col-md-6 pe-md-2">
|
||||
<mat-card>
|
||||
<mat-card-header class="bg-accent text-navy d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ warInfo.clanEnemyName }} Heroes {{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="pt-3">
|
||||
<app-fortification-card-content type="heroes" [fortification]="getLighthouse()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<app-fortification-card-content type="heroes" [fortification]="getBarracks()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<app-fortification-card-content type="heroes" [fortification]="getMageAcademy()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content type="heroes" [fortification]="getFoundry()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content type="heroes" [fortification]="getCitadel()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="col col-md-6 ps-md-2">
|
||||
<mat-card>
|
||||
<mat-card-header class="bg-accent text-navy d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ warInfo.clanEnemyName }} Titans {{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="pt-3">
|
||||
<app-fortification-card-content type="titans" [fortification]="getBridge()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content type="titans" [fortification]="getGatesOfNature()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<app-fortification-card-content type="titans" [fortification]="getBastionOfFire()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<app-fortification-card-content type="titans" [fortification]="getBastionOfIce()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content type="titans" [fortification]="getSpringOfElements()" [members]="guildEnemies"></app-fortification-card-content>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildwarAttackComponent } from './guildwar-attack.component';
|
||||
|
||||
describe('GuildwarAttackComponent', () => {
|
||||
let component: GuildwarAttackComponent;
|
||||
let fixture: ComponentFixture<GuildwarAttackComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildwarAttackComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildwarAttackComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { FortificationCardContentComponent } from 'src/app/components/shared';
|
||||
import {
|
||||
HWGuildWarEnemySlot, HWGuildWarEnemyTeam, HWGuildWarFortification,
|
||||
HWGuildWarHeroTeam, HWGuildWarTitanTeam, HWGuildWarSlots, HWMember
|
||||
} from 'src/app/core/models';
|
||||
|
||||
/* JSON data */
|
||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
||||
import guildWarInfo from 'src/files-data/hw-guild-war-info.json'; // page Guild War -> Guild War
|
||||
//import guildWarLog from 'src/files-data/hw-guild-war-log.json'; // page Guild War -> Guild War
|
||||
import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
||||
|
||||
@Component({
|
||||
selector: 'app-guildwar-attack',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe, DecimalPipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule,
|
||||
FortificationCardContentComponent
|
||||
],
|
||||
templateUrl: './guildwar-attack.component.html',
|
||||
styleUrl: './guildwar-attack.component.scss'
|
||||
})
|
||||
export class GuildwarAttackComponent implements OnInit {
|
||||
private _championsByPower: HWMember[] = [];
|
||||
private _enemySlots: number[] = [];
|
||||
public guildEnemies: HWMember[] = [];
|
||||
public guildMembers: HWMember[] = [];
|
||||
public title = 'Fortifications';
|
||||
public subtitle = 'Guild War Attack';
|
||||
public now = new Date();
|
||||
public warInfo: { day: number, clanEnemyName: string, endTime: number, nextWarTime: number, nextLockTime: number } = {
|
||||
day: 0,
|
||||
clanEnemyName: '',
|
||||
endTime: 0,
|
||||
nextWarTime: 0,
|
||||
nextLockTime: 0
|
||||
};
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.warInfo.day = parseInt(guildWarInfo.day);
|
||||
this.warInfo.clanEnemyName = guildWarInfo.enemyClan.title;
|
||||
this.warInfo.endTime = (guildWarInfo.endTime * 1000);
|
||||
this.warInfo.nextWarTime = (guildWarInfo.nextWarTime * 1000);
|
||||
this.warInfo.nextLockTime = (guildWarInfo.nextLockTime * 1000);
|
||||
this._setChampionsByPower();
|
||||
this._setEnemies();
|
||||
}
|
||||
|
||||
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
||||
const teams: HWMember[] = [];
|
||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
||||
let count = 0;
|
||||
indexes.forEach((data) => {
|
||||
switch (type) {
|
||||
case 'heroes':
|
||||
teams.push(this.guildEnemies[data]);
|
||||
count += this.guildEnemies[data].heroes.power;
|
||||
break;
|
||||
case 'titans':
|
||||
teams.push(this.guildEnemies[data]);
|
||||
count += this.guildEnemies[data].titans.power;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
count: count,
|
||||
teams: teams,
|
||||
positions: this._enemySlots,
|
||||
slots: slots[name]
|
||||
};
|
||||
}
|
||||
|
||||
private _getDefense(type: string, name: string): HWGuildWarFortification {
|
||||
const teams: HWMember[] = [];
|
||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
||||
let count = 0;
|
||||
slots[name].forEach(slot => {
|
||||
let enemies: HWMember[] = [];
|
||||
let team: HWMember = {} as HWMember;
|
||||
enemies = this.guildEnemies.filter(enemy => parseInt(enemy.id) === this._enemySlots[slot]);
|
||||
if (enemies.length) {
|
||||
team = enemies[0];
|
||||
teams.push(team);
|
||||
switch (type) {
|
||||
case 'heroes':
|
||||
count += team.heroes.power;
|
||||
break;
|
||||
case 'titans':
|
||||
count += team.titans.power;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
count: count,
|
||||
teams: teams,
|
||||
positions: this._enemySlots,
|
||||
slots: slots[name]
|
||||
};
|
||||
}
|
||||
|
||||
private _setEnemies(): void {
|
||||
const warriors: number[] = [];
|
||||
for (const data of Object.entries(guildWarInfo.enemyClanTries)) {
|
||||
warriors.push(parseInt(data[0]));
|
||||
}
|
||||
for (const data of Object.entries(guildWarInfo.enemyClanMembers)) {
|
||||
const enemy: HWMember = {} as HWMember;
|
||||
Object.assign(enemy, data[1]);
|
||||
if (warriors.indexOf(parseInt(enemy.id)) !== -1) {
|
||||
enemy.champion = true;
|
||||
} else {
|
||||
enemy.champion = false;
|
||||
}
|
||||
enemy.heroes = { power: 0, teams: []};
|
||||
enemy.titans = { power: 0, teams: []};
|
||||
|
||||
//console.log(guildWarInfo.enemySlots);
|
||||
|
||||
this.guildEnemies.push(enemy);
|
||||
}
|
||||
|
||||
for (const data of Object.entries(guildWarInfo.enemySlots)) {
|
||||
const ennemySlot: HWGuildWarEnemySlot = {} as HWGuildWarEnemySlot;
|
||||
Object.assign(ennemySlot, data[1]);
|
||||
//console.log(ennemySlot.slotId, ennemySlot.user.name, ennemySlot.user.id); //, ennemySlot.team["1"].power);
|
||||
ennemySlot.teams = [];
|
||||
let totalHeroPower = 0;
|
||||
let totalTitanPower = 0;
|
||||
if (ennemySlot.user !== null) {
|
||||
this._enemySlots[ennemySlot.slotId] = parseInt(ennemySlot.user.id);
|
||||
for (const team of Object.entries(data[1].team[0])) {
|
||||
/*
|
||||
ennemySlot.teams.push(enemyTeam);
|
||||
console.log(enemyTeam);
|
||||
*/
|
||||
const enemyTeam: HWGuildWarEnemyTeam = {} as HWGuildWarEnemyTeam;
|
||||
Object.assign(enemyTeam, team[1]);
|
||||
switch (enemyTeam.type) {
|
||||
case 'hero':
|
||||
case 'pet':
|
||||
totalHeroPower += enemyTeam.power;
|
||||
break;
|
||||
case 'titan':
|
||||
totalTitanPower += enemyTeam.power;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ennemySlot.teams.push(team[1]);
|
||||
//console.log(team[1]);
|
||||
}
|
||||
//console.log(totalHeroPower, totalTitanPower, ennemySlot.teams);
|
||||
|
||||
this.guildEnemies.some((item) => {
|
||||
if (item.id === ennemySlot.user.id) {
|
||||
if (totalHeroPower) {
|
||||
item.heroes.power = totalHeroPower;
|
||||
item.heroes.teams = ennemySlot.teams;
|
||||
}
|
||||
if (totalTitanPower) {
|
||||
item.titans.power = totalTitanPower;
|
||||
item.titans.teams = ennemySlot.teams;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.guildEnemies.sort((a, b) => ((a.heroes.power + a.titans.power) > (b.heroes.power + b.titans.power) ? -1 : 1)); // Descending
|
||||
}
|
||||
}
|
||||
|
||||
private _setChampionsByPower(): void {
|
||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
||||
const index = this.guildMembers.findIndex(member => member.id === teamId);
|
||||
let totalHeroPower = 0;
|
||||
let totalTitanPower = 0;
|
||||
const heroes: HWGuildWarHeroTeam[] = [];
|
||||
const titans: HWGuildWarTitanTeam[] = [];
|
||||
|
||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
||||
heroes.push(unit[1]);
|
||||
totalHeroPower += unit[1].power;
|
||||
}
|
||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
||||
titans.push(unit[1]);
|
||||
totalTitanPower += unit[1].power;
|
||||
}
|
||||
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
||||
}
|
||||
this.guildMembers.sort((a, b) => ((a.heroes.power + a.titans.power) > (b.heroes.power + b.titans.power) ? -1 : 1)); // Descending
|
||||
this._championsByPower = this.guildMembers.filter(member => member.champion === true);
|
||||
}
|
||||
|
||||
getEnemies(): HWMember[] {
|
||||
return this.guildEnemies;
|
||||
}
|
||||
|
||||
getMembers(): HWMember[] {
|
||||
return this.guildMembers;
|
||||
}
|
||||
|
||||
getLighthouse(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [0, 4, 8];
|
||||
//return this._getFortification(indexes, 'heroes', 'Lighthouse');
|
||||
return this._getDefense('heroes', 'Lighthouse');
|
||||
}
|
||||
|
||||
getBarracks(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [1, 5, 6];
|
||||
//return this._getFortification(indexes, 'heroes', 'Barracks');
|
||||
return this._getDefense('heroes', 'Barracks');
|
||||
}
|
||||
|
||||
getMageAcademy(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [2, 3, 7];
|
||||
//return this._getFortification(indexes, 'heroes', 'Mage Academy');
|
||||
return this._getDefense('heroes', 'Mage Academy');
|
||||
}
|
||||
|
||||
getFoundry(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [9, 11, 12, 13];
|
||||
//return this._getFortification(indexes, 'heroes', 'Foundry');
|
||||
return this._getDefense('heroes', 'Foundry');
|
||||
}
|
||||
|
||||
getCitadel(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [10, 14, 15, 16, 17, 18, 19];
|
||||
//return this._getFortification(indexes, 'heroes', 'Citadel');
|
||||
return this._getDefense('heroes', 'Citadel');
|
||||
}
|
||||
|
||||
getBridge(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [0, 1, 2, 3];
|
||||
//return this._getFortification(indexes, 'titans', 'Bridge');
|
||||
return this._getDefense('titans', 'Bridge');
|
||||
}
|
||||
|
||||
getGatesOfNature(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [4, 9, 14, 19];
|
||||
//return this._getFortification(indexes, 'titans', 'Gates Of Nature');
|
||||
return this._getDefense('titans', 'Gates Of Nature');
|
||||
}
|
||||
|
||||
getBastionOfFire(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [5, 10, 15, 16];
|
||||
//return this._getFortification(indexes, 'titans', 'Bastion Of Fire');
|
||||
return this._getDefense('titans', 'Bastion Of Fire');
|
||||
}
|
||||
|
||||
getBastionOfIce(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [6, 11, 12, 17];
|
||||
//return this._getFortification(indexes, 'titans', 'Bastion Of Ice');
|
||||
return this._getDefense('titans', 'Bastion Of Ice');
|
||||
}
|
||||
|
||||
getSpringOfElements(): HWGuildWarFortification {
|
||||
//const indexes: number[] = [7, 8, 13, 18];
|
||||
//return this._getFortification(indexes, 'titans', 'Spring Of Elements');
|
||||
return this._getDefense('titans', 'Spring Of Elements');
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="bg-{{color}}-light text-bg-primary d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="p-0">
|
||||
<table class="table table-striped table-condensed border-top border-light">
|
||||
<thead>
|
||||
<tr role="row" class="bg-{{color}}-light text-bg-primary bg-opacity-50">
|
||||
<th class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Name
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto pe-4">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Power
|
||||
<mat-icon fontIcon="arrow_downward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (champion of getChampionsByPower(); track champion; let index = $index) {
|
||||
<tr role="row" class="align-middle">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
{{ champion.name }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
@if (teamType === 'heroes') {
|
||||
{{ champion.heroes.power | number : '1.0' }}
|
||||
}
|
||||
@else {
|
||||
{{ champion.titans.power | number : '1.0' }}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
+1
@@ -0,0 +1 @@
|
||||
/* guildwar-champions */
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildwarChampionsComponent } from './guildwar-champions.component';
|
||||
|
||||
describe('GuildwarChampionsComponent', () => {
|
||||
let component: GuildwarChampionsComponent;
|
||||
let fixture: ComponentFixture<GuildwarChampionsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildwarChampionsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildwarChampionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { HWMember } from 'src/app/core/models';
|
||||
//import { HWGuildWarFortification, HWMember } from 'src/app/core/models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-guildwar-champions',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DecimalPipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule
|
||||
],
|
||||
templateUrl: './guildwar-champions.component.html',
|
||||
styleUrl: './guildwar-champions.component.scss'
|
||||
})
|
||||
export class GuildwarChampionsComponent implements OnInit {
|
||||
private _championsByPower: HWMember[] = [];
|
||||
public guildMembers: HWMember[] = [];
|
||||
public color: string = 'primary';
|
||||
public teamType: string = '';
|
||||
public title = 'Champions';
|
||||
public subtitle = 'by power';
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
@Input() set type(value: string) {
|
||||
this.teamType = value;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
switch (this.teamType) {
|
||||
case 'heroes':
|
||||
this.color = 'navy';
|
||||
this.subtitle = 'heroes power';
|
||||
this.guildMembers.sort((a, b) => (a.heroes.power > b.heroes.power ? -1 : 1)); // Descending
|
||||
this._championsByPower = this.guildMembers.filter(member => member.champion === true);
|
||||
break;
|
||||
case 'titans':
|
||||
this.color = 'purple';
|
||||
this.subtitle = 'titans power';
|
||||
this.guildMembers.sort((a, b) => (a.titans.power > b.titans.power ? -1 : 1)); // Descending
|
||||
this._championsByPower = this.guildMembers.filter(member => member.champion === true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
getChampionsByPower(): HWMember[] {
|
||||
return this._championsByPower;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="bg-accent text-navy d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="pt-3">
|
||||
@if (teamType === 'heroes') {
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getLighthouse()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getBarracks()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getMageAcademy()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getFoundry()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getCitadel()" [members]="guildMembers"></app-fortification-card-content>
|
||||
}
|
||||
@else {
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getBridge()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getGatesOfNature()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getBastionOfFire()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getBastionOfIce()" [members]="guildMembers"></app-fortification-card-content>
|
||||
<mat-divider class="my-3"></mat-divider>
|
||||
<app-fortification-card-content [type]="teamType" [fortification]="getSpringOfElements()" [members]="guildMembers"></app-fortification-card-content>
|
||||
}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<div class="d-flex align-items-center ps-2 mb-3">
|
||||
<mat-icon fontIcon="fiber_manual_record" class="me-2 icon-small text-red"></mat-icon> <span class="d-inline-block">Position to check</span>
|
||||
</div>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildwarDefenceComponent } from './guildwar-defence.component';
|
||||
|
||||
describe('GuildwarDefenceComponent', () => {
|
||||
let component: GuildwarDefenceComponent;
|
||||
let fixture: ComponentFixture<GuildwarDefenceComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildwarDefenceComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildwarDefenceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
//import { DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { FortificationCardContentComponent } from 'src/app/components/shared';
|
||||
//import { HWMember } from 'src/app/core/models';
|
||||
import { HWGuildWarFortification, HWGuildWarHeroTeam, HWGuildWarSlots, HWGuildWarTitanTeam, HWMember } from 'src/app/core/models';
|
||||
|
||||
/* JSON data */
|
||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
||||
import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
||||
|
||||
@Component({
|
||||
selector: 'app-guildwar-defence',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatCardModule, MatDividerModule, MatIconModule,
|
||||
FortificationCardContentComponent
|
||||
],
|
||||
templateUrl: './guildwar-defence.component.html',
|
||||
styleUrl: './guildwar-defence.component.scss'
|
||||
})
|
||||
export class GuildwarDefenceComponent implements OnInit {
|
||||
private _championsByPower: HWMember[] = [];
|
||||
private _championSlots: number[] = [];
|
||||
public guildMembers: HWMember[] = [];
|
||||
public teamType: string = '';
|
||||
public title = 'Fortifications';
|
||||
public subtitle = 'Guild War Defence';
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
@Input() set type(value: string) {
|
||||
this.teamType = value;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
||||
const index = this.guildMembers.findIndex(member => member.id === teamId);
|
||||
let totalHeroPower = 0;
|
||||
let totalTitanPower = 0;
|
||||
const heroes: HWGuildWarHeroTeam[] = [];
|
||||
const titans: HWGuildWarTitanTeam[] = [];
|
||||
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
||||
|
||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
||||
heroes.push(unit[1]);
|
||||
totalHeroPower += unit[1].power;
|
||||
}
|
||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
||||
titans.push(unit[1]);
|
||||
totalTitanPower += unit[1].power;
|
||||
}
|
||||
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
||||
}
|
||||
for (const data of Object.entries(guildWarData.slots)) {
|
||||
this._championSlots[parseInt(data[0])] = data[1];
|
||||
}
|
||||
switch (this.teamType) {
|
||||
case 'heroes':
|
||||
this.title = 'Heroes Fortifications';
|
||||
this.guildMembers.sort((a, b) => (a.heroes.power > b.heroes.power ? -1 : 1)); // Descending
|
||||
break;
|
||||
case 'titans':
|
||||
this.title = 'Titans Fortifications';
|
||||
this.guildMembers.sort((a, b) => (a.titans.power > b.titans.power ? -1 : 1)); // Descending
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this._championsByPower = this.guildMembers.filter(member => member.champion === true);
|
||||
}
|
||||
|
||||
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
||||
const teams: HWMember[] = [];
|
||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
||||
let count = 0;
|
||||
indexes.forEach((data) => {
|
||||
switch (type) {
|
||||
case 'heroes':
|
||||
//console.log(name, data, this._championsByPower[data]);
|
||||
teams.push(this._championsByPower[data]);
|
||||
count += this._championsByPower[data].heroes.power;
|
||||
break;
|
||||
case 'titans':
|
||||
teams.push(this._championsByPower[data]);
|
||||
count += this._championsByPower[data].titans.power;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
count: count,
|
||||
teams: teams,
|
||||
positions: this._championSlots,
|
||||
slots: slots[name]
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------
|
||||
0 - 3 - 6
|
||||
1 - 4 - 7
|
||||
2 - 5 - 8
|
||||
--------------------------------
|
||||
9 - 10 - 11 - 12
|
||||
--------------------------------
|
||||
13 - 14 - 15 - 16 - 17 - 18 - 19
|
||||
--------------------------------
|
||||
Mage Academy 1-2-31
|
||||
Lighthouse 3-4-32
|
||||
Barracks 5-6-33
|
||||
Foundry 13-14-15-36
|
||||
Citadel 25-26-28-28-29-30-40
|
||||
*/
|
||||
|
||||
getLighthouse(): HWGuildWarFortification {
|
||||
const indexes: number[] = [0, 4, 8];
|
||||
return this._getFortification(indexes, 'heroes', 'Lighthouse');
|
||||
}
|
||||
|
||||
getBarracks(): HWGuildWarFortification {
|
||||
const indexes: number[] = [1, 5, 6];
|
||||
return this._getFortification(indexes, 'heroes', 'Barracks');
|
||||
}
|
||||
|
||||
getMageAcademy(): HWGuildWarFortification {
|
||||
const indexes: number[] = [2, 3, 7];
|
||||
return this._getFortification(indexes, 'heroes', 'Mage Academy');
|
||||
}
|
||||
|
||||
getFoundry(): HWGuildWarFortification {
|
||||
const indexes: number[] = [9, 11, 12, 13];
|
||||
return this._getFortification(indexes, 'heroes', 'Foundry');
|
||||
}
|
||||
|
||||
getCitadel(): HWGuildWarFortification {
|
||||
const indexes: number[] = [10, 14, 15, 16, 17, 18, 19];
|
||||
return this._getFortification(indexes, 'heroes', 'Citadel');
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------
|
||||
0 - 1 - 2 - 3
|
||||
--------------------------------
|
||||
4 - 8 - 12 - 16
|
||||
5 - 9 - 13 - 17
|
||||
6 - 10 - 14 - 18
|
||||
7 - 11 - 15 - 19
|
||||
--------------------------------
|
||||
Bridge 7-8-9-34
|
||||
Spring of Elements 10-11-12-35
|
||||
Gates of Nature 16-17-18-37
|
||||
Bastion of Fire 19-20-21-38
|
||||
Bastion of Ice 22-23-24-39
|
||||
*/
|
||||
|
||||
getBridge(): HWGuildWarFortification {
|
||||
const indexes: number[] = [0, 1, 2, 3];
|
||||
return this._getFortification(indexes, 'titans', 'Bridge');
|
||||
}
|
||||
|
||||
getGatesOfNature(): HWGuildWarFortification {
|
||||
const indexes: number[] = [4, 9, 14, 19];
|
||||
return this._getFortification(indexes, 'titans', 'Gates Of Nature');
|
||||
}
|
||||
|
||||
getBastionOfFire(): HWGuildWarFortification {
|
||||
const indexes: number[] = [5, 10, 15, 16];
|
||||
return this._getFortification(indexes, 'titans', 'Bastion Of Fire');
|
||||
}
|
||||
|
||||
getBastionOfIce(): HWGuildWarFortification {
|
||||
const indexes: number[] = [6, 11, 12, 17];
|
||||
return this._getFortification(indexes, 'titans', 'Bastion Of Ice');
|
||||
}
|
||||
|
||||
getSpringOfElements(): HWGuildWarFortification {
|
||||
const indexes: number[] = [7, 8, 13, 18];
|
||||
return this._getFortification(indexes, 'titans', 'Spring Of Elements');
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="text-bg-teal d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="p-0">
|
||||
<table class="table table-striped table-condensed border-top border-light">
|
||||
<thead>
|
||||
<tr role="row" class="text-bg-teal bg-opacity-50">
|
||||
<th class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Name
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center justify-content-end">
|
||||
Avg
|
||||
<mat-icon fontIcon="arrow_downward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Heroes
|
||||
</div>
|
||||
</th>
|
||||
<th class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Titans
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (member of getChampionsByPower(); track member; let index = $index) {
|
||||
<tr role="row" class="align-middle">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
<div class="d-flex {{ member.champion ? 'text-green' : 'text-red' }}">
|
||||
<mat-icon [fontIcon]="member.champion ? 'gpp_good' : 'gpp_bad'" class="me-2 icon-small"></mat-icon>
|
||||
{{ member.name }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ ((member.heroes.power + member.titans.power) / 2) | number : '1.0-0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span [class]="member.heroes.power < guildAverageHeroesPower ? 'text-orange' : 'text-megna'">{{ member.heroes.power | number : '1.0' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span [class]="member.titans.power < guildAverageTitansPower ? 'text-orange' : 'text-megna'">{{ member.titans.power | number : '1.0' }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr role="row" class="bg-light fw-medium align-middle">
|
||||
<td colspan="3" class="cell text-end fw-medium pe-sm-2">
|
||||
Totals
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildTotalHeroesPower | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildTotalTitansPower | number : '1.0' }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr role="row" class="bg-teal text-bg-primary fw-medium align-middle">
|
||||
<td colspan="3" class="cell text-end pe-sm-2">
|
||||
Averages
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildAverageHeroesPower | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildAverageTitansPower | number : '1.0' }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<div class="d-flex align-items-center ps-2 mb-3">
|
||||
<mat-icon fontIcon="gpp_good" class="me-2 icon-small text-megna"></mat-icon> <span class="d-inline-block">Champion signet</span>
|
||||
<mat-icon fontIcon="gpp_bad" class="ms-3 me-2 icon-small text-red"></mat-icon> <span class="d-inline-block">No Champion signet</span>
|
||||
<mat-icon fontIcon="fiber_manual_record" class="ms-3 me-2 icon-small text-orange"></mat-icon> <span class="d-inline-block">Below average</span>
|
||||
<mat-icon fontIcon="fiber_manual_record" class="ms-3 me-2 icon-small text-megna"></mat-icon> <span class="d-inline-block">Above average</span>
|
||||
</div>
|
||||
+1
@@ -0,0 +1 @@
|
||||
/* guildwar-teams */
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuildwarTeamsComponent } from './guildwar-teams.component';
|
||||
|
||||
describe('GuildwarTeamsComponent', () => {
|
||||
let component: GuildwarTeamsComponent;
|
||||
let fixture: ComponentFixture<GuildwarTeamsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GuildwarTeamsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GuildwarTeamsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { HWGuildWarHeroTeam, HWGuildWarTitanTeam, HWMember } from 'src/app/core/models';
|
||||
|
||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
||||
|
||||
@Component({
|
||||
selector: 'app-guildwar-teams',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DecimalPipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule
|
||||
],
|
||||
templateUrl: './guildwar-teams.component.html',
|
||||
styleUrl: './guildwar-teams.component.scss'
|
||||
})
|
||||
export class GuildwarTeamsComponent implements OnInit {
|
||||
private _championsByPower: HWMember[] = [];
|
||||
public guildMembers: HWMember[] = [];
|
||||
public title = 'Members';
|
||||
public subtitle = 'guild war teams power';
|
||||
public guildAverageHeroesPower: number = 0;
|
||||
public guildAverageTitansPower: number = 0;
|
||||
public guildTotalHeroesPower: number = 0;
|
||||
public guildTotalTitansPower: number = 0;
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this.guildMembers.sort((a, b) => (((a.heroes.power + a.titans.power) / 2) > ((b.heroes.power + b.titans.power) / 2) ? -1 : 1))
|
||||
.map((data) => {
|
||||
/*
|
||||
this.guildTotalHeroesPower += data.heroes.power;
|
||||
this.guildTotalTitansPower += data.titans.power;
|
||||
this.guildAverageHeroesPower = Math.floor((this.guildTotalHeroesPower / this.guildMembers.length));
|
||||
this.guildAverageTitansPower = Math.floor((this.guildTotalTitansPower / this.guildMembers.length));
|
||||
*/
|
||||
this._championsByPower.push(data);
|
||||
return data;
|
||||
});
|
||||
|
||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
||||
const index = this._championsByPower.findIndex(member => member.id === teamId);
|
||||
let totalHeroPower = 0;
|
||||
let totalTitanPower = 0;
|
||||
const heroes: HWGuildWarHeroTeam[] = [];
|
||||
const titans: HWGuildWarTitanTeam[] = [];
|
||||
|
||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
||||
heroes.push(unit[1]);
|
||||
totalHeroPower += unit[1].power;
|
||||
}
|
||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
||||
titans.push(unit[1]);
|
||||
totalTitanPower += unit[1].power;
|
||||
}
|
||||
this._championsByPower[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||
this._championsByPower[index].titans = { power: totalTitanPower, teams: titans };
|
||||
this.guildTotalHeroesPower += totalHeroPower;
|
||||
this.guildTotalTitansPower += totalTitanPower;
|
||||
this._championsByPower[index].rewards = Math.floor((this._championsByPower[index].scoreGifts + this._championsByPower[index].warGifts));
|
||||
}
|
||||
this.guildAverageHeroesPower = Math.floor((this.guildTotalHeroesPower / this._championsByPower.length));
|
||||
this.guildAverageTitansPower = Math.floor((this.guildTotalTitansPower / this._championsByPower.length));
|
||||
}
|
||||
|
||||
getChampionsByPower(): HWMember[] {
|
||||
return this._championsByPower;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from './fortification-card-content/fortification-card-content.component';
|
||||
export * from './guild-card/guild-card.component';
|
||||
export * from './guildraids-log/guildraids-log.component';
|
||||
export * from './guildwar-attack/guildwar-attack.component';
|
||||
export * from './guildwar-champions/guildwar-champions.component';
|
||||
export * from './guildwar-defence/guildwar-defence.component';
|
||||
export * from './guildwar-teams/guildwar-teams.component';
|
||||
export * from './members-statistics/members-statistics.component';
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
<mat-card class="my-3">
|
||||
<mat-card-header class="bg-megna text-bg-primary d-flex rounded-top py-2 px-3">
|
||||
<div class="flex-fill">
|
||||
<mat-card-title>
|
||||
{{ title }}
|
||||
</mat-card-title>
|
||||
</div>
|
||||
<span class="flex-spacer"></span>
|
||||
<div class="align-self-center text-end">
|
||||
<span class="fs-5 font-light">{{ subtitle }}</span>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="table-responsive p-0">
|
||||
<table class="table table-striped table-condensed border-top border-light">
|
||||
<thead>
|
||||
<tr role="row" class="bg-megna text-bg-primary bg-opacity-50">
|
||||
<th scope="col" class="align-middle w-auto ps-4">
|
||||
<div class="text-start">
|
||||
#
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="d-flex align-items-center text-start">
|
||||
Name
|
||||
<mat-icon fontIcon="arrow_upward" class="ms-1 icon-xsmall"></mat-icon>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
ID
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Last Login
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-start">
|
||||
Dismissal Delay
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Dungeon
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Activity
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Prestige
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
War Fights
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Adventures
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Score
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto">
|
||||
<div class="text-end">
|
||||
Name
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="align-middle w-auto pe-4">
|
||||
<div class="text-end">
|
||||
Rewards
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (member of getMembersByName(); track member; let index = $index) {
|
||||
<tr role="row" class="align-middle">
|
||||
<td class="cell text-start ps-4">
|
||||
{{ (index+1) }}
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
<div class="d-flex">
|
||||
<mat-icon [fontIcon]="member.champion ? 'gpp_good' : 'gpp_bad'" class="me-2 icon-small {{ member.champion ? 'text-green' : 'text-muted' }}"></mat-icon>
|
||||
<span [class]="member.champion ? 'text-green' : ''">{{ member.name }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span class="me-3">{{ member.id }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span class="me-3">{{ member.lastLoginTime + '000' | date: 'dd/MM HH:mm' }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-start">
|
||||
<span [class]="member.inactivity.daysLeft < daysToWarn ? 'text-red' : ''">{{ member.inactivity.dropDelay }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ member.stat.todayDungeonActivity | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
<span [class]="member.stat.dungeonActivitySum < guildSumAverages.titanite ? 'text-orange' : 'text-megna'">{{ member.stat.dungeonActivitySum | number : '1.0' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ member.stat.todayActivity | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
<span [class]="member.stat.activitySum < guildSumAverages.activity ? 'text-orange' : 'text-megna'">{{ member.stat.activitySum | number : '1.0' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ member.stat.todayPrestige | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
<span [class]="member.stat.prestigeSum < guildSumAverages.prestige ? 'text-orange' : 'text-megna'">{{ member.stat.prestigeSum | number : '1.0' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span [class]="!member.champion ? 'text-muted' : member.clanWarSum < guildSumAverages.war ? 'text-orange' : 'text-megna'">{{ member.clanWarSum }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span [class]="member.adventureSum < guildSumAverages.adventure ? 'text-orange' : 'text-megna'">{{ member.adventureSum }}</span>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<span [class]="member.score < guildSumAverages.score ? 'text-orange' : 'text-megna'">{{ member.score | number : '1.0' }}</span>
|
||||
</td>
|
||||
<td class="cell text-start">
|
||||
<div class="d-flex">
|
||||
<span [class]="member.champion ? 'text-green' : ''">{{ member.name }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end pe-4">
|
||||
<span [class]="member.rewards < guildSumAverages.rewards ? 'text-orange' : 'text-megna'">{{ member.rewards | number : '1.0' }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr role="row" class="bg-light fw-medium align-middle">
|
||||
<td colspan="5" class="cell text-end fw-medium pe-sm-2">
|
||||
Totals
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayTotal.titanite | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumTotal.titanite | number : '1.0' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayTotal.activity | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumTotal.activity | number : '1.0' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayTotal.prestige | number : '1.0' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumTotal.prestige | number : '1.0' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumTotal.war | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumTotal.adventure | number : '1.0' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumTotal.score | number : '1.0' }}
|
||||
</td>
|
||||
<td colspan="2" class="cell font-monospace text-end pe-4">
|
||||
{{ guildSumTotal.rewards }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr role="row" class="bg-megna text-bg-primary fw-medium align-middle">
|
||||
<td colspan="5" class="cell text-end pe-sm-2">
|
||||
Averages
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayAverages.titanite | number : '1.0-1' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumAverages.titanite | number : '1.0-1' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayAverages.activity | number : '1.0-1' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumAverages.activity | number : '1.0-1' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
<div class="hstack gap-2">
|
||||
<div class="value px-1 ms-auto">
|
||||
{{ guildTodayAverages.prestige | number : '1.0-1' }}
|
||||
</div>
|
||||
<div class="vr"></div>
|
||||
<div class="value px-1">
|
||||
{{ guildSumAverages.prestige | number : '1.0-1' }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumAverages.war | number : '1.0-1' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumAverages.adventure | number : '1.0-1' }}
|
||||
</td>
|
||||
<td class="cell font-monospace text-end">
|
||||
{{ guildSumAverages.score | number : '1.0-1' }}
|
||||
</td>
|
||||
<td colspan="2" class="cell font-monospace text-end pe-4">
|
||||
{{ guildSumAverages.rewards | number : '1.0-1' }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<div class="d-flex align-items-center ps-2 mb-3">
|
||||
<mat-icon fontIcon="gpp_good" class="me-2 icon-small text-megna"></mat-icon> <span class="d-inline-block">Champion signet</span>
|
||||
<mat-icon fontIcon="gpp_bad" class="ms-3 me-2 icon-small text-muted"></mat-icon> <span class="d-inline-block">No Champion signet</span>
|
||||
<mat-icon fontIcon="fiber_manual_record" class="ms-3 me-2 icon-small text-red"></mat-icon> <span class="d-inline-block">Inactivity > {{ daysToWarn }} days</span>
|
||||
<mat-icon fontIcon="fiber_manual_record" class="ms-3 me-2 icon-small text-orange"></mat-icon> <span class="d-inline-block">Below average</span>
|
||||
<mat-icon fontIcon="fiber_manual_record" class="ms-3 me-2 icon-small text-megna"></mat-icon> <span class="d-inline-block">Above average</span>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/* members-statistics */
|
||||
|
||||
.hstack .value {
|
||||
min-width: 56px;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MembersStatisticsComponent } from './members-statistics.component';
|
||||
|
||||
describe('MembersStatisticsComponent', () => {
|
||||
let component: MembersStatisticsComponent;
|
||||
let fixture: ComponentFixture<MembersStatisticsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MembersStatisticsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MembersStatisticsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
import { HWActivityStat, HWGuildClan, HWGuildData, HWMember, HWMemberStat, HWWeekStat } from 'src/app/core/models/herowars';
|
||||
import { UtilitiesService } from 'src/app/core/services';
|
||||
|
||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
||||
import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
||||
|
||||
@Component({
|
||||
selector: 'app-members-statistics',
|
||||
standalone: true,
|
||||
imports: [
|
||||
DatePipe, DecimalPipe,
|
||||
MatCardModule, MatDividerModule, MatIconModule
|
||||
],
|
||||
templateUrl: './members-statistics.component.html',
|
||||
styleUrl: './members-statistics.component.scss'
|
||||
})
|
||||
export class MembersStatisticsComponent implements OnInit {
|
||||
public guildMembers: HWMember[] = [];
|
||||
public title = 'Members';
|
||||
public subtitle = 'statistics';
|
||||
public daysToWarn = 1;
|
||||
public guildSumAverages: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
|
||||
public guildTodayAverages: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
|
||||
public guildSumTotal: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
|
||||
public guildTodayTotal: HWActivityStat = { activity: 0, prestige: 0, titanite: 0, war: 0, adventure: 0, gifts: 0, score: 0, scoreGifts: 0, warGifts: 0, rewards: 0 };
|
||||
public guildData: HWGuildData = {} as HWGuildData;
|
||||
private _guildClan: HWGuildClan = {} as HWGuildClan;
|
||||
private _membersByName: HWMember[] = [];
|
||||
private _deviations: { activity: number[], prestige: number[], titanite: number[] } = { activity: [], prestige: [], titanite: [] };
|
||||
|
||||
@Input() set members(value: HWMember[]) {
|
||||
this.guildMembers = value;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _utilitiesService: UtilitiesService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
const oneDayInSec = (24 * 60 * 60);
|
||||
const today = new Date();
|
||||
const daysToKick = parseInt(guildData.clan.daysToKick);
|
||||
this.daysToWarn = (parseInt(guildData.clan.daysToKick) / 2);
|
||||
this.guildMembers.sort((a, b) => (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1)).map((data) => {
|
||||
const last = new Date((parseInt(data.lastLoginTime) * 1000));
|
||||
const exp = new Date(last.getTime() + ((daysToKick * oneDayInSec) * 1000));
|
||||
const diff = Math.floor(((exp.getTime() - today.getTime()) / 1000));
|
||||
const daysLeft = Math.floor((diff / oneDayInSec));
|
||||
let timeLeft = diff;
|
||||
if (daysLeft >= 1) {
|
||||
timeLeft = (diff - (daysLeft * oneDayInSec));
|
||||
}
|
||||
data.inactivity = {
|
||||
daysLeft: daysLeft,
|
||||
timeLeft: timeLeft,
|
||||
dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
|
||||
dropDate: Math.floor((exp.getTime() / 1000))
|
||||
};
|
||||
this._membersByName.push(data);
|
||||
return data;
|
||||
});
|
||||
|
||||
Object.assign(this._guildClan, guildData.clan);
|
||||
this.guildData.clan = this._guildClan;
|
||||
this.guildData.membersStat = guildData.membersStat;
|
||||
|
||||
for (const item of Object.entries(guildStatistics.stat)) {
|
||||
const index = this._membersByName.findIndex(member => member.id === item[1].id);
|
||||
if (index !== -1) {
|
||||
this._membersByName[index].adventureSum = item[1].adventureStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
this._membersByName[index].clanGiftsSum = item[1].clanGifts.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
this._membersByName[index].clanWarSum = item[1].clanWarStat.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
|
||||
this.guildSumTotal.adventure += this._membersByName[index].adventureSum;
|
||||
this.guildSumTotal.gifts += this._membersByName[index].clanGiftsSum;
|
||||
this.guildSumTotal.war += this._membersByName[index].clanWarSum;
|
||||
const stat: HWWeekStat = {} as HWWeekStat;
|
||||
Object.assign(stat, item[1]);
|
||||
this._membersByName[index].weekStat = stat;
|
||||
} else {
|
||||
console.log(item[1].id);
|
||||
}
|
||||
}
|
||||
|
||||
for (const data of Object.entries(guildData.membersStat)) {
|
||||
const stat: HWMemberStat = {} as HWMemberStat;
|
||||
Object.assign(stat, data[1]);
|
||||
const index = this._membersByName.findIndex(member => member.id === data[1].userId);
|
||||
if (index !== -1) {
|
||||
this._membersByName[index].stat = stat;
|
||||
}
|
||||
this._membersByName[index].score = (this._membersByName[index].stat.dungeonActivitySum + this._membersByName[index].stat.activitySum + this._membersByName[index].stat.prestigeSum);
|
||||
this._membersByName[index].warGifts = (((guildData.clan.giftsCount / 2) * ((this._membersByName[index].clanWarSum * 10) / 100)) / 20);
|
||||
|
||||
this.guildTodayTotal.activity += stat.todayActivity;
|
||||
this.guildTodayTotal.prestige += stat.todayPrestige;
|
||||
this.guildTodayTotal.titanite += stat.todayDungeonActivity;
|
||||
this.guildTodayTotal.score += (this._membersByName[index].stat.todayDungeonActivity + this._membersByName[index].stat.todayActivity + this._membersByName[index].stat.todayPrestige);
|
||||
this.guildSumTotal.activity += stat.activitySum;
|
||||
this.guildSumTotal.prestige += stat.prestigeSum;
|
||||
this.guildSumTotal.titanite += stat.dungeonActivitySum;
|
||||
this.guildSumTotal.score += this._membersByName[index].score;
|
||||
this.guildSumTotal.warGifts += this._membersByName[index].warGifts;
|
||||
this._deviations.activity.push(stat.activitySum);
|
||||
this._deviations.prestige.push(stat.prestigeSum);
|
||||
this._deviations.titanite.push(stat.dungeonActivitySum);
|
||||
//this.guildSumTotal.warGifts += ((this._membersByName[index].score / this.guildSumTotal.score) * (guildData.clan.giftsCount / 2))
|
||||
}
|
||||
this.guildSumTotal.scoreGifts = (guildData.clan.giftsCount - Math.floor(this.guildSumTotal.warGifts));
|
||||
this.guildTodayAverages.activity = (this.guildTodayTotal.activity / this._membersByName.length);
|
||||
this.guildTodayAverages.prestige = (this.guildTodayTotal.prestige / this._membersByName.length);
|
||||
this.guildTodayAverages.titanite = (this.guildTodayTotal.titanite / this._membersByName.length);
|
||||
this.guildTodayAverages.score = (this.guildTodayTotal.score / this._membersByName.length);
|
||||
this.guildSumAverages.activity = (this.guildSumTotal.activity / this._membersByName.length);
|
||||
this.guildSumAverages.prestige = (this.guildSumTotal.prestige / this._membersByName.length);
|
||||
this.guildSumAverages.titanite = (this.guildSumTotal.titanite / this._membersByName.length);
|
||||
this.guildSumAverages.war = (this.guildSumTotal.war / 20);
|
||||
this.guildSumAverages.adventure = (this.guildSumTotal.adventure / this._membersByName.length);
|
||||
this.guildSumAverages.gifts = (this.guildSumTotal.gifts / this._membersByName.length);
|
||||
this.guildSumAverages.score = (this.guildSumTotal.score / this._membersByName.length);
|
||||
|
||||
this._membersByName.map((data) => {
|
||||
data.scoreGifts = ((data.score / this.guildSumTotal.score) * this.guildSumTotal.scoreGifts);
|
||||
data.rewards = Math.floor((data.scoreGifts + data.warGifts));
|
||||
this.guildSumTotal.rewards += data.rewards;
|
||||
return data;
|
||||
});
|
||||
this.guildSumAverages.rewards = (this.guildSumTotal.rewards / this._membersByName.length);
|
||||
}
|
||||
|
||||
getMembersByName(): HWMember[] {
|
||||
return this._membersByName;
|
||||
}
|
||||
|
||||
private _standardDeviation(array: number[]): number {
|
||||
const n = array.length;
|
||||
const mean = array.reduce((a, b) => a + b) / n;
|
||||
return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
||||
}
|
||||
|
||||
getStandardDeviationActivity(): number {
|
||||
return this._standardDeviation(this._deviations.activity);
|
||||
}
|
||||
|
||||
getStandardDeviationAPrestige(): number {
|
||||
return this._standardDeviation(this._deviations.prestige);
|
||||
}
|
||||
|
||||
getStandardDeviationTitanite(): number {
|
||||
return this._standardDeviation(this._deviations.titanite);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from './accordion';
|
||||
export * from './dashboard-components';
|
||||
export * from './fortification-card-content/fortification-card-content.component';
|
||||
export * from './helpers-chart';
|
||||
export * from './helpers-jump';
|
||||
export * from './herowars-components';
|
||||
|
||||
@@ -53,7 +53,9 @@ const MENUITEMS: Menu[] = [
|
||||
{ parent: 'page', state: 'les-fleurs', type: 'link', name: 'Fleurs', icon: 'marijuana', desc: '' },
|
||||
{ parent: 'page', state: 'les-resines', type: 'link', name: 'Résines', icon: 'butter', desc: '' },
|
||||
{ parent: 'page', state: 'les-molecules', type: 'link', name: 'Molécules', icon: 'molecule', desc: '' },
|
||||
{ state: 'herowars', type: 'link', name: 'Hero Wars', icon: 'military_tech', icontype: 'mat', desc: '' }
|
||||
{ state: 'herowars', type: 'menu', name: 'Hero Wars', icon: 'military_tech', icontype: 'mat', desc: '' },
|
||||
{ parent: 'herowars', state: 'guildwar', type: 'link', name: 'Guild War', icon: 'military_tech', icontype: 'mat', desc: '' },
|
||||
{ parent: 'herowars', state: 'guildraid', type: 'link', name: 'Guild Raid', icon: 'military_tech', icontype: 'mat', desc: '' }
|
||||
];
|
||||
|
||||
const MENUPJUMP: Menu[] = [
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export interface HWClanListConfig {
|
||||
type: string;
|
||||
filters: HWClanListFilters;
|
||||
}
|
||||
|
||||
export interface HWClanListFilters {
|
||||
id?: string;
|
||||
title?: string;
|
||||
country?: string;
|
||||
level?: string;
|
||||
minLevel?: string;
|
||||
ownerId?: string;
|
||||
serverId?: string;
|
||||
topActivity?: string;
|
||||
topDungeon?: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { HWClan } from './clan.model';
|
||||
|
||||
export interface HWClanList {
|
||||
clans: Array<HWClan>;
|
||||
clansCount: number;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { HWMember } from './member.model';
|
||||
import { HWActivityStat, HWGuildStat, HWMemberStat } from './stat.model';
|
||||
import { PageLinks, PageMeta } from '../shared.model';
|
||||
|
||||
export interface HWGuildClan {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
level: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
country: string;
|
||||
minLevel: string;
|
||||
serverId: string;
|
||||
membersCount: string;
|
||||
disbanding: boolean;
|
||||
topActivity: string;
|
||||
topDungeon: string;
|
||||
roleNames: never[];
|
||||
frameId: number;
|
||||
members: {[key: string]: HWMember};
|
||||
news: string;
|
||||
activityPoints: number;
|
||||
dungeonPoints: number;
|
||||
blackList: {[key: string]: number};
|
||||
warriors: number[];
|
||||
giftsCount: number;
|
||||
daysToKick: string;
|
||||
league: string;
|
||||
sumAverages: HWActivityStat;
|
||||
sumTotal: HWActivityStat;
|
||||
todayAverages: HWActivityStat;
|
||||
todayTotal: HWActivityStat;
|
||||
}
|
||||
export interface HWGuildData {
|
||||
clan: HWGuildClan;
|
||||
slots: {[key: string]: number};
|
||||
membersStat: HWMemberStat[];
|
||||
stat: HWGuildStat;
|
||||
serverResetTime: number;
|
||||
clanWarEndSeasonTime: number;
|
||||
freeClanChangeInterval: {
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
giftUids: string[];
|
||||
}
|
||||
|
||||
export interface HWClan {
|
||||
id: string;
|
||||
country: string;
|
||||
description: string;
|
||||
disbanding: boolean;
|
||||
frameId: number;
|
||||
icon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
level: string;
|
||||
members: {[key: string]: HWMember};
|
||||
membersCount: string;
|
||||
minLevel: string;
|
||||
ownerId: string;
|
||||
/*roleNames: never[];*/
|
||||
serverId: string;
|
||||
title: string;
|
||||
topActivity: string;
|
||||
topDungeon: string;
|
||||
}
|
||||
|
||||
export interface HWClanPageData {
|
||||
clan: HWClan;
|
||||
_links: PageLinks;
|
||||
_meta: PageMeta;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { HWMember } from './member.model';
|
||||
|
||||
export interface HWGuildWarFortification {
|
||||
name: string;
|
||||
type: string;
|
||||
count: number;
|
||||
teams: HWMember[];
|
||||
positions: number[];
|
||||
slots: number[];
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
export interface HWGuildWarHeroTeam {
|
||||
id: number;
|
||||
level: number;
|
||||
color: number;
|
||||
star: number;
|
||||
power: number;
|
||||
}
|
||||
export interface HWGuildWarTitanTeam {
|
||||
id: number;
|
||||
level: number;
|
||||
star: number;
|
||||
element: string;
|
||||
elementSpiritLevel: number;
|
||||
elementSpiritStar: number;
|
||||
elementSpiritSkills: {
|
||||
skillId: number;
|
||||
level: number;
|
||||
tierScale: number;
|
||||
}[];
|
||||
elementAffinityPower: number;
|
||||
power: number;
|
||||
}
|
||||
export interface HWGuildWarEnemyTeam {
|
||||
element: string;
|
||||
elementSpiritLevel: number;
|
||||
elementSpiritStar: number;
|
||||
elementSpiritSkills: {
|
||||
skillId: number;
|
||||
level: number;
|
||||
tierScale: number;
|
||||
}[];
|
||||
elementAffinityPower: number;
|
||||
state: {
|
||||
isDead: boolean;
|
||||
hp: number;
|
||||
energy: number;
|
||||
maxHp: number;
|
||||
};
|
||||
id: number;
|
||||
star: number;
|
||||
color: number;
|
||||
level: number;
|
||||
power: number;
|
||||
type: string;
|
||||
}
|
||||
export interface HWGuildWarSlots {
|
||||
[key: string]: number[];
|
||||
}
|
||||
export interface HWGuildWarEnemySlot {
|
||||
attackerId: number;
|
||||
status: string;
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
lastLoginTime: string;
|
||||
serverId: string;
|
||||
level: string;
|
||||
clanId: string;
|
||||
clanRole: string;
|
||||
commander: boolean;
|
||||
avatarId: string;
|
||||
isChatModerator: boolean;
|
||||
frameId: number;
|
||||
leagueId: number;
|
||||
allowPm: string;
|
||||
clanTitle: string;
|
||||
clanIcon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
};
|
||||
pointsFarmed: number;
|
||||
slotId: number;
|
||||
totalPoints: number;
|
||||
teams: HWGuildWarEnemyTeam[];
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
export interface HWMember {
|
||||
id: string;
|
||||
name: string;
|
||||
lastLoginTime: string;
|
||||
serverId: string;
|
||||
level: string;
|
||||
clanId: string;
|
||||
clanRole: string;
|
||||
commander: boolean;
|
||||
avatarId: string;
|
||||
isChatModerator: boolean;
|
||||
frameId: number;
|
||||
leagueId: number;
|
||||
allowPm: string;
|
||||
showProfile: boolean;
|
||||
clanTitle: string;
|
||||
clanIcon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
champion: boolean;
|
||||
heroes: {
|
||||
power: number;
|
||||
teams: HWGuildWarHeroTeam[];
|
||||
};
|
||||
titans: {
|
||||
power: number;
|
||||
teams: HWGuildWarTitanTeam[];
|
||||
};
|
||||
stat: HWMemberStat;
|
||||
inactivity: {
|
||||
daysLeft: number,
|
||||
timeLeft: number,
|
||||
dropDate: number;
|
||||
dropDelay: string;
|
||||
}
|
||||
adventureSum: number;
|
||||
clanGiftsSum: number;
|
||||
clanWarSum: number;
|
||||
weekStat: HWWeekStat;
|
||||
score: number;
|
||||
scoreGifts: number;
|
||||
warGifts: number;
|
||||
rewards: number;
|
||||
raids: HWGuildRaid[];
|
||||
raidsInfo: {
|
||||
variationAvg: number;
|
||||
variationSum: number;
|
||||
}
|
||||
}
|
||||
export interface HWGuildWarHeroTeam {
|
||||
id: number;
|
||||
level: number;
|
||||
color: number;
|
||||
star: number;
|
||||
power: number;
|
||||
}
|
||||
export interface HWGuildWarTitanTeam {
|
||||
id: number;
|
||||
level: number;
|
||||
star: number;
|
||||
element: string;
|
||||
elementSpiritLevel: number;
|
||||
elementSpiritStar: number;
|
||||
elementSpiritSkills: {
|
||||
skillId: number;
|
||||
level: number;
|
||||
tierScale: number;
|
||||
}[];
|
||||
elementAffinityPower: number;
|
||||
power: number;
|
||||
}
|
||||
export interface HWGuildWarFortification {
|
||||
name: string;
|
||||
type: string;
|
||||
count: number;
|
||||
teams: HWMember[];
|
||||
positions: number[];
|
||||
slots: number[];
|
||||
}
|
||||
export interface HWGuildStat {
|
||||
todayActivity: number;
|
||||
activitySum: number;
|
||||
dungeonActivitySum: number;
|
||||
todayRaid: never[];
|
||||
todayItemsActivity: number;
|
||||
todayDungeonActivity: number;
|
||||
activityForRuneAvailable: boolean;
|
||||
adventureStat: number;
|
||||
clanWarStat: number;
|
||||
}
|
||||
export interface HWGuildClan {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
level: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
country: string;
|
||||
minLevel: string;
|
||||
serverId: string;
|
||||
membersCount: string;
|
||||
disbanding: boolean;
|
||||
topActivity: string;
|
||||
topDungeon: string;
|
||||
roleNames: never[];
|
||||
frameId: number;
|
||||
members: {[key: string]: HWMember};
|
||||
news: string;
|
||||
activityPoints: number;
|
||||
dungeonPoints: number;
|
||||
blackList: {[key: string]: number};
|
||||
warriors: number[];
|
||||
giftsCount: number;
|
||||
daysToKick: string;
|
||||
league: string;
|
||||
}
|
||||
export interface HWGuildData {
|
||||
clan: HWGuildClan;
|
||||
slots: {[key: string]: number};
|
||||
membersStat: HWMemberStat[];
|
||||
stat: HWGuildStat;
|
||||
serverResetTime: number;
|
||||
clanWarEndSeasonTime: number;
|
||||
freeClanChangeInterval: {
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
giftUids: string[];
|
||||
}
|
||||
export interface HWActivityStat {
|
||||
activity: number;
|
||||
prestige: number;
|
||||
titanite: number;
|
||||
war: number;
|
||||
adventure: number;
|
||||
gifts: number;
|
||||
score: number;
|
||||
scoreGifts: number;
|
||||
warGifts: number;
|
||||
rewards: number;
|
||||
}
|
||||
export interface HWWeekStat {
|
||||
activity: number[];
|
||||
dungeonActivity: number[];
|
||||
adventureStat: number[];
|
||||
clanWarStat: number[];
|
||||
prestigeStat: number[];
|
||||
clanGifts: number[];
|
||||
}
|
||||
export interface HWMemberStat {
|
||||
activitySum: number;
|
||||
todayActivity: number;
|
||||
dungeonActivitySum: number;
|
||||
todayDungeonActivity: number;
|
||||
raidSum: number;
|
||||
wasChampion: boolean;
|
||||
todayPrestige: number;
|
||||
prestigeSum: number;
|
||||
}
|
||||
export interface HWGuildRaidAttacker {
|
||||
id: number;
|
||||
power: number;
|
||||
type: string;
|
||||
}
|
||||
export interface HWGuildRaidStage {
|
||||
num: number;
|
||||
name: string;
|
||||
maxPower: number;
|
||||
duration: number;
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
}
|
||||
export interface HWGuildRaid {
|
||||
userId: string;
|
||||
userName: string;
|
||||
power: number;
|
||||
variation: {
|
||||
value: number;
|
||||
percent: number;
|
||||
color: string;
|
||||
};
|
||||
tooltip: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
damage: {
|
||||
"1": number;
|
||||
"2": number;
|
||||
};
|
||||
level: string;
|
||||
attackers: HWGuildRaidAttacker[];
|
||||
stage: HWGuildRaidStage;
|
||||
|
||||
}
|
||||
export interface HWGuildRaidAttackers {
|
||||
[key: string]: HWGuildRaidAttacker;
|
||||
}
|
||||
export interface HWGuildWarEnemySlot {
|
||||
attackerId: number;
|
||||
status: string;
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
lastLoginTime: string;
|
||||
serverId: string;
|
||||
level: string;
|
||||
clanId: string;
|
||||
clanRole: string;
|
||||
commander: boolean;
|
||||
avatarId: string;
|
||||
isChatModerator: boolean;
|
||||
frameId: number;
|
||||
leagueId: number;
|
||||
allowPm: string;
|
||||
clanTitle: string;
|
||||
clanIcon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
};
|
||||
pointsFarmed: number;
|
||||
slotId: number;
|
||||
totalPoints: number;
|
||||
teams: HWGuildWarEnemyTeam[];
|
||||
}
|
||||
|
||||
export interface HWGuildWarEnemyTeam {
|
||||
element: string;
|
||||
elementSpiritLevel: number;
|
||||
elementSpiritStar: number;
|
||||
elementSpiritSkills: {
|
||||
skillId: number;
|
||||
level: number;
|
||||
tierScale: number;
|
||||
}[];
|
||||
elementAffinityPower: number;
|
||||
state: {
|
||||
isDead: boolean;
|
||||
hp: number;
|
||||
energy: number;
|
||||
maxHp: number;
|
||||
};
|
||||
id: number;
|
||||
star: number;
|
||||
color: number;
|
||||
level: number;
|
||||
power: number;
|
||||
type: string;
|
||||
}
|
||||
export interface HWGuildWarSlots {
|
||||
[key: string]: number[];
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export * from './clan-list-config.model';
|
||||
export * from './clan-list.model';
|
||||
export * from './clan.model';
|
||||
export * from './fortification.model';
|
||||
export * from './guildwar.model';
|
||||
//export * from './hw.model';
|
||||
export * from './member.model';
|
||||
export * from './raid.model';
|
||||
export * from './stat.model';
|
||||
@@ -0,0 +1,57 @@
|
||||
import { HWGuildRaid } from './raid.model';
|
||||
import { HWMemberStat, HWWeekStat } from './stat.model';
|
||||
import { HWGuildWarHeroTeam, HWGuildWarTitanTeam } from './guildwar.model';
|
||||
|
||||
export interface HWMember {
|
||||
id: string;
|
||||
allowPm: string;
|
||||
avatarId: string;
|
||||
clanIcon: {
|
||||
flagColor1: number;
|
||||
flagColor2: number;
|
||||
flagShape: number;
|
||||
iconColor: number;
|
||||
iconShape: number;
|
||||
};
|
||||
clanId: string;
|
||||
clanRole: string;
|
||||
clanTitle: string;
|
||||
commander: boolean;
|
||||
frameId: number;
|
||||
isChatModerator: boolean;
|
||||
lastLoginTime: string;
|
||||
leagueId: number;
|
||||
level: string;
|
||||
name: string;
|
||||
serverId: string;
|
||||
showProfile: boolean;
|
||||
champion: boolean;
|
||||
heroes: {
|
||||
power: number;
|
||||
teams: HWGuildWarHeroTeam[];
|
||||
};
|
||||
titans: {
|
||||
power: number;
|
||||
teams: HWGuildWarTitanTeam[];
|
||||
};
|
||||
stat: HWMemberStat;
|
||||
inactivity: {
|
||||
daysLeft: number,
|
||||
timeLeft: number,
|
||||
dropDate: number;
|
||||
dropDelay: string;
|
||||
}
|
||||
adventureSum: number;
|
||||
clanGiftsSum: number;
|
||||
clanWarSum: number;
|
||||
weekStat: HWWeekStat;
|
||||
score: number;
|
||||
scoreGifts: number;
|
||||
warGifts: number;
|
||||
rewards: number;
|
||||
raids: HWGuildRaid[];
|
||||
raidsInfo: {
|
||||
variationAvg: number;
|
||||
variationSum: number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
export interface HWGuildRaidAttacker {
|
||||
id: number;
|
||||
power: number;
|
||||
type: string;
|
||||
}
|
||||
export interface HWGuildRaidStage {
|
||||
num: number;
|
||||
name: string;
|
||||
maxPower: number;
|
||||
duration: number;
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
}
|
||||
export interface HWGuildRaid {
|
||||
userId: string;
|
||||
userName: string;
|
||||
power: number;
|
||||
variation: {
|
||||
value: number;
|
||||
percent: number;
|
||||
color: string;
|
||||
};
|
||||
tooltip: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
damage: {
|
||||
"1": number;
|
||||
"2": number;
|
||||
};
|
||||
level: string;
|
||||
attackers: HWGuildRaidAttacker[];
|
||||
stage: HWGuildRaidStage;
|
||||
|
||||
}
|
||||
export interface HWGuildRaidAttackers {
|
||||
[key: string]: HWGuildRaidAttacker;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
export interface HWGuildStat {
|
||||
todayActivity: number;
|
||||
activitySum: number;
|
||||
dungeonActivitySum: number;
|
||||
todayRaid: never[];
|
||||
todayItemsActivity: number;
|
||||
todayDungeonActivity: number;
|
||||
activityForRuneAvailable: boolean;
|
||||
adventureStat: number;
|
||||
clanWarStat: number;
|
||||
}
|
||||
export interface HWActivityStat {
|
||||
activity: number;
|
||||
prestige: number;
|
||||
titanite: number;
|
||||
war: number;
|
||||
adventure: number;
|
||||
gifts: number;
|
||||
score: number;
|
||||
scoreGifts: number;
|
||||
warGifts: number;
|
||||
rewards: number;
|
||||
}
|
||||
export interface HWWeekStat {
|
||||
activity: number[];
|
||||
dungeonActivity: number[];
|
||||
adventureStat: number[];
|
||||
clanWarStat: number[];
|
||||
prestigeStat: number[];
|
||||
clanGifts: number[];
|
||||
}
|
||||
export interface HWMemberStat {
|
||||
activitySum: number;
|
||||
todayActivity: number;
|
||||
dungeonActivitySum: number;
|
||||
todayDungeonActivity: number;
|
||||
raidSum: number;
|
||||
wasChampion: boolean;
|
||||
todayPrestige: number;
|
||||
prestigeSum: number;
|
||||
}
|
||||
@@ -13,7 +13,7 @@ export * from './category.model';
|
||||
export * from './chart.model';
|
||||
export * from './dropzone.model';
|
||||
export * from './errors.model';
|
||||
export * from './hw.model';
|
||||
export * from './herowars/';
|
||||
export * from './jump.model';
|
||||
export * from './jump-list.model';
|
||||
export * from './jump-list-config.model';
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { ApiService } from './api.service';
|
||||
import {
|
||||
HWClan, HWClanList, HWClanListConfig, HWClanListFilters, HWClanPageData
|
||||
} from 'src/app/core/models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HWClanService {
|
||||
constructor(
|
||||
private apiService: ApiService
|
||||
) { }
|
||||
|
||||
query(config: HWClanListConfig): Observable<HWClanList> {
|
||||
// Convert any filters over to Angular's URLSearchParams
|
||||
const params: HWClanListFilters = {} as HWClanListFilters;
|
||||
Object.assign(params, config.filters);
|
||||
return this.apiService
|
||||
.get(
|
||||
'/clans',
|
||||
new HttpParams({ fromObject: <{
|
||||
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||
}>params })
|
||||
);
|
||||
}
|
||||
|
||||
get(id: string): Observable<HWClanPageData> {
|
||||
return this.apiService.get(`/clans/${id}`);
|
||||
}
|
||||
|
||||
getAll(): Observable<Array<HWClan>> {
|
||||
return this.apiService.get('/clans').pipe(map(data => data.clans));
|
||||
}
|
||||
|
||||
create(clan: HWClan): Observable<HWClan> {
|
||||
return this.apiService.post('/clans/', { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
|
||||
update(clan: HWClan): Observable<HWClan> {
|
||||
return this.apiService.put(`/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
|
||||
destroy(id: string): Observable<boolean> {
|
||||
return this.apiService.delete(`/clans/${id}`).pipe(map(data => data.deleted));
|
||||
}
|
||||
|
||||
save(clan: HWClan): Observable<HWClan> {
|
||||
// If we're updating an existing clan
|
||||
if (clan.id) {
|
||||
return this.apiService.put(`/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
|
||||
// Otherwise, create a new clan
|
||||
} else {
|
||||
return this.apiService.post('/clans/', { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { ApiService } from './api.service';
|
||||
import {
|
||||
HWClan, HWClanList, HWClanListConfig, HWClanListFilters, HWClanPageData
|
||||
} from 'src/app/core/models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HWClanService {
|
||||
constructor(
|
||||
private apiService: ApiService
|
||||
) { }
|
||||
|
||||
query(config: HWClanListConfig): Observable<HWClanList> {
|
||||
// Convert any filters over to Angular's URLSearchParams
|
||||
const params: HWClanListFilters = {} as HWClanListFilters;
|
||||
Object.assign(params, config.filters);
|
||||
return this.apiService
|
||||
.get(
|
||||
'/clans',
|
||||
new HttpParams({ fromObject: <{
|
||||
[param: string]: string | number | boolean | readonly (string | number | boolean)[];
|
||||
}>params })
|
||||
);
|
||||
}
|
||||
|
||||
get(id: string): Observable<HWClanPageData> {
|
||||
return this.apiService.get(`/clans/${id}`);
|
||||
}
|
||||
|
||||
getAll(): Observable<Array<HWClan>> {
|
||||
return this.apiService.get('/clans').pipe(map(data => data.clans));
|
||||
}
|
||||
|
||||
create(clan: HWClan): Observable<HWClan> {
|
||||
return this.apiService.post('/clans/', { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
|
||||
update(clan: HWClan): Observable<HWClan> {
|
||||
return this.apiService.put(`/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
|
||||
destroy(id: string): Observable<boolean> {
|
||||
return this.apiService.delete(`/clans/${id}`).pipe(map(data => data.deleted));
|
||||
}
|
||||
|
||||
save(clan: HWClan): Observable<HWClan> {
|
||||
// If we're updating an existing clan
|
||||
if (clan.id) {
|
||||
return this.apiService.put(`/clans/${clan.id}`, { clan: clan }).pipe(map(data => data.clan));
|
||||
// Otherwise, create a new clan
|
||||
} else {
|
||||
return this.apiService.post('/clans/', { clan: clan }).pipe(map(data => data.clan));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,8 @@ import { Routes } from '@angular/router';
|
||||
|
||||
import {
|
||||
AeronefsComponent, CalculatorComponent, CanopiesComponent, CredentialsComponent,
|
||||
DashboardComponent, DemoComponent, DropzonesComponent, HerowarsComponent, JumpComponent, JumpsComponent,
|
||||
HerowarsComponent, HerowarsGuildraidComponent, HerowarsGuildwarComponent,
|
||||
DashboardComponent, DemoComponent, DropzonesComponent, JumpComponent, JumpsComponent,
|
||||
LogbookComponent, PageComponent, PagesComponent, ProductComponent, ProductsComponent, ProfileComponent, QcmComponent, SettingsComponent
|
||||
} from 'src/app/components';
|
||||
import { authGuard, adminGuard } from 'src/app/core/guards';
|
||||
@@ -62,6 +63,16 @@ export const AUTH_ROUTES: Routes = [
|
||||
component: HerowarsComponent,
|
||||
canActivate: [ authGuard ]
|
||||
},
|
||||
{
|
||||
path: 'herowars/guildwar',
|
||||
component: HerowarsGuildwarComponent,
|
||||
canActivate: [ authGuard ]
|
||||
},
|
||||
{
|
||||
path: 'herowars/guildraid',
|
||||
component: HerowarsGuildraidComponent,
|
||||
canActivate: [ authGuard ]
|
||||
},
|
||||
{
|
||||
path: 'jumps',
|
||||
component: JumpsComponent,
|
||||
|
||||
@@ -580,6 +580,40 @@ $md-custom-pink: (
|
||||
A700 : #000000,
|
||||
)
|
||||
);
|
||||
|
||||
$md-custom-jinza: (
|
||||
50 : #ffecef,
|
||||
100 : #ffd0d4,
|
||||
200 : #f3a09d,
|
||||
300 : #eb7a77,
|
||||
400 : #f65e54,
|
||||
500 : #fa5039,
|
||||
600 : #ed4739,
|
||||
700 : #da3d33,
|
||||
800 : #cd372c,
|
||||
900 : #be2c20,
|
||||
A100 : #fdf1f1,
|
||||
A200 : #fbe4e4,
|
||||
A400 : #f7cac9,
|
||||
A700 : #f1a19f,
|
||||
contrast: (
|
||||
50 : #000000,
|
||||
100 : #000000,
|
||||
200 : #000000,
|
||||
300 : #000000,
|
||||
400 : #000000,
|
||||
500 : #000000,
|
||||
600 : #000000,
|
||||
700 : #ffffff,
|
||||
800 : #ffffff,
|
||||
900 : #ffffff,
|
||||
A100 : #000000,
|
||||
A200 : #000000,
|
||||
A400 : #000000,
|
||||
A700 : #000000,
|
||||
)
|
||||
);
|
||||
|
||||
$md-custom-red: (
|
||||
50: #ffebee,
|
||||
100: #ffcdd2,
|
||||
|
||||
@@ -259,6 +259,9 @@ dl.dl-horizontal {
|
||||
.text-error {
|
||||
color: $error !important;
|
||||
}
|
||||
.text-muted {
|
||||
color: $muted !important;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Extra Background Colors *
|
||||
|
||||
Reference in New Issue
Block a user