app.component.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import { Component, HostListener, inject, OnInit } from '@angular/core';
  2. import { ActivatedRoute, Router, RouterModule, RouterOutlet, RoutesRecognized } from '@angular/router';
  3. import { MatModule } from '../dependencies/angularlib/mat.module';
  4. import { Angularlib } from 'angularlib/angularlib.module';
  5. import { BaseComponent, untilDestroy } from 'angularlib/base.component';
  6. import { Subject, Subscription, filter, map, repeat, takeUntil, timer } from 'rxjs';
  7. import { Title } from '@angular/platform-browser';
  8. import { LoginService } from 'angularlib/login/login.service';
  9. import { CommonModule, DatePipe } from '@angular/common';
  10. import { ChangeLanguage } from 'angularlib/labels/label.actions';
  11. import { ComponentService } from 'angularlib/component.service';
  12. import { NotificationModule } from 'angularlib/notification/notification.module';
  13. import { NOTIFICATION_STATE_TOKEN } from 'angularlib/notification/notification.state';
  14. import { Notification } from 'angularlib/notification/notification.actions';
  15. import { generateId } from 'angularlib/base.service';
  16. import { Store } from '@ngxs/store';
  17. import config from '../config/config.json';
  18. import { UIAuthActions } from 'angularlib/login/state/login.actions';
  19. import { Platform } from '@angular/cdk/platform';
  20. import { AppSettingsAction } from 'angularlib/ui.state/ui.state.actions';
  21. import { PushNotificationDecorator as LeavePushNotif } from 'fis/leave/decorators/push.notification.decorator';
  22. import { FISMessaging } from 'fis/index';
  23. import { BusinessDataModule } from 'fis/business.data/business.data.module';
  24. import { NotificationService } from 'angularlib/notification/notification.service';
  25. import { env } from 'angularlib/environments/environment';
  26. import { TranslatePipe } from 'angularlib/labels/translate.pipe';
  27. import { ChatComponent } from 'angularlib/chat/chat.component';
  28. @Component({
  29. selector: 'app-root',
  30. imports: [
  31. CommonModule,
  32. RouterOutlet,
  33. MatModule,
  34. RouterModule,
  35. Angularlib,
  36. NotificationModule,
  37. BusinessDataModule,
  38. ChatComponent
  39. ],
  40. providers: [DatePipe, FISMessaging],
  41. templateUrl: './app.component.html',
  42. styleUrls: [
  43. './app.component.scss'
  44. ]
  45. })
  46. export class AppComponent extends BaseComponent implements OnInit {
  47. title = 'Financial Information System';
  48. /**current date */
  49. protected currentDate = new Date();
  50. /**session timeout duration in milliseconds*/
  51. private duration: number = config?.sessionTimeoutDuration;
  52. private startTimeout$ = new Subject();
  53. private stopTimeout$ = new Subject();
  54. private timeout = timer(this.duration).pipe(
  55. map(() => {
  56. if(this.loginService.user){
  57. console.warn('session inactive timeout, logging out...');
  58. this.store.dispatch(new UIAuthActions.RedirectAfterLogin(this.route.snapshot));
  59. this.loginService.logout();
  60. }
  61. }),
  62. takeUntil(this.stopTimeout$),
  63. repeat({delay:() => this.startTimeout$})
  64. );
  65. /**current theme of application */
  66. protected theme;
  67. /**number of notifications */
  68. protected notificationCount: number = 0;
  69. private leavePushNotif$: Subscription;
  70. private messaging = inject(FISMessaging);
  71. private notification = inject(NotificationService);
  72. private tr = inject(TranslatePipe);
  73. protected sampleMap = {
  74. hidden:true,
  75. markers: [
  76. {position:{lat:1.55176,lng:110.33429},title:'Software Optima'}
  77. ],
  78. polygons: [
  79. {paths: [{lat:1.551703,lng:110.334149},{lat:1.551703,lng:110.334409},{lat:1.55222,lng:110.33444},{lat:1.552223,lng:110.33417}],fillColor: "blue",strokeColor:'navy'},
  80. {paths: [{lat:1.55222,lng:110.33413},{lat:1.55224,lng:110.33375},{lat:1.551432,lng:110.333715},{lat:1.551404,lng:110.334387},{lat:1.551685,lng:110.334395},{lat:1.551704,lng:110.334100}],fillColor: "red",strokeColor:'red'}
  81. ]
  82. };
  83. constructor(
  84. private router: Router,
  85. private store: Store,
  86. protected loginService: LoginService,
  87. /**Platform Browser title */
  88. protected pbTitle: Title,
  89. protected cs: ComponentService,
  90. private route: ActivatedRoute,
  91. private platform: Platform
  92. ) {
  93. super(store,cs);
  94. }
  95. @HostListener('window:mousedown')
  96. refreshTimeout() {
  97. this.stopTimeout$.next(null);
  98. this.startTimeout$.next(null);
  99. }
  100. ngOnInit(): void {
  101. this.router.events.pipe(untilDestroy(this),
  102. filter((event) => event instanceof RoutesRecognized),
  103. map((res:any) => {
  104. const data = res.state.root.firstChild.firstChild || res.state.root.firstChild;
  105. return data.data?.title;
  106. })
  107. ).subscribe(title => {
  108. if (typeof title === 'string')
  109. this.title = title;
  110. else this.title = this.getLabel(title?.key,title?.default);
  111. if (env !== 'PROD') this.title += ` (${this.tr.transform('test','Test')})`;
  112. this.pbTitle.setTitle(this.title);
  113. });
  114. this.store.select(NOTIFICATION_STATE_TOKEN).pipe(untilDestroy(this)).subscribe({
  115. next: (state:any) => {
  116. this.notificationCount = state.notifications.length;
  117. }
  118. });
  119. if (this.platform.ANDROID || this.platform.IOS) this.pwaPrompt();
  120. }
  121. ngAfterViewInit() {
  122. /**subsribe user changes and initiate timeout timer */
  123. this.loginService.user$.pipe(untilDestroy(this)).subscribe((user:any) => {
  124. if (user) this.timeout.pipe(untilDestroy(this),takeUntil(this.loginService.loggedOut)).subscribe();
  125. this.subscribePushNotifications();
  126. });
  127. if (this.cs.isMobileClient) this.mobile.init();
  128. }
  129. /**
  130. * change application language
  131. * @param {string} language
  132. */
  133. protected changeLanguage(language: string) {
  134. this.store.dispatch(new ChangeLanguage(language));
  135. if (language.startsWith('en')) this.store.dispatch(new AppSettingsAction.SetLocale('en-MY'));
  136. if (language.startsWith('zh')) this.store.dispatch(new AppSettingsAction.SetLocale('zh-CN'));
  137. if (language.startsWith('ms')) this.store.dispatch(new AppSettingsAction.SetLocale('ms-MY'));
  138. }
  139. protected addNotification() {
  140. this.store.dispatch(new Notification.Add({
  141. message:{title:generateId(),desc:generateId(),timestamp: new Date()}
  142. }));
  143. }
  144. /**prompt to install PWA App */
  145. private pwaPrompt() {
  146. let installPrompt = null;
  147. const installButton = document.querySelector("#installApp");
  148. const disableInAppInstallPrompt = () => {
  149. installPrompt = null;
  150. installButton.setAttribute("hidden","");
  151. }
  152. window.addEventListener("beforeinstallprompt",(event) => {
  153. event.preventDefault();
  154. installPrompt = event;
  155. installButton.removeAttribute("hidden");
  156. });
  157. installButton.addEventListener("click", async () => {
  158. if (!installPrompt) return;
  159. const result = await installPrompt.prompt();
  160. disableInAppInstallPrompt();
  161. });
  162. window.addEventListener("appinstalled", () => {
  163. disableInAppInstallPrompt();
  164. });
  165. }
  166. private subscribePushNotifications() {
  167. if (this.loginService.user?.fisInfo) {
  168. if (this.leavePushNotif$ === undefined) {
  169. this.leavePushNotif$ = new LeavePushNotif(
  170. this,
  171. this.loginService,
  172. this.messaging,
  173. this.notification
  174. ).subscribe();
  175. }
  176. } else {
  177. if (this.leavePushNotif$) this.leavePushNotif$.unsubscribe();
  178. this.leavePushNotif$ = undefined;
  179. }
  180. }
  181. /**mobile controls */
  182. protected mobile = {
  183. /**init mobile controls */
  184. init: () => {
  185. const chatButton = document.getElementById('chat-toggle-button') as HTMLElement;
  186. if (chatButton) chatButton.style.display = 'none';
  187. },
  188. /**toggle chat window */
  189. toggleChat: () => {
  190. const chat = document.getElementById('chat-panel') as HTMLElement;
  191. if (chat) chat.style.display = chat.style.display === 'none' ? 'flex' : 'none';
  192. }
  193. }
  194. }