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 { MAT_DATE_LOCALE, MAT_DATE_FORMATS, provideNativeDateAdapter } from '@angular/material/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
@@ -31,8 +31,9 @@ export const MY_FORMATS = {
|
|||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.scss'
|
styleUrl: './app.component.scss'
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit, AfterContentInit {
|
||||||
public title = 'Ad Astra';
|
public title = 'Ad Astra';
|
||||||
|
public appClass = 'grayscale';
|
||||||
|
|
||||||
constructor(private userService: UserService, private titleService: Title) { }
|
constructor(private userService: UserService, private titleService: Title) { }
|
||||||
|
|
||||||
@@ -40,4 +41,8 @@ export class AppComponent implements OnInit {
|
|||||||
this.userService.populate();
|
this.userService.populate();
|
||||||
this.titleService.setTitle(this.title);
|
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 './demo/demo.component';
|
||||||
export * from './dropzones/dropzones.component';
|
export * from './dropzones/dropzones.component';
|
||||||
export * from './herowars/herowars.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 './home/home.component';
|
||||||
export * from './jump/jump.component';
|
export * from './jump/jump.component';
|
||||||
export * from './jumps/jumps.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 './accordion';
|
||||||
export * from './dashboard-components';
|
export * from './dashboard-components';
|
||||||
export * from './fortification-card-content/fortification-card-content.component';
|
|
||||||
export * from './helpers-chart';
|
export * from './helpers-chart';
|
||||||
export * from './helpers-jump';
|
export * from './helpers-jump';
|
||||||
export * from './herowars-components';
|
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-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-resines', type: 'link', name: 'Résines', icon: 'butter', desc: '' },
|
||||||
{ parent: 'page', state: 'les-molecules', type: 'link', name: 'Molécules', icon: 'molecule', 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[] = [
|
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 './chart.model';
|
||||||
export * from './dropzone.model';
|
export * from './dropzone.model';
|
||||||
export * from './errors.model';
|
export * from './errors.model';
|
||||||
export * from './hw.model';
|
export * from './herowars/';
|
||||||
export * from './jump.model';
|
export * from './jump.model';
|
||||||
export * from './jump-list.model';
|
export * from './jump-list.model';
|
||||||
export * from './jump-list-config.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 {
|
import {
|
||||||
AeronefsComponent, CalculatorComponent, CanopiesComponent, CredentialsComponent,
|
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
|
LogbookComponent, PageComponent, PagesComponent, ProductComponent, ProductsComponent, ProfileComponent, QcmComponent, SettingsComponent
|
||||||
} from 'src/app/components';
|
} from 'src/app/components';
|
||||||
import { authGuard, adminGuard } from 'src/app/core/guards';
|
import { authGuard, adminGuard } from 'src/app/core/guards';
|
||||||
@@ -62,6 +63,16 @@ export const AUTH_ROUTES: Routes = [
|
|||||||
component: HerowarsComponent,
|
component: HerowarsComponent,
|
||||||
canActivate: [ authGuard ]
|
canActivate: [ authGuard ]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'herowars/guildwar',
|
||||||
|
component: HerowarsGuildwarComponent,
|
||||||
|
canActivate: [ authGuard ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'herowars/guildraid',
|
||||||
|
component: HerowarsGuildraidComponent,
|
||||||
|
canActivate: [ authGuard ]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'jumps',
|
path: 'jumps',
|
||||||
component: JumpsComponent,
|
component: JumpsComponent,
|
||||||
|
|||||||
@@ -580,6 +580,40 @@ $md-custom-pink: (
|
|||||||
A700 : #000000,
|
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: (
|
$md-custom-red: (
|
||||||
50: #ffebee,
|
50: #ffebee,
|
||||||
100: #ffcdd2,
|
100: #ffcdd2,
|
||||||
|
|||||||
@@ -259,6 +259,9 @@ dl.dl-horizontal {
|
|||||||
.text-error {
|
.text-error {
|
||||||
color: $error !important;
|
color: $error !important;
|
||||||
}
|
}
|
||||||
|
.text-muted {
|
||||||
|
color: $muted !important;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************
|
/****************************
|
||||||
* Extra Background Colors *
|
* Extra Background Colors *
|
||||||
|
|||||||
Reference in New Issue
Block a user