First step to add achievements to frontend #268_achievements
This commit is contained in:
		| @@ -16,6 +16,9 @@ type Server implements TableWithHistoryQuery { | ||||
|     userCount: Int | ||||
|     users(filter: UserFilter, page: Page, sort: Sort): [User] | ||||
|  | ||||
|     achievementCount: Int | ||||
|     achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement] | ||||
|  | ||||
|     createdAt: String | ||||
|     modifiedAt: String | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
|  | ||||
| from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC | ||||
| from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC | ||||
| from bot_data.abc.client_repository_abc import ClientRepositoryABC | ||||
| from bot_data.abc.level_repository_abc import LevelRepositoryABC | ||||
| @@ -9,8 +10,8 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoic | ||||
| from bot_data.abc.user_repository_abc import UserRepositoryABC | ||||
| from bot_data.model.server import Server | ||||
| from bot_data.model.server_history import ServerHistory | ||||
| from bot_graphql.abc.data_query_abc import DataQueryABC | ||||
| from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC | ||||
| from bot_graphql.filter.achievement_filter import AchievementFilter | ||||
| from bot_graphql.filter.auto_role_filter import AutoRoleFilter | ||||
| from bot_graphql.filter.client_filter import ClientFilter | ||||
| from bot_graphql.filter.level_filter import LevelFilter | ||||
| @@ -28,6 +29,7 @@ class ServerQuery(DataQueryWithHistoryABC): | ||||
|         users: UserRepositoryABC, | ||||
|         ujs: UserJoinedServerRepositoryABC, | ||||
|         ujvs: UserJoinedVoiceChannelRepositoryABC, | ||||
|         achievements: AchievementRepositoryABC, | ||||
|     ): | ||||
|         DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db) | ||||
|  | ||||
| @@ -54,6 +56,9 @@ class ServerQuery(DataQueryWithHistoryABC): | ||||
|         ) | ||||
|         self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter) | ||||
|         self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter) | ||||
|         self.add_collection( | ||||
|             "achievement", lambda server, *_: achievements.get_achievements_by_server_id(server.id), AchievementFilter | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_id(server: Server, *_): | ||||
|   | ||||
							
								
								
									
										20
									
								
								kdb-web/src/app/models/data/achievement.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								kdb-web/src/app/models/data/achievement.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| import { DataWithHistory } from "./data.model"; | ||||
| import { Server, ServerFilter } from "./server.model"; | ||||
|  | ||||
| export interface Achievement extends DataWithHistory { | ||||
|   id?: number; | ||||
|   name?: string; | ||||
|   attribute?: string; | ||||
|   operator?: string; | ||||
|   value?: string; | ||||
|   server?: Server; | ||||
| } | ||||
|  | ||||
| export interface AchievementFilter { | ||||
|   id?: number; | ||||
|   name?: string; | ||||
|   attribute?: string; | ||||
|   operator?: string; | ||||
|   value?: string; | ||||
|   server?: ServerFilter; | ||||
| } | ||||
| @@ -121,4 +121,46 @@ export class Mutations { | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static createAchievement = ` | ||||
|     mutation createAchievement($name: String, $attribute: String, $operator: String, $value: String, $serverId: ID) { | ||||
|       level { | ||||
|         createAchievement(input: { name: $name, attribute: $attribute, operator: $operator, value: $value, serverId: $serverId}) { | ||||
|           id | ||||
|           name | ||||
|           attribute | ||||
|           operator | ||||
|           value | ||||
|           server { | ||||
|             id | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static updateAchievement = ` | ||||
|     mutation updateAchievement($name: String, $attribute: String, $operator: String, $value: String, $serverId: ID) { | ||||
|       level { | ||||
|         updateAchievement(input: { name: $name, attribute: $attribute, operator: $operator, value: $value}) { | ||||
|           id | ||||
|           name | ||||
|           attribute | ||||
|           operator | ||||
|           value | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static deleteAchievement = ` | ||||
|     mutation deleteAchievement($id: ID) { | ||||
|       level { | ||||
|         deleteLevel(id: $id) { | ||||
|           id | ||||
|           name | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
| } | ||||
|   | ||||
| @@ -90,6 +90,50 @@ export class Queries { | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static achievementQuery = ` | ||||
|     query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) { | ||||
|       servers(filter: {id: $serverId}) { | ||||
|         achievementCount | ||||
|         achievements(filter: $filter, page: $page, sort: $sort) { | ||||
|           id | ||||
|           name | ||||
|           attribute | ||||
|           operator | ||||
|           value | ||||
|           server { | ||||
|             id | ||||
|             name | ||||
|           } | ||||
|           createdAt | ||||
|           modifiedAt | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static achievementWithHistoryQuery = ` | ||||
|     query AchievementHistory($serverId: ID, $id: ID) { | ||||
|       servers(filter: {id: $serverId}) { | ||||
|         achievementCount | ||||
|         achievements(filter: {id: $id}) { | ||||
|           id | ||||
|  | ||||
|           history { | ||||
|             id | ||||
|             name | ||||
|             attribute | ||||
|             operator | ||||
|             value | ||||
|             server | ||||
|             deleted | ||||
|             dateFrom | ||||
|             dateTo | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static usersQuery = ` | ||||
|     query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) { | ||||
|       servers(filter: {id: $serverId}) { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import { User } from "../data/user.model"; | ||||
| import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; | ||||
| import { Guild } from "../data/discord.model"; | ||||
| import { Level } from "../data/level.model"; | ||||
| import { Achievement } from "../data/achievement.model"; | ||||
|  | ||||
| export interface Query { | ||||
|   serverCount: number; | ||||
| @@ -23,6 +24,11 @@ export interface LevelListQuery { | ||||
|   levels: Level[]; | ||||
| } | ||||
|  | ||||
| export interface AchievementListQuery { | ||||
|   achievementCount: number; | ||||
|   achievements: Achievement[]; | ||||
| } | ||||
|  | ||||
| export interface AutoRoleQuery { | ||||
|   autoRoleCount: number; | ||||
|   autoRoles: AutoRole[]; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { User } from "../data/user.model"; | ||||
| import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; | ||||
| import { Level } from "../data/level.model"; | ||||
| import { Server } from "../data/server.model"; | ||||
| import { Achievement } from "../data/achievement.model"; | ||||
|  | ||||
| export interface GraphQLResult { | ||||
|   data: { | ||||
| @@ -45,3 +46,11 @@ export interface LevelMutationResult { | ||||
|     deleteLevel?: Level | ||||
|   }; | ||||
| } | ||||
|  | ||||
| export interface AchievementMutationResult { | ||||
|   achievement: { | ||||
|     createAchievement?: Achievement | ||||
|     updateAchievement?: Achievement | ||||
|     deleteAchievement?: Achievement | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,16 @@ | ||||
| import {NgModule} from "@angular/core"; | ||||
| import {RouterModule, Routes} from "@angular/router"; | ||||
| import { AchievementComponent } from "./components/achievement/achievement.component"; | ||||
|  | ||||
| const routes: Routes = [ | ||||
|  | ||||
|   {path: '', component: AchievementComponent}, | ||||
| ]; | ||||
|  | ||||
| @NgModule({ | ||||
|   imports: [RouterModule.forChild(routes)], | ||||
|   exports: [RouterModule] | ||||
| }) | ||||
| export class AchievementsRoutingModule { | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,18 @@ | ||||
| import { NgModule } from "@angular/core"; | ||||
| import { CommonModule } from "@angular/common"; | ||||
| import { AchievementComponent } from "./components/achievement/achievement.component"; | ||||
| import { AchievementsRoutingModule } from "./achievements-routing.module"; | ||||
| import { SharedModule } from "../../../shared/shared.module"; | ||||
|  | ||||
|  | ||||
| @NgModule({ | ||||
|   declarations: [ | ||||
|     AchievementComponent | ||||
|   ], | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
|     AchievementsRoutingModule, | ||||
|     SharedModule | ||||
|   ] | ||||
| }) | ||||
| export class AchievementsModule { } | ||||
| @@ -0,0 +1,215 @@ | ||||
| <h1> | ||||
|   {{'view.server.achievements.header' | translate}} | ||||
| </h1> | ||||
| <div class="content-wrapper"> | ||||
|   <div class="content"> | ||||
|     <p-table #dt [value]="achievements" dataKey="id" editMode="row" [rowHover]="true" [rows]="10" | ||||
|              [rowsPerPageOptions]="[10,25,50]" [paginator]="true" [loading]="loading" [totalRecords]="totalRecords" | ||||
|              [lazy]="true" (onLazyLoad)="nextPage($event)"> | ||||
|  | ||||
|       <ng-template pTemplate="caption"> | ||||
|         <div class="table-caption"> | ||||
|           <div class="table-caption-text"> | ||||
|             <ng-container *ngIf="!loading">{{achievements.length}} {{'common.of' | translate}} | ||||
|               {{dt.totalRecords}} | ||||
|             </ng-container> | ||||
|             {{'view.server.achievements.achievements' | translate}} | ||||
|           </div> | ||||
|  | ||||
|           <div class="table-caption-btn-wrapper btn-wrapper"> | ||||
|             <button pButton label="{{'common.add' | translate}}" class="icon-btn btn" | ||||
|                     icon="pi pi-user-plus" (click)="addAchievement(dt)" [disabled]="isEditingNew || user?.isModerator && !user?.isAdmin"> | ||||
|             </button> | ||||
|             <button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo" | ||||
|                     class="icon-btn btn" (click)="resetFilters()"> | ||||
|             </button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </ng-template> | ||||
|  | ||||
|       <ng-template pTemplate="header"> | ||||
|         <tr> | ||||
|           <th pSortableColumn="id"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'common.id' | translate}}</div> | ||||
|               <p-sortIcon field="id" class="table-header-icon"></p-sortIcon> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th pSortableColumn="name"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'view.server.achievements.headers.name' | translate}}</div> | ||||
|               <p-sortIcon field="name" class="table-header-icon"></p-sortIcon> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th pSortableColumn="attribute"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'view.server.achievements.headers.attribute' | translate}}</div> | ||||
|               <p-sortIcon field="attribute" class="table-header-icon"></p-sortIcon> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th pSortableColumn="operator"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'view.server.achievements.headers.operator' | translate}}</div> | ||||
|               <p-sortIcon field="operator" class="table-header-icon"></p-sortIcon> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th pSortableColumn="value"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'view.server.achievements.headers.value' | translate}}</div> | ||||
|               <p-sortIcon field="value" class="table-header-icon"></p-sortIcon> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'common.created_at' | translate}}</div> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'common.modified_at' | translate}}</div> | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'common.actions' | translate}}</div> | ||||
|             </div> | ||||
|           </th> | ||||
|         </tr> | ||||
|  | ||||
|         <tr> | ||||
|           <th class="table-header-small"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="id" | ||||
|                      placeholder="{{'common.id' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="name" | ||||
|                      placeholder="{{'view.server.achievements.headers.name' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th></th> | ||||
|           <th></th> | ||||
|           <th></th> | ||||
|           <th class="table-header-small-dropdown"></th> | ||||
|           <th class="table-header-small-dropdown"></th> | ||||
|           <th class="table-header-actions"></th> | ||||
|         </tr> | ||||
|       </ng-template> | ||||
|  | ||||
|       <ng-template pTemplate="body" let-achievement let-editing="editing" let-ri="rowIndex"> | ||||
|         <tr [pEditableRow]="achievement"> | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{achievement.id}} | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.id}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.name"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.name}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.attribute"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.attribute}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="achievement.operator"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.operator}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <input class="table-edit-input" pInputText min="0" type="text" [(ngModel)]="achievement.value"> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.value}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|  | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{achievement.createdAt | date:'dd.MM.yy HH:mm'}} | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.createdAt | date:'dd.MM.yy HH:mm'}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|           <td> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}} | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|           <td> | ||||
|             <div class="btn-wrapper"> | ||||
|               <app-history-btn *ngIf="!isEditingNew" [id]="achievement.id" [query]="query" translationKey="view.server.achievements.header"></app-history-btn> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" | ||||
|                       (click)="onRowEditInit(dt, achievement, ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button> | ||||
|               <button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash" | ||||
|                       (click)="deleteAchievement(achievement)" [disabled]="!user || user.isModerator && !user.isAdmin"></button> | ||||
|  | ||||
|               <button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn" | ||||
|                       icon="pi pi-check-circle" (click)="onRowEditSave(dt, achievement, ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button> | ||||
|               <button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn" | ||||
|                       icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button> | ||||
|             </div> | ||||
|           </td> | ||||
|         </tr> | ||||
|       </ng-template> | ||||
|  | ||||
|       <ng-template pTemplate="emptymessage"> | ||||
|         <tr></tr> | ||||
|         <tr> | ||||
|           <td colspan="10">{{'common.no_entries_found' | translate}}</td> | ||||
|         </tr> | ||||
|         <tr></tr> | ||||
|       </ng-template> | ||||
|  | ||||
|       <ng-template pTemplate="paginatorleft"> | ||||
|       </ng-template> | ||||
|     </p-table> | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
| @@ -0,0 +1,23 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
|  | ||||
| import { AchievementComponent } from './achievement.component'; | ||||
|  | ||||
| describe('AchievementComponent', () => { | ||||
|   let component: AchievementComponent; | ||||
|   let fixture: ComponentFixture<AchievementComponent>; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ AchievementComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|  | ||||
|     fixture = TestBed.createComponent(AchievementComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
|  | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @@ -0,0 +1,268 @@ | ||||
| import { Component, OnDestroy, OnInit } from "@angular/core"; | ||||
| import { Achievement, AchievementFilter } from "../../../../../../models/data/achievement.model"; | ||||
| import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; | ||||
| import { Page } from "../../../../../../models/graphql/filter/page.model"; | ||||
| import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model"; | ||||
| import { Subject, throwError } from "rxjs"; | ||||
| import { Server } from "../../../../../../models/data/server.model"; | ||||
| import { UserDTO } from "../../../../../../models/auth/auth-user.dto"; | ||||
| import { Queries } from "../../../../../../models/graphql/queries.model"; | ||||
| import { AuthService } from "../../../../../../services/auth/auth.service"; | ||||
| import { SpinnerService } from "../../../../../../services/spinner/spinner.service"; | ||||
| import { ToastService } from "../../../../../../services/toast/toast.service"; | ||||
| import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service"; | ||||
| import { TranslateService } from "@ngx-translate/core"; | ||||
| import { DataService } from "../../../../../../services/data/data.service"; | ||||
| import { SidebarService } from "../../../../../../services/sidebar/sidebar.service"; | ||||
| import { ActivatedRoute } from "@angular/router"; | ||||
| import { AchievementListQuery, Query } from "../../../../../../models/graphql/query.model"; | ||||
| import { catchError, debounceTime, takeUntil } from "rxjs/operators"; | ||||
| import { LazyLoadEvent } from "primeng/api"; | ||||
| import { Table } from "primeng/table"; | ||||
| import { User } from "../../../../../../models/data/user.model"; | ||||
| import { AchievementMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model"; | ||||
| import { Mutations } from "../../../../../../models/graphql/mutations.model"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: "app-achievement", | ||||
|   templateUrl: "./achievement.component.html", | ||||
|   styleUrls: ["./achievement.component.scss"] | ||||
| }) | ||||
| export class AchievementComponent implements OnInit, OnDestroy { | ||||
|   public achievements: Achievement[] = []; | ||||
|   public loading = true; | ||||
|  | ||||
|   public isEditingNew: boolean = false; | ||||
|  | ||||
|   public filterForm!: FormGroup<{ | ||||
|     id: FormControl<number | null>, | ||||
|     name: FormControl<string | null>, | ||||
|     color: FormControl<string | null>, | ||||
|     min_xp: FormControl<number | null>, | ||||
|     permissions: FormControl<string | null>, | ||||
|   }>; | ||||
|  | ||||
|   public filter: AchievementFilter = {}; | ||||
|   public page: Page = { | ||||
|     pageSize: undefined, | ||||
|     pageIndex: undefined | ||||
|   }; | ||||
|   public sort: Sort = { | ||||
|     sortColumn: undefined, | ||||
|     sortDirection: undefined | ||||
|   }; | ||||
|  | ||||
|   public totalRecords: number = 0; | ||||
|  | ||||
|   public clonedAchievements: { [s: string]: Achievement; } = {}; | ||||
|  | ||||
|   private unsubscriber = new Subject<void>(); | ||||
|   private server: Server = {}; | ||||
|   public user: UserDTO | null = null; | ||||
|  | ||||
|   query: string = Queries.achievementWithHistoryQuery; | ||||
|  | ||||
|   public constructor( | ||||
|     private authService: AuthService, | ||||
|     private spinner: SpinnerService, | ||||
|     private toastService: ToastService, | ||||
|     private confirmDialog: ConfirmationDialogService, | ||||
|     private fb: FormBuilder, | ||||
|     private translate: TranslateService, | ||||
|     private data: DataService, | ||||
|     private sidebar: SidebarService, | ||||
|     private route: ActivatedRoute) { | ||||
|   } | ||||
|  | ||||
|   public ngOnInit(): void { | ||||
|     this.setFilterForm(); | ||||
|     this.data.getServerFromRoute(this.route).then(async server => { | ||||
|       this.server = server; | ||||
|       this.loadNextPage(); | ||||
|       let authUser = await this.authService.getLoggedInUser(); | ||||
|       this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   public ngOnDestroy(): void { | ||||
|     this.unsubscriber.next(); | ||||
|     this.unsubscriber.complete(); | ||||
|   } | ||||
|  | ||||
|   public loadNextPage(): void { | ||||
|     this.loading = true; | ||||
|     this.data.query<AchievementListQuery>(Queries.achievementQuery, { | ||||
|         serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort | ||||
|       }, | ||||
|       (data: Query) => { | ||||
|         return data.servers[0]; | ||||
|       } | ||||
|     ).subscribe(data => { | ||||
|       this.totalRecords = data.achievementCount; | ||||
|       this.achievements = data.achievements; | ||||
|       this.spinner.hideSpinner(); | ||||
|       this.loading = false; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   public setFilterForm(): void { | ||||
|     this.filterForm = this.fb.group({ | ||||
|       id: new FormControl<number | null>(null), | ||||
|       name: new FormControl<string | null>(null), | ||||
|       color: new FormControl<string | null>(null), | ||||
|       min_xp: new FormControl<number | null>(null), | ||||
|       permissions: new FormControl<string | null>(null) | ||||
|     }); | ||||
|  | ||||
|     this.filterForm.valueChanges.pipe( | ||||
|       takeUntil(this.unsubscriber), | ||||
|       debounceTime(600) | ||||
|     ).subscribe(changes => { | ||||
|       if (changes.id) { | ||||
|         this.filter.id = changes.id; | ||||
|       } else { | ||||
|         this.filter.id = undefined; | ||||
|       } | ||||
|  | ||||
|       if (changes.name) { | ||||
|         this.filter.name = changes.name; | ||||
|       } else { | ||||
|         this.filter.name = undefined; | ||||
|       } | ||||
|  | ||||
|       if (this.page.pageSize) | ||||
|         this.page.pageSize = 10; | ||||
|  | ||||
|       if (this.page.pageIndex) | ||||
|         this.page.pageIndex = 0; | ||||
|  | ||||
|       this.loadNextPage(); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   public newAchievementTemplate: Achievement = { | ||||
|     id: 0, | ||||
|     createdAt: "", | ||||
|     modifiedAt: "" | ||||
|   }; | ||||
|  | ||||
|   public nextPage(event: LazyLoadEvent): void { | ||||
|     this.page.pageSize = event.rows ?? 0; | ||||
|     if (event.first != null && event.rows != null) | ||||
|       this.page.pageIndex = event.first / event.rows; | ||||
|     this.sort.sortColumn = event.sortField ?? undefined; | ||||
|     this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC; | ||||
|  | ||||
|     this.loadNextPage(); | ||||
|   } | ||||
|  | ||||
|   public resetFilters(): void { | ||||
|     this.filterForm.reset(); | ||||
|   } | ||||
|  | ||||
|   public onRowEditInit(table: Table, user: User, index: number): void { | ||||
|     this.clonedAchievements[index] = { ...user }; | ||||
|   } | ||||
|  | ||||
|   public onRowEditSave(table: Table, newAchievement: Achievement, index: number): void { | ||||
|     if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) { | ||||
|       this.isEditingNew = false; | ||||
|       this.achievements.splice(index, 1); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!newAchievement.id && !this.isEditingNew || !newAchievement.name && !newAchievement.attribute && !newAchievement?.operator && !newAchievement?.value) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (this.isEditingNew) { | ||||
|       this.spinner.showSpinner(); | ||||
|       this.data.mutation<AchievementMutationResult>(Mutations.createAchievement, { | ||||
|           name: newAchievement.name, | ||||
|         attribute: newAchievement.attribute, | ||||
|         operator: newAchievement.operator, | ||||
|         value: newAchievement.value, | ||||
|           serverId: this.server.id | ||||
|         } | ||||
|       ).pipe(catchError(err => { | ||||
|         this.isEditingNew = false; | ||||
|         this.spinner.hideSpinner(); | ||||
|         this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_create_failed"), this.translate.instant("view.server.achievements.message.achievement_create_failed_d")); | ||||
|         return throwError(err); | ||||
|       })).subscribe(result => { | ||||
|         this.isEditingNew = false; | ||||
|         this.spinner.hideSpinner(); | ||||
|         this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_create"), this.translate.instant("view.server.achievements.message.achievement_create_d", { name: result.achievement.createAchievement?.name })); | ||||
|         this.loadNextPage(); | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.spinner.showSpinner(); | ||||
|     this.data.mutation<AchievementMutationResult>(Mutations.updateAchievement, { | ||||
|         id: newAchievement.id, | ||||
|         name: newAchievement.name, | ||||
|         attribute: newAchievement.attribute, | ||||
|         operator: newAchievement.operator, | ||||
|         value: newAchievement.value | ||||
|       } | ||||
|     ).pipe(catchError(err => { | ||||
|       this.spinner.hideSpinner(); | ||||
|       this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_update_failed"), this.translate.instant("view.server.achievements.message.achievement_update_failed_d", { name: newAchievement.name })); | ||||
|       return throwError(err); | ||||
|     })).subscribe(_ => { | ||||
|       this.spinner.hideSpinner(); | ||||
|       this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_update"), this.translate.instant("view.server.achievements.message.achievement_update_d", { name: newAchievement.name })); | ||||
|       this.loadNextPage(); | ||||
|     }); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   public onRowEditCancel(index: number): void { | ||||
|     if (this.isEditingNew) { | ||||
|       this.achievements.splice(index, 1); | ||||
|       delete this.clonedAchievements[index]; | ||||
|       this.isEditingNew = false; | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.achievements[index] = this.clonedAchievements[index]; | ||||
|     delete this.clonedAchievements[index]; | ||||
|   } | ||||
|  | ||||
|   public deleteAchievement(achievement: Achievement): void { | ||||
|     this.confirmDialog.confirmDialog( | ||||
|       this.translate.instant("view.server.achievements.message.achievement_delete"), this.translate.instant("view.server.achievements.message.achievement_delete_q", { name: achievement.name }), | ||||
|       () => { | ||||
|         this.spinner.showSpinner(); | ||||
|         this.data.mutation<AchievementMutationResult>(Mutations.deleteAchievement, { | ||||
|             id: achievement.id | ||||
|           } | ||||
|         ).pipe(catchError(err => { | ||||
|           this.spinner.hideSpinner(); | ||||
|           this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_delete_failed"), this.translate.instant("view.server.achievements.message.achievement_delete_failed_d", { name: achievement.name })); | ||||
|           return throwError(err); | ||||
|         })).subscribe(l => { | ||||
|           this.spinner.hideSpinner(); | ||||
|           this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_deleted"), this.translate.instant("view.server.achievements.message.achievement_deleted_d", { name: achievement.name })); | ||||
|           this.loadNextPage(); | ||||
|         }); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   public addAchievement(table: Table): void { | ||||
|     const newAchievement = JSON.parse(JSON.stringify(this.newAchievementTemplate)); | ||||
|     newAchievement.id = Math.max.apply(Math, this.achievements.map(l => { | ||||
|       return l.id ?? 0; | ||||
|     })) + 1; | ||||
|  | ||||
|     this.achievements.push(newAchievement); | ||||
|  | ||||
|     table.initRowEdit(newAchievement); | ||||
|  | ||||
|     const index = this.achievements.findIndex(l => l.id == newAchievement.id); | ||||
|     this.onRowEditInit(table, newAchievement, index); | ||||
|  | ||||
|     this.isEditingNew = true; | ||||
|   } | ||||
| } | ||||
| @@ -9,7 +9,8 @@ const routes: Routes = [ | ||||
|   { path: "members", component: MembersComponent }, | ||||
|   { path: "members/:memberId", component: ProfileComponent }, | ||||
|   { path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) }, | ||||
|   { path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) } | ||||
|   { path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) }, | ||||
|   { path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) } | ||||
| ]; | ||||
|  | ||||
| @NgModule({ | ||||
|   | ||||
| @@ -24,6 +24,7 @@ export class SidebarService { | ||||
|   serverMembers: MenuItem = {}; | ||||
|   serverAutoRoles: MenuItem = {}; | ||||
|   serverLevels: MenuItem = {}; | ||||
|   serverAchievements: MenuItem = {}; | ||||
|   serverMenu: MenuItem = {}; | ||||
|   adminConfig: MenuItem = {}; | ||||
|   adminUsers: MenuItem = {}; | ||||
| @@ -102,12 +103,19 @@ export class SidebarService { | ||||
|       routerLink: `server/${this.server$.value?.id}/levels` | ||||
|     }; | ||||
|  | ||||
|     this.serverAchievements = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "", | ||||
|       icon: "pi pi-angle-double-up", | ||||
|       visible: true, | ||||
|       routerLink: `server/${this.server$.value?.id}/achievements` | ||||
|     }; | ||||
|  | ||||
|     this.serverMenu = { | ||||
|       label: this.isSidebarOpen ? this.server$.value?.name : "", | ||||
|       icon: "pi pi-server", | ||||
|       visible: false, | ||||
|       expanded: true, | ||||
|       items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels] | ||||
|       items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements] | ||||
|     }; | ||||
|     this.adminConfig = { | ||||
|       label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", | ||||
| @@ -142,6 +150,7 @@ export class SidebarService { | ||||
|         this.serverMembers.visible = !!user?.isModerator; | ||||
|         this.serverAutoRoles.visible = !!user?.isModerator; | ||||
|         this.serverLevels.visible = !!user?.isModerator; | ||||
|         this.serverAchievements.visible = !!user?.isModerator; | ||||
|       } else { | ||||
|         this.serverMenu.visible = false; | ||||
|       } | ||||
|   | ||||
| @@ -397,6 +397,32 @@ | ||||
|           "level_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!" | ||||
|         } | ||||
|       }, | ||||
|       "achievements": { | ||||
|         "header": "Errungenschaften", | ||||
|         "headers": { | ||||
|           "name": "Name", | ||||
|           "attribute": "Attribut", | ||||
|           "operator": "Operator", | ||||
|           "value": "Wert" | ||||
|         }, | ||||
|         "achievements": "Errungenschaften", | ||||
|         "message": { | ||||
|           "achievement_create": "Errungenschaft erstellt", | ||||
|           "achievement_create_d": "Errungenschaft {{name}} erfolgreich erstellt", | ||||
|           "achievement_create_failed": "Errungenschaft Erstellung fehlgeschlagen", | ||||
|           "achievement_create_failed_d": "Die Erstellung der Errungenschaft ist fehlgeschlagen!", | ||||
|           "achievement_delete": "Errungenschaft löschen", | ||||
|           "achievement_delete_failed": "Errungenschaft Löschung fehlgeschlagen", | ||||
|           "achievement_delete_failed_d": "Die Löschung der Errungenschaft {{name}} ist fehlgeschlagen!", | ||||
|           "achievement_delete_q": "Sind Sie sich sicher, dass Sie das Errungenschaft {{name}} löschen möchten?", | ||||
|           "achievement_deleted": "Errungenschaft gelöscht", | ||||
|           "achievement_deleted_d": "Errungenschaft {{name}} erfolgreich gelöscht", | ||||
|           "achievement_update": "Errungenschaft bearbeitet", | ||||
|           "achievement_update_d": "Errungenschaft {{name}} erfolgreich bearbeitet", | ||||
|           "achievement_update_failed": "Errungenschaft Bearbeitung fehlgeschlagen", | ||||
|           "achievement_update_failed_d": "Die Bearbeitung der Errungenschaft ist fehlgeschlagen!" | ||||
|         } | ||||
|       }, | ||||
|       "members": { | ||||
|         "header": "Mitglieder", | ||||
|         "headers": { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user