Skip to content

Commit

Permalink
Fixed the bug: if a new changelog notification is opened from the pop…
Browse files Browse the repository at this point in the history
…up, the badge indicating the number of new changelog remains visible
  • Loading branch information
Nicola Lanzilotto committed Dec 27, 2024
1 parent 510e8d4 commit 3b52cbe
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 61 deletions.
178 changes: 131 additions & 47 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { ProjectService } from './services/project.service';
import { HttpClient } from '@angular/common/http';
import { SleekplanSsoService } from './services/sleekplan-sso.service';
import { SleekplanService } from './services/sleekplan.service';
import { SleekplanApiService } from './services/sleekplan-api.service';
// import { UsersService } from './services/users.service';


Expand Down Expand Up @@ -103,9 +104,11 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
private notify: NotifyService,
public usersLocalDbService: LocalDbService,
private projectService: ProjectService,

private sleekplanSsoService: SleekplanSsoService,
private sleekplanService: SleekplanService
private sleekplanService: SleekplanService,
private sleekplanApiService: SleekplanApiService

// public usersService: UsersService,
// private faqKbService: FaqKbService,
) {
Expand Down Expand Up @@ -234,16 +237,97 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
} else {
this.logger.log('[APP-COMPONENT] There is no logged in user')
}

// --------------------------
// Get if page is refreshed
// --------------------------
this.subscription = router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
browserRefresh = !router.navigated;
this.logger.log('APP-COMP browserRefresh ', browserRefresh)
if (browserRefresh === true) {
window.addEventListener('load', () => {
this.logger.log('Page fully loaded');

// Check if there is the sleelplan chagenlog live announcemnt popup
this.checkSPPopupIframeWithRetries(3, 1000); // Retry 3 times with a 1-second delay
});


}
}
});


this.loadStyle(JSON.parse(localStorage.getItem('custom_style')))

}

checkSPPopupIframeWithRetries = (maxRetries = 3, delay = 1000) => {
let attempts = 0;

const checkForIframe = () => {
attempts++;
this.logger.log(`Attempt ${attempts} to find the iframe...`);

const wrapper = document.getElementById('sleek-widget-wrap');

if (wrapper) {
this.logger.log('wrapper', wrapper)
this.observeClassChange('.i-sl-wrapper.right.popup.active', 'expanded', () => {
this.logger.log('The "expanded" class was added!');
this.sleekplanApiService.hasOpenedSPChangelogFromPopup()
});

return; // Stop further retries once the iframe is found
}

if (attempts < maxRetries) {
setTimeout(checkForIframe, delay);
} else {
this.logger.log('Max attempts reached. Iframe not found.');
}
};

checkForIframe();
};


observeClassChange(targetSelector: string, classToDetect: string, callback: () => void): void {
const targetElement = document.querySelector(targetSelector);
this.logger.log('targetElement ', targetElement);
if (!targetElement) {
this.logger.error('Target element not found');
return;
}

// Create a MutationObserver instance
const observer = new MutationObserver((mutationsList) => {

for (const mutation of mutationsList) {
this.logger.log('mutation ', mutation);
if (
mutation.type === 'attributes' &&
mutation.attributeName === 'class'
) {
const element = mutation.target as HTMLElement;

// Check if the target element has the specified class
if (element.classList.contains(classToDetect)) {
this.logger.log(`Class "${classToDetect}" added to the element`);
callback(); // Trigger the callback
observer.disconnect();
}
}
}
});

// Observe the element for class attribute changes
observer.observe(targetElement, { attributes: true });
}



async loadStyle(data) {

if (!data || !data.parameter) {
Expand Down Expand Up @@ -355,13 +439,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
// this.logger.log('[APP-COMPONENT] project from $ubscription ', project)
// // this.current_selected_prjct = project
// this.projectService.getProjects().subscribe((projects: any) => {
// console.log('[APP-COMPONENT] getProjects projects ', projects)
// this.logger.log('[APP-COMPONENT] getProjects projects ', projects)
// if (projects) {
// this.current_selected_prjct_user = projects.find(prj => prj.id_project.id === project._id);
// console.log('[APP-COMPONENT] current_selected_prjct_user ', this.current_selected_prjct_user)
// this.logger.log('[APP-COMPONENT] current_selected_prjct_user ', this.current_selected_prjct_user)

// this.USER_ROLE = this.current_selected_prjct_user.role
// console.log('[APP-COMPONENT] USER_ROLE ', this.USER_ROLE)
// this.logger.log('[APP-COMPONENT] USER_ROLE ', this.USER_ROLE)
// }
// })
// }
Expand Down Expand Up @@ -628,44 +712,44 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
// id: user._id,
// name: user.firstname,
// }

this.sleekplanSsoService.getSsoToken(user).subscribe(
(response) => {
this.logger.log('[APP-COMP] sleekplanSso response ', response)
this.logger.log('[APP-COMP] sleekplanSso response token', response['token'])
// Configure Sleekplan with SSO
// window['Sleekplan'] = {
// id: 'YOUR_SLEEKPLAN_ID',
// sso: response.token,
// };
// window['$sleek'].setUser({
// token: response['token'],
// });
// window.document.addEventListener('sleek:init', () => {
// window['$sleek'].setUser({ token: response['token'] });
// }, false);
// window['$sleek'].sso = { token: response['token'] }
window['SLEEK_USER'] = { token: response['token'] }

// Load the Sleekplan widget
this.sleekplanService.loadSleekplan().then(() => {
this.logger.log('[APP-COMP] - Sleekplan successfully initialized');
})
.catch(err => {
this.logger.error('[APP-COMP] - Sleekplan initialization failed', err);
});
},
(error) => {
this.logger.error('[APP-COMP] - Failed to fetch Sleekplan SSO token', error);
}
(response) => {
this.logger.log('[APP-COMP] sleekplanSso response ', response)
this.logger.log('[APP-COMP] sleekplanSso response token', response['token'])

// Configure Sleekplan with SSO
// window['Sleekplan'] = {
// id: 'YOUR_SLEEKPLAN_ID',
// sso: response.token,
// };

// window['$sleek'].setUser({
// token: response['token'],
// });

// window.document.addEventListener('sleek:init', () => {
// window['$sleek'].setUser({ token: response['token'] });
// }, false);

// window['$sleek'].sso = { token: response['token'] }

window['SLEEK_USER'] = { token: response['token'] }

// Load the Sleekplan widget
this.sleekplanService.loadSleekplan().then(() => {
this.logger.log('[APP-COMP] - Sleekplan successfully initialized');
})
.catch(err => {
this.logger.error('[APP-COMP] - Sleekplan initialization failed', err);
});
},
(error) => {
this.logger.error('[APP-COMP] - Failed to fetch Sleekplan SSO token', error);

}
);
}
}

getCurrentUserAndConnectToWs() {
this.auth.user_bs.subscribe((user) => {
Expand Down Expand Up @@ -913,11 +997,11 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
(this.route.indexOf('/createfaq') !== -1) ||
(this.route.indexOf('/cds') !== -1) ||
(this.route.indexOf('/desktop-access') !== -1) ||
(this.route.indexOf('/desktop--access') !== -1)
(this.route.indexOf('/desktop--access') !== -1)

) {
// && this.USER_ROLE === 'agent'

elemNavbar.setAttribute('style', 'display:none;');
elemAppSidebar.setAttribute('style', 'display:none;');
// margin-top: -70px
Expand All @@ -941,8 +1025,8 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
} else {
// elemSidebarWrapper.style.height = "calc(100vh - 44px)";
elemSidebarWrapper.style.height = "calc(100vh - 60px)";


}

if (this.route.indexOf('/request-for-panel') !== -1) {
Expand Down
43 changes: 29 additions & 14 deletions src/app/components/navbar/navbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { AppConfigService } from '../../services/app-config.service';
// import { public_Key } from '../../utils/util';
// import { environment } from '../../../environments/environment';
import { Subject } from 'rxjs';
import { filter, takeUntil, throttleTime } from 'rxjs/operators'
import { filter, skip, takeUntil, throttleTime } from 'rxjs/operators'
import { Subscription } from 'rxjs'

// import brand from 'assets/brand/brand.json';
Expand Down Expand Up @@ -300,9 +300,10 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft
this.getTestSiteUrl();
this.translateStrings();
this.listenHasDeleteUserProfileImage();


this.listenSoundPreference()
this.listenToLiveAnnouncementOpened()
// this.listenToQuotasReachedInHome()

// this.listenToWSRequestsDataCallBack()
Expand Down Expand Up @@ -2012,7 +2013,7 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft
this.displayLogoutModal = 'none';
}



testExpiredSessionFirebaseLogout() {
this.auth.testExpiredSessionFirebaseLogout(true)
Expand All @@ -2038,7 +2039,7 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft


openFeedback(): void {
// console.log('[NAVBAR] open Sleekplan ', window['Sleekplan'])
// this.logger.log('[NAVBAR] open Sleekplan ', window['Sleekplan'])
// if (window['Sleekplan']?.open) {
// window['Sleekplan'].open();
// }this.user
Expand All @@ -2048,9 +2049,23 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft
const lastSeen = Date.now()
this.logger.log('[NAVBAR] open Sleekplan lastSeen ', lastSeen)
// localStorage.setItem('lastSeenTimestamp', this.lastSeen.toString());
localStorage.setItem(`lastSeenTimestamp-${this.user._id}`,lastSeen.toString())
localStorage.setItem(`lastSeenTimestamp-${this.user._id}`, lastSeen.toString())
this.newChangelogCount = false


}

listenToLiveAnnouncementOpened() {
this.sleekplanApi.hasOpenedChangelogfromPopup$
.pipe(
takeUntil(this.unsubscribe$)
)
.pipe(skip(1))
.subscribe((hasSeenChangelog) => {
this.logger.log('[NAVBAR] listenToLiveAnnouncementOpened hasSeenChangelog', hasSeenChangelog);
const lastSeen = Date.now()
localStorage.setItem(`lastSeenTimestamp-${this.user._id}`, lastSeen.toString())
this.newChangelogCount = false
})
}

fetchNewChangelogCount(user) {
Expand All @@ -2059,7 +2074,7 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft
this.logger.log('[NAVBAR] changelog lastSeen form storedLastSeen', storedLastSeen);
this.logger.log('[NAVBAR] changelog lastSeen form storage type of', typeof storedLastSeen);
let lastSeen = 0
if (storedLastSeen !== null ) {
if (storedLastSeen !== null) {
lastSeen = +storedLastSeen
}
this.sleekplanApi.getNewChangelogCount().subscribe(
Expand All @@ -2069,26 +2084,26 @@ export class NavbarComponent extends PricingBaseComponent implements OnInit, Aft
this.logger.log('[NAVBAR] changelog count resp data ', resp['data']);
this.logger.log('[NAVBAR] changelog count resp data items ', resp['data']['items']);
const data = resp['data']['items']

const firstKey = Object.keys(data)[0]; // Get the first key in the object
const createdValue = data[firstKey].created; // Access the created property

this.logger.log('[NAVBAR] last changelog createdValue ', createdValue);
this.logger.log('[NAVBAR] last changelog createdValue ', createdValue);
const createdValueTimestamp = new Date(createdValue).getTime();
this.logger.log('[NAVBAR] last changelog createdValue as Timestamp ', createdValueTimestamp);
this.logger.log('[NAVBAR] lastSeen ', lastSeen);
if (lastSeen ) {
if (lastSeen) {
if (createdValueTimestamp > lastSeen) {
this.newChangelogCount = true
this.logger.log('[NAVBAR] there is A notification Changelog created at', createdValueTimestamp, ' last seen ', lastSeen , ' newChangelogCount ', this.newChangelogCount);
this.logger.log('[NAVBAR] there is A notification Changelog created at', createdValueTimestamp, ' last seen ', lastSeen, ' newChangelogCount ', this.newChangelogCount);
} else {
this.newChangelogCount = false
this.logger.log('[NAVBAR] there is NOT notification Changelog created at', createdValueTimestamp, ' last seen ', lastSeen , ' newChangelogCount ', this.newChangelogCount);
this.logger.log('[NAVBAR] there is NOT notification Changelog created at', createdValueTimestamp, ' last seen ', lastSeen, ' newChangelogCount ', this.newChangelogCount);
}
} else {
this.newChangelogCount = true;
this.logger.log('[NAVBAR] there is A notification (else) Changelog created at', createdValueTimestamp, ' last seen ', lastSeen , ' newChangelogCount ', this.newChangelogCount);
this.logger.log('[NAVBAR] there is A notification (else) Changelog created at', createdValueTimestamp, ' last seen ', lastSeen, ' newChangelogCount ', this.newChangelogCount);

}
},
(error) => {
Expand Down
7 changes: 7 additions & 0 deletions src/app/services/sleekplan-api.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { LoggerService } from './logger/logger.service';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
Expand All @@ -9,6 +10,8 @@ export class SleekplanApiService {
SLEEKPLAN_API_KEY = '410017437c9fbea3a57b12346860fae9741ad0921'; // The good one
// SLEEKPLAN_API_KEY = '9834831126380f3d69fff6251cd3a690cb97e41ac'; // for test
SLEEKPLAN_API_URL = 'https://api.sleekplan.com/v1/updates';

public hasOpenedChangelogfromPopup$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);

constructor(
private httpClient: HttpClient,
Expand All @@ -33,5 +36,9 @@ export class SleekplanApiService {
return this.httpClient.get(url, httpOptions);
}

hasOpenedSPChangelogFromPopup() {
this.hasOpenedChangelogfromPopup$.next(true)
}


}

0 comments on commit 3b52cbe

Please sign in to comment.