refactor: use reactive breakpoints with observables and constants in ResizeService

This commit is contained in:
Chneemann 2025-04-12 09:49:41 +02:00
parent ab6c4ce2b9
commit 815b8ef605
7 changed files with 76 additions and 22 deletions

View file

@ -12,7 +12,7 @@ import { ApiService } from '../../services/api.service';
import { Task } from '../../interfaces/task.interface';
import { TaskService } from '../../services/task.service';
import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner/loading-spinner.component';
import { debounceTime, finalize, Subject, takeUntil } from 'rxjs';
import { debounceTime, finalize, Subject, take, takeUntil } from 'rxjs';
import { UpdateNotifierService } from '../../services/update-notifier.service';
import { ToastNotificationService } from '../../services/toast-notification.service';
import { ResizeService } from '../../services/resize.service';
@ -48,6 +48,7 @@ export class BoardComponent implements OnInit, OnDestroy {
isLoading = false;
private destroy$ = new Subject<void>();
private pageViewMedia$ = this.resizeService.pageViewMedia$;
constructor(
public dragDropService: DragDropService,
@ -143,9 +144,11 @@ export class BoardComponent implements OnInit, OnDestroy {
* @param status The status to be used for the new task.
*/
addNewTaskOverlay(status: string) {
this.resizeService.isPageViewMedia
? this.router.navigate(['/add-task', status])
: this.overlayService.setOverlayData('newTaskOverlay', status);
this.pageViewMedia$.pipe(take(1)).subscribe((isPageViewMedia) => {
isPageViewMedia
? this.router.navigate(['/add-task', status])
: this.overlayService.setOverlayData('newTaskOverlay', status);
});
}
/**

View file

@ -13,7 +13,7 @@
>
{{ task.category }}
</div>
@if (resizeService.isPageViewMedia) {
@if (pageViewMedia$ | async) {
<div class="menu-btn" (click)="handleMenuButtonClick($event, task.id)">
<img
class="menu-img"

View file

@ -6,6 +6,7 @@ import { OverlayService } from '../../../services/overlay.service';
import { Router } from '@angular/router';
import { TaskMenuComponent } from './task-menu/task-menu.component';
import { ResizeService } from '../../../services/resize.service';
import { take } from 'rxjs';
@Component({
selector: 'app-task',
@ -16,6 +17,7 @@ import { ResizeService } from '../../../services/resize.service';
})
export class TaskComponent {
@Input() task: Task = {} as Task;
isMenuOpen: boolean = false;
AssignedDialogId: string = '';
dialogX: number = 0;
@ -23,12 +25,13 @@ export class TaskComponent {
creator: any = '';
assignees: any[] = [];
categoryColors = new Map<string, string>([
['User Story', '#0038ff'],
['Technical Task', '#20d7c2'],
]);
pageViewMedia$ = this.resizeService.pageViewMedia$;
constructor(
public dragDropService: DragDropService,
public overlayService: OverlayService,
@ -72,9 +75,11 @@ export class TaskComponent {
if (this.isMenuOpen) {
this.toggleTaskMenu();
}
this.resizeService.isPageViewMedia
? this.router.navigate(['/task', taskId])
: this.overlayService.setOverlayData('taskOverlay', taskId);
this.pageViewMedia$.pipe(take(1)).subscribe((isPageViewMedia) => {
isPageViewMedia
? this.router.navigate(['/task', taskId])
: this.overlayService.setOverlayData('taskOverlay', taskId);
});
}
@HostListener('document:click', ['$event'])

View file

@ -132,7 +132,7 @@ export class ContactsComponent implements OnInit, OnDestroy {
@HostListener('window:resize', ['$event'])
onResize() {
if (window.innerWidth <= 1150 && this.selectedUserId != undefined) {
if (window.innerWidth <= 1000 && this.selectedUserId != undefined) {
this.showAllUsers = false;
} else {
this.showAllUsers = true;

View file

@ -1,29 +1,73 @@
import { Injectable } from '@angular/core';
import { Injectable, OnDestroy } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class ResizeService {
isPageViewMedia: boolean = window.innerWidth <= 650;
isContactViewMedia: boolean = window.innerWidth <= 800;
export class ResizeService implements OnDestroy {
private readonly PAGE_VIEW_BREAKPOINT = 650;
private readonly CONTACT_VIEW_BREAKPOINT = 800;
private pageViewMediaSubject = new BehaviorSubject<boolean>(
window.innerWidth <= this.PAGE_VIEW_BREAKPOINT
);
private contactViewMediaSubject = new BehaviorSubject<boolean>(
window.innerWidth <= this.CONTACT_VIEW_BREAKPOINT
);
pageViewMedia$ = this.pageViewMediaSubject.asObservable();
contactViewMedia$ = this.contactViewMediaSubject.asObservable();
private resizeListener!: () => void;
/**
* Initializes the resize event listener, which updates the media query subjects
* based on the current window width whenever the window is resized.
*/
constructor() {
this.initResizeListener();
}
private initResizeListener() {
/**
* Cleans up resources by removing the resize event listener,
* ensuring that no memory leaks occur when the service is no longer in use.
*/
ngOnDestroy(): void {
this.cleanup();
}
/**
* Initializes the resize event listener.
*
* This method binds the onResize method to the resizeListener and adds it as an event listener
* for the window's resize event. This allows the service to respond to changes in window size
* by updating the relevant media query subjects.
*/
private initResizeListener(): void {
this.resizeListener = this.onResize.bind(this);
window.addEventListener('resize', this.resizeListener);
}
private onResize() {
this.isPageViewMedia = window.innerWidth <= 650;
this.isContactViewMedia = window.innerWidth <= 800;
/**
* Updates the media query subjects based on the current window width.
*
* This method checks the window's inner width against predefined breakpoints
* and updates the pageViewMediaSubject and contactViewMediaSubject accordingly.
* It is triggered whenever a window resize event occurs.
*/
private onResize(): void {
this.pageViewMediaSubject.next(
window.innerWidth <= this.PAGE_VIEW_BREAKPOINT
);
this.contactViewMediaSubject.next(
window.innerWidth <= this.CONTACT_VIEW_BREAKPOINT
);
}
cleanup() {
/**
* Remove the event listener for window resizing.
*/
cleanup(): void {
window.removeEventListener('resize', this.resizeListener);
}
}

View file

@ -22,7 +22,7 @@
autocomplete="off"
required
/>
@if (resizeService.isContactViewMedia) {
@if (contactViewMedia$ | async) {
<div class="error-msg">
@if (firstName.hasError('pattern') && firstName.touched) {
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
@ -48,7 +48,7 @@
required
/>
</div>
@if (resizeService.isContactViewMedia) {
@if (contactViewMedia$ | async) {
<div class="error-msg">
@if (lastName.hasError('pattern') && lastName.touched) {
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
@ -56,7 +56,7 @@
<p>{{ "contactDialogForm.invalidLastName" | translate }}</p>
}}
</div>
} @if (!resizeService.isContactViewMedia) {
} @else {
<div class="error-msg">
@if (firstName.hasError('pattern') || lastName.hasError('pattern') &&
firstName.touched) {

View file

@ -63,6 +63,8 @@ export class ContactFormComponent implements OnInit, OnChanges {
lastLogin: 0,
};
contactViewMedia$ = this.resizeService.contactViewMedia$;
/**
* OnInit lifecycle hook.
*