Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
xPosition="before"
yPosition="below"
>
<div class="notifications-container">
<div class="notifications-container" (mouseenter)="pauseTimer()" (mouseleave)="resumeTimer()">
@if (unreadNotifications.length === 0 && displayedReadNotifications.length === 0) {
<div class="no-notifications">
<mat-icon class="no-notifications-icon">notifications_none</mat-icon>
Expand Down
38 changes: 26 additions & 12 deletions src/app/shared/notifications-tray/notifications-tray.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ export class NotificationsTrayComponent implements OnInit, OnDestroy {
/** Timer to refetch notifications every 60 seconds */
timer: any;

/**
* Gets router link prefix from notification's objectType attribute
* Shares, Savings, Deposits, Loans routes inaccessible because of dependency on entity ID.
*/
/** track if timer is paused */
private timerPaused = false;

routeMap: any = {
client: '/clients/',
group: '/groups/',
Expand Down Expand Up @@ -102,9 +101,6 @@ export class NotificationsTrayComponent implements OnInit, OnDestroy {
clearTimeout(this.timer);
}

/**
* Restructures displayed read notifications vis-a-vis unread notifications.
*/
setNotifications() {
const length = this.unreadNotifications.length;
this.displayedReadNotifications = length < 9 ? this.readNotifications.slice(0, 9 - length) : [];
Expand All @@ -114,16 +110,34 @@ export class NotificationsTrayComponent implements OnInit, OnDestroy {
* Recursively fetch unread notifications.
*/
fetchUnreadNotifications() {
// Clear any existing timer
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

this.notificationsService.getNotifications(false, 9).subscribe((response: any) => {
this.unreadNotifications = this.unreadNotifications.concat(response.pageItems);
this.unreadNotifications = response.pageItems; // Avoid concat duplication
this.setNotifications();
});
// this.mockNotifications(); // Uncomment for Testing.
this.timer = setTimeout(() => {
this.fetchUnreadNotifications();
}, this.waitTime * 1000);

// Schedule next poll ONLY if not paused
if (!this.timerPaused) {
this.timer = setTimeout(() => {
this.fetchUnreadNotifications();
}, this.waitTime * 1000);
}
}

pauseTimer = () => {
this.timerPaused = true;
clearTimeout(this.timer);
};

resumeTimer = () => {
this.timerPaused = false;
this.fetchUnreadNotifications();
};
Comment thread
Nightwing-77 marked this conversation as resolved.
/**
* Update read/unread notifications.
*/
Expand Down
55 changes: 51 additions & 4 deletions src/app/web-app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import { Component, OnInit, HostListener, HostBinding, OnDestroy } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatSnackBar, MatSnackBarRef } from '@angular/material/snack-bar';
import { MatDialog } from '@angular/material/dialog';

/** rxjs Imports */
Expand Down Expand Up @@ -59,6 +59,7 @@ import localeNE from '@angular/common/locales/ne';
import localePT from '@angular/common/locales/pt';
import localeSW from '@angular/common/locales/sw';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';

registerLocaleData(localeCS);
registerLocaleData(localeEN);
registerLocaleData(localeES);
Expand Down Expand Up @@ -209,14 +210,17 @@ export class WebAppComponent implements OnInit, OnDestroy {
localStorage.setItem('mifosXLocation', JSON.stringify(activities));
});

// Setup alerts
// Setup alerts with hover behavior
this.alertService.alertEvent.subscribe((alertEvent: Alert) => {
this.snackBar.open(`${alertEvent.message}`, 'Close', {
duration: 2000,
const snackBarRef = this.snackBar.open(`${alertEvent.message}`, 'Close', {
duration: 0, // Set to 0 - no auto-dismiss initially
horizontalPosition: 'right',
verticalPosition: 'top'
});
// Handle hover behavior
this.handleSnackbarHover(snackBarRef, 2000);
});

this.buttonConfig = new KeyboardShortcutsConfiguration();

// initialize language and date format if they are null.
Expand Down Expand Up @@ -258,6 +262,49 @@ export class WebAppComponent implements OnInit, OnDestroy {
}
}

/**
* Handle snackbar hover behavior - pause dismiss on hover, resume on leave
* @param snackBarRef Reference to the snackbar
* @param defaultDuration Default duration in milliseconds before auto-dismiss
*/
private handleSnackbarHover(snackBarRef: MatSnackBarRef<any>, defaultDuration: number): void {
snackBarRef
.afterOpened()
.pipe(take(1))
.subscribe(() => {
const snackbarContainer = document.querySelector('.mat-mdc-snack-bar-container');
if (!snackbarContainer) {
snackBarRef.dismiss();
return;
}

let dismissTimer: any;

// Start the auto-dismiss timer
const startDismissTimer = () => {
dismissTimer = setTimeout(() => {
snackBarRef.dismiss();
}, defaultDuration);
};

// Pause auto-dismiss on hover (mouseenter)
snackbarContainer.addEventListener('mouseenter', () => {
if (dismissTimer) {
clearTimeout(dismissTimer);
dismissTimer = null;
}
});

// Resume auto-dismiss when cursor leaves (mouseleave)
snackbarContainer.addEventListener('mouseleave', () => {
startDismissTimer();
});

// Start initial timer
startDismissTimer();
});
}

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
Expand Down
Loading