조직도 detail > 그룹에 추가, 대화, 화상회의 연결.

This commit is contained in:
leejinho 2020-03-05 14:53:42 +09:00
parent e7356b3ad3
commit bf351bf690
8 changed files with 304 additions and 72 deletions

View File

@ -15,6 +15,7 @@
<app-layout-messenger-organization
(openProfile)="onClickOpenProfile($event)"
(createConference)="onClickConferenceCreate($event)"
[style.display]="
MainMenu.Organization === (this.gnbMenuIndex$ | async) ? 'block' : 'none'
"

View File

@ -1,6 +1,5 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs';
import { OpenProfileOptions } from '@ucap-webmessenger/protocol-buddy';
import * as AppStore from '@app/store';
import { select, Store } from '@ngrx/store';
@ -24,6 +23,9 @@ export class MainContentsComponent implements OnInit {
@Output()
closeRightDrawer = new EventEmitter();
@Output()
createConference = new EventEmitter<number[]>();
MainMenu = MainMenu;
gnbMenuIndex$: Observable<string>;
@ -42,4 +44,8 @@ export class MainContentsComponent implements OnInit {
onCloseRightDrawer() {
this.closeRightDrawer.emit();
}
onClickConferenceCreate(userSeqs: number[]) {
this.createConference.emit(userSeqs);
}
}

View File

@ -24,7 +24,7 @@
<ng-container *ngIf="!!(isSearch | async)">
{{ 'common.searchResult' | translate
}}<span class="text-accent-color"
>({{ selectedDepartmentUserInfoList.length }}
>({{ departmentUserInfoList.length }}
{{ 'common.units.persons' | translate }})</span
>
</ng-container>
@ -49,10 +49,14 @@
<div fxFlex="auto" class="organization-content">
<div fxFlex="0 0 auto" class="table-box">
<ucap-organization-detail-table
[loginRes]="loginRes"
[presence]="presence$ | async"
[selectedDepartmentUserInfoList]="selectedDepartmentUserInfoList"
[departmentUserInfoList]="departmentUserInfoList"
[profileImageRoot]="profileImageRoot"
[selectedUserList]="selectedUserList"
(openProfile)="onClickOpenProfile($event)"
(toggleAllUser)="onToggleAllUser($event)"
(toggleUser)="onToggleUser($event)"
class="detail-table"
></ucap-organization-detail-table>
</div>
@ -63,22 +67,60 @@
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Personal data
{{ 'organization.selectedUser' | translate }}
<span *ngIf="selectedUserList.length > 0">
({{ selectedUserList.length }})
{{ 'common.units.persons' | translate }}
</span>
</mat-panel-title>
<mat-panel-description>
Type your name and age
</mat-panel-description>
<mat-panel-description> </mat-panel-description>
</mat-expansion-panel-header>
<mat-form-field>
<mat-label>First name</mat-label>
<input matInput />
</mat-form-field>
<mat-form-field>
<mat-label>Age</mat-label>
<input matInput type="number" min="1" />
</mat-form-field>
<div class="list-chip">
<mat-chip-list aria-label="User selection">
<mat-chip
*ngFor="let userInfo of selectedUserList"
(removed)="onClickDeleteUser(userInfo)"
>
{{ userInfo.name }}
<mat-icon matChipRemove>clear</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
<div class="btn-box">
<ul>
<li>
<button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickAddGroup()"
class="mat-primary"
>
{{ 'organization.addToGroup' | translate }}
</button>
</li>
<li>
<button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickChatOpen()"
class="mat-primary"
>
{{ 'organization.startChat' | translate }}
</button>
</li>
<li *ngIf="!!authInfo && authInfo.canVideoConference">
<button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickConference()"
class="mat-primary"
>
{{ 'organization.startVideoConference' | translate }}
</button>
</li>
</ul>
</div>
</mat-expansion-panel>
</mat-accordion>
</div>

View File

@ -103,3 +103,36 @@
width: 100%;
}
}
.btn-box {
padding: 10px;
button {
width: 100%;
@include ellipsis(1);
span {
vertical-align: baseline;
}
}
ul {
display: flex;
flex-flow: row;
align-content: space-between;
margin-top: 4px;
li {
display: inline-flex;
align-items: center;
flex-grow: 1;
width: 33%;
margin-right: 4px;
&:last-child {
margin-right: 0;
}
button {
text-align: center;
width: 100%;
height: 100%;
padding: 0 6px;
}
}
}
}

View File

@ -6,7 +6,11 @@ import {
Output,
EventEmitter
} from '@angular/core';
import { SelectedDept, UserInfoSS } from '@ucap-webmessenger/protocol-query';
import {
SelectedDept,
UserInfoSS,
AuthResponse
} from '@ucap-webmessenger/protocol-query';
import { NGXLogger } from 'ngx-logger';
import { TranslateService } from '@ngx-translate/core';
import { DialogService } from '@ucap-webmessenger/ui';
@ -25,8 +29,16 @@ import {
WorkStatusType
} from '@ucap-webmessenger/protocol-status';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { KEY_VER_INFO } from '@app/types';
import { KEY_VER_INFO, KEY_AUTH_INFO } from '@app/types';
import { Sort } from '@angular/material/sort';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { tap } from 'rxjs/operators';
import {
SelectGroupDialogComponent,
SelectGroupDialogData,
SelectGroupDialogResult
} from '../../dialogs/group/select-group.dialog.component';
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
@Component({
selector: 'app-layout-messenger-organization',
@ -36,8 +48,13 @@ import { Sort } from '@angular/material/sort';
export class OrganizationComponent implements OnInit, OnDestroy {
@Output()
openProfile = new EventEmitter<number>();
@Output()
createConference = new EventEmitter<number[]>();
loginRes: LoginResponse;
loginResSubscription: Subscription;
sessionVerinfo: VersionInfo2Response;
authInfo: AuthResponse;
isSearch: boolean;
isSearchSubscription: Subscription;
@ -47,7 +64,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
departmentUserInfoListSubscription: Subscription;
searchDepartmentUserInfoListSubscription: Subscription;
selectedDepartmentUserInfoList: UserInfoSS[] = [];
departmentUserInfoList: UserInfoSS[] = [];
selectedUserList: UserInfoSS[] = []; // selected user in departmentUserList detail
profileImageRoot: string;
presence$: Observable<StatusBulkInfo[]>;
@ -64,9 +83,19 @@ export class OrganizationComponent implements OnInit, OnDestroy {
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO
);
this.authInfo = this.sessionStorageService.get<AuthResponse>(KEY_AUTH_INFO);
}
ngOnInit() {
this.loginResSubscription = this.store
.pipe(
select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
tap(loginRes => {
this.loginRes = loginRes;
})
)
.subscribe();
this.isSearchSubscription = this.store
.pipe(select(AppStore.MessengerSelector.QuerySelector.isSearch))
.subscribe(isSearch => {
@ -89,7 +118,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
)
.subscribe(list => {
if (!this.isSearch) {
this.selectedDepartmentUserInfoList = list;
this.departmentUserInfoList = list;
}
});
@ -101,7 +130,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
)
.subscribe(list => {
if (!!this.isSearch) {
this.selectedDepartmentUserInfoList = list;
this.departmentUserInfoList = list;
}
});
@ -113,6 +142,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
if (!!this.loginResSubscription) {
this.loginResSubscription.unsubscribe();
}
if (!!this.isSearchSubscription) {
this.isSearchSubscription.unsubscribe();
}
@ -124,6 +156,97 @@ export class OrganizationComponent implements OnInit, OnDestroy {
}
}
/** 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) {
const seq: number[] = [];
this.selectedUserList.map(user => seq.push(user.seq));
this.store.dispatch(ChatStore.openRoom({ userSeqList: seq }));
}
}
onClickConference() {
const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq);
this.createConference.emit(targetUserSeqs);
}
onClickOpenProfile(userSeq: number) {
this.openProfile.emit(userSeq);
}

View File

@ -29,6 +29,7 @@
[selectedChat]="this.selectedChat$ | async"
(openProfile)="onClickOpenProfile($event)"
(closeRightDrawer)="onCloseRightDrawer()"
(createConference)="conferenceCreate($event)"
>
</app-layout-messenger-main-contents>
<button

View File

@ -138,8 +138,9 @@
<td mat-cell *matCellDef="let element">
<mat-checkbox
#checkbox
[checked]="getCheckedAllUser()"
(change)="onCheckAllUser(checkbox.checked)"
*ngIf="loginRes.userSeq !== element.seq"
[checked]="getCheckedUser(element)"
(change)="onToggleUser(checkbox.checked, element)"
(click)="$event.stopPropagation()"
>
</mat-checkbox>

View File

@ -1,4 +1,11 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ChangeDetectorRef
} from '@angular/core';
import { NGXLogger } from 'ngx-logger';
import { UserInfoSS } from '@ucap-webmessenger/protocol-query';
import { PresenceType, StatusCode } from '@ucap-webmessenger/core';
@ -7,6 +14,7 @@ import {
StatusBulkInfo
} from '@ucap-webmessenger/protocol-status';
import { Sort } from '@angular/material/sort';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
@Component({
selector: 'ucap-organization-detail-table',
@ -14,12 +22,13 @@ import { Sort } from '@angular/material/sort';
styleUrls: ['./detail-table.component.scss']
})
export class DetailTableComponent implements OnInit {
@Input('selectedDepartmentUserInfoList')
@Input('departmentUserInfoList')
set userInfoListIn(userInfo: UserInfoSS[]) {
this.selectedDepartmentUserInfoList = userInfo;
this.departmentUserInfoList = userInfo;
this.sortedData = userInfo;
}
@Input()
loginRes: LoginResponse;
@Input()
presence: StatusBulkInfo[];
@Input()
@ -30,19 +39,14 @@ export class DetailTableComponent implements OnInit {
@Output()
openProfile = new EventEmitter<number>();
@Output()
checkUser = new EventEmitter<{
isChecked: boolean;
userInfo: UserInfoSS;
}>();
@Output()
toggleUser = new EventEmitter<UserInfoSS>();
@Output()
checkAllUser = new EventEmitter<{
toggleAllUser = new EventEmitter<{
isChecked: boolean;
userInfos: UserInfoSS[];
}>();
@Output()
toggleUser = new EventEmitter<UserInfoSS>();
selectedDepartmentUserInfoList: UserInfoSS[];
departmentUserInfoList: UserInfoSS[];
sortedData: UserInfoSS[] = [];
PresenceType = PresenceType;
@ -55,7 +59,10 @@ export class DetailTableComponent implements OnInit {
'checkable'
];
constructor(private logger: NGXLogger) {}
constructor(
private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger
) {}
ngOnInit() {}
@ -158,7 +165,7 @@ export class DetailTableComponent implements OnInit {
}
sortData(sort: Sort) {
const data = this.selectedDepartmentUserInfoList.slice();
const data = this.departmentUserInfoList.slice();
if (!sort.active || sort.direction === '') {
this.sortedData = data;
return;
@ -196,43 +203,61 @@ export class DetailTableComponent implements OnInit {
/** 전체 체크여부 */
getCheckedAllUser() {
// if (!this.loginRes) {
// return false;
// }
// const compareList: UserInfoSS[] = this.isShowSearch
// ? this.searchUserInfos
// : this.selectedDepartmentUserInfoList;
// if (
// !compareList ||
// compareList.length === 0 ||
// compareList
// .filter(item => item.seq !== this.loginRes.userSeq)
// .filter(
// item =>
// !(
// this.selectedUserList.filter(user => user.seq === item.seq)
// .length > 0
// )
// ).length > 0
// ) {
// return false;
// } else {
// return true;
// }
if (!this.loginRes) {
return false;
}
const compareList: UserInfoSS[] = this.departmentUserInfoList;
if (
!compareList ||
compareList.length === 0 ||
compareList
.filter(item => item.seq !== this.loginRes.userSeq)
.filter(
item =>
!(
this.selectedUserList.filter(user => user.seq === item.seq)
.length > 0
)
).length > 0
) {
return false;
} else {
return true;
}
}
/** 전체선택 이벤트 */
onCheckAllUser(value: boolean) {
// if (!this.loginRes) {
// return false;
// }
// this.checkAllUser.emit({
// isChecked: value,
// userInfos: (this.isShowSearch
// ? this.searchUserInfos
// : this.selectedDepartmentUserInfoList
// ).filter(user => user.seq !== this.loginRes.userSeq)
// });
// this.changeDetectorRef.detectChanges();
if (!this.loginRes) {
return false;
}
this.toggleAllUser.emit({
isChecked: value,
userInfos: this.departmentUserInfoList.filter(
user => user.seq !== this.loginRes.userSeq
)
});
this.changeDetectorRef.detectChanges();
}
/** 개별 체크여부 */
getCheckedUser(userInfo: UserInfoSS) {
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
return (
this.selectedUserList.filter(item => item.seq === userInfo.seq).length >
0
);
}
return false;
}
/** 개별선택(토글) 이벤트 */
onToggleUser(isChecked: boolean, userInfo: UserInfoSS) {
console.log(isChecked, userInfo);
if (!this.loginRes || userInfo.seq === this.loginRes.userSeq) {
return;
}
this.toggleUser.emit(userInfo);
}
onClickOpenProfile(event: MouseEvent, userSeq: number) {