조직도 필터 기능 추가.

This commit is contained in:
leejinho 2020-03-06 13:19:23 +09:00
parent 3a591fb351
commit 3cfa9a39ac
7 changed files with 466 additions and 30 deletions

View File

@ -31,9 +31,113 @@
</h3> </h3>
</div> </div>
<div class="organization-option"> <div class="organization-option">
<button mat-icon-button aria-label="more"> <mat-form-field>
<mat-icon>more_vert</mat-icon> <mat-label>{{ 'search.fieldCompany' | translate }}</mat-label>
</button> <mat-select
#filterCompany
[formControl]="fcCompany"
multiple
(openedChange)="onOpenedChange($event)"
>
<mat-select-trigger>
{{ fcCompany.value ? fcCompany.value[0] : '' }}
<span
*ngIf="fcCompany.value?.length > 1"
class="example-additional-selection"
>
(+{{ fcCompany.value.length - 1 }}
{{ fcCompany.value?.length === 2 ? 'other' : 'others' }})
</span>
</mat-select-trigger>
<mat-option
*ngFor="let option of filterCompanyOption"
[value]="option"
>{{ option }}</mat-option
>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'search.fieldGrade' | translate }}</mat-label>
<mat-select
#filterGrade
[formControl]="fcGrade"
multiple
(openedChange)="onOpenedChange($event)"
>
<mat-select-trigger>
{{ fcGrade.value ? fcGrade.value[0] : '' }}
<span
*ngIf="fcGrade.value?.length > 1"
class="example-additional-selection"
>
(+{{ fcGrade.value.length - 1 }}
{{ fcGrade.value?.length === 2 ? 'other' : 'others' }})
</span>
</mat-select-trigger>
<mat-option
*ngFor="let option of filterGradeOption"
[value]="option"
>{{ option }}</mat-option
>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'search.fieldWorkPlace' | translate }}</mat-label>
<mat-select
#filterWorkPlace
[formControl]="fcWorkPlace"
multiple
(openedChange)="onOpenedChange($event)"
>
<mat-select-trigger>
{{ fcWorkPlace.value ? fcWorkPlace.value[0] : '' }}
<span
*ngIf="fcWorkPlace.value?.length > 1"
class="example-additional-selection"
>
(+{{ fcWorkPlace.value.length - 1 }}
{{ fcWorkPlace.value?.length === 2 ? 'other' : 'others' }})
</span>
</mat-select-trigger>
<mat-option
*ngFor="let option of filterWorkPlaceOption"
[value]="option"
>{{ option }}</mat-option
>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'presence.label' | translate }}</mat-label>
<mat-select
#filterPresence
[formControl]="fcPresence"
multiple
(openedChange)="onOpenedChange($event)"
>
<mat-select-trigger>
{{ setFilterOptionSelectedTextPresence() }}
<span
*ngIf="fcPresence.value?.length > 1"
class="example-additional-selection"
>
(+{{ fcPresence.value.length - 1 }}
{{ fcPresence.value?.length === 2 ? 'other' : 'others' }})
</span>
</mat-select-trigger>
<mat-option [value]="StatusCode.OnLine">{{
'presence.online' | translate
}}</mat-option>
<mat-option [value]="StatusCode.Away">{{
'presence.away' | translate
}}</mat-option>
<mat-option [value]="StatusCode.Busy">{{
'presence.statusMessage1' | translate
}}</mat-option>
<mat-option [value]="StatusCode.Offline">{{
'presence.offline' | translate
}}</mat-option>
</mat-select>
</mat-form-field>
</div> </div>
</div> </div>
<div class="progress"> <div class="progress">
@ -50,7 +154,7 @@
<div fxFlex="0 0 auto" class="table-box"> <div fxFlex="0 0 auto" class="table-box">
<ucap-organization-detail-table <ucap-organization-detail-table
[loginRes]="loginRes" [loginRes]="loginRes"
[presence]="presence$ | async" [presence$]="presenceSubject.asObservable()"
[departmentUserInfoList]="departmentUserInfoList" [departmentUserInfoList]="departmentUserInfoList"
[profileImageRoot]="profileImageRoot" [profileImageRoot]="profileImageRoot"
[selectedUserList]="selectedUserList" [selectedUserList]="selectedUserList"

View File

@ -4,7 +4,8 @@ import {
ChangeDetectorRef, ChangeDetectorRef,
OnDestroy, OnDestroy,
Output, Output,
EventEmitter EventEmitter,
ViewChild
} from '@angular/core'; } from '@angular/core';
import { import {
SelectedDept, SelectedDept,
@ -12,7 +13,7 @@ import {
AuthResponse AuthResponse
} from '@ucap-webmessenger/protocol-query'; } from '@ucap-webmessenger/protocol-query';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { DialogService } from '@ucap-webmessenger/ui'; import { DialogService } from '@ucap-webmessenger/ui';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
@ -22,8 +23,8 @@ import * as SettingsStore from '@app/store/messenger/settings';
import * as SyncStore from '@app/store/messenger/sync'; import * as SyncStore from '@app/store/messenger/sync';
import * as ChatStore from '@app/store/messenger/chat'; import * as ChatStore from '@app/store/messenger/chat';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription, BehaviorSubject, merge } from 'rxjs';
import { PresenceType } from '@ucap-webmessenger/core'; import { PresenceType, StatusCode } from '@ucap-webmessenger/core';
import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status'; import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { KEY_VER_INFO, KEY_AUTH_INFO, MainMenu } from '@app/types'; import { KEY_VER_INFO, KEY_AUTH_INFO, MainMenu } from '@app/types';
@ -36,6 +37,10 @@ import {
SelectGroupDialogResult SelectGroupDialogResult
} from '../../dialogs/group/select-group.dialog.component'; } from '../../dialogs/group/select-group.dialog.component';
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
import { FormControl } from '@angular/forms';
import { MatSelect } from '@angular/material/select';
import { MatOption } from '@angular/material/core';
@Component({ @Component({
selector: 'app-layout-messenger-organization', selector: 'app-layout-messenger-organization',
@ -48,10 +53,37 @@ export class OrganizationComponent implements OnInit, OnDestroy {
@Output() @Output()
createConference = new EventEmitter<number[]>(); createConference = new EventEmitter<number[]>();
@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; loginRes: LoginResponse;
loginResSubscription: Subscription; loginResSubscription: Subscription;
sessionVerinfo: VersionInfo2Response; sessionVerinfo: VersionInfo2Response;
authInfo: AuthResponse; authInfo: AuthResponse;
ucapLangChangeSubscription: Subscription;
ucapCurrentLocale: string;
isSearch: boolean; isSearch: boolean;
isSearchSubscription: Subscription; isSearchSubscription: Subscription;
@ -62,25 +94,32 @@ export class OrganizationComponent implements OnInit, OnDestroy {
searchDepartmentUserInfoListSubscription: Subscription; searchDepartmentUserInfoListSubscription: Subscription;
departmentUserInfoList: UserInfoSS[] = []; departmentUserInfoList: UserInfoSS[] = [];
originDepartmentUserInfoList: UserInfoSS[] = [];
selectedUserList: UserInfoSS[] = []; // selected user in departmentUserList detail selectedUserList: UserInfoSS[] = []; // selected user in departmentUserList detail
profileImageRoot: string; profileImageRoot: string;
presence$: Observable<StatusBulkInfo[]>; presenceSubscription: Subscription;
presenceSubject = new BehaviorSubject<StatusBulkInfo[]>(undefined);
PresenceType = PresenceType; PresenceType = PresenceType;
StatusCode = StatusCode;
constructor( constructor(
private store: Store<any>, private store: Store<any>,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private dialogService: DialogService, private dialogService: DialogService,
private translateService: TranslateService, private translateService: TranslateService,
private ucapTranslateService: UCapTranslateService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger private logger: NGXLogger
) { ) {
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>( this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO KEY_VER_INFO
); );
this.authInfo = this.sessionStorageService.get<AuthResponse>(KEY_AUTH_INFO); this.authInfo = this.sessionStorageService.get<AuthResponse>(KEY_AUTH_INFO);
this.ucapCurrentLocale = this.ucapTranslateService.currentLang;
} }
ngOnInit() { ngOnInit() {
@ -93,6 +132,13 @@ export class OrganizationComponent implements OnInit, OnDestroy {
) )
.subscribe(); .subscribe();
this.ucapLangChangeSubscription = this.ucapTranslateService.changedLang.subscribe(
(event: LangChangeEvent) => {
this.ucapCurrentLocale = event.lang;
this.setFilterOptionsLang();
}
);
this.isSearchSubscription = this.store this.isSearchSubscription = this.store
.pipe(select(AppStore.MessengerSelector.QuerySelector.isSearch)) .pipe(select(AppStore.MessengerSelector.QuerySelector.isSearch))
.subscribe(isSearch => { .subscribe(isSearch => {
@ -116,6 +162,12 @@ export class OrganizationComponent implements OnInit, OnDestroy {
.subscribe(list => { .subscribe(list => {
if (!this.isSearch) { if (!this.isSearch) {
this.departmentUserInfoList = list; 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 => { .subscribe(list => {
if (!!this.isSearch) { if (!!this.isSearch) {
this.departmentUserInfoList = list; this.departmentUserInfoList = list;
this.originDepartmentUserInfoList = list;
// filter option add
if (!!list && list.length > 0) {
this.setFilterOptions(list);
}
} }
}); });
this.presence$ = this.store.pipe( this.presenceSubscription = this.store
select(AppStore.MessengerSelector.StatusSelector.selectAllStatusBulkInfo) .pipe(
); select(
AppStore.MessengerSelector.StatusSelector.selectAllStatusBulkInfo
)
)
.subscribe(presence => {
this.presenceSubject.next(presence);
});
this.profileImageRoot = this.sessionVerinfo.profileRoot; this.profileImageRoot = this.sessionVerinfo.profileRoot;
} }
@ -142,6 +206,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
if (!!this.loginResSubscription) { if (!!this.loginResSubscription) {
this.loginResSubscription.unsubscribe(); this.loginResSubscription.unsubscribe();
} }
if (!!this.ucapLangChangeSubscription) {
this.ucapLangChangeSubscription.unsubscribe();
}
if (!!this.isSearchSubscription) { if (!!this.isSearchSubscription) {
this.isSearchSubscription.unsubscribe(); this.isSearchSubscription.unsubscribe();
} }
@ -151,6 +218,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
if (!!this.searchDepartmentUserInfoListSubscription) { if (!!this.searchDepartmentUserInfoListSubscription) {
this.searchDepartmentUserInfoListSubscription.unsubscribe(); this.searchDepartmentUserInfoListSubscription.unsubscribe();
} }
if (!!this.presenceSubscription) {
this.presenceSubscription.unsubscribe();
}
} }
/** Selected User Handling */ /** Selected User Handling */
@ -251,8 +321,249 @@ export class OrganizationComponent implements OnInit, OnDestroy {
const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq); const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq);
this.createConference.emit(targetUserSeqs); this.createConference.emit(targetUserSeqs);
} }
onClickOpenProfile(userSeq: number) { onClickOpenProfile(userSeq: number) {
this.openProfile.emit(userSeq); 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);
}
} }

View File

@ -72,6 +72,10 @@ export const reducer = createReducer(
on(updateSuccess, (state, action) => { on(updateSuccess, (state, action) => {
const curRoomInfo = state.roomInfo; const curRoomInfo = state.roomInfo;
if (!curRoomInfo) {
return { ...state };
}
let roomName = curRoomInfo.roomName; let roomName = curRoomInfo.roomName;
let receiveAlarm = curRoomInfo.receiveAlarm; let receiveAlarm = curRoomInfo.receiveAlarm;

View File

@ -142,6 +142,7 @@
} }
}, },
"presence": { "presence": {
"label": "Status",
"settingOfAwayTime": "Setting of away time", "settingOfAwayTime": "Setting of away time",
"offline": "Offline", "offline": "Offline",
"online": "Online", "online": "Online",

View File

@ -142,6 +142,7 @@
} }
}, },
"presence": { "presence": {
"label": "상태",
"settingOfAwayTime": "부재 중 시간 설정", "settingOfAwayTime": "부재 중 시간 설정",
"offline": "오프라인", "offline": "오프라인",
"online": "온라인", "online": "온라인",

View File

@ -60,14 +60,14 @@
{{ getWorkstatusInfo(element, 'text') }} {{ getWorkstatusInfo(element, 'text') }}
</span> </span>
<span class="name"> <span class="name">
{{ element.name }} {{ element | ucapTranslate: 'name' }}
</span> </span>
<span class="grade"> <span class="grade">
{{ element.grade }} {{ element | ucapTranslate: 'grade' }}
</span> </span>
</div> </div>
<div class="deptName"> <div class="deptName">
{{ element.deptName }} {{ element | ucapTranslate: 'deptName' }}
</div> </div>
</td> </td>
</ng-container> </ng-container>

View File

@ -4,7 +4,8 @@ import {
Input, Input,
Output, Output,
EventEmitter, EventEmitter,
ChangeDetectorRef ChangeDetectorRef,
OnDestroy
} from '@angular/core'; } from '@angular/core';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { UserInfoSS } from '@ucap-webmessenger/protocol-query'; import { UserInfoSS } from '@ucap-webmessenger/protocol-query';
@ -15,13 +16,14 @@ import {
} from '@ucap-webmessenger/protocol-status'; } from '@ucap-webmessenger/protocol-status';
import { Sort } from '@angular/material/sort'; import { Sort } from '@angular/material/sort';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { Observable, Subscription } from 'rxjs';
@Component({ @Component({
selector: 'ucap-organization-detail-table', selector: 'ucap-organization-detail-table',
templateUrl: './detail-table.component.html', templateUrl: './detail-table.component.html',
styleUrls: ['./detail-table.component.scss'] styleUrls: ['./detail-table.component.scss']
}) })
export class DetailTableComponent implements OnInit { export class DetailTableComponent implements OnInit, OnDestroy {
@Input('departmentUserInfoList') @Input('departmentUserInfoList')
set userInfoListIn(userInfo: UserInfoSS[]) { set userInfoListIn(userInfo: UserInfoSS[]) {
this.departmentUserInfoList = userInfo; this.departmentUserInfoList = userInfo;
@ -30,7 +32,7 @@ export class DetailTableComponent implements OnInit {
@Input() @Input()
loginRes: LoginResponse; loginRes: LoginResponse;
@Input() @Input()
presence: StatusBulkInfo[]; presence$: Observable<StatusBulkInfo[]>;
@Input() @Input()
profileImageRoot: string; profileImageRoot: string;
@Input() @Input()
@ -46,6 +48,9 @@ export class DetailTableComponent implements OnInit {
@Output() @Output()
toggleUser = new EventEmitter<UserInfoSS>(); toggleUser = new EventEmitter<UserInfoSS>();
presenceSubscription: Subscription;
presence: StatusBulkInfo[];
departmentUserInfoList: UserInfoSS[]; departmentUserInfoList: UserInfoSS[];
sortedData: UserInfoSS[] = []; sortedData: UserInfoSS[] = [];
@ -64,7 +69,17 @@ export class DetailTableComponent implements OnInit {
private logger: NGXLogger 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 { getPresence(userInfo: UserInfoSS, type: PresenceType): string {
const presences = this.presence.filter(p => p.userSeq === userInfo.seq); const presences = this.presence.filter(p => p.userSeq === userInfo.seq);