import { Component, OnInit, Inject, OnDestroy, ChangeDetectorRef, NgZone, ViewChild } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { KEY_VER_INFO, MainMenu, KEY_AUTH_INFO } from '@app/types'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { Store, select } from '@ngrx/store'; import * as AppStore from '@app/store'; import * as QueryStore from '@app/store/messenger/query'; import * as ChatStore from '@app/store/messenger/chat'; import * as SettingsStore from '@app/store/messenger/settings'; import * as SyncStore from '@app/store/messenger/sync'; import { UserInfoSS, AuthResponse } from '@ucap-webmessenger/protocol-query'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { map, take, tap, catchError } from 'rxjs/operators'; import { Subscription, Observable, BehaviorSubject, of } from 'rxjs'; import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types'; import { NGXLogger } from 'ngx-logger'; import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native'; import { environment } from '../../../../../environments/environment'; import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { DaesangProtocolService } from '@ucap-webmessenger/daesang'; import { DialogService, AlertDialogComponent, AlertDialogData, AlertDialogResult, ConfirmDialogComponent, ConfirmDialogData, ConfirmDialogResult, TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui'; import { ProfileDialogComponent, ProfileDialogData, ProfileDialogResult } from '../profile/profile.dialog.component'; import { SelectGroupDialogComponent, SelectGroupDialogData, SelectGroupDialogResult } from '../group/select-group.dialog.component'; import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; import { GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { ConferenceService, PromptMessageStatusCode, CallService } from '@ucap-webmessenger/api-prompt'; import { MessageWriteDialogComponent, MessageWriteDialogResult, MessageWriteDialogData } from '../message/message-write.dialog.component'; import { MatSelect } from '@angular/material/select'; import { FormControl } from '@angular/forms'; import { StatusCode } from '@ucap-webmessenger/core'; import { MatOption } from '@angular/material/core'; export interface IntegratedSearchDialogData { keyword: string; } export interface IntegratedSearchDialogResult { clear: boolean; } @Component({ selector: 'app-integrated-search.dialog', templateUrl: './integrated-search.dialog.component.html', styleUrls: ['./integrated-search.dialog.component.scss'] }) export class IntegratedSearchDialogComponent implements OnInit, OnDestroy { loginRes: LoginResponse; loginResSubscription: Subscription; sessionVerinfo: VersionInfo2Response; environmentsInfo: EnvironmentsInfo; authInfo: AuthResponse; ucapLangChangeSubscription: Subscription; ucapCurrentLocale: string; searchDepartmentUserInfoListSubscription: Subscription; searchingProcessing$: Observable; departmentUserInfoList: UserInfoSS[] = []; originDepartmentUserInfoList: UserInfoSS[] = []; selectedUserList: UserInfoSS[] = []; // selected user in departmentUserList detail profileImageRoot: string; presenceSubscription: Subscription; presenceSubject = new BehaviorSubject(undefined); currentSearchWord: string; StatusCode = StatusCode; @ViewChild('filterCompany', { static: false }) filterCompany: MatSelect; filterCompanyOption: string[] = []; fcCompany = new FormControl(); @ViewChild('filterGrade', { static: false }) filterGrade: MatSelect; filterGradeOption: string[] = []; filterGradeOptionSet: { value: string[]; valueEn: string[]; valueCn: string[]; } = { value: [], valueEn: [], valueCn: [] }; fcGrade = new FormControl(); @ViewChild('filterWorkPlace', { static: false }) filterWorkPlace: MatSelect; filterWorkPlaceOption: string[] = []; fcWorkPlace = new FormControl(); @ViewChild('filterPresence', { static: false }) filterPresence: MatSelect; fcPresence = new FormControl(); constructor( public dialogRef: MatDialogRef< IntegratedSearchDialogData, IntegratedSearchDialogResult >, @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService, @Inject(MAT_DIALOG_DATA) public data: IntegratedSearchDialogData, private sessionStorageService: SessionStorageService, private daesangProtocolService: DaesangProtocolService, private dialogService: DialogService, private translateService: TranslateService, private ucapTranslateService: UCapTranslateService, private conferenceService: ConferenceService, private callService: CallService, private store: Store, private changeDetectorRef: ChangeDetectorRef, private logger: NGXLogger, private ngZone: NgZone ) { this.environmentsInfo = this.sessionStorageService.get( KEY_ENVIRONMENTS_INFO ); this.authInfo = this.sessionStorageService.get(KEY_AUTH_INFO); this.sessionVerinfo = this.sessionStorageService.get( KEY_VER_INFO ); this.ucapCurrentLocale = this.ucapTranslateService.currentLang; } ngOnInit() { this.profileImageRoot = this.sessionVerinfo.profileRoot; this.loginResSubscription = this.store .pipe( select(AppStore.AccountSelector.AuthenticationSelector.loginRes), tap(loginRes => { this.loginRes = loginRes; }) ) .subscribe(); this.ucapLangChangeSubscription = this.ucapTranslateService.changedLang.subscribe( (event: LangChangeEvent) => { this.ucapCurrentLocale = event.lang; this.setFilterOptionsLang(); } ); this.searchDepartmentUserInfoListSubscription = this.store .pipe( select( AppStore.MessengerSelector.QuerySelector .integrateSearchDepartmentUserInfoList ) ) .subscribe(list => { this.departmentUserInfoList = list; this.originDepartmentUserInfoList = list; // filter option add if (!!list && list.length > 0) { this.setFilterOptions(list); } }); this.searchingProcessing$ = this.store.pipe( select( AppStore.MessengerSelector.QuerySelector .integrateSearchDepartmentProcessing ) ); this.presenceSubscription = this.store .pipe( select( AppStore.MessengerSelector.StatusSelector.selectAllStatusBulkInfo ) ) .subscribe(presence => { this.presenceSubject.next(presence); }); this.onSearch(this.data.keyword); } ngOnDestroy(): void { if (!!this.loginResSubscription) { this.loginResSubscription.unsubscribe(); } if (!!this.ucapLangChangeSubscription) { this.ucapLangChangeSubscription.unsubscribe(); } if (!!this.searchDepartmentUserInfoListSubscription) { this.searchDepartmentUserInfoListSubscription.unsubscribe(); } if (!!this.presenceSubscription) { this.presenceSubscription.unsubscribe(); } } onSearch(searchWord: string) { if (this.currentSearchWord !== searchWord) { this.currentSearchWord = searchWord; } if (searchWord.trim().length > 0) { this.store.dispatch( QueryStore.integrateSearchDeptUser({ companyCode: this.loginRes.companyCode, search: searchWord.trim() }) ); } else { // clear list. this.store.dispatch(QueryStore.integrateClearSearchDeptUser({})); } } /** Selected User Handling */ onToggleAllUser(params: { isChecked: boolean; userInfos: UserInfoSS[] }) { params.userInfos.forEach(userInfo => { if (params.isChecked) { if ( this.selectedUserList.filter(user => user.seq === userInfo.seq) .length === 0 ) { this.selectedUserList = [...this.selectedUserList, userInfo]; } } else { this.selectedUserList = this.selectedUserList.filter( user => user.seq !== userInfo.seq ); } }); } onToggleUser(userInfo: UserInfoSS) { if (userInfo.seq === this.loginRes.userSeq) { return; } if ( this.selectedUserList.filter(user => user.seq === userInfo.seq).length === 0 ) { this.selectedUserList = [...this.selectedUserList, userInfo]; } else { this.selectedUserList = this.selectedUserList.filter( item => item.seq !== userInfo.seq ); } this.changeDetectorRef.detectChanges(); } /** Handling chipset for selectedUserList */ onClickDeleteUser(userInfo: UserInfoSS) { this.selectedUserList = this.selectedUserList.filter( item => item.seq !== userInfo.seq ); this.changeDetectorRef.detectChanges(); } /** Handling Button */ async onClickAddGroup() { this.logger.debug('onClickAddGroup', this.selectedUserList); const result = await this.dialogService.open< SelectGroupDialogComponent, SelectGroupDialogData, SelectGroupDialogResult >(SelectGroupDialogComponent, { width: '600px', data: { title: this.translateService.instant('group.selectTargetGroup') } }); if (!!result && !!result.choice && result.choice) { if (!!result.group) { const oldGroup: GroupDetailData = result.group; const trgtUserSeq: number[] = []; result.group.userSeqs.map(seq => trgtUserSeq.push(seq)); this.selectedUserList .filter(v => result.group.userSeqs.indexOf(v.seq) < 0) .forEach(user => { trgtUserSeq.push(user.seq); }); this.store.dispatch( SyncStore.updateGroupMember({ oldGroup, trgtUserSeq }) ); } } } onClickChatOpen() { if (!!this.selectedUserList && this.selectedUserList.length > 0) { // Open Room. const seq: number[] = []; this.selectedUserList.map(user => seq.push(user.seq)); this.store.dispatch(ChatStore.openRoom({ userSeqList: seq })); // GNB Change to Chat this.store.dispatch( SettingsStore.selectedGnbMenuIndex({ menuIndex: MainMenu.Chat }) ); this.onClickHide(); } } onClickConference() { const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq); if (!!targetUserSeqs && targetUserSeqs.length > 0) { this.conferenceService.conferenceCreate({ userSeq: this.loginRes.userSeq, deviceType: this.environmentsInfo.deviceType, tokenKey: this.loginRes.tokenString, targetUserSeqs }); } } onClickMessage() { this.ngZone.run(() => { const receiverList: UserInfoSS[] = this.selectedUserList.slice(); if (receiverList.length > 0) { this.dialogService.open< MessageWriteDialogComponent, MessageWriteDialogData, MessageWriteDialogResult >(MessageWriteDialogComponent, { width: '600px', height: '600px', disableClose: true, hasBackdrop: false, data: { loginRes: this.loginRes, environmentsInfo: this.environmentsInfo, receiverList } }); } }); } onClickOpenProfile(userSeq: number) { if (!userSeq || userSeq < 0) { return; } this.daesangProtocolService .dataUserDaesang({ divCd: 'OPENPROF', seq: userSeq, senderCompanyCode: this.loginRes.userInfo.companyCode, senderEmployeeType: this.loginRes.userInfo.employeeType }) .pipe( take(1), map(async res => { if (!!res && !!res.userInfo) { const result = await this.dialogService.open< ProfileDialogComponent, ProfileDialogData, ProfileDialogResult >(ProfileDialogComponent, { maxWidth: '90vw', height: '500px', data: { userInfo: res.userInfo } }); if (!!result) { if (!!result.closeEvent && result.closeEvent === 'CHAT') { this.onCancel(); } } } }) ) .subscribe(); } async onClickCall(calleeNumber: string) { const madn = this.loginRes.madn; if (!madn || madn.trim().length === 0) { this.dialogService.open< AlertDialogComponent, AlertDialogData, AlertDialogResult >(AlertDialogComponent, { panelClass: 'miniSize-dialog', data: { title: this.translateService.instant('call.errors.label'), html: this.translateService.instant('call.errors.cannotCallToUser') } }); return false; } calleeNumber = calleeNumber.replace(/\D/g, ''); if (!!calleeNumber && calleeNumber.length > 0) { // const result = await this.dialogService.open< // ConfirmDialogComponent, // ConfirmDialogData, // ConfirmDialogResult // >(ConfirmDialogComponent, { // width: '360px', // data: { // title: this.translateService.instant('call.callTo'), // html: this.translateService.instant('call.callWithNumber', { // phoneNumber: calleeNumber // }) // } // }); // if (!!result && !!result.choice && result.choice) { this.callService .sendCall({ userSeq: this.loginRes.userSeq, deviceType: this.environmentsInfo.deviceType, tokenKey: this.loginRes.tokenString, calleeNumber }) .pipe( take(1), map(res => { if (res.responseCode === PromptMessageStatusCode.Success) { this.logger.debug('SUCCESS'); this.logger.debug(res); } else { this.logger.error(res); } }), catchError(error => of(this.logger.debug(error))) ) .subscribe(); // } } else { this.dialogService.open< AlertDialogComponent, AlertDialogData, AlertDialogResult >(AlertDialogComponent, { panelClass: 'miniSize-dialog', data: { title: this.translateService.instant('call.errors.label'), html: this.translateService.instant( 'call.errors.cannotCallToUserWithoutPhomeNumber' ) } }); } } onClickHide(): void { this.dialogRef.addPanelClass('hideDialog'); } onCancel(): void { this.dialogRef.close({ clear: true }); } /** Handling Filters */ setFilterOptions(list: UserInfoSS[]) { // option set this.filterCompanyOption = []; this.filterGradeOption = []; this.filterGradeOptionSet = { value: [], valueEn: [], valueCn: [] }; this.filterWorkPlaceOption = []; list.forEach(info => { if (!!info.companyName) { this.filterCompanyOption.push(info.companyName); } if (!!info.grade) { this.filterGradeOptionSet.value.push(info.grade); } if (!!info.gradeEn) { this.filterGradeOptionSet.valueEn.push(info.gradeEn); } if (!!info.gradeCn) { this.filterGradeOptionSet.valueCn.push(info.gradeCn); } if (!!info.workplace) { this.filterWorkPlaceOption.push(info.workplace); } }); // remove duplication. if (!!this.filterCompanyOption && this.filterCompanyOption.length > 0) { this.filterCompanyOption = this.filterCompanyOption.reduce( (unique, item) => (unique.includes(item) ? unique : [...unique, item]), [] ); } if ( !!this.filterGradeOptionSet && this.filterGradeOptionSet.value && this.filterGradeOptionSet.value.length > 0 ) { this.filterGradeOptionSet.value = this.filterGradeOptionSet.value.reduce( (unique, item) => (unique.includes(item) ? unique : [...unique, item]), [] ); } if ( !!this.filterGradeOptionSet && this.filterGradeOptionSet.valueEn && this.filterGradeOptionSet.valueEn.length > 0 ) { this.filterGradeOptionSet.valueEn = this.filterGradeOptionSet.valueEn.reduce( (unique, item) => (unique.includes(item) ? unique : [...unique, item]), [] ); } if ( !!this.filterGradeOptionSet && this.filterGradeOptionSet.valueCn && this.filterGradeOptionSet.valueCn.length > 0 ) { this.filterGradeOptionSet.valueCn = this.filterGradeOptionSet.valueCn.reduce( (unique, item) => (unique.includes(item) ? unique : [...unique, item]), [] ); } if (!!this.filterWorkPlaceOption && this.filterWorkPlaceOption.length > 0) { this.filterWorkPlaceOption = this.filterWorkPlaceOption.reduce( (unique, item) => (unique.includes(item) ? unique : [...unique, item]), [] ); } this.setFilterOptionsLang(); } setFilterOptionsLang() { const ucapLang = this.ucapCurrentLocale; switch (ucapLang) { case 'en': this.filterGradeOption = !!this.filterGradeOptionSet.valueEn && this.filterGradeOptionSet.valueEn.length > 0 ? this.filterGradeOptionSet.valueEn.slice() : []; break; case 'cn': this.filterGradeOption = !!this.filterGradeOptionSet.valueCn && this.filterGradeOptionSet.valueCn.length > 0 ? this.filterGradeOptionSet.valueCn.slice() : []; break; default: // ko this.filterGradeOption = !!this.filterGradeOptionSet.value && this.filterGradeOptionSet.value.length > 0 ? this.filterGradeOptionSet.value.slice() : []; this.filterGradeOption = this.filterGradeOptionSet.value.slice(); } } setFilterOptionSelectedTextPresence() { let firstPresence = ''; if (!this.filterPresence) { return firstPresence; } const presences = this.filterPresence.selected as MatOption[]; if (!!presences && presences.length > 0) { firstPresence = presences[0].value; } switch (firstPresence) { case StatusCode.OnLine: firstPresence = this.translateService.instant('presence.online'); break; case StatusCode.Away: firstPresence = this.translateService.instant('presence.away'); break; case StatusCode.Busy: firstPresence = this.translateService.instant( 'presence.statusMessage1' ); break; case StatusCode.Offline: firstPresence = this.translateService.instant('presence.offline'); break; } return firstPresence; } onOpenedChange(isOpened: boolean) { // only close action. if (!isOpened) { this.filteredDeptUserList(); } } filteredDeptUserList() { const companies = this.filterCompany.selected as MatOption[]; const grades = this.filterGrade.selected as MatOption[]; const workplaces = this.filterWorkPlace.selected as MatOption[]; const presences = this.filterPresence.selected as MatOption[]; let isMulti = false; if (!!companies && companies.length > 0) { const data = !isMulti ? this.originDepartmentUserInfoList : this.departmentUserInfoList; isMulti = true; this.departmentUserInfoList = data.filter(userInfo => { if ( companies .map(option => option.value) .some(opt => opt === userInfo.companyName) ) { return true; } return false; }); } if (!!grades && grades.length > 0) { const data = !isMulti ? this.originDepartmentUserInfoList : this.departmentUserInfoList; isMulti = true; this.departmentUserInfoList = data.filter(userInfo => { if ( grades .map(option => option.value) .some(opt => { let trgtGrade = userInfo.grade; if (this.ucapCurrentLocale === 'en') { trgtGrade = userInfo.gradeEn; } else if (this.ucapCurrentLocale === 'cn') { trgtGrade = userInfo.gradeCn; } return opt === trgtGrade; }) ) { return true; } return false; }); } if (!!workplaces && workplaces.length > 0) { const data = !isMulti ? this.originDepartmentUserInfoList : this.departmentUserInfoList; isMulti = true; this.departmentUserInfoList = data.filter(userInfo => { if ( workplaces .map(option => option.value) .some(opt => opt === userInfo.workplace) ) { return true; } return false; }); } if (!!presences && presences.length > 0) { const data = !isMulti ? this.originDepartmentUserInfoList : this.departmentUserInfoList; isMulti = true; this.departmentUserInfoList = data.filter(userInfo => { const userPresences = this.presenceSubject.value.filter( presence => presence.userSeq === userInfo.seq ); let userPresence = StatusCode.Offline; if (!!userPresences && userPresences.length > 0) { userPresence = userPresences[0].pcStatus; } if ( presences .map(option => option.value) .some(opt => { return opt === userPresence; }) ) { return true; } return false; }); } if (!isMulti) { this.departmentUserInfoList = this.originDepartmentUserInfoList.slice(); } // // reset filterOption by data filtered. // this.setFilterOptions(this.departmentUserInfoList); } }