diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/main-contents/organization.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/main-contents/organization.component.html index 407640fb..42541ded 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/main-contents/organization.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/main-contents/organization.component.html @@ -31,9 +31,113 @@
- + + {{ 'search.fieldCompany' | translate }} + + + {{ fcCompany.value ? fcCompany.value[0] : '' }} + + (+{{ fcCompany.value.length - 1 }} + {{ fcCompany.value?.length === 2 ? 'other' : 'others' }}) + + + {{ option }} + + + + {{ 'search.fieldGrade' | translate }} + + + {{ fcGrade.value ? fcGrade.value[0] : '' }} + + (+{{ fcGrade.value.length - 1 }} + {{ fcGrade.value?.length === 2 ? 'other' : 'others' }}) + + + {{ option }} + + + + {{ 'search.fieldWorkPlace' | translate }} + + + {{ fcWorkPlace.value ? fcWorkPlace.value[0] : '' }} + + (+{{ fcWorkPlace.value.length - 1 }} + {{ fcWorkPlace.value?.length === 2 ? 'other' : 'others' }}) + + + {{ option }} + + + + {{ 'presence.label' | translate }} + + + {{ setFilterOptionSelectedTextPresence() }} + + (+{{ fcPresence.value.length - 1 }} + {{ fcPresence.value?.length === 2 ? 'other' : 'others' }}) + + + {{ + 'presence.online' | translate + }} + {{ + 'presence.away' | translate + }} + {{ + 'presence.statusMessage1' | translate + }} + {{ + 'presence.offline' | translate + }} + +
@@ -50,7 +154,7 @@
(); + @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(); + loginRes: LoginResponse; loginResSubscription: Subscription; sessionVerinfo: VersionInfo2Response; authInfo: AuthResponse; + ucapLangChangeSubscription: Subscription; + ucapCurrentLocale: string; isSearch: boolean; isSearchSubscription: Subscription; @@ -62,25 +94,32 @@ export class OrganizationComponent implements OnInit, OnDestroy { searchDepartmentUserInfoListSubscription: Subscription; departmentUserInfoList: UserInfoSS[] = []; + originDepartmentUserInfoList: UserInfoSS[] = []; selectedUserList: UserInfoSS[] = []; // selected user in departmentUserList detail profileImageRoot: string; - presence$: Observable; + presenceSubscription: Subscription; + presenceSubject = new BehaviorSubject(undefined); PresenceType = PresenceType; + StatusCode = StatusCode; constructor( private store: Store, private sessionStorageService: SessionStorageService, private dialogService: DialogService, private translateService: TranslateService, + private ucapTranslateService: UCapTranslateService, private changeDetectorRef: ChangeDetectorRef, private logger: NGXLogger ) { this.sessionVerinfo = this.sessionStorageService.get( KEY_VER_INFO ); + this.authInfo = this.sessionStorageService.get(KEY_AUTH_INFO); + + this.ucapCurrentLocale = this.ucapTranslateService.currentLang; } ngOnInit() { @@ -93,6 +132,13 @@ export class OrganizationComponent implements OnInit, OnDestroy { ) .subscribe(); + this.ucapLangChangeSubscription = this.ucapTranslateService.changedLang.subscribe( + (event: LangChangeEvent) => { + this.ucapCurrentLocale = event.lang; + this.setFilterOptionsLang(); + } + ); + this.isSearchSubscription = this.store .pipe(select(AppStore.MessengerSelector.QuerySelector.isSearch)) .subscribe(isSearch => { @@ -116,6 +162,12 @@ export class OrganizationComponent implements OnInit, OnDestroy { .subscribe(list => { if (!this.isSearch) { this.departmentUserInfoList = list; + this.originDepartmentUserInfoList = list; + + // filter option add + if (!!list && list.length > 0) { + this.setFilterOptions(list); + } } }); @@ -128,12 +180,24 @@ export class OrganizationComponent implements OnInit, OnDestroy { .subscribe(list => { if (!!this.isSearch) { this.departmentUserInfoList = list; + this.originDepartmentUserInfoList = list; + + // filter option add + if (!!list && list.length > 0) { + this.setFilterOptions(list); + } } }); - this.presence$ = this.store.pipe( - select(AppStore.MessengerSelector.StatusSelector.selectAllStatusBulkInfo) - ); + this.presenceSubscription = this.store + .pipe( + select( + AppStore.MessengerSelector.StatusSelector.selectAllStatusBulkInfo + ) + ) + .subscribe(presence => { + this.presenceSubject.next(presence); + }); this.profileImageRoot = this.sessionVerinfo.profileRoot; } @@ -142,6 +206,9 @@ export class OrganizationComponent implements OnInit, OnDestroy { if (!!this.loginResSubscription) { this.loginResSubscription.unsubscribe(); } + if (!!this.ucapLangChangeSubscription) { + this.ucapLangChangeSubscription.unsubscribe(); + } if (!!this.isSearchSubscription) { this.isSearchSubscription.unsubscribe(); } @@ -151,6 +218,9 @@ export class OrganizationComponent implements OnInit, OnDestroy { if (!!this.searchDepartmentUserInfoListSubscription) { this.searchDepartmentUserInfoListSubscription.unsubscribe(); } + if (!!this.presenceSubscription) { + this.presenceSubscription.unsubscribe(); + } } /** Selected User Handling */ @@ -251,8 +321,249 @@ export class OrganizationComponent implements OnInit, OnDestroy { const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq); this.createConference.emit(targetUserSeqs); } - onClickOpenProfile(userSeq: number) { this.openProfile.emit(userSeq); } + + /** 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) { + isMulti = true; + const data = !!isMulti + ? this.originDepartmentUserInfoList + : this.departmentUserInfoList; + + 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) { + isMulti = true; + const data = !!isMulti + ? this.originDepartmentUserInfoList + : this.departmentUserInfoList; + + 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) { + isMulti = true; + const data = !!isMulti + ? this.originDepartmentUserInfoList + : this.departmentUserInfoList; + + 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) { + isMulti = true; + const data = !!isMulti + ? this.originDepartmentUserInfoList + : this.departmentUserInfoList; + + 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); + } } diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/room/reducers.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/room/reducers.ts index bba3bec5..b9d15f7c 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/room/reducers.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/room/reducers.ts @@ -72,6 +72,10 @@ export const reducer = createReducer( on(updateSuccess, (state, action) => { const curRoomInfo = state.roomInfo; + if (!curRoomInfo) { + return { ...state }; + } + let roomName = curRoomInfo.roomName; let receiveAlarm = curRoomInfo.receiveAlarm; diff --git a/projects/ucap-webmessenger-app/src/assets/i18n/en.json b/projects/ucap-webmessenger-app/src/assets/i18n/en.json index 54728b02..f7169da3 100644 --- a/projects/ucap-webmessenger-app/src/assets/i18n/en.json +++ b/projects/ucap-webmessenger-app/src/assets/i18n/en.json @@ -142,6 +142,7 @@ } }, "presence": { + "label": "Status", "settingOfAwayTime": "Setting of away time", "offline": "Offline", "online": "Online", diff --git a/projects/ucap-webmessenger-app/src/assets/i18n/ko.json b/projects/ucap-webmessenger-app/src/assets/i18n/ko.json index 44f1bff8..8d660134 100644 --- a/projects/ucap-webmessenger-app/src/assets/i18n/ko.json +++ b/projects/ucap-webmessenger-app/src/assets/i18n/ko.json @@ -142,6 +142,7 @@ } }, "presence": { + "label": "상태", "settingOfAwayTime": "부재 중 시간 설정", "offline": "오프라인", "online": "온라인", @@ -364,16 +365,16 @@ } }, "conference": { - "detailView": "상세 보기", - "videoConferenceTypeNow": "[화상회의] 개설", - "videoConferenceTypeNew": "[화상회의] 예약", - "videoConferenceTypeUpdate": "[화상회의] 수정", - "videoConferenceTypeDelete": "[화상회의] 삭제", - "videoConferenceRegister": "개설자", - "videoConferenceAttendee": "참여자", - "videoConferenceDate": "날짜", - "videoConferenceRoom": "회의실", - "videoConferenceEnjoy": "참석하기" + "detailView": "상세 보기", + "videoConferenceTypeNow": "[화상회의] 개설", + "videoConferenceTypeNew": "[화상회의] 예약", + "videoConferenceTypeUpdate": "[화상회의] 수정", + "videoConferenceTypeDelete": "[화상회의] 삭제", + "videoConferenceRegister": "개설자", + "videoConferenceAttendee": "참여자", + "videoConferenceDate": "날짜", + "videoConferenceRoom": "회의실", + "videoConferenceEnjoy": "참석하기" }, "update": { "label": "업데이트" diff --git a/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.html b/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.html index 1bd36d22..e5771efe 100644 --- a/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.html +++ b/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.html @@ -60,14 +60,14 @@ {{ getWorkstatusInfo(element, 'text') }} - {{ element.name }} + {{ element | ucapTranslate: 'name' }} - {{ element.grade }} + {{ element | ucapTranslate: 'grade' }}
- {{ element.deptName }} + {{ element | ucapTranslate: 'deptName' }}
diff --git a/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.ts b/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.ts index 1b2a248d..2b101df2 100644 --- a/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.ts +++ b/projects/ucap-webmessenger-ui-organization/src/lib/components/detail-table.component.ts @@ -4,7 +4,8 @@ import { Input, Output, EventEmitter, - ChangeDetectorRef + ChangeDetectorRef, + OnDestroy } from '@angular/core'; import { NGXLogger } from 'ngx-logger'; import { UserInfoSS } from '@ucap-webmessenger/protocol-query'; @@ -15,13 +16,14 @@ import { } from '@ucap-webmessenger/protocol-status'; import { Sort } from '@angular/material/sort'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; +import { Observable, Subscription } from 'rxjs'; @Component({ selector: 'ucap-organization-detail-table', templateUrl: './detail-table.component.html', styleUrls: ['./detail-table.component.scss'] }) -export class DetailTableComponent implements OnInit { +export class DetailTableComponent implements OnInit, OnDestroy { @Input('departmentUserInfoList') set userInfoListIn(userInfo: UserInfoSS[]) { this.departmentUserInfoList = userInfo; @@ -30,7 +32,7 @@ export class DetailTableComponent implements OnInit { @Input() loginRes: LoginResponse; @Input() - presence: StatusBulkInfo[]; + presence$: Observable; @Input() profileImageRoot: string; @Input() @@ -46,6 +48,9 @@ export class DetailTableComponent implements OnInit { @Output() toggleUser = new EventEmitter(); + presenceSubscription: Subscription; + presence: StatusBulkInfo[]; + departmentUserInfoList: UserInfoSS[]; sortedData: UserInfoSS[] = []; @@ -64,7 +69,17 @@ export class DetailTableComponent implements OnInit { private logger: NGXLogger ) {} - ngOnInit() {} + ngOnInit() { + this.presenceSubscription = this.presence$.subscribe(presence => { + this.presence = presence; + }); + } + + ngOnDestroy(): void { + if (!!this.presenceSubscription) { + this.presenceSubscription.unsubscribe(); + } + } getPresence(userInfo: UserInfoSS, type: PresenceType): string { const presences = this.presence.filter(p => p.userSeq === userInfo.seq);