diff --git a/src/app/dashboard/components/sections/admin-settings/admin-settings.component.ts b/src/app/dashboard/components/sections/admin-settings/admin-settings.component.ts index 2adb832..c3a26d4 100644 --- a/src/app/dashboard/components/sections/admin-settings/admin-settings.component.ts +++ b/src/app/dashboard/components/sections/admin-settings/admin-settings.component.ts @@ -1,5 +1,12 @@ /* eslint-disable max-lines */ -import { Component, inject, OnDestroy } from '@angular/core'; +import { + Component, + EventEmitter, + inject, + Input, + OnDestroy, + Output, +} from '@angular/core'; import { ModalComponent } from '../../shared/modal.component'; import { AdministrationEndpointsService } from '@endpoints/administration-endpoints.service'; import { NotificationService } from 'app/shared/services/notification.service'; @@ -15,137 +22,154 @@ import { RouterLink } from '@angular/router'; standalone: true, imports: [ModalComponent, CommonModule, AllowedRolesDirective, RouterLink], template: ` -

- Administration settings -

+
- - - -
- @if (modalVisibility !== null) { - -
-

- {{ modalTitle }} -

-
- -
- @if ( - modalVisibility === 'banUnbanUser' && selectedUserData !== null - ) { -
- - -
- } @else if ( - modalVisibility === 'changeUserRole' && selectedUserData !== null - ) { -
- Current user role:  - {{ - selectedUserData.role - }} -
-
- Choose new role:  - + + @for (user of usersList; track user.id) { + + }
- } @else if ( - modalVisibility === 'getUserDetails' && selectedUserData !== null - ) { - - Check user details - - } - @if (modalButtonText !== null) { + @if ( + modalVisibility === 'banUnbanUser' && selectedUserData !== null + ) { +
+ + +
+ } @else if ( + modalVisibility === 'changeUserRole' && selectedUserData !== null + ) { +
+ Current user role:  + {{ + selectedUserData.role + }} +
+
+ Choose new role:  + +
+ } @else if ( + modalVisibility === 'getUserDetails' && selectedUserData !== null + ) { + + Check user details + + } + @if (modalButtonText !== null) { + + } - } - -
- @if (errorMessage !== null) { -

{{ errorMessage }}

- } +
+ @if (errorMessage !== null) { +

{{ errorMessage }}

+ } +
-
-
- } + + } + `, }) export class AdminSettingsComponent implements OnDestroy { + @Input({ required: true }) public isOptionsVisible = false; + @Output() public optionsVisibleEmitter = new EventEmitter(); + private _adminEndpointsService = inject(AdministrationEndpointsService); private _notificationService = inject(NotificationService); @@ -170,6 +194,13 @@ export class AdminSettingsComponent implements OnDestroy { public modalButtonText: string | null = ''; public modalButtonFunction!: () => void; + public showOptions(): void { + this.isOptionsVisible = !this.isOptionsVisible; + if (this.isOptionsVisible) { + this.optionsVisibleEmitter.emit('admin'); + } + } + public setSelectedUser(event: Event): void { const target = event.target as HTMLSelectElement; const selectedId = parseInt(target?.value, 10); diff --git a/src/app/dashboard/components/sections/courses-settings/courses-settings.component.ts b/src/app/dashboard/components/sections/courses-settings/courses-settings.component.ts index ec07ef1..5e669af 100644 --- a/src/app/dashboard/components/sections/courses-settings/courses-settings.component.ts +++ b/src/app/dashboard/components/sections/courses-settings/courses-settings.component.ts @@ -1,5 +1,12 @@ /* eslint-disable max-lines */ -import { Component, inject, OnDestroy } from '@angular/core'; +import { + Component, + EventEmitter, + inject, + Input, + OnDestroy, + Output, +} from '@angular/core'; import { ModalComponent } from '../../shared/modal.component'; import { ICourseRequest, @@ -19,107 +26,124 @@ import { NotificationService } from 'app/shared/services/notification.service'; standalone: true, imports: [ModalComponent, ReactiveFormsModule], template: ` -

- Courses settings -

+
- - - -
- @if (modalVisibility !== null) { - -
-

- {{ modalTitle }} -

-
- @if (modalVisibility === 'addNewCourse') { -
- - -
- } @else if ( - (modalVisibility === 'editCourse' || - modalVisibility === 'removeCourse') && - courseList !== null - ) { - - } - @if (modalVisibility === 'editCourse') { -
- - -
- } -
- - -
- @if (errorMessage !== null) { -

{{ errorMessage }}

- } + class="relative ease-in-out duration-150 transition-all {{ + isOptionsVisible + ? 'top-0 opacity-100 z-30 h-fit' + : '-top-32 xs:-top-16 opacity-0 -z-50 h-0' + }}"> +
+ + + +
+ @if (modalVisibility !== null) { + +
+

+ {{ modalTitle }} +

+
+ @if (modalVisibility === 'addNewCourse') { +
+ + +
+ } @else if ( + (modalVisibility === 'editCourse' || + modalVisibility === 'removeCourse') && + courseList !== null + ) { + + } + @if (modalVisibility === 'editCourse') { +
+ + +
+ } +
+ + +
+ @if (errorMessage !== null) { +

{{ errorMessage }}

+ } +
-
- - } + + } +
`, }) export class CoursesSettingsComponent implements OnDestroy { + @Input({ required: true }) public isOptionsVisible = false; + @Output() public optionsVisibleEmitter = new EventEmitter(); + private _courseEndpointsService = inject(CourseEndpointsService); private _notificationService = inject(NotificationService); private _formBuilder = inject(NonNullableFormBuilder); @@ -148,6 +172,13 @@ export class CoursesSettingsComponent implements OnDestroy { editedCourseName: ['', [Validators.required]], }); + public showOptions(): void { + this.isOptionsVisible = !this.isOptionsVisible; + if (this.isOptionsVisible) { + this.optionsVisibleEmitter.emit('courses'); + } + } + public setSelectedCourseId(event: Event): void { const target = event.target as HTMLSelectElement; const selectedId = target?.value; diff --git a/src/app/dashboard/components/sections/game-handling-options/game-handling-options.component.ts b/src/app/dashboard/components/sections/game-handling-options/game-handling-options.component.ts index d52fbf2..0068081 100644 --- a/src/app/dashboard/components/sections/game-handling-options/game-handling-options.component.ts +++ b/src/app/dashboard/components/sections/game-handling-options/game-handling-options.component.ts @@ -1,5 +1,13 @@ /* eslint-disable max-lines */ -import { Component, inject, OnDestroy, OnInit } from '@angular/core'; +import { + Component, + EventEmitter, + inject, + Input, + OnDestroy, + OnInit, + Output, +} from '@angular/core'; import { ModalComponent } from '../../shared/modal.component'; import { GameEndpointsService } from '@endpoints/game-endpoints.service'; import { NotificationService } from 'app/shared/services/notification.service'; @@ -16,127 +24,144 @@ import { standalone: true, imports: [ModalComponent, ReactiveFormsModule], template: ` -

- Game handling options -

+
- - - -
- @if (modalVisibility !== null) { - -
-

- {{ modalTitle }} -

-
- @if (modalVisibility === 'addNewGame') { -
- - - - -
- } @else if ( - (modalVisibility === 'editGame' || - modalVisibility === 'removeGame') && - gameList !== null - ) { - - } - @if (modalVisibility === 'editGame') { -
- - - - -
- } -
- - -
- @if (errorMessage !== null) { -

{{ errorMessage }}

- } + class="relative ease-in-out duration-150 transition-all {{ + isOptionsVisible + ? 'top-0 opacity-100 z-30 h-fit' + : '-top-32 xs:-top-16 opacity-0 -z-50 h-0' + }}"> +
+ + + +
+ @if (modalVisibility !== null) { + +
+

+ {{ modalTitle }} +

+
+ @if (modalVisibility === 'addNewGame') { +
+ + + + +
+ } @else if ( + (modalVisibility === 'editGame' || + modalVisibility === 'removeGame') && + gameList !== null + ) { + + } + @if (modalVisibility === 'editGame') { +
+ + + + +
+ } +
+ + +
+ @if (errorMessage !== null) { +

{{ errorMessage }}

+ } +
-
- - } + + } +
`, }) export class GameHandlingOptionsComponent implements OnDestroy { + @Input({ required: true }) public isOptionsVisible = false; + @Output() public optionsVisibleEmitter = new EventEmitter(); + private _gameEndpointsService = inject(GameEndpointsService); private _notificationService = inject(NotificationService); private _formBuilder = inject(NonNullableFormBuilder); @@ -165,6 +190,13 @@ export class GameHandlingOptionsComponent implements OnDestroy { public modalButtonText = ''; public modalButtonFunction!: () => void; + public showOptions(): void { + this.isOptionsVisible = !this.isOptionsVisible; + if (this.isOptionsVisible) { + this.optionsVisibleEmitter.emit('game-handling'); + } + } + public setSelectedGameId(event: Event): void { const target = event.target as HTMLSelectElement; const selectedId = target?.value; diff --git a/src/app/dashboard/components/sections/user-account-settings/user-account-settings.component.ts b/src/app/dashboard/components/sections/user-account-settings/user-account-settings.component.ts index d526126..16539b0 100644 --- a/src/app/dashboard/components/sections/user-account-settings/user-account-settings.component.ts +++ b/src/app/dashboard/components/sections/user-account-settings/user-account-settings.component.ts @@ -3,6 +3,7 @@ import { Component, EventEmitter, inject, + Input, OnDestroy, Output, } from '@angular/core'; @@ -29,217 +30,235 @@ import { TRole } from 'app/shared/models/role.enum'; standalone: true, imports: [ModalComponent, ReactiveFormsModule], template: ` -

- My account settings -

+
- - - -
- @if (modalVisibility !== null) { - -
-

- {{ modalTitle }} -

- @if (modalVisibility === 'changePassword') { -
-
- - -
-
- - -
-
- } @else if (modalVisibility === 'editAccount') { -
-
- - -
- @if (userData!.role !== teacherRole) { -
-
- - -
-
- - -
+ class="relative ease-in-out duration-150 transition-all {{ + isOptionsVisible + ? 'top-0 opacity-100 z-30 h-fit' + : '-top-32 xs:-top-16 opacity-0 -z-50 h-0' + }}"> +
+ + + +
+ @if (modalVisibility !== null) { + +
+

+ {{ modalTitle }} +

+ @if (modalVisibility === 'changePassword') { + +
+ +
New password - +
+ + } @else if (modalVisibility === 'editAccount') { +
Name
- } -
- } @else if (modalVisibility === 'deleteAccount') { -

- You will lose all your data, progress, and saved games and will - not be able to undo it. -

-

- Are you sure about this action? It can't be undone later! -

- } - - - @if ( - (changePasswordForm.invalid && - (changePasswordForm.dirty || changePasswordForm.touched)) || - errorMessage !== null - ) { -
- @for (error of getFormErrors(); track error) { - @if (modalVisibility === 'changePassword') { -

{{ error }}

+ @if (userData?.role !== teacherRole) { +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
} - } - @if (errorMessage !== null) { -

{{ errorMessage }}

- } -
- } - @if ( - (accountDataForm.invalid && - (accountDataForm.dirty || accountDataForm.touched)) || - errorMessage !== null - ) { -
- @for (error of getFormErrorsAccountData(); track error) { - @if (modalVisibility === 'editAccount') { -

{{ error }}

+ + } @else if (modalVisibility === 'deleteAccount') { +

+ You will lose all your data, progress, and saved games and will + not be able to undo it. +

+

+ Are you sure about this action? It can't be undone later! +

+ } + + + @if ( + (changePasswordForm.invalid && + (changePasswordForm.dirty || changePasswordForm.touched)) || + errorMessage !== null + ) { +
+ @for (error of getFormErrors(); track error) { + @if (modalVisibility === 'changePassword') { +

{{ error }}

+ } } - } -
- } -
- - } + @if (errorMessage !== null) { +

{{ errorMessage }}

+ } +
+ } + @if ( + (accountDataForm.invalid && + (accountDataForm.dirty || accountDataForm.touched)) || + errorMessage !== null + ) { +
+ @for (error of getFormErrorsAccountData(); track error) { + @if (modalVisibility === 'editAccount') { +

{{ error }}

+ } + } +
+ } +
+ + } +
`, }) export class UserAccountSettingsComponent implements OnDestroy { + @Input({ required: true }) public isOptionsVisible = false; + @Output() public optionsVisibleEmitter = new EventEmitter(); @Output() public refreshUserData = new EventEmitter(false); private _formBuilder = inject(NonNullableFormBuilder); @@ -283,6 +302,13 @@ export class UserAccountSettingsComponent implements OnDestroy { public modalButtonText = ''; public modalButtonFunction!: () => void; + public showOptions(): void { + this.isOptionsVisible = !this.isOptionsVisible; + if (this.isOptionsVisible) { + this.optionsVisibleEmitter.emit('user-account'); + } + } + public shouldShowError(controlName: string): boolean | undefined { return this._formValidationService.shouldShowError( this.changePasswordForm, @@ -419,6 +445,7 @@ export class UserAccountSettingsComponent implements OnDestroy { courseId: formValues.courseId, group: formValues.group ? formValues.group : null, }; + console.log(userInfo); this._editAccountSubscribtion = this._userEndpointsService .updateAccountInfo(userInfo) .subscribe({ diff --git a/src/app/dashboard/components/sections/user-info/user-info.component.ts b/src/app/dashboard/components/sections/user-info/user-info.component.ts index f8adcf3..ebfaf4d 100644 --- a/src/app/dashboard/components/sections/user-info/user-info.component.ts +++ b/src/app/dashboard/components/sections/user-info/user-info.component.ts @@ -50,7 +50,7 @@ import { ProgressCircleBarComponent } from '../../shared/progress-circle-bar.com

Your course of study: - {{ aboutMeUserInfo?.course }} + {{ aboutMeUserInfo?.course?.name }}

} diff --git a/src/app/dashboard/dashboard.page.component.ts b/src/app/dashboard/dashboard.page.component.ts index 95710f0..0411df7 100644 --- a/src/app/dashboard/dashboard.page.component.ts +++ b/src/app/dashboard/dashboard.page.component.ts @@ -21,6 +21,7 @@ import { RecordedGamesComponent } from './components/sections/recorded-games/rec import { AllowedRolesDirective } from '@utils/directives/allowed-roles.directive'; import { TRole } from 'app/shared/models/role.enum'; import { CoursesSettingsComponent } from './components/sections/courses-settings/courses-settings.component'; +import { AuthRequiredDirective } from '@utils/directives/auth-required.directive'; @Component({ selector: 'app-dashboard-page', @@ -32,29 +33,42 @@ import { CoursesSettingsComponent } from './components/sections/courses-settings AdminSettingsComponent, RecordedGamesComponent, AllowedRolesDirective, + AuthRequiredDirective, CoursesSettingsComponent, ], template: `
+ class="flex flex-col overflow-y-hidden space-y-10 sm:space-y-16 font-mono w-full bg-mainGray pt-6 pb-12 xl:pt-14"> + (refreshDataEmitter)="userStatsRefresh($event)" + class="flex flex-col px-10" />
- + class="flex flex-col px-10 w-full" /> + + [isOptionsVisible]="optionChoosen === 'game-handling'" + (optionsVisibleEmitter)="changeOptionsVisibility($event)" + class="flex flex-col px-10 w-full" /> + [isOptionsVisible]="optionChoosen === 'admin'" + (optionsVisibleEmitter)="changeOptionsVisibility($event)" + class="flex flex-col px-10 w-full" />
`, }) @@ -73,10 +87,36 @@ export class DashboardPageComponent public allowedRolesAdmin: TRole[] = [TRole.Admin]; public allowedRolesAdminTeacher: TRole[] = [TRole.Admin, TRole.Teacher]; + public optionChoosen: + | 'user-account' + | 'courses' + | 'game-handling' + | 'admin' + | null = null; + public ngOnInit(): void { this.getMeData(); } + public changeOptionsVisibility(option: string): void { + switch (option) { + case 'user-account': + this.optionChoosen = 'user-account'; + break; + case 'courses': + this.optionChoosen = 'courses'; + break; + case 'game-handling': + this.optionChoosen = 'game-handling'; + break; + case 'admin': + this.optionChoosen = 'admin'; + break; + default: + break; + } + } + public getMeData(): void { this._getMeSubscription = this._authEndpointsService.getMe().subscribe({ next: (response: IUserResponse) => {