Added birthday to wi #401

This commit is contained in:
2023-10-10 18:50:20 +02:00
parent 61bdc8a52a
commit 7aff767a4b
27 changed files with 449 additions and 148 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "kdb-web",
"version": "1.0.dev127_config_in_wi",
"version": "1.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "kdb-web",
"version": "1.0.dev127_config_in_wi",
"version": "1.2.0",
"dependencies": {
"@angular/animations": "^15.1.4",
"@angular/common": "^15.1.4",
@@ -21,7 +21,7 @@
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"@types/socket.io-client": "^3.0.0",
"primeflex": "^3.3.1",
"moment": "^2.29.4",
"primeicons": "^6.0.1",
"primeng": "^15.2.0",
"rxjs": "~7.5.0",
@@ -8157,6 +8157,14 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -9303,11 +9311,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/primeflex": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
"integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ=="
},
"node_modules/primeicons": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "kdb-web",
"version": "1.1.dev402",
"version": "1.2.0",
"scripts": {
"ng": "ng",
"update-version": "ts-node update-version.ts",
@@ -30,6 +30,7 @@
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"@types/socket.io-client": "^3.0.0",
"moment": "^2.29.4",
"primeicons": "^6.0.1",
"primeng": "^15.2.0",
"rxjs": "~7.5.0",
@@ -51,4 +52,4 @@
"tslib": "^2.4.1",
"typescript": "~4.9.5"
}
}
}

View File

@@ -1,23 +1,22 @@
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { JwtModule } from '@auth0/angular-jwt';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { ConfirmationService, MessageService } from 'primeng/api';
import { DialogService } from 'primeng/dynamicdialog';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NotFoundComponent } from './components/error/not-found/not-found.component';
import { FooterComponent } from './components/footer/footer.component';
import { HeaderComponent } from './components/header/header.component';
import { SidebarComponent } from './components/sidebar/sidebar.component';
import { SpinnerComponent } from './components/spinner/spinner.component';
import { SharedModule } from './modules/shared/shared.module';
import { ErrorHandlerService } from './services/error-handler/error-handler.service';
import { SettingsService } from './services/settings/settings.service';
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { JwtModule } from "@auth0/angular-jwt";
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { ConfirmationService, MessageService } from "primeng/api";
import { DialogService } from "primeng/dynamicdialog";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { NotFoundComponent } from "./components/error/not-found/not-found.component";
import { FooterComponent } from "./components/footer/footer.component";
import { HeaderComponent } from "./components/header/header.component";
import { SidebarComponent } from "./components/sidebar/sidebar.component";
import { SpinnerComponent } from "./components/spinner/spinner.component";
import { SharedModule } from "./modules/shared/shared.module";
import { ErrorHandlerService } from "./services/error-handler/error-handler.service";
import { SettingsService } from "./services/settings/settings.service";
@NgModule({
@@ -63,7 +62,7 @@ import { SettingsService } from './services/settings/settings.service';
},
MessageService,
ConfirmationService,
DialogService
DialogService,
],
bootstrap: [AppComponent]
})

View File

@@ -12,8 +12,9 @@ export interface User extends DataWithHistory {
discordId?: number;
name?: string;
xp?: number;
message_count?: number;
reaction_count?: number;
messageCount?: number;
reactionCount?: number;
birthday?: string;
ontime?: number;
level?: Level;
server?: Server;

View File

@@ -1,11 +1,14 @@
export class Mutations {
static updateUser = `
mutation updateUser($id: ID, $xp: Int, $levelId: ID, $userWarnings: [UserWarningInput]) {
mutation updateUser($id: ID, $xp: Int $birthday: String, $levelId: ID, $userWarnings: [UserWarningInput]) {
user {
updateUser(input: { id: $id, xp: $xp, levelId: $levelId, userWarnings: $userWarnings }) {
updateUser(input: { id: $id, xp: $xp, birthday: $birthday, levelId: $levelId, userWarnings: $userWarnings }) {
id
name
xp
messageCount
reactionCount
birthday
level {
id
name

View File

@@ -285,6 +285,9 @@ export class Queries {
discordId
name
xp
messageCount
reactionCount
birthday
ontime
level {
id

View File

@@ -32,8 +32,37 @@ import { HideableHeaderComponent } from './components/hideable-header/hideable-h
import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component';
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
import { InputSwitchModule } from "primeng/inputswitch";
import { CalendarModule } from "primeng/calendar";
const PrimeNGModules = [
ButtonModule,
PasswordModule,
MenuModule,
DialogModule,
ProgressSpinnerModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
ToastModule,
ConfirmDialogModule,
TableModule,
InputTextModule,
CheckboxModule,
DropdownModule,
TranslateModule,
DynamicDialogModule,
PanelMenuModule,
PanelModule,
InputNumberModule,
ImageModule,
SidebarModule,
DataViewModule,
MultiSelectModule,
InputSwitchModule,
CalendarModule,
]
@NgModule({
declarations: [
AuthRolePipe,
@@ -48,66 +77,20 @@ import { InputSwitchModule } from "primeng/inputswitch";
],
imports: [
CommonModule,
ButtonModule,
PasswordModule,
MenuModule,
DialogModule,
ProgressSpinnerModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
ToastModule,
ConfirmDialogModule,
TableModule,
InputTextModule,
CheckboxModule,
DropdownModule,
TranslateModule,
DynamicDialogModule,
PanelMenuModule,
PanelModule,
InputNumberModule,
ImageModule,
SidebarModule,
DataViewModule,
MultiSelectModule,
InputSwitchModule,
...PrimeNGModules
],
exports: [
ButtonModule,
PasswordModule,
MenuModule,
DialogModule,
ProgressSpinnerModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
ToastModule,
ConfirmDialogModule,
TableModule,
InputTextModule,
CheckboxModule,
DropdownModule,
TranslateModule,
DynamicDialogModule,
PanelMenuModule,
PanelModule,
...PrimeNGModules,
AuthRolePipe,
IpAddressPipe,
BoolPipe,
InputNumberModule,
ImageModule,
SidebarModule,
HistoryBtnComponent,
DataViewModule,
DataViewLayoutOptions,
ConfigListComponent,
MultiSelectModule,
HideableColumnComponent,
HideableHeaderComponent,
MultiSelectColumnsComponent,
FeatureFlagListComponent,
InputSwitchModule,
]
})
export class SharedModule {

View File

@@ -204,7 +204,7 @@
<span class="p-column-title">{{'common.level' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
<p-dropdown [options]="levels" [(ngModel)]="member.level" placeholder="{{'common.level' | translate}}"></p-dropdown>
<p-dropdown [options]="levels" [(ngModel)]="member.level" dataKey="id" placeholder="{{'common.level' | translate}}"></p-dropdown>
</ng-template>
<ng-template pTemplate="output">
{{member.level.name}}

View File

@@ -30,7 +30,32 @@
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.xp' | translate}}:</div>
<div class="content-data-value">{{user.xp}}</div>
<div *ngIf="!isEditing" class="content-data-value">{{user.xp}}</div>
<div *ngIf="isModerator && isEditing" class="content-data-value"><input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="user.xp"></div>
</div>
</div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.message_count' | translate}}:</div>
<div class="content-data-value">{{user.messageCount}}</div>
</div>
</div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.reaction_count' | translate}}:</div>
<div class="content-data-value">{{user.reactionCount}}</div>
</div>
</div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.birthday' | translate}}:</div>
<div *ngIf="!isEditing" class="content-data-value">{{user.birthday}}</div>
<div *ngIf="isEditing" class="content-data-value">
<p-calendar [(ngModel)]="user.birthday" dateFormat="dd.mm.yy" [showIcon]="true"></p-calendar>
</div>
</div>
</div>
@@ -41,17 +66,14 @@
</div>
</div>
<!-- <div class="content-row">-->
<!-- <div class="content-column">-->
<!-- <div class="content-data-name">{{'view.server.profile.minecraft_id' | translate}}:</div>-->
<!-- <div class="content-data-value">{{user.minecraftId}}</div>-->
<!-- </div>-->
<!-- </div>-->
<div class="content-row">
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.level' | translate}}:</div>
<div class="content-data-value">{{user.level?.name}}</div>
<div *ngIf="!isEditing" class="content-data-value">{{user.level?.name}}</div>
<div *ngIf="isModerator && isEditing" class="content-data-value">
<p-dropdown [options]="levels" [(ngModel)]="user.level" dataKey="id" placeholder="{{'common.level' | translate}}">
</p-dropdown>
</div>
</div>
</div>
@@ -266,8 +288,12 @@
<div class="content-divider"></div>
<div class="content-row">
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
(click)="updateUser()"></button>
<div style="width: 100%; display: flex; gap: 10px; justify-content: end;">
<button pButton icon="pi pi-edit" label="{{'common.edit' | translate}}" class="btn login-form-submit-btn"
(click)="toogleEditUser()"></button>
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
(click)="updateUser()" [disabled]="!isEditing"></button>
</div>
</div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { Queries } from "../../../../models/graphql/queries.model";
import { UserListQuery, UserWarningQuery } from "../../../../models/graphql/query.model";
import { LevelListQuery, Query, UserListQuery, UserWarningQuery } from "../../../../models/graphql/query.model";
import { SpinnerService } from "../../../../services/spinner/spinner.service";
import { DataService } from "../../../../services/data/data.service";
import { User } from "../../../../models/data/user.model";
@@ -13,10 +13,11 @@ import { Server } from "../../../../models/data/server.model";
import { forkJoin, Subject, throwError } from "rxjs";
import { catchError, takeUntil } from "rxjs/operators";
import { Table } from "primeng/table";
import { UserWarning } from "../../../../models/data/user_warning.model";
import { LevelMutationResult, UpdateUserMutationResult, UserWarningMutationResult } from "../../../../models/graphql/result.model";
import { UpdateUserMutationResult } from "../../../../models/graphql/result.model";
import { Mutations } from "../../../../models/graphql/mutations.model";
import { ConfirmationDialogService } from "../../../../services/confirmation-dialog/confirmation-dialog.service";
import { MenuItem } from "primeng/api";
import { UserWarning } from "../../../../models/data/user_warning.model";
import moment from "moment";
@Component({
selector: "app-profile",
@@ -26,11 +27,13 @@ import { ConfirmationDialogService } from "../../../../services/confirmation-dia
export class ProfileComponent implements OnInit, OnDestroy {
user: User = { createdAt: "", modifiedAt: "" };
levels!: MenuItem[];
private server: Server = {};
private author?: UserDTO;
private clonedUserWarnings: UserWarning[] = [];
public isEditingNewUserWarning: boolean = false;
public isEditing: boolean = false;
public isModerator: boolean = false;
private unsubscriber = new Subject<void>();
@@ -47,6 +50,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
}
public ngOnInit(): void {
this.isEditing = false;
this.loadProfile();
}
@@ -59,6 +63,18 @@ export class ProfileComponent implements OnInit, OnDestroy {
}
this.server = server;
this.data.query<LevelListQuery>(Queries.levelQuery, {
serverId: server.id
},
(data: Query) => {
return data.servers[0];
}
).subscribe(data => {
this.levels = data.levels.map(level => {
return { label: level.name, value: level };
});
});
let authUser = await this.auth.getLoggedInUser();
this.spinner.showSpinner();
let user: UserDTO | null = authUser?.users?.find(u => u.server == server.id) ?? null;
@@ -69,6 +85,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
return;
}
this.author = user;
this.isModerator = user?.isModerator;
this.data.query<UserListQuery>(Queries.userProfile, {
serverId: this.server.id,
@@ -90,7 +107,6 @@ export class ProfileComponent implements OnInit, OnDestroy {
).subscribe(result => {
this.user.userWarningCount = result.userWarningCount;
this.user.userWarnings = result.userWarnings;
console.log(result);
this.spinner.hideSpinner();
});
@@ -99,12 +115,16 @@ export class ProfileComponent implements OnInit, OnDestroy {
});
}
public toogleEditUser() {
this.isEditing = !this.isEditing;
}
public updateUser() {
this.spinner.showSpinner();
this.spinner.showSpinner();
this.data.mutation<UpdateUserMutationResult>(Mutations.updateUser, {
id: this.user.id,
xp: this.user.xp,
birthday: moment(this.user.birthday).format("DD.MM.YYYY"),
levelId: this.user.level?.id,
userWarnings: this.user.userWarnings?.map(userWarning => {
return {
@@ -112,15 +132,17 @@ export class ProfileComponent implements OnInit, OnDestroy {
user: userWarning.user?.id ?? this.user.id,
description: userWarning.description,
author: userWarning.author?.id ?? this.author?.id
}
};
})
}
).pipe(catchError(err => {
this.spinner.hideSpinner();
this.isEditing = false;
return throwError(err);
})).subscribe(_ => {
this.spinner.hideSpinner();
this.toastService.success(this.translate.instant("view.server.members.message.user_changed"), this.translate.instant("view.server.members.message.user_changed_d", { name: this.user.name }));
this.isEditing = false;
this.loadProfile();
});
}
@@ -180,7 +202,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
this.user.joinedVoiceChannels = [];
}
addNewUserWarning(table: Table) {
public addNewUserWarning(table: Table) {
const newWarning: UserWarning = {
description: "",
user: this.user
@@ -200,11 +222,11 @@ export class ProfileComponent implements OnInit, OnDestroy {
this.clonedUserWarnings[index] = { ...user };
}
deleteUserWarning(index: number) {
public deleteUserWarning(index: number) {
this.user.userWarnings?.splice(index, 1);
}
editSaveUserWarning(value: any, index: number) {
public editSaveUserWarning(value: any, index: number) {
this.isEditingNewUserWarning = false;
if (!value.value || !this.user.userWarnings || this.user.userWarnings[index] == this.clonedUserWarnings[index]) {
return;
@@ -213,7 +235,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
delete this.clonedUserWarnings[index];
}
editCancelUserWarning(index: number) {
public editCancelUserWarning(index: number) {
if (this.user.userWarnings) {
this.user.userWarnings[index] = this.clonedUserWarnings[index];
}

View File

@@ -122,6 +122,7 @@
}
},
"common": {
"edit": "Bearbeiten",
"user_warnings": "Verwarnungen",
"author": "Autor",
"404": "404 - Der Eintrag konnte nicht gefunden werden",
@@ -484,6 +485,9 @@
}
},
"profile": {
"message_count": "Anzahl Nachrichten",
"reaction_count": "Anzahl Reaktionen",
"birthday": "Geburtstag",
"achievements": {
"header": "Errungeschaften",
"time": "Erreicht am"

View File

@@ -1,7 +1,7 @@
{
"WebVersion": {
"Major": "1",
"Minor": "1",
"Micro": "dev402"
"Minor": "2",
"Micro": "0"
}
}

View File

@@ -94,8 +94,13 @@ p-table {
}
}
.p-dropdown {
width: 100% !important;
.content-row {
p-dropdown,
.p-dropdown,
p-calendar,
.p-calendar, {
width: 100% !important;
}
}
.pi-sort-alt:before {

View File

@@ -683,4 +683,77 @@
p-inputNumber {
background-color: $primaryBackgroundColor !important;
}
p-calendar > span > button {
background-color: $primaryHeaderColor !important;
border: 1px solid $primaryHeaderColor !important;
&:focus {
box-shadow: none !important;
}
}
.p-calendar {
.p-datepicker:not(.p-datepicker-inline) {
background-color: $secondaryBackgroundColor !important;
}
.p-datepicker {
.p-datepicker-header {
color: $primaryHeaderColor !important;
background-color: $primaryBackgroundColor !important;
.p-datepicker-title .p-datepicker-year,
.p-datepicker-title .p-datepicker-month,
.p-datepicker .p-datepicker-header .p-datepicker-title .p-datepicker-month {
color: $primaryTextColor !important;
&:hover {
color: $primaryHeaderColor !important;
}
&:focus {
box-shadow: none !important;
}
}
}
}
table td > span {
color: $primaryTextColor !important;
&:hover {
color: $primaryHeaderColor !important;
background-color: $primaryBackgroundColor !important;
}
&:focus {
box-shadow: none !important;
}
}
table td.p-datepicker-today > span {
color: $primaryHeaderColor !important;
background-color: $primaryBackgroundColor !important;
}
table td > span.p-highlight {
color: $primaryHeaderColor !important;
background-color: $primaryBackgroundColor !important;
}
.p-yearpicker .p-yearpicker-year,
.p-monthpicker .p-monthpicker-month:not(.p-disabled):not(.p-highlight) {
color: $primaryTextColor !important;
background-color: $secondaryBackgroundColor !important;
&:hover {
color: $primaryHeaderColor !important;
}
&:focus {
box-shadow: none !important;
}
}
}
}